1 /* 2 Copyright (c) 2008-2009 NetAllied Systems GmbH 3 4 This file is part of COLLADAMax. 5 6 Portions of the code are: 7 Copyright (c) 2005-2007 Feeling Software Inc. 8 Copyright (c) 2005-2007 Sony Computer Entertainment America 9 10 Based on the 3dsMax COLLADASW Tools: 11 Copyright (c) 2005-2006 Autodesk Media Entertainment 12 13 Licensed under the MIT Open Source License, 14 for details please see LICENSE file or the website 15 http://www.opensource.org/licenses/mit-license.php 16 */ 17 18 #include "COLLADAMaxStableHeaders.h" 19 #include "COLLADAMaxPhysiqueSkinInterface.h" 20 21 22 namespace COLLADAMax 23 { 24 PhysiqueSkinInterface(Modifier * modifier,INode * node)25 PhysiqueSkinInterface::PhysiqueSkinInterface(Modifier *modifier, INode *node) 26 : mInode( node ) 27 , mModifier( modifier ) 28 , mModifierInterface( mModifier ? (IPhysiqueExport*)mModifier->GetInterface(I_PHYINTERFACE) : 0) 29 , mSkinContext( ( mInode && mModifierInterface) ? mModifierInterface->GetContextInterface(mInode) : 0) 30 , mNumBones( 0 ) 31 { 32 assert( mModifier ); 33 assert( mModifierInterface ); 34 assert( !node || mSkinContext ); 35 36 37 if ( mSkinContext ) 38 { 39 // Now, Physique does'nt provide a way for us to list 40 // all our bones nicely, so try and find all our info here. 41 42 //convert to rigid for time independent vertex assignment 43 mSkinContext->ConvertToRigid(TRUE); 44 45 //allow blending to export multi-link assignments 46 mSkinContext->AllowBlending(true); 47 48 // Attempt to find all Physique bone nodes by using its MATRIX_RETURNED 49 // inherent hierarchical nature - ie find the root 50 // bone, by definition all children are physique nodes too 51 52 if (mSkinContext->GetNumberVertices() > 0) 53 { 54 Matrix3 ignored; 55 INode *nextNode, *rootNode = 0; 56 IPhyVertexExport *vtxExport = mSkinContext->GetVertexInterface(0); 57 if (vtxExport) 58 { 59 //need to check if vertex has blending 60 if (vtxExport->GetVertexType() & BLENDED_TYPE) 61 { 62 IPhyBlendedRigidVertex *vtxBlend = (IPhyBlendedRigidVertex *)vtxExport; 63 rootNode = vtxBlend->GetNode(0); 64 } 65 else 66 { 67 IPhyRigidVertex *vtxNoBlend = (IPhyRigidVertex *)vtxExport; 68 rootNode = vtxNoBlend->GetNode(); 69 } 70 mSkinContext->ReleaseVertexInterface(vtxExport); 71 } 72 73 if (rootNode != NULL) 74 { 75 nextNode = rootNode->GetParentNode(); 76 while (nextNode != NULL && !nextNode->IsRootNode()) 77 { 78 if (mModifierInterface->GetInitNodeTM(nextNode, ignored) == NODE_NOT_FOUND) 79 break; 80 81 rootNode = nextNode; 82 nextNode = rootNode->GetParentNode(); 83 } 84 85 // now we have a root node, turn around and add all children to our nodeList. 86 //mBonesMap[rootNode] = 1; 87 fillBoneMap(rootNode); 88 } 89 } 90 size_t blsize = mBonesList.size(); 91 size_t bmsize = mBonesMap.size(); 92 size_t nbsize = (size_t)mNumBones; 93 assert(blsize == bmsize && nbsize == bmsize); 94 } 95 96 } 97 98 // Release our interfaces on death ~PhysiqueSkinInterface()99 PhysiqueSkinInterface::~PhysiqueSkinInterface() 100 { 101 // Are we all released? 102 assert( !mSkinContext ); 103 assert( !mModifierInterface ); 104 } 105 releaseMe()106 void PhysiqueSkinInterface::releaseMe() 107 { 108 mModifierInterface->ReleaseContextInterface(mSkinContext); 109 mSkinContext = 0; 110 mModifier->ReleaseInterface(I_PHYINTERFACE, mModifierInterface); 111 mModifierInterface = 0; 112 // when we are all released, delete ourselves 113 delete this; 114 } 115 getSkinInitTM(Matrix3 & initTM,bool bObjOffset)116 bool PhysiqueSkinInterface::getSkinInitTM(Matrix3 &initTM, bool bObjOffset) 117 { 118 // We should really allow some errors. 119 bObjOffset = bObjOffset; 120 return mModifierInterface->GetInitNodeTM(mInode, initTM) == MATRIX_RETURNED; 121 } 122 getNumBones()123 int PhysiqueSkinInterface::getNumBones() 124 { 125 //return mBonesList.Count(); 126 return mNumBones; 127 } 128 getBone(int i)129 INode *PhysiqueSkinInterface::getBone(int i) 130 { 131 return mBonesList[i]; 132 } 133 getBoneInitTM(INode * mInode,Matrix3 & boneInitTM)134 bool PhysiqueSkinInterface::getBoneInitTM(INode *mInode, Matrix3 &boneInitTM) 135 { 136 return mModifierInterface->GetInitNodeTM(mInode, boneInitTM) == MATRIX_RETURNED; 137 } 138 getNumVertices()139 int PhysiqueSkinInterface::getNumVertices() 140 { 141 return mSkinContext->GetNumberVertices(); 142 } 143 getNumAssignedBones(int i)144 int PhysiqueSkinInterface::getNumAssignedBones(int i) 145 { 146 int retval = 0; 147 148 IPhyVertexExport *vtxExport = mSkinContext->GetVertexInterface(i); 149 if (vtxExport) 150 { 151 if (vtxExport->GetVertexType() & BLENDED_TYPE) 152 { 153 IPhyBlendedRigidVertex *vtxBlend = (IPhyBlendedRigidVertex *)vtxExport; 154 retval = vtxBlend->GetNumberNodes(); 155 } 156 else 157 { 158 retval = 1; 159 } 160 mSkinContext->ReleaseVertexInterface(vtxExport); 161 } 162 return retval; 163 } 164 getBoneWeight(int vertexIdx,int boneIdx)165 float PhysiqueSkinInterface::getBoneWeight(int vertexIdx, int boneIdx) 166 { 167 float retval = 0.0f; 168 169 IPhyVertexExport *vtxExport = mSkinContext->GetVertexInterface(vertexIdx); 170 if (vtxExport) 171 { 172 if (vtxExport->GetVertexType() & BLENDED_TYPE) 173 { 174 IPhyBlendedRigidVertex *vtxBlend = (IPhyBlendedRigidVertex *)vtxExport; 175 retval = vtxBlend->GetWeight(boneIdx); 176 } 177 else 178 { 179 if (boneIdx == 0) 180 retval = 1.0f; 181 } 182 mSkinContext->ReleaseVertexInterface(vtxExport); 183 } 184 return retval; 185 } 186 getAssignedBone(int vertexIdx,int boneIdx)187 int PhysiqueSkinInterface::getAssignedBone(int vertexIdx, int boneIdx) 188 { 189 int retval = -1; 190 IPhyVertexExport *vtxExport = mSkinContext->GetVertexInterface(vertexIdx); 191 if (vtxExport) 192 { 193 if (vtxExport->GetVertexType() & BLENDED_TYPE) 194 { 195 IPhyBlendedRigidVertex *vtxBlend = (IPhyBlendedRigidVertex *)vtxExport; 196 retval = getBonesListIdx(vtxBlend->GetNode(boneIdx)); 197 } 198 else 199 { 200 IPhyRigidVertex *vtxBlend = (IPhyRigidVertex *)vtxExport; 201 if (boneIdx == 0) retval = getBonesListIdx(vtxBlend->GetNode()); 202 } 203 mSkinContext->ReleaseVertexInterface(vtxExport); 204 } 205 assert(retval >= 0); 206 return retval; 207 } 208 209 /** private methods **/ 210 getBonesListIdx(INode * mInode)211 int PhysiqueSkinInterface::getBonesListIdx(INode *mInode) 212 { 213 std::map<INode*, int>::iterator itr = mBonesMap.find(mInode); 214 if (itr != mBonesMap.end()) 215 return (*itr).second; 216 return -1; 217 /* for (int j = 0; j < mBonesList.Count(); j++) 218 { 219 if (mBonesList[j] == node) 220 return j; 221 } 222 return -1; */ 223 } 224 fillBoneMap(INode * parentNode)225 void PhysiqueSkinInterface::fillBoneMap(INode* parentNode) 226 { 227 if ( !parentNode ) 228 return; 229 230 //If the bone is a biped bone, scale needs to be 231 //restored before exporting skin data 232 scaleBiped(parentNode, 0); 233 234 mBonesMap[parentNode] = (int)mNumBones++; 235 mBonesList.push_back(parentNode); 236 237 int numChildren = parentNode->NumberOfChildren(); 238 for (int i = 0; i < numChildren; i++) 239 { 240 fillBoneMap(parentNode->GetChildNode(i)); 241 } 242 } 243 244 // Taken from PhyExportSample 245 // 246 // This function can be used to set the non-uniform scale of a biped. 247 // The node argument should be a biped node. 248 // If the scale argument is non-zero the non-uniform scale will be removed from the biped. 249 // Remove the non-uniform scale before exporting biped nodes and animation data 250 // If the scale argument is zero the non-uniform scaling will be reapplied to the biped. 251 // Add the non-uniform scaling back on the biped before exporting skin data 252 //*********************************************************************************** scaleBiped(INode * mInode,int scale)253 void PhysiqueSkinInterface::scaleBiped(INode* mInode, int scale) 254 { 255 if (mInode->IsRootNode()) return; 256 257 // Use the class ID to check to see if we have a biped node 258 Control* c = mInode->GetTMController(); 259 if ((c->ClassID() == BIPSLAVE_CONTROL_CLASS_ID) || 260 (c->ClassID() == BIPBODY_CONTROL_CLASS_ID) || 261 (c->ClassID() == FOOTPRINT_CLASS_ID)) 262 { 263 264 // Get the Biped Export Interface from the controller 265 IBipedExport *BipIface = (IBipedExport *) c->GetInterface(I_BIPINTERFACE); 266 267 // Either remove the non-uniform scale from the biped, 268 // or add it back in depending on the boolean scale value 269 BipIface->RemoveNonUniformScale(scale); 270 Control* iMaster = (Control *) c->GetInterface(I_MASTER); 271 iMaster->NotifyDependents(FOREVER, PART_TM, REFMSG_CHANGE); 272 273 // Release the interfaces 274 c->ReleaseInterface(I_MASTER,iMaster); 275 c->ReleaseInterface(I_BIPINTERFACE,BipIface); 276 } 277 } 278 279 } // namespace COLLADAMax 280