1 | /**************************************************************************************** |
2 | |
3 | Copyright (C) 2015 Autodesk, Inc. |
4 | All rights reserved. |
5 | |
6 | Use of this software is subject to the terms of the Autodesk license agreement |
7 | provided at the time of installation or download, or which otherwise accompanies |
8 | this software in either electronic or hard copy form. |
9 | |
10 | ****************************************************************************************/ |
11 | |
12 | //! \file fbxpose.h |
13 | #ifndef _FBXSDK_SCENE_POSE_H_ |
14 | #define _FBXSDK_SCENE_POSE_H_ |
15 | |
16 | #include <fbxsdk/fbxsdk_def.h> |
17 | |
18 | #include <fbxsdk/core/fbxobject.h> |
19 | #include <fbxsdk/core/base/fbxarray.h> |
20 | #include <fbxsdk/core/math/fbxmatrix.h> |
21 | |
22 | #include <fbxsdk/fbxsdk_nsbegin.h> |
23 | |
24 | class FbxStatus; |
25 | class FbxPose; |
26 | class FbxNode; |
27 | class FbxUserNotification; |
28 | |
29 | /** This structure contains the description of a named pose. |
30 | * FbxPose contains one FbxPoseInfo array to store all of FBX nodes and their transform matrix info. |
31 | */ |
32 | struct FbxPoseInfo |
33 | { |
34 | FbxMatrix mMatrix; //!< Transform matrix of the node. |
35 | bool mMatrixIsLocal; //!< If true, the transform matrix above is defined in local coordinates. |
36 | FbxNode* mNode; //!< FBX node, which may be skeleton or geometry (skinned) node. |
37 | }; |
38 | |
39 | typedef FbxArray<FbxNode*> NodeList; |
40 | typedef FbxArray<FbxPose*> PoseList; |
41 | typedef FbxArray<FbxPoseInfo*> PoseInfoList; |
42 | |
43 | /** This class contains the description of a Pose and provide some methods to access Pose info in one FBX scene. |
44 | * \nosubgrouping |
45 | * The FbxPose object can be setup to hold "Bind Pose" data or "Rest Pose" data. |
46 | * |
47 | * The Bind Pose holds the transformation (translation, rotation and scaling) |
48 | * matrix of all the nodes implied in a link deformation. This includes the geometry |
49 | * being deformed, the links deforming the geometry, and recursively all the |
50 | * ancestors nodes of the link. The Bind Pose gives you the transformation of the nodes |
51 | * at the moment of the binding operation when no deformation occurs. |
52 | * |
53 | * The Rest Pose is a snapshot of a node transformation. A Rest Pose can be used |
54 | * to store the position of every node of a character at a certain point in |
55 | * time. This pose can then be used as a reference position for animation tasks, |
56 | * like editing walk cycles. |
57 | * |
58 | * One difference between the two modes is in the validation performed before |
59 | * adding an item and the kind of matrix stored. |
60 | * |
61 | * In "Bind Pose" mode, the matrix is assumed to be defined in the global space, |
62 | * while in "Rest Pose" the type of the matrix may be specified by the caller. So |
63 | * local system matrices can be used. Actually, because there is one such flag for |
64 | * each entry (FbxPoseInfo), it is possible to have mixed types in a FbxPose elements. |
65 | * It is therefore the responsibility of the caller to check for the type of the retrieved |
66 | * matrix and to do the appropriate conversions if required. |
67 | * |
68 | * The validation of the data to be added consists of the following steps: |
69 | * |
70 | * \li If this FbxPose object stores "Bind Poses", then |
71 | * add a FbxPoseInfo only if the node is not already |
72 | * associated to another "Bind Pose". This check is done |
73 | * by visiting ALL the FbxPose objects in the system. |
74 | * |
75 | * The above test is only performed for the "Bind Pose" type. While |
76 | * the next one is always performed, no matter what kind of poses this |
77 | * FbxPose object is setup to hold. |
78 | * |
79 | * \li If a node is already inserted in the FbxPose internal list, |
80 | * then the passed matrix MUST be equal to the one already stored. |
81 | * If this is not the case, the Add method will return -1, indicating |
82 | * that no new FbxPoseInfo has been created. |
83 | * |
84 | * If the Add method succeeds, it will return the index of the FbxPoseInfo |
85 | * structure that as been created and held by the FbxPose object. |
86 | * |
87 | * To ensure data integrity, the stored information can only be |
88 | * accessed using the provided methods (read-only). If an entry needs to be |
89 | * modified, the caller has to remove the FbxPoseInfo item by calling Remove(i) |
90 | * and then Add a new one. |
91 | * |
92 | * The internal list is not ordered and the search inside this list is linear |
93 | * (from the first element to ... the first match or the end of the list). |
94 | * |
95 | */ |
96 | class FBXSDK_DLL FbxPose : public FbxObject |
97 | { |
98 | FBXSDK_OBJECT_DECLARE(FbxPose,FbxObject); |
99 | |
100 | public: |
101 | /** Set the type of pose. |
102 | * \param pIsBindPose If true, type will be bind pose, else rest pose. |
103 | */ |
104 | void SetIsBindPose(bool pIsBindPose); |
105 | |
106 | /** Pose identifier flag. |
107 | * \return \c true if this object holds BindPose data. |
108 | */ |
109 | bool IsBindPose() const { return mType == 'b'; } |
110 | |
111 | /** Pose identifier flag. |
112 | * \return \c true if this object holds RestPose data. |
113 | */ |
114 | bool IsRestPose() const { return mType == 'r'; } |
115 | |
116 | /** Get number of stored items. |
117 | * \return The number of items stored. |
118 | */ |
119 | int GetCount() const { return mPoseInfo.GetCount(); } |
120 | |
121 | /** Stores the pose transformation for the given node. |
122 | * \param pNode pointer to the node for which the pose is stored. |
123 | * \param pMatrix Pose transform of the node. |
124 | * \param pLocalMatrix Flag to indicate if pMatrix is defined in Local or Global space. |
125 | * \param pMultipleBindPose Flag to indicate if multiple bind pose exist. If this is false, all matrix for one node should be same in different bind pose. |
126 | * \return -1 if the function failed or the index of the stored item. |
127 | */ |
128 | int Add(FbxNode* pNode, const FbxMatrix& pMatrix, bool pLocalMatrix = false, bool pMultipleBindPose = true); |
129 | |
130 | /** Remove the pIndexth item from the Pose object. |
131 | * \param pIndex Index of the item to be removed. |
132 | */ |
133 | void Remove(int pIndex); |
134 | |
135 | /** Get the node name. |
136 | * \param pIndex Index of the queried item. |
137 | * \return The node initial and current names. |
138 | * \remarks If the index is invalid an empty FbxNameHandler is returned. |
139 | */ |
140 | FbxNameHandler GetNodeName(int pIndex) const; |
141 | |
142 | /** Get the node. |
143 | * \param pIndex Index of the queried item. |
144 | * \return A pointer to the node referenced. |
145 | * \remarks If the index is invalid or no pointer to a node is set, returns NULL. |
146 | * The returned pointer will become undefined if the FbxPose object is destroyed. |
147 | */ |
148 | FbxNode* GetNode(int pIndex) const; |
149 | |
150 | /** Get the transform matrix. |
151 | * \param pIndex Index of the queried item. |
152 | * \return A reference to the pose matrix. |
153 | * \remarks If the index is invalid a reference to an identity matrix is returned. |
154 | * The reference will become undefined if the FbxPose object is destroyed. |
155 | */ |
156 | const FbxMatrix& GetMatrix(int pIndex) const; |
157 | |
158 | /** Get the type of the matrix. |
159 | * \param pIndex Index of the queried item. |
160 | * \return \c true if the matrix is defined in the Local coordinate space and false otherwise. |
161 | * \remarks If the FbxPose object is configured to hold BindPose data, this method will always return \c false. |
162 | */ |
163 | bool IsLocalMatrix(int pIndex) const; |
164 | |
165 | /** |
166 | * \name Search Section |
167 | */ |
168 | //@{ |
169 | /** This structure defines the strategy of comparing FBX node name. |
170 | * FBX node has an initial name and a current name (refer to FbxNameHandler). The structure defines which name to use when compare two nodes. |
171 | */ |
172 | enum ENameComponent |
173 | { |
174 | eInitialNameComponent = 1, //! use initial name when compare two nodes |
175 | eCurrentNameComponent = 2, //! use current name when compare two nodes |
176 | eAllNameComponents = 3 //! use both initial and current name when compare two nodes, it's true if one or both matched |
177 | }; |
178 | |
179 | /** Look in the FbxPose object for the given node name. |
180 | * \param pNodeName Name of the node we are looking for. |
181 | * \param pCompareWhat Bitwise or of the following flags: INTIALNAME_COMPONENT, eCurrentNameComponent |
182 | * \return -1 if the node is not in the list. Otherwise, the index of the corresponding FbxPoseInfo element. |
183 | */ |
184 | int Find(const FbxNameHandler& pNodeName, char pCompareWhat = eAllNameComponents) const; |
185 | |
186 | /** Look in the FbxPose object for the given node. |
187 | * \param pNode the node we are looking for. |
188 | * \return -1 if the node is not in the list. Otherwise, the index of the corresponding FbxPoseInfo element. |
189 | */ |
190 | int Find(const FbxNode* pNode) const; |
191 | //@} |
192 | |
193 | /** |
194 | * \name Utility Section |
195 | */ |
196 | //@{ |
197 | /** Get the list of Poses objects that contain the node with name pNodeName. |
198 | * This method will look in all the poses of all the scenes. |
199 | * \param pManager The manager owning the poses and scenes. |
200 | * \param pNode The node being explored. |
201 | * \param pPoseList List of BindPoses/RestPoses that have the node. |
202 | * \param pIndex List of indices of the nodes in the corresponding poses lists. |
203 | * \return \c true if the node belongs to at least one Pose (either a BindPose or a RestPose). |
204 | * \remarks The pPoseList and pIndex are filled by this method. |
205 | * The elements of the returned list must not be deleted since they still belong to the scene. |
206 | */ |
207 | static bool GetPosesContaining(FbxManager& pManager, FbxNode* pNode, PoseList& pPoseList, FbxArray<int>& pIndex); |
208 | |
209 | /** Get the list of Poses objects that contain the node with name pNodeName. |
210 | * \param pScene Scene owning the poses. |
211 | * \param pNode The node being explored. |
212 | * \param pPoseList List of BindPoses/RestPoses that have the node. |
213 | * \param pIndex List of indices of the nodes in the corresponding poses lists. |
214 | * \return \c true if the node belongs to at least one Pose (either a BindPose or a RestPose). |
215 | * \remarks The pPoseList and pIndex are filled by this method. |
216 | * The elements of the returned list must not be deleted since they still belong to the scene. |
217 | */ |
218 | static bool GetPosesContaining(FbxScene* pScene, FbxNode* pNode, PoseList& pPoseList, FbxArray<int>& pIndex); |
219 | |
220 | /** Get the list of BindPose objects that contain the node with name pNodeName. |
221 | * This method will look in all the bind poses of all the scenes. |
222 | * \param pManager The manager owning the poses. |
223 | * \param pNode The node being explored. |
224 | * \param pPoseList List of BindPoses that have the node. |
225 | * \param pIndex List of indices of the nodes in the corresponding bind poses lists. |
226 | * \return \c true if the node belongs to at least one BindPose. |
227 | * \remarks The pPoseList and pIndex are filled by this method. |
228 | * The elements of the returned list must not be deleted since they still belong to the scene. |
229 | */ |
230 | static bool GetBindPoseContaining(FbxManager& pManager, FbxNode* pNode, PoseList& pPoseList, FbxArray<int>& pIndex); |
231 | |
232 | /** Get the list of BindPose objects that contain the node with name pNodeName. |
233 | * \param pScene The scene owning the poses. |
234 | * \param pNode The node being explored. |
235 | * \param pPoseList List of BindPoses that have the node. |
236 | * \param pIndex List of indices of the nodes in the corresponding bind poses lists. |
237 | * \return \c true if the node belongs to at least one BindPose. |
238 | * \remarks The pPoseList and pIndex are filled by this method. |
239 | * The elements of the returned list must not be deleted since they still belong to the scene. |
240 | */ |
241 | static bool GetBindPoseContaining(FbxScene* pScene, FbxNode* pNode, PoseList& pPoseList, FbxArray<int>& pIndex); |
242 | |
243 | /** Get the list of RestPose objects that contain the node with name pNodeName. |
244 | * This method will look in all the bind poses of all the scenes. |
245 | * \param pManager The manager owning the poses. |
246 | * \param pNode The node being explored. |
247 | * \param pPoseList List of RestPoses that have the node. |
248 | * \param pIndex List of indices of the nodes in the corresponding rest poses lists. |
249 | * \return \c true if the node belongs to at least one RestPose. |
250 | * \remarks The pPoseList and pIndex are filled by this method. |
251 | * The elements of the returned list must not be deleted since they still belong to the scene. |
252 | */ |
253 | static bool GetRestPoseContaining(FbxManager& pManager, FbxNode* pNode, PoseList& pPoseList, FbxArray<int>& pIndex); |
254 | |
255 | /** Get the list of RestPose objects that contain the node with name pNodeName. |
256 | * \param pScene The scene owning the poses. |
257 | * \param pNode The node being explored. |
258 | * \param pPoseList List of RestPoses that have the node. |
259 | * \param pIndex List of indices of the nodes in the corresponding rest poses lists. |
260 | * \return \c true if the node belongs to at least one RestPose. |
261 | * \remarks The pPoseList and pIndex are filled by this method. |
262 | * The elements of the returned list must not be deleted since they still belong to the scene. |
263 | */ |
264 | static bool GetRestPoseContaining(FbxScene* pScene, FbxNode* pNode, PoseList& pPoseList, FbxArray<int>& pIndex); |
265 | |
266 | /** Check this BindPose and report an error if all the conditions to a valid bind pose are not |
267 | * met. The conditions are: |
268 | * |
269 | * \li a) We are a BindPose. |
270 | * \li b) For every node in the bind pose, all their parent node are part of the bind pose. |
271 | * \li c) All the deforming nodes are part of the bind pose. |
272 | * \li d) All the parents of the deforming nodes are part of the bind pose. |
273 | * \li e) Each deformer relative matrix correspond to the deformer Inv(bindMatrix) * deformed Geometry bindMatrix. |
274 | * |
275 | * \param pRoot This node is used as the stop point when visiting the parents (cannot be NULL). |
276 | * \param pMatrixCmpTolerance Tolerance value when comparing the matrices. |
277 | * \param pStatus The FbxStatus object to hold error codes. |
278 | * \return true if all the above conditions are met and false otherwise. |
279 | * \remarks |
280 | * a) If pRoot node is not defined in the BindPose it must not have a Geometry or Skeleton attribute and its |
281 | * transform must be an Identity. |
282 | * \remarks |
283 | * b) If the returned value is false, querying for the error will return the reason of the failure. |
284 | * As soon as one of the above conditions is not met, this method return ignoring any subsequent errors. |
285 | * Run the IsBindPoseVerbose if more details are needed. |
286 | */ |
287 | bool IsValidBindPose(FbxNode* pRoot, double pMatrixCmpTolerance=0.0001, FbxStatus* pStatus = NULL); |
288 | |
289 | /** Same as IsValidBindPose() but slower because it will not stop as soon as a failure occurs. Instead, |
290 | * keeps running to accumulate the faulty nodes (stored in the appropriate array). It is then up to the |
291 | * caller to fill the UserNotification if desired. |
292 | * |
293 | * \param pRoot This node is used as the stop point when visiting the parents (cannot be NULL). |
294 | * \param pMissingAncestors Each ancestor missing from the BindPose is added to this list. |
295 | * \param pMissingDeformers Each deformer missing from the BindPose is added to this list. |
296 | * \param pMissingDeformersAncestors Each deformer ancestors missing from the BindPose is added to this list. |
297 | * \param pWrongMatrices Nodes that yield to a wrong matrix comparisons are added to this list. |
298 | * \param pMatrixCmpTolerance Tolerance value when comparing the matrices. |
299 | * \param pStatus The FbxStatus object to hold error codes. |
300 | * \remarks If pRoot node is not defined in the BindPose it must not have a Geometry or Skeleton attribute and its |
301 | * transform must be an Identity. |
302 | */ |
303 | bool IsValidBindPoseVerbose(FbxNode* pRoot, NodeList& pMissingAncestors, NodeList& pMissingDeformers, NodeList& pMissingDeformersAncestors, NodeList& pWrongMatrices, double pMatrixCmpTolerance=0.0001, FbxStatus* pStatus = NULL); |
304 | |
305 | /** Same as IsValidBindPose() but slower because it will not stop as soon as a failure occurs. Instead, |
306 | * keeps running to accumulate the faulty nodes and send them directly to the UserNotification. |
307 | * |
308 | * \param pRoot This node is used as the stop point when visiting the parents (cannot be NULL). |
309 | * \param pUserNotification Pointer to the user notification where the messages will be accumulated. |
310 | * \param pMatrixCmpTolerance Tolerance value when comparing the matrices. |
311 | * \param pStatus The FbxStatus object to hold error codes. |
312 | * \remarks If the pUserNotification parameter is NULL, this method will call IsValidBindPose(). |
313 | * \remarks If pRoot node is not defined in the BindPose it must not have a Geometry or Skeleton attribute and its |
314 | * transform must be an Identity. |
315 | */ |
316 | bool IsValidBindPoseVerbose(FbxNode* pRoot, FbxUserNotification* pUserNotification, double pMatrixCmpTolerance=0.0001, FbxStatus* pStatus = NULL); |
317 | |
318 | //@} |
319 | |
320 | /***************************************************************************************************************************** |
321 | ** WARNING! Anything beyond these lines is for internal use, may not be documented and is subject to change without notice! ** |
322 | *****************************************************************************************************************************/ |
323 | #ifndef DOXYGEN_SHOULD_SKIP_THIS |
324 | protected: |
325 | virtual void Construct(const FbxObject* pFrom); |
326 | virtual void Destruct(bool pRecursive); |
327 | virtual void ConstructProperties(bool pForceSet); |
328 | |
329 | virtual FbxObject& Copy(const FbxObject& pObject); |
330 | virtual const char* GetTypeName() const; |
331 | |
332 | //Returns false if pNode is already inserted in the list and the current matrix is different from the stored one. Also, if this pose is a rest pose, check if |
333 | //pNode belongs to other BindPoses (accessed through the scene pointer). pPos will contains the index of the FbxPoseInfo if the parameters are already stored in this object. |
334 | bool ValidateParams(const FbxNode* pNode, const FbxMatrix& pMatrix, int& pPos); |
335 | |
336 | bool LocalValidateParams(const FbxNode* pNode, const FbxMatrix& pMatrix, int& pPos); |
337 | static bool GetSpecificPoseContaining(int poseType, FbxScene* pScene, FbxNode* pNode, PoseList& pPoseList, FbxArray<int>& pIndex); |
338 | |
339 | private: |
340 | FbxPoseInfo* GetItem(int pIndex) const; |
341 | void UpdatePosInfoList(); |
342 | bool IsValidBindPoseCommon(FbxNode* pRoot, NodeList* pMissingAncestors, NodeList* pMissingDeformers, NodeList* pMissingDeformersAncestors, NodeList* pWrongMatrices, FbxStatus* pStatus, double pMatrixCmpTolerance=0.0001); |
343 | |
344 | char mType; |
345 | PoseInfoList mPoseInfo; |
346 | bool mPoseInfoIsDirty; |
347 | FbxPropertyT<FbxReference> Nodes; |
348 | |
349 | #endif /* !DOXYGEN_SHOULD_SKIP_THIS *****************************************************************************************/ |
350 | }; |
351 | |
352 | #include <fbxsdk/fbxsdk_nsend.h> |
353 | |
354 | #endif /* _FBXSDK_SCENE_POSE_H_ */ |
355 | |