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
24class FbxStatus;
25class FbxPose;
26class FbxNode;
27class 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 */
32struct 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
39typedef FbxArray<FbxNode*> NodeList;
40typedef FbxArray<FbxPose*> PoseList;
41typedef 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 */
96class FBXSDK_DLL FbxPose : public FbxObject
97{
98 FBXSDK_OBJECT_DECLARE(FbxPose,FbxObject);
99
100public:
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
324protected:
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
339private:
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