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