| 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 | |