From 72d87b7cc5426d91553809a46b6b379a5a976e1f Mon Sep 17 00:00:00 2001 From: Shon Ferguson <shonferg@users.sourceforge.net> Date: Tue, 6 Jun 2006 01:31:36 +0000 Subject: [PATCH] More functions implemented. NiNode and NiObjectNET are now good examples of how to deal with pointers. With implementation of NiNode::GetChildren function, I was able to re-enable the building up of the bind position. --- gen/obj_defines.h | 4 ++-- niflib.cpp | 30 +++++++++++++++--------------- obj/NiAVObject.cpp | 7 +++++-- obj/NiAVObject.h | 3 +-- obj/NiNode.cpp | 35 ++++++++++++++++++++++++++++++++++- obj/NiNode.h | 6 ++++++ obj/NiObjectNET.cpp | 12 +++++++++++- obj/NiTimeController.cpp | 10 +++++++++- obj/NiTimeController.h | 12 ++++++++++++ 9 files changed, 95 insertions(+), 24 deletions(-) diff --git a/gen/obj_defines.h b/gen/obj_defines.h index b42cf597..e615342a 100644 --- a/gen/obj_defines.h +++ b/gen/obj_defines.h @@ -1399,7 +1399,7 @@ float frequency; \ float phase; \ float startTime; \ float stopTime; \ -NiObject * target; \ +NiObjectNET * target; \ #define NI_TIME_CONTROLLER_INCLUDE "NiObject.h" \ @@ -1463,7 +1463,7 @@ link_stack.pop_front(); \ if (link_stack.empty()) \ throw runtime_error("Trying to pop a link from empty stack. This is probably a bug."); \ if (link_stack.front() != 0xffffffff) { \ - target = DynamicCast<NiObject>(objects[link_stack.front()]); \ + target = DynamicCast<NiObjectNET>(objects[link_stack.front()]); \ if ( target == NULL ) \ throw runtime_error("Link could not be cast to required type during file read. This NIF file may be invalid or improperly understood."); \ } else \ diff --git a/niflib.cpp b/niflib.cpp index f3508d44..4a81f07a 100644 --- a/niflib.cpp +++ b/niflib.cpp @@ -17,7 +17,7 @@ map<string, blk_factory_func> global_block_map; //Utility Functions void EnumerateObjects( NiObjectRef const & root, map<Type*,uint> & type_map, map<NiObjectRef, uint> & link_map ); -void BuildUpBindPositions( const NiAVObjectRef & av ); +void BuildUpBindPositions( const NiAVObjectRef & root ); NiObjectRef FindRoot( vector<NiObjectRef> const & blocks ); void RegisterBlockFactories (); NiObjectRef GetObjectByType( const NiObjectRef & root, const Type & block_type ); @@ -509,30 +509,30 @@ void EnumerateObjects( NiObjectRef const & root, map<Type*,uint> & type_map, map } } -void BuildUpBindPositions( const NiAVObjectRef & av ) { +void BuildUpBindPositions( const NiAVObjectRef & root ) { //Get parent if there is one - NiNodeRef par = av->GetParent(); + NiNodeRef par = root->GetParent(); if ( par != NULL ) { //There is a node parent //Post-multipy the block's bind matrix with the parent's bind matrix - Matrix44 result = av->GetWorldBindPos() * par->GetWorldBindPos(); + Matrix44 result = root->GetWorldBindPos() * par->GetWorldBindPos(); //Store result back to block bind position - av->SetWorldBindPos( result ); + root->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<NiObjectRef> children = child_attr->asLinkList(); - // list<NiObjectRef>::iterator it; - // for (it = children.begin(); it != children.end(); ++it) { - // BuildUpBindPositions( *it ); - // } - //} + //If this is a NiNode, call this function for all child AVObjects + NiNodeRef node = DynamicCast<NiNode>(root); + if ( node != NULL ) { + vector<NiAVObjectRef> children = node->GetChildren(); + for (vector<NiAVObjectRef>::iterator it = children.begin(); it != children.end(); ++it) { + if ( *it != NULL ) { + BuildUpBindPositions( *it ); + } + } + } } //TODO: Should this be returning an object of a derived type too? diff --git a/obj/NiAVObject.cpp b/obj/NiAVObject.cpp index 62ab0c8d..4e790b29 100644 --- a/obj/NiAVObject.cpp +++ b/obj/NiAVObject.cpp @@ -12,7 +12,10 @@ const Type NiAVObject::TYPE("NiAVObject", &NI_A_V_OBJECT_PARENT::TYPE ); NiAVObject::NiAVObject() NI_A_V_OBJECT_CONSTRUCT, parent(NULL) {} -NiAVObject::~NiAVObject() {} +NiAVObject::~NiAVObject() { + //Clear Properties + ClearProperties(); +} void NiAVObject::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { NI_A_V_OBJECT_READ @@ -93,7 +96,7 @@ Matrix44 NiAVObject::GetLocalBindPos() const { */ void NiAVObject::SetWorldBindPos( Matrix44 const & m ) {} -void NiAVObject::SetParent( Ref<NiNode> new_parent ) { +void NiAVObject::SetParent( NiNode * new_parent ) { parent = new_parent; } diff --git a/obj/NiAVObject.h b/obj/NiAVObject.h index 08f8fe6f..6d4214e3 100644 --- a/obj/NiAVObject.h +++ b/obj/NiAVObject.h @@ -36,7 +36,6 @@ public: virtual void FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ); virtual list<NiObjectRef> GetRefs() const; - //TODO: list of NiProperty pointers. Need functions to add/remove. //TODO: Bounding Box. What to do with newer files that have a link? Wrap this in a function and translate? /*! @@ -74,7 +73,7 @@ public: void SetWorldBindPos( Matrix44 const & m ); /*! Meant to be called by NiNode during the addition of new children. Should not be called directly. */ - void SetParent( Ref<NiNode> new_parent ); + void SetParent( NiNode * new_parent ); Ref<NiNode> GetParent() const; diff --git a/obj/NiNode.cpp b/obj/NiNode.cpp index 69645d24..e98f6134 100644 --- a/obj/NiNode.cpp +++ b/obj/NiNode.cpp @@ -10,7 +10,10 @@ const Type NiNode::TYPE("NiNode", &NI_NODE_PARENT::TYPE ); NiNode::NiNode() NI_NODE_CONSTRUCT {} -NiNode::~NiNode() {} +NiNode::~NiNode() { + //Clear Children + ClearChildren(); +} void NiNode::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { NI_NODE_READ @@ -36,3 +39,33 @@ const Type & NiNode::GetType() const { return TYPE; }; +void NiNode::AddChild( Ref<NiAVObject> & obj ) { + if ( obj->GetParent() != NULL ) { + throw runtime_error( "You have attempted to add a child to a NiNode which already is the child of another NiNode." ); + } + obj->SetParent( this ); + children.push_back( obj ); +} + +void NiNode::RemoveChild( Ref<NiAVObject> obj ) { + //Search child list for the one to remove + for ( vector< NiAVObjectRef >::iterator it = children.begin(); it != children.end(); ) { + if ( *it == obj ) { + (*it)->SetParent(NULL); + it = children.erase( it ); + } else { + ++it; + } + } +} + +void NiNode::ClearChildren() { + for ( vector< NiAVObjectRef >::iterator it = children.begin(); it != children.end(); ) { + (*it)->SetParent(NULL); + } + children.clear(); +} + +vector< Ref<NiAVObject> > NiNode::GetChildren() const { + return children; +} diff --git a/obj/NiNode.h b/obj/NiNode.h index 57f80936..7fee411f 100644 --- a/obj/NiNode.h +++ b/obj/NiNode.h @@ -14,6 +14,7 @@ class NiDynamicEffect; #include "../gen/obj_defines.h" class NiNode; +class NiAVObject; typedef Ref<NiNode> NiNodeRef; /*! @@ -32,6 +33,11 @@ public: virtual void FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ); virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; + + void AddChild( Ref<NiAVObject> & obj ); + void RemoveChild( Ref<NiAVObject> obj ); + void ClearChildren(); + vector< Ref<NiAVObject> > GetChildren() const; protected: NI_NODE_MEMBERS }; diff --git a/obj/NiObjectNET.cpp b/obj/NiObjectNET.cpp index e40044b8..7efe516f 100644 --- a/obj/NiObjectNET.cpp +++ b/obj/NiObjectNET.cpp @@ -10,7 +10,11 @@ const Type NiObjectNET::TYPE("NiObjectNET", &NI_OBJECT_N_E_T_PARENT::TYPE ); NiObjectNET::NiObjectNET() NI_OBJECT_N_E_T_CONSTRUCT {} -NiObjectNET::~NiObjectNET() {} +NiObjectNET::~NiObjectNET() { + //Clear Lists + ClearExtraData(); + ClearControllers(); +} void NiObjectNET::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { NI_OBJECT_N_E_T_READ @@ -129,6 +133,7 @@ list< Ref<NiExtraData> > NiObjectNET::GetExtraData() const { void NiObjectNET::AddController( Ref<NiTimeController> & obj ) { //Insert at begining of list + obj->SetTarget( this ); obj->SetNextController( controller ); controller = obj; } @@ -138,6 +143,7 @@ void NiObjectNET::RemoveController( Ref<NiTimeController> obj ) { while ( (*cont) != NULL ) { if ( (*cont) == obj ) { //Cut this reference out of the list + (*cont)->SetTarget( NULL ); (*cont) = (*cont)->GetNextController(); } else { //Advance to the next controller @@ -146,6 +152,10 @@ void NiObjectNET::RemoveController( Ref<NiTimeController> obj ) { } } void NiObjectNET::ClearControllers() { + NiTimeControllerRef cont = controller; + while ( cont != NULL ) { + cont->SetTarget(NULL); + } controller = NULL; } diff --git a/obj/NiTimeController.cpp b/obj/NiTimeController.cpp index 9fa87f72..f2addda8 100644 --- a/obj/NiTimeController.cpp +++ b/obj/NiTimeController.cpp @@ -2,7 +2,7 @@ All rights reserved. Please see niflib.h for licence. */ #include "NiTimeController.h" -#include "NiObject.h" +#include "NiObjectNET.h" //Definition of TYPE constant const Type NiTimeController::TYPE("NiTimeController", &NI_TIME_CONTROLLER_PARENT::TYPE ); @@ -42,3 +42,11 @@ NiTimeControllerRef NiTimeController::GetNextController() const { void NiTimeController::SetNextController( const NiTimeControllerRef & obj ) { nextController = obj; } + +void NiTimeController::SetTarget( NiObjectNET * new_target ) { + target = new_target; +} + +Ref<NiObjectNET> NiTimeController::GetTarget() { + return target; +} diff --git a/obj/NiTimeController.h b/obj/NiTimeController.h index 3576dd3a..0af01fb0 100644 --- a/obj/NiTimeController.h +++ b/obj/NiTimeController.h @@ -13,6 +13,7 @@ class NiObject; #include "../gen/obj_defines.h" class NiTimeController; +class NiObjectNET; typedef Ref<NiTimeController> NiTimeControllerRef; /*! @@ -43,6 +44,17 @@ public: * \param obj A reference to the object to set as the one after this in the chain. */ void SetNextController( const NiTimeControllerRef & obj ); + + /*! This function should only be called by NiObjectNET. It sets the target of + * this controller when it is attatched to the NiObjectNET class. */ + void SetTarget( NiObjectNET * new_target ); + + /*! This function returns the current target NiObjectNET, if any, that this controller + * is acting on. + * \return A reference to the current target of this controller. + */ + Ref<NiObjectNET> GetTarget(); + protected: NI_TIME_CONTROLLER_MEMBERS }; -- GitLab