diff --git a/include/obj/bhkConstraint.h b/include/obj/bhkConstraint.h index eb9e701e8f663783a64c1fa7ab7d2cc94c2f3389..8fdf8f2ab74c114fd7a3807d30a1b31a9b53f318 100644 --- a/include/obj/bhkConstraint.h +++ b/include/obj/bhkConstraint.h @@ -55,6 +55,27 @@ public: NIFLIB_API virtual const Type & GetType() const; //--BEGIN MISC CUSTOM CODE--// + + /*! + * Adds an entity to this bhkConstraint. + */ + NIFLIB_API void AddEntity( bhkEntity * obj ); + + /*! + * Removes an entity from this bhkConstraint. + */ + NIFLIB_API void RemoveEntity( bhkEntity * obj ); + + /*! + * Removes all entities from this bhkConstraint. + */ + NIFLIB_API void ClearEntities(); + + /*! + * Retrieves all the entities attached to this bhkConstraint. + */ + NIFLIB_API vector< bhkEntity * > GetEntities() const; + //--END CUSTOM CODE--// protected: /*! Number of bodies affected by this constraint. */ diff --git a/include/obj/bhkRigidBody.h b/include/obj/bhkRigidBody.h index 9d2eb8b828c995e59e8dba5aae7a07c07a284cbe..835dd1c08d6503c428121843508c85ee4e80fac3 100644 --- a/include/obj/bhkRigidBody.h +++ b/include/obj/bhkRigidBody.h @@ -290,6 +290,26 @@ public: // \param[in] value The new value. NIFLIB_API void SetSolverDeactivation( const SolverDeactivation & value ); + /*! + * Adds a constraint to this bhkRigidBody. + */ + NIFLIB_API void AddConstraint( bhkSerializable * obj ); + + /*! + * Removes a constraint from this bhkRigidBody. + */ + NIFLIB_API void RemoveConstraint( bhkSerializable * obj ); + + /*! + * Removes all constraints from this bhkRigidBody. + */ + NIFLIB_API void ClearConstraints(); + + /*! + * Retrieves all the constraints attached to this bhkRigidBody. + */ + NIFLIB_API vector< Ref<bhkSerializable> > GetConstraints() const; + // Apply scale factor <scale> on data. // \param[in] scale Factor to scale by NIFLIB_API void ApplyScale(float scale); diff --git a/src/niflib.cpp b/src/niflib.cpp index ed6393adf16859c6861d453f830c4abbd3f65b32..680ce248f5a1e3a7150273f8f062d444274be182 100644 --- a/src/niflib.cpp +++ b/src/niflib.cpp @@ -31,8 +31,7 @@ All rights reserved. Please see niflib.h for license. */ #include "../include/obj/NiMultiTargetTransformController.h" #include "../include/obj/NiStringExtraData.h" #include "../include/obj/NiExtraData.h" -#include "../include/obj/bhkRigidBody.h" -#include "../include/obj/bhkCollisionObject.h" +#include "../include/obj/bhkConstraint.h" #include "../include/gen/Header.h" #include "../include/gen/Footer.h" @@ -43,7 +42,8 @@ bool g_objects_registered = false; void RegisterObjects(); //Utility Functions -void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map, bool reverse = false ); +bool BlockChildBeforeParent( NiObject * root ); +void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map ); NiObjectRef FindRoot( vector<NiObjectRef> const & objects ); NiObjectRef GetObjectByType( NiObject * root, const Type & type ); @@ -577,50 +577,62 @@ void WriteNifTree( ostream & out, NiObject * root, const NifInfo & info ) { WriteNifTree( out, roots, info ); } -void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map, bool reverse ) { - //Ensure that this object has not already been visited +// Determine whether block comes before its parent or not, depending on the block type. +// return: 'True' if child should come first, 'False' otherwise. +bool BlockChildBeforeParent( NiObject * root ) { + Type *t = (Type*)&(root->GetType()); + return (t->IsDerivedType(bhkRefObject::TYPE) && !t->IsDerivedType(bhkConstraint::TYPE)); +} + +// This is a helper function for write to set up the list of all blocks, +// the block index map, and the block type map. +void EnumerateObjects( NiObject * root, map<Type*,unsigned int> & type_map, map<NiObjectRef, unsigned int> & link_map ) { + // Ensure that this object has not already been visited if ( link_map.find( root ) != link_map.end() ) { //This object has already been visited. Return. return; } - //Add this object type to the map if it isn't there already - if ( type_map.find( (Type*)&(root->GetType()) ) == type_map.end() ) { - //The type has not yet been registered, so register it - unsigned int n = type_map.size(); - type_map[ (Type*)&(root->GetType()) ] = n; + list<NiObjectRef> links = root->GetRefs(); + Type *t = (Type*)&(root->GetType()); + + // special case: add bhkConstraint entities before bhkConstraint + // (these are actually links, not refs) + if ( t->IsDerivedType(bhkConstraint::TYPE) ) { + vector< bhkEntity * > entities = ((bhkConstraint *)root)->GetEntities(); + for ( vector< bhkEntity * >::iterator it = entities.begin(); it != entities.end(); ++it ) { + if ( *it != NULL ) { + EnumerateObjects( (NiObject*)(*it), type_map, link_map ); + } + } } - // Oblivion has very rigid requirements about object ordering and the bhkRigidBody - // must be after its children. Hopefully this can be removed and replaced with - // a more generic mechanism in the future. - Type *t = (Type*)&(root->GetType()); - if ( reverse - || t->IsDerivedType(bhkRigidBody::TYPE) - || t->IsDerivedType(bhkCollisionObject::TYPE) - ) - { - reverse = true; - } + // Call this function on all links of this object + // add children that come before the block + for ( list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) { + if ( *it != NULL && BlockChildBeforeParent(*it) ) { + EnumerateObjects( *it, type_map, link_map ); + } + } - // If reverse is set then add the link after children otherwise add it before - if (!reverse) { - unsigned int n = link_map.size(); - link_map[root] = n; - } + // Add this object type to the map if it isn't there already + // TODO: add support for NiDataStreams + if ( type_map.find(t) == type_map.end() ) { + //The type has not yet been registered, so register it + unsigned int n = type_map.size(); + type_map[t] = n; + } - //Call this function on all links of this object - list<NiObjectRef> links = root->GetRefs(); - for ( list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) { - if ( *it != NULL ) { - EnumerateObjects( *it, type_map, link_map, reverse ); - } - } + // add the block + unsigned int n = link_map.size(); + link_map[root] = n; - if (reverse) { - unsigned int n = link_map.size(); - link_map[root] = n; - } + // add children that come after the block + for ( list<NiObjectRef>::iterator it = links.begin(); it != links.end(); ++it ) { + if ( *it != NULL && !BlockChildBeforeParent(*it) ) { + EnumerateObjects( *it, type_map, link_map ); + } + } } //TODO: Should this be returning an object of a derived type too? diff --git a/src/obj/bhkConstraint.cpp b/src/obj/bhkConstraint.cpp index 0409924d747beec0ecf859a409cd484cbc5535b6..31cf7299075734146fcf85acdbb62182e47c31ec 100644 --- a/src/obj/bhkConstraint.cpp +++ b/src/obj/bhkConstraint.cpp @@ -145,4 +145,28 @@ std::list<NiObject *> bhkConstraint::GetPtrs() const { } //--BEGIN MISC CUSTOM CODE--// + +void bhkConstraint::AddEntity( bhkEntity * obj ) { + entities.push_back( obj ); +} + +void bhkConstraint::RemoveEntity( bhkEntity * obj ) { + //Search Effect list for the one to remove + for ( vector< bhkEntity * >::iterator it = entities.begin(); it != entities.end(); ) { + if ( *it == obj ) { + it = entities.erase( it ); + } else { + ++it; + } + } +} + +void bhkConstraint::ClearEntities() { + entities.clear(); +} + +vector< bhkEntity * > bhkConstraint::GetEntities() const { + return entities; +} + //--END CUSTOM CODE--// diff --git a/src/obj/bhkRigidBody.cpp b/src/obj/bhkRigidBody.cpp index 4d8a299b3ca3dd3c348a60019c5f10e566e41bfd..267355db9180ec7338386666b9cfc724c0b8a4e3 100644 --- a/src/obj/bhkRigidBody.cpp +++ b/src/obj/bhkRigidBody.cpp @@ -447,6 +447,28 @@ void bhkRigidBody::SetSolverDeactivation( const SolverDeactivation & value ) { solverDeactivation = value; } +void bhkRigidBody::AddConstraint( bhkSerializable * obj ) { + constraints.push_back( obj ); +} + +void bhkRigidBody::RemoveConstraint( bhkSerializable * obj ) { + //Search Effect list for the one to remove + for ( vector< bhkSerializableRef >::iterator it = constraints.begin(); it != constraints.end(); ) { + if ( *it == obj ) { + it = constraints.erase( it ); + } else { + ++it; + } + } +} + +void bhkRigidBody::ClearConstraints() { + constraints.clear(); +} + +vector< Ref<bhkSerializable> > bhkRigidBody::GetConstraints() const { + return constraints; +} // Apply scale factor <scale> on data.