diff --git a/Ref.h b/Ref.h index 3c64d134da78550e0e420b3f97056ddfd27a90d6..fc153ff0dc1aae385b73186065dfa560c2c98f36 100644 --- a/Ref.h +++ b/Ref.h @@ -103,6 +103,11 @@ Ref<T> & Ref<T>::operator=( T * object ) { return *this; //Do nothing } + //Increment reference count on new object if it is not NULL + if ( object != NULL ) { + object->AddRef(); + } + //Decriment reference count on previously referenced object, if any if ( _object != NULL ) { _object->SubtractRef(); @@ -111,11 +116,6 @@ Ref<T> & Ref<T>::operator=( T * object ) { //Change reference to new object _object = object; - //Increment reference count on new object if it is not NULL - if ( _object != NULL ) { - _object->AddRef(); - } - return *this; } @@ -127,6 +127,11 @@ Ref<T> & Ref<T>::operator=( const Ref & ref ) { return *this; //Do nothing } + //Increment reference count on new object if it is not NULL + if ( ref._object != NULL ) { + ref._object->AddRef(); + } + //Decriment reference count on previously referenced object, if any if ( _object != NULL ) { _object->SubtractRef(); @@ -135,11 +140,6 @@ Ref<T> & Ref<T>::operator=( const Ref & ref ) { //Change reference to new object _object = ref._object; - //Increment reference count on new object if it is not NULL - if ( _object != NULL ) { - _object->AddRef(); - } - return *this; } #endif diff --git a/nif_math.cpp b/nif_math.cpp index 28995d50bd8908aa9128de195dd32b050510371c..60a428120cadb99d38e1d05e9bf6eb3ffc0dbc48 100644 --- a/nif_math.cpp +++ b/nif_math.cpp @@ -393,7 +393,7 @@ float Matrix44::Determinant() const { - t[0][3] * Submatrix(0, 3).Determinant(); } -void Matrix44::Decompose( Vector3 & translate, Matrix33 & rotation, Float3 & scale ) const { +void Matrix44::Decompose( Vector3 & translate, Matrix33 & rotation, float & scale ) const { translate = Vector3( (*this)[3][0], (*this)[3][1], (*this)[3][2] ); Matrix33 rotT; for ( int i = 0; i < 3; i++ ){ @@ -403,12 +403,15 @@ void Matrix44::Decompose( Vector3 & translate, Matrix33 & rotation, Float3 & sca } } Matrix33 mtx = rotation * rotT; - scale = Float3( sqrt(mtx[0][0]), sqrt(mtx[1][1]), sqrt(mtx[2][2]) ); + Float3 scale3( sqrt(mtx[0][0]), sqrt(mtx[1][1]), sqrt(mtx[2][2]) ); for ( int i = 0; i < 3; i++ ){ for ( int j = 0; j < 3; j++ ){ - rotation[i][j] /= scale[i]; + rotation[i][j] /= scale3[i]; } } + + //averate the scale since NIF doesn't support discreet scaling + scale = scale3[0] + scale3[1] + scale3[2] / 3.0f; } /* * Quaternion Methods diff --git a/nif_math.h b/nif_math.h index 3811d18bffaeb0597df99b120d344b19ac20da1a..49224082324dfff6d516f6c2b04e28902328cae2 100644 --- a/nif_math.h +++ b/nif_math.h @@ -744,7 +744,7 @@ struct Matrix44 { } // undocumented - NIFLIB_API void Decompose( Vector3 & translate, Matrix33 & rotation, Float3 & scale ) const; + NIFLIB_API void Decompose( Vector3 & translate, Matrix33 & rotation, float & scale ) const; //Python Operator Overloads NIFLIB_API Float4 & __getitem__(int n) { diff --git a/obj/NiNode.cpp b/obj/NiNode.cpp index 1b0bfadbc6061be7a812456f91d1cb9edaebd5a2..daa96dcf5b187f4dff79a4beba2ac58716c32b62 100644 --- a/obj/NiNode.cpp +++ b/obj/NiNode.cpp @@ -170,7 +170,7 @@ void NiNode::GoToSkeletonBindPosition() { //Loop through all attached skins, straightening the skeleton on each for ( list<NiSkinInstance*>::iterator it = skins.begin(); it != skins.end(); ++it ) { //Get Bone list and Skin Data - vector<NiNodeRef> bones = (*it)->GetBones(); + vector<NiNodeRef> bone_nodes = (*it)->GetBones(); NiSkinDataRef skin_data = (*it)->GetSkinData(); if ( skin_data == NULL ) { @@ -178,59 +178,32 @@ void NiNode::GoToSkeletonBindPosition() { continue; } - //Get bone data from NiSkinData class - vector<SkinData> bone_data = skin_data->GetBoneData(); - //Make sure the counts match - if ( bones.size() != bone_data.size() ) { + if ( bone_nodes.size() != skin_data->GetBoneCount() ) { throw runtime_error( "Bone counts in NiSkinInstance and attached NiSkinData must match" ); } //Loop through all bones influencing this skin - for ( uint i = 0; i < bones.size(); ++i ) { + for ( uint i = 0; i < bone_nodes.size(); ++i ) { //Get current offset Matrix for this bone - //Matrix44 parent_offset( bone_data[i].translation, - // bone_data[i].rotation, - // bone_data[i].scale ); - Matrix44 parent_offset( - bone_data[i].rotation[0][0], bone_data[i].rotation[0][1], bone_data[i].rotation[0][2], 0.0f, - bone_data[i].rotation[1][0], bone_data[i].rotation[1][1], bone_data[i].rotation[1][2], 0.0f, - bone_data[i].rotation[2][0], bone_data[i].rotation[2][1], bone_data[i].rotation[2][2], 0.0f, - bone_data[i].translation.x, bone_data[i].translation.y, bone_data[i].translation.z, 1.0f - ); + Matrix44 parent_offset = skin_data->GetBoneTransform(i); //Loop through all bones again, checking for any that have this bone as a parent - for ( uint j = 0; j < bones.size(); ++j ) { - if ( bones[j]->GetParent() == bones[i] ) { + for ( uint j = 0; j < bone_nodes.size(); ++j ) { + if ( bone_nodes[j]->GetParent() == bone_nodes[i] ) { //cout << "Bone " << bones[j] << " has bone " << bones[i] << " as parent." << endl; //Node 2 has node 1 as a parent //Get child offset Matrix33 - /*Matrix44 child_offset( bone_data[j].translation, - bone_data[j].rotation, - bone_data[j].scale );*/ - Matrix44 child_offset( - bone_data[j].rotation[0][0], bone_data[j].rotation[0][1], bone_data[j].rotation[0][2], 0.0f, - bone_data[j].rotation[1][0], bone_data[j].rotation[1][1], bone_data[j].rotation[1][2], 0.0f, - bone_data[j].rotation[2][0], bone_data[j].rotation[2][1], bone_data[j].rotation[2][2], 0.0f, - bone_data[j].translation.x, bone_data[j].translation.y, bone_data[j].translation.z, 1.0f - ); + Matrix44 child_offset = skin_data->GetBoneTransform(j); //Do calculation to get correct bone postion in relation to parent - //Matrix44 inverse_co = child_offset.Inverse(); - //world_positions[bones[j]] = inverse_co * parent_offset; - Matrix44 inverse_co = child_offset.Inverse(); - Matrix44 child_pos = inverse_co * parent_offset; + Matrix44 child_pos = child_offset.Inverse() * parent_offset; //bones[j]->SetWorldBindPos( child_pos ); - bones[j]->SetLocalRotation( child_pos.GetRotation() ); - bones[j]->SetLocalScale( 1.0f ); - bones[j]->SetLocalTranslation( child_pos.GetTranslation() ); - - //cout << "Matrix: " << cout << "Translation: " << world_positions[bones[j]] << endl; - //cout << "Translation: " << world_positions[bones[j]].GetTranslation() << endl; - //cout << "Rotation: " << world_positions[bones[j]].GetRotation() << endl; - //cout << "Scale: " << world_positions[bones[j]].GetScale() << endl; + bone_nodes[j]->SetLocalRotation( child_pos.GetRotation() ); + bone_nodes[j]->SetLocalScale( 1.0f ); + bone_nodes[j]->SetLocalTranslation( child_pos.GetTranslation() ); } } } @@ -261,30 +234,24 @@ void NiNode::RepositionGeom( NiAVObjectRef root ) { return; } - //Get bone info - vector<NiNodeRef> bones = skin_inst->GetBones(); - vector<SkinData> bone_data = skin_data->GetBoneData(); + //Get bone nodes + vector<NiNodeRef> bone_nodes = skin_inst->GetBones(); //Make sure the counts match - if ( bones.size() != bone_data.size() ) { + if ( bone_nodes.size() != skin_data->GetBoneCount() ) { throw runtime_error( "Bone counts in NiSkinInstance and attached NiSkinData must match" ); } //There must be at least one bone to do anything - if ( bones.size() == 0 ) { + if ( bone_nodes.size() == 0 ) { return; } //Use first bone (arbitrary choice) - Matrix44 offset_mat( - bone_data[0].rotation[0][0], bone_data[0].rotation[0][1], bone_data[0].rotation[0][2], 0.0f, - bone_data[0].rotation[1][0], bone_data[0].rotation[1][1], bone_data[0].rotation[1][2], 0.0f, - bone_data[0].rotation[2][0], bone_data[0].rotation[2][1], bone_data[0].rotation[2][2], 0.0f, - bone_data[0].translation.x, bone_data[0].translation.y, bone_data[0].translation.z, 1.0f - ); + Matrix44 offset_mat = skin_data->GetBoneTransform(0); //Get built up rotations to the root of the skeleton from this bone - Matrix44 bone_mat = bones[0]->GetWorldTransform(); + Matrix44 bone_mat = bone_nodes[0]->GetWorldTransform(); Matrix44 world_mat = offset_mat * bone_mat; diff --git a/obj/NiObject.cpp b/obj/NiObject.cpp index 5a392431ecc0e3ca2e4fa2c62a6c58a24ad5c255..809855645af1146c433da3866c05066e6361b402 100644 --- a/obj/NiObject.cpp +++ b/obj/NiObject.cpp @@ -34,7 +34,7 @@ void NiObject::AddRef() const { } void NiObject::SubtractRef() const { - if ( --_ref_count == 0 ) { + if ( _ref_count-- == 0 ) { delete this; } } diff --git a/obj/NiSkinData.cpp b/obj/NiSkinData.cpp index fa252e0395e17ffa5885e9e3cfeadbede542096a..22933978305960558b1fd8cbdad836459faa2a2a 100644 --- a/obj/NiSkinData.cpp +++ b/obj/NiSkinData.cpp @@ -5,6 +5,8 @@ All rights reserved. Please see niflib.h for licence. */ #include "../gen/SkinData.h" #include "../gen/SkinWeight.h" #include "NiSkinPartition.h" +#include "NiTriBasedGeom.h" +#include "NiSkinInstance.h" using namespace Niflib; //Definition of TYPE constant @@ -38,21 +40,78 @@ const Type & NiSkinData::GetType() const { return TYPE; }; -void NiSkinData::SetBoneData( const vector<SkinData> & n ) { - boneList = n; +uint NiSkinData::GetBoneCount() const { + return uint( boneList.size() ); } -vector<SkinData> NiSkinData::GetBoneData() const { - return boneList; +Matrix44 NiSkinData::GetBoneTransform( uint bone_index ) const { + if ( bone_index > boneList.size() ) { + throw runtime_error( "The specified bone index was larger than the number of bones in this NiSkinData." ); + } + + return Matrix44( boneList[bone_index].translation, boneList[bone_index].rotation, boneList[bone_index].scale ); } -void NiSkinData::SetOverallTransform( const Matrix44 & n ) { - translation = n.GetTranslation(); - rotation = n.GetRotation(); - Vector3 s = n.GetScale(); - scale = s.x + s.y + s.z / 3.0f; +vector<SkinWeight> NiSkinData::GetBoneWeights( uint bone_index ) const { + if ( bone_index > boneList.size() ) { + throw runtime_error( "The specified bone index was larger than the number of bones in this NiSkinData." ); + } + + return boneList[bone_index].vertexWeights; } - + +void NiSkinData::SetBoneWeights( uint bone_index, const vector<SkinWeight> & n ) { + if ( bone_index > boneList.size() ) { + throw runtime_error( "The specified bone index was larger than the number of bones in this NiSkinData." ); + } + + boneList[bone_index].vertexWeights = n; +} + Matrix44 NiSkinData::GetOverallTransform() const { return Matrix44( translation, rotation, scale ); +} + +NiSkinData::NiSkinData( const Ref<NiTriBasedGeom> & owner ) { + //Get skin instance + NiSkinInstanceRef skinInst = owner->GetSkinInstance(); + + if ( skinInst == NULL ) { + throw runtime_error("Skin instance should have already been created."); + } + + boneList.resize( skinInst->GetBoneCount() ); + vector<NiNodeRef> bone_nodes = skinInst->GetBones(); + + //--Calculate Overall Offset--// + + //Get TriBasedGeom world transform + Matrix44 owner_mat = owner->GetWorldTransform(); + + //Get Skeleton root world transform + Matrix44 skel_root_mat = skinInst->GetSkeletonRoot()->GetWorldTransform(); + + //Inverse owner NiTriBasedGeom matrix & multiply with skeleton root matrix + Matrix44 res_mat = owner_mat.Inverse() * skel_root_mat; + + //Store result + res_mat.Decompose( translation, rotation, scale ); + + //--Calculate Bone Offsets--// + + Matrix44 bone_mat; + for (uint i = 0; i < boneList.size(); ++i ) { + //--Get Bone Bind Pose--// + + //Get bone world position + bone_mat = bone_nodes[i]->GetWorldTransform(); + + //Multiply NiTriBasedGeom matrix with inversed bone matrix + res_mat = owner_mat * bone_mat.Inverse(); + + //Store result + res_mat.Decompose( boneList[i].translation, boneList[i].rotation, boneList[i].scale ); + + //TODO: Calculate center and radius of each bone + } } \ No newline at end of file diff --git a/obj/NiSkinData.h b/obj/NiSkinData.h index b08f3d171efbbcd4c3da719cfed13e7aaf5d52bb..baa99a39266ab8a2de20f6f324beb575a60ce8c7 100644 --- a/obj/NiSkinData.h +++ b/obj/NiSkinData.h @@ -12,6 +12,7 @@ namespace Niflib { // Forward define of referenced blocks class NiSkinPartition; +class NiTriBasedGeom; #include "../gen/obj_defines.h" @@ -25,7 +26,15 @@ typedef Ref<NiSkinData> NiSkinDataRef; class NIFLIB_API NiSkinData : public NI_SKIN_DATA_PARENT { public: NiSkinData(); + + /*! + * This constructor is called by NiTriBasedGeom when it creates a new skin + * instance using the BindSkin function. + */ + NiSkinData( const Ref<NiTriBasedGeom> & owner ); + ~NiSkinData(); + //Run-Time Type Information static const Type & TypeConst() { return TYPE; } private: @@ -38,11 +47,12 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; - void SetOverallTransform( const Matrix44 & n ); Matrix44 GetOverallTransform() const; + uint GetBoneCount() const; + Matrix44 GetBoneTransform( uint bone_index ) const; + vector<SkinWeight> GetBoneWeights( uint bone_index ) const; + void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n ); - void SetBoneData( const vector<SkinData> & n ); - vector<SkinData> GetBoneData() const; protected: NI_SKIN_DATA_MEMBERS STANDARD_INTERNAL_METHODS diff --git a/obj/NiSkinInstance.cpp b/obj/NiSkinInstance.cpp index ed286738be7639fd3628d4497e4997b85d667a67..4633917f768269d480f48833f9c2d39be12b8e37 100644 --- a/obj/NiSkinInstance.cpp +++ b/obj/NiSkinInstance.cpp @@ -13,51 +13,7 @@ const Type NiSkinInstance::TYPE("NiSkinInstance", &NI_SKIN_INSTANCE_PARENT::Type NiSkinInstance::NiSkinInstance() NI_SKIN_INSTANCE_CONSTRUCT {} -NiSkinInstance::~NiSkinInstance() {} - -void NiSkinInstance::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { - NI_SKIN_INSTANCE_READ -} - -void NiSkinInstance::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { - NI_SKIN_INSTANCE_WRITE -} - -string NiSkinInstance::asString( bool verbose ) const { - NI_SKIN_INSTANCE_STRING -} - -void NiSkinInstance::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { - NI_SKIN_INSTANCE_FIXLINKS - - //Inform newly fixed skeleton root of attachment - if ( skeletonRoot != NULL ) { - skeletonRoot->AddSkin( this ); - } -} - -list<NiObjectRef> NiSkinInstance::GetRefs() const { - NI_SKIN_INSTANCE_GETREFS -} - -const Type & NiSkinInstance::GetType() const { - return TYPE; -}; - -vector< Ref<NiNode> > NiSkinInstance::GetBones() const { - vector<NiNodeRef> ref_bones( bones.size() ); - for (uint i = 0; i < bones.size(); ++i ) { - ref_bones[i] = bones[i]; - } - return ref_bones; -} - -void NiSkinInstance::Bind( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ) { - //Ensure skin is not aleady bound - if ( bones.size() != 0 ) { - throw runtime_error("You have attempted to re-bind a skin that is already bound. Unbind it first."); - } - +NiSkinInstance::NiSkinInstance( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ) NI_SKIN_INSTANCE_CONSTRUCT { //Ensure that all bones are below the skeleton root node on the scene graph for ( uint i = 0; i < bone_nodes.size(); ++i ) { bool is_decended = false; @@ -88,23 +44,48 @@ void NiSkinInstance::Bind( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone //Store skeleton root and inform it of this attachment skeletonRoot = skeleton_root; skeletonRoot->AddSkin( this ); -}; +} -void NiSkinInstance::Unbind() { +NiSkinInstance::~NiSkinInstance() { //Inform Skeleton Root of detatchment and clear it. skeletonRoot->RemoveSkin( this ); - skeletonRoot = NULL; +} - //Clear bone list - bones.clear(); +void NiSkinInstance::Read( istream& in, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NI_SKIN_INSTANCE_READ +} - //Destroy skin data - data = NULL; - skinPartition = NULL; +void NiSkinInstance::Write( ostream& out, map<NiObjectRef,uint> link_map, unsigned int version, unsigned int user_version ) const { + NI_SKIN_INSTANCE_WRITE +} + +string NiSkinInstance::asString( bool verbose ) const { + NI_SKIN_INSTANCE_STRING +} + +void NiSkinInstance::FixLinks( const vector<NiObjectRef> & objects, list<uint> & link_stack, unsigned int version, unsigned int user_version ) { + NI_SKIN_INSTANCE_FIXLINKS + + //Inform newly fixed skeleton root of attachment + if ( skeletonRoot != NULL ) { + skeletonRoot->AddSkin( this ); + } } -void NiSkinInstance::CalcHardwareSkinningData () { +list<NiObjectRef> NiSkinInstance::GetRefs() const { + NI_SKIN_INSTANCE_GETREFS +} + +const Type & NiSkinInstance::GetType() const { + return TYPE; +}; +vector< Ref<NiNode> > NiSkinInstance::GetBones() const { + vector<NiNodeRef> ref_bones( bones.size() ); + for (uint i = 0; i < bones.size(); ++i ) { + ref_bones[i] = bones[i]; + } + return ref_bones; } Ref<NiSkinData> NiSkinInstance::GetSkinData() const { @@ -132,4 +113,12 @@ void NiSkinInstance::SkeletonLost() { //Destroy skin data data = NULL; skinPartition = NULL; +} + +uint NiSkinInstance::GetBoneCount() const { + return uint(bones.size()); +} + +Ref<NiNode> NiSkinInstance::GetSkeletonRoot() const { + return skeletonRoot; } \ No newline at end of file diff --git a/obj/NiSkinInstance.h b/obj/NiSkinInstance.h index 7f987936062a7d76f709a118ab652c58c3880f2c..5fa4fd8c9088d2aa7be806d644439b7662854e92 100644 --- a/obj/NiSkinInstance.h +++ b/obj/NiSkinInstance.h @@ -27,6 +27,13 @@ typedef Ref<NiSkinInstance> NiSkinInstanceRef; class NIFLIB_API NiSkinInstance : public NI_SKIN_INSTANCE_PARENT { public: NiSkinInstance(); + + /*! + * This constructor is called by NiTriBasedGeom when it creates a new skin + * instance using the BindSkin function. + */ + NiSkinInstance( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ); + ~NiSkinInstance(); //Run-Time Type Information static const Type & TypeConst() { return TYPE; } @@ -40,27 +47,9 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; + uint GetBoneCount() const; vector< Ref<NiNode> > GetBones() const; - - /*! - * Binds any geometry that uses this skin instance to a list of bones. - * The bones must have a common ancestor in the scenegraph. This becomes - * the skeleton root. - */ - void Bind( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ); - - /*! - * Detatches this skin instance from any bones it was previously bound to. - */ - void Unbind(); - - /*! - * Calculates a NiSkinPartition and attaches it to both pointers, the one - * used in later versions in this class, and the one in the attached - * NiSkinData class. This way it will be written regardless of the - * version. SkinData must be set before this can be calculated. - */ - void CalcHardwareSkinningData (); + Ref<NiNode> GetSkeletonRoot() const; Ref<NiSkinData> GetSkinData() const; void SetSkinData( const Ref<NiSkinData> & n ); diff --git a/obj/NiTriBasedGeom.cpp b/obj/NiTriBasedGeom.cpp index b31a87a9a55128f6cd39403d7e0a86d808eb5984..50db534b06df89a62abca66cddf119b5fab31268 100644 --- a/obj/NiTriBasedGeom.cpp +++ b/obj/NiTriBasedGeom.cpp @@ -5,6 +5,7 @@ All rights reserved. Please see niflib.h for licence. */ #include "NiTriBasedGeomData.h" #include "NiSkinInstance.h" #include "NiObject.h" +#include "NiSkinData.h" using namespace Niflib; //Definition of TYPE constant @@ -67,11 +68,25 @@ void NiTriBasedGeom::SetShader( const string & n ) { shaderName = n; } } - -void NiTriBasedGeom::SetSkinInstance( Ref<NiSkinInstance> & n ) { - skinInstance = n; -} Ref<NiSkinInstance> NiTriBasedGeom::GetSkinInstance() const { return skinInstance; +} + +void NiTriBasedGeom::BindSkin( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ) { + //Ensure skin is not aleady bound + if ( skinInstance != 0 ) { + throw runtime_error("You have attempted to re-bind a skin that is already bound. Unbind it first."); + } + + //Create a skin instance using the bone and root data + skinInstance = new NiSkinInstance( skeleton_root, bone_nodes ); + + //Create a NiSkinData object based on this mesh + skinInstance->SetSkinData( new NiSkinData( this ) ); +}; + +void NiTriBasedGeom::UnbindSkin() { + //Clear skin instance + skinInstance = NULL; } \ No newline at end of file diff --git a/obj/NiTriBasedGeom.h b/obj/NiTriBasedGeom.h index 5a94c1fde15c8209d26086f59b6efdacdae70b2b..767f08289f3597d5c03179d0752dc754a8833c46 100644 --- a/obj/NiTriBasedGeom.h +++ b/obj/NiTriBasedGeom.h @@ -40,7 +40,14 @@ public: virtual list<NiObjectRef> GetRefs() const; virtual const Type & GetType() const; - //TODO: Handle attatchment of SkinInstance with new skinning API + /*! + * Binds this geometry to a list of bones. Creates and attatches a + * NiSkinInstance and NiSkinData class. The bones must have a common + * ancestor in the scenegraph. This becomes the skeleton root. + */ + void BindSkin( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ); + void UnbindSkin(); + Ref<NiSkinInstance> GetSkinInstance() const; Ref<NiTriBasedGeomData> GetData() const; void SetData( const Ref<NiTriBasedGeomData> & n ); @@ -51,8 +58,7 @@ public: string GetShader() const; void SetShader( const string & n ); - void SetSkinInstance( Ref<NiSkinInstance> & n ); - Ref<NiSkinInstance> GetSkinInstance() const; + protected: NI_TRI_BASED_GEOM_MEMBERS