| 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 fbxclonemanager.h |
| 13 | #ifndef _FBXSDK_UTILS_CLONE_MANAGER_H_ |
| 14 | #define _FBXSDK_UTILS_CLONE_MANAGER_H_ |
| 15 | |
| 16 | #include <fbxsdk/fbxsdk_def.h> |
| 17 | |
| 18 | #include <fbxsdk/core/fbxobject.h> |
| 19 | #include <fbxsdk/core/fbxquery.h> |
| 20 | |
| 21 | #include <fbxsdk/fbxsdk_nsbegin.h> |
| 22 | |
| 23 | /** The clone manager is a utility for cloning entire networks of FbxObject. |
| 24 | * Options are available for specifying how the clones inherit the connections |
| 25 | * of the original. |
| 26 | * |
| 27 | * Networks of FbxObject (inter-connected objects by OO, OP, PO or PP connections) |
| 28 | * can be cloned. How the connections of clones are handled depends on mSrcPolicy and mExternalDstPolicy. |
| 29 | * |
| 30 | * To clone FbxObject instances and their dependents, put them into a CloneSet |
| 31 | * and pass the CloneSet to this class: |
| 32 | * \code |
| 33 | * FbxCloneManager cloneManager; |
| 34 | * FbxCloneManager::CloneSet cloneSet; |
| 35 | * FbxCloneManager::CloneSetElement defaultCloneOptions(FbxCloneManager::sConnectToClone, |
| 36 | * FbxCloneManager::sConnectToOriginal, |
| 37 | * FbxObject::eDeepClone); |
| 38 | * cloneSet.Insert(someObject, defaultCloneOptions); |
| 39 | * cloneManager.AddDependents(cloneSet, someObject, defaultCloneOptions); |
| 40 | * cloneManager.Clone(cloneSet, scene) |
| 41 | * \endcode |
| 42 | * |
| 43 | * \remark If cloning occurs on the same scene as the original objects, the system will contain duplicated names. Although this is acceptable in FBX, |
| 44 | * some applications may not behave correctly with duplicated names. It is the responsability of the caller to resolve any conflicts. |
| 45 | * |
| 46 | * \see FbxCloneManager::CloneSetElement |
| 47 | * \see FbxCloneManager::CloneSet |
| 48 | * \nosubgrouping |
| 49 | */ |
| 50 | class FBXSDK_DLL FbxCloneManager |
| 51 | { |
| 52 | public: |
| 53 | |
| 54 | //! Maximum depth to clone dependents. |
| 55 | static const int sMaximumCloneDepth; |
| 56 | |
| 57 | /** Connect to objects that are connected to original object. |
| 58 | * This is a flag to mSrcPolicy or mExternalDstPolicy. |
| 59 | */ |
| 60 | static const int sConnectToOriginal; |
| 61 | |
| 62 | /** Connect to clones of objects that are connected to original object. |
| 63 | * (only if those original objects are also in the clone set) |
| 64 | * This is a flag to mSrcPolicy. |
| 65 | */ |
| 66 | static const int sConnectToClone; |
| 67 | |
| 68 | /** This represents an element in FbxCloneManager::CloneSet to be cloned. |
| 69 | * This class contains the option for specifying how connections are cloned and the |
| 70 | * cloned object. |
| 71 | * \see FbxCloneManager |
| 72 | * \see FbxCloneManager::CloneSet |
| 73 | */ |
| 74 | struct FBXSDK_DLL CloneSetElement |
| 75 | { |
| 76 | public: |
| 77 | /** Constructor. |
| 78 | * \param pSrcPolicy Specify how to handle source connections. Valid values are 0, sConnectToOriginal, |
| 79 | * sConnectToClone or sConnectToOriginal|sConnectToClone. |
| 80 | * \param pExternalDstPolicy Specify how to handle destination connections to objects NOT in |
| 81 | * the clone set. Valid values are 0 or sConnectToOriginal. |
| 82 | * \param pCloneType Specify the type of cloning. FbxObject::Clone uses the same parameter. |
| 83 | */ |
| 84 | CloneSetElement( int pSrcPolicy = 0, |
| 85 | int pExternalDstPolicy = 0, |
| 86 | FbxObject::ECloneType pCloneType = FbxObject::eReferenceClone ); |
| 87 | |
| 88 | //! the type of cloning to perform |
| 89 | FbxObject::ECloneType mType; |
| 90 | |
| 91 | /** Policy on how to handle source connections on the original object. Valid values are 0 |
| 92 | * or any bitwise OR'd combination of sConnectToOriginal, and sConnectToClone. |
| 93 | */ |
| 94 | int mSrcPolicy; |
| 95 | |
| 96 | /** policy on how to handle destination connections on the original object to |
| 97 | * objects NOT in the clone set. (Destination connections to objects in the set |
| 98 | * are handled by that object's source policy) Valid values are 0 or sConnectToOriginal. |
| 99 | */ |
| 100 | int mExternalDstPolicy; |
| 101 | |
| 102 | /** This is a pointer to the newly created clone. |
| 103 | * It is set after the call to FbxCloneManager::Clone() |
| 104 | */ |
| 105 | FbxObject* mObjectClone; |
| 106 | |
| 107 | /** Internal use. |
| 108 | */ |
| 109 | bool mLayerElementProcessed; |
| 110 | bool mConnectionsProcessed; |
| 111 | }; |
| 112 | |
| 113 | /** The CloneSet is a collection of pointers to objects that will be cloned in Clone() |
| 114 | * Attached to each object is a CloneSetElement. Its member variables dictate how |
| 115 | * the corresponding object will be cloned, and how it will inherit connections |
| 116 | * on the original object. |
| 117 | */ |
| 118 | typedef FbxMap<FbxObject*,CloneSetElement> CloneSet; |
| 119 | |
| 120 | /** Constructor |
| 121 | */ |
| 122 | FbxCloneManager(); |
| 123 | |
| 124 | /** Destructor |
| 125 | */ |
| 126 | virtual ~FbxCloneManager(); |
| 127 | |
| 128 | /** This function simplifies the process of cloning one object and all its depedency graph by automatically preparing |
| 129 | * the CloneSet and calling the Clone method using the code below. |
| 130 | * |
| 131 | * \code |
| 132 | * FbxCloneManager cloneManager; |
| 133 | * FbxCloneManager::CloneSet cloneSet; |
| 134 | * FbxCloneManager::CloneSetElement defaultCloneOptions(FbxCloneManager::sConnectToClone, |
| 135 | * FbxCloneManager::sConnectToOriginal, |
| 136 | * FbxObject::eDeepClone); |
| 137 | * FbxObject* lReturnObj = (FbxObject*)pObject; |
| 138 | * |
| 139 | * cloneManager.AddDependents(cloneSet, pObject, defaultCloneOptions, FbxCriteria::ObjectType(FbxObject::ClassId)); |
| 140 | * cloneSet.Insert((FbxObject*)pObject, defaultCloneOptions); |
| 141 | * |
| 142 | * // collect all the FbxCharacters, if any (these are indirect dependencies not visible by the AddDependents recursion) |
| 143 | * FbxArray<FbxObject*> lExtras; |
| 144 | * FbxCloneManager::CloneSet::RecordType* lIterator = cloneSet.Minimum(); |
| 145 | * while( lIterator ) |
| 146 | * { |
| 147 | * FbxObject* lObj = lIterator->GetKey(); |
| 148 | * cloneManager.LookForIndirectDependent(lObj, cloneSet, lExtras); |
| 149 | * lIterator = lIterator->Successor(); |
| 150 | * } |
| 151 | * |
| 152 | * // and add them to cloneSet |
| 153 | * for (int i = 0, c = lExtras.GetCount(); i < c; i++) |
| 154 | * { |
| 155 | * FbxObject* lObj = lExtras[i]; |
| 156 | * cloneManager.AddDependents(cloneSet, lObj, defaultCloneOptions); |
| 157 | * cloneSet.Insert(lObj, defaultCloneOptions); |
| 158 | * } |
| 159 | * |
| 160 | * // clone everything |
| 161 | * if (cloneManager.Clone(cloneSet, pContainer)) |
| 162 | * { |
| 163 | * // get the clone of pObject |
| 164 | * CloneSet::RecordType* lIterator = cloneSet.Find((FbxObject* const)pObject); |
| 165 | * if( lIterator ) |
| 166 | * { |
| 167 | * lReturnObj = lIterator->GetValue().mObjectClone; |
| 168 | * } |
| 169 | * } |
| 170 | * return lReturnObj; |
| 171 | * \endcode |
| 172 | * |
| 173 | * \param pObject Object to clone. |
| 174 | * \param pContainer This object (typically a scene or document) will contain the new clones. |
| 175 | * \return The clone of \e pObject if all its depedency graph have been cloned successfully, NULL otherwise. |
| 176 | * \remark It is advised not to use an FbxNode object for \e pContainer to group the cloned dependency graph. |
| 177 | * Some objects of the FBX SDK are not meant to be connected to FbxNode objects and if they are, the final scene |
| 178 | * will not comply to the FBX standard and its behavior cannot be guaranteed. |
| 179 | * \remark If \e pContainer is left \c NULL the cloned objects only exists in the FbxSdkManager and need to be |
| 180 | * manually connected to the scene in order to be saved to disk. |
| 181 | * |
| 182 | * Example: |
| 183 | * \code |
| 184 | * FbxObject* lObj2BCloned = ... |
| 185 | * FbxNode* myNewParent = FbxNode::Create(lNewScene, "Clone"); |
| 186 | * lNewScene->GetRootNode()->AddChild(lN); |
| 187 | * |
| 188 | * FbxCloneManager cloneManager; |
| 189 | * FbxNode *lClone = (FbxNode*)cloneManager.Clone(lObj2BCloned); |
| 190 | * |
| 191 | * // make sure the cloned object is connected to the scene |
| 192 | * lClone->ConnectDstObject(lNewScene); |
| 193 | * \endcode |
| 194 | */ |
| 195 | static FbxObject* Clone(const FbxObject* pObject, FbxObject* pContainer = NULL); |
| 196 | |
| 197 | /** Clone all objects in the set using the given policies for duplication |
| 198 | * of connections. Each CloneSetElement in the set will have its mObjectClone |
| 199 | * pointer set to the newly created clone. The following code shows how to access the cloned objects: |
| 200 | * |
| 201 | * \code |
| 202 | * if (cloneManager.Clone(cloneSet, pContainer)) |
| 203 | * { |
| 204 | * // access the clones |
| 205 | * FbxCloneManager::CloneSet::RecordType* lIterator = cloneSet.Minimum(); |
| 206 | * while( lIterator ) |
| 207 | * { |
| 208 | * FbxObject* lOriginalObject = lIterator->GetKey(); |
| 209 | * FbxObject* lClonedObject = lIterator->GetValue().mObjectClone; |
| 210 | * lIterator = lIterator->Successor(); |
| 211 | * } |
| 212 | * } |
| 213 | * \endcode |
| 214 | * |
| 215 | * \param pSet Set of objects to clone |
| 216 | * \param pContainer This object (typically a scene or document) will contain the new clones |
| 217 | * \return true if all objects were cloned, false otherwise. |
| 218 | * \remark It is advised not to use an FbxNode object for \e pContainer to group the cloned dependency graph. |
| 219 | * Some objects of the FBX SDK are not meant to be connected to FbxNode objects and if they are, the final scene |
| 220 | * will not comply to the FBX standard and its behavior cannot be guaranteed. |
| 221 | * \remark If \e pContainer is left \c NULL the cloned objects only exists in the FbxSdkManager and need to be |
| 222 | * manually connected to the scene in order to be saved to disk. |
| 223 | */ |
| 224 | virtual bool Clone( CloneSet& pSet, FbxObject* pContainer = NULL ) const; |
| 225 | |
| 226 | /** Add all dependents of the given object to the CloneSet. |
| 227 | * Dependents of items already in the set are ignored to prevent |
| 228 | * infinite recursion on cyclic dependencies. |
| 229 | * \param pSet The set to add items. |
| 230 | * \param pObject Object to add dependents to |
| 231 | * \param pCloneOptions |
| 232 | * \param pTypes Types of dependent objects to consider |
| 233 | * \param pDepth Maximum recursive depth. Valid range is [0,sMaximumCloneDepth] |
| 234 | * |
| 235 | * The following example shows how to perform multiple calls to AddDependents() to collect several |
| 236 | * subgraphs to be cloned: |
| 237 | * \code |
| 238 | * FbxObject* lRoot = ... // initialized with the root of the graph to be cloned |
| 239 | * FbxCharacter* lCharacter = ... // points to the FbxCharacter driving the character defined by "lRoot" graph |
| 240 | * |
| 241 | * FbxCloneManager cloneManager; |
| 242 | * FbxCloneManager::CloneSet cloneSet; |
| 243 | * |
| 244 | * cloneManager.AddDependents(cloneSet, lRoot); |
| 245 | * cloneSet.Insert(lRoot, defaultCloneOptions); |
| 246 | * |
| 247 | * cloneManager.AddDependents(cloneSet, lCharacter); |
| 248 | * cloneSet.Insert(lCharacter, defaultCloneOptions); |
| 249 | * |
| 250 | * \endcode |
| 251 | */ |
| 252 | virtual void AddDependents( CloneSet& pSet, |
| 253 | const FbxObject* pObject, |
| 254 | const CloneSetElement& pCloneOptions = CloneSetElement(), |
| 255 | FbxCriteria pTypes = FbxCriteria::ObjectType(FbxObject::ClassId), |
| 256 | int pDepth = sMaximumCloneDepth ) const; |
| 257 | |
| 258 | /***************************************************************************************************************************** |
| 259 | ** WARNING! Anything beyond these lines is for internal use, may not be documented and is subject to change without notice! ** |
| 260 | *****************************************************************************************************************************/ |
| 261 | #ifndef DOXYGEN_SHOULD_SKIP_THIS |
| 262 | static FbxObject* Clone(const FbxObject* pObject, CloneSet* pSet, FbxObject* pContainer = NULL); |
| 263 | |
| 264 | private: |
| 265 | friend class FbxScene; |
| 266 | |
| 267 | bool ReAssignLayerElements( FbxCloneManager::CloneSet::RecordType* pIterator, const FbxCloneManager::CloneSet& pSet) const; |
| 268 | bool CloneConnections( CloneSet::RecordType* pIterator, const CloneSet& pSet) const; |
| 269 | bool CheckIfCloneOnSameScene(const FbxObject* pObject, FbxObject* pContainer) const; |
| 270 | |
| 271 | virtual void LookForIndirectDependent(const FbxObject* pObject, CloneSet& pSet, FbxArray<FbxObject*>& lIndirectDepend); |
| 272 | virtual bool NeedToBeExcluded(FbxObject* lObj) const; |
| 273 | |
| 274 | bool mCloneOnSameScene; |
| 275 | |
| 276 | #endif /* !DOXYGEN_SHOULD_SKIP_THIS *****************************************************************************************/ |
| 277 | }; |
| 278 | |
| 279 | #include <fbxsdk/fbxsdk_nsend.h> |
| 280 | |
| 281 | #define CloneSetCast(x) ((FbxCloneManager::CloneSet*)(x)) |
| 282 | #define CloneSetElementCast(x) ((FbxCloneManager::CloneSetElement*)((x!=NULL)?&(x->GetValue()):NULL)) |
| 283 | |
| 284 | #endif /* _FBXSDK_UTILS_CLONE_MANAGER_H_ */ |
| 285 | |