1 #pragma once 2 3 #ifndef PLASTIDEFORMERSTORAGE_H 4 #define PLASTIDEFORMERSTORAGE_H 5 6 #include <memory> 7 8 // TnzExt includes 9 #include "ext/plasticdeformer.h" 10 11 #undef DVAPI 12 #undef DVVAR 13 #ifdef TNZEXT_EXPORTS 14 #define DVAPI DV_EXPORT_API 15 #define DVVAR DV_EXPORT_VAR 16 #else 17 #define DVAPI DV_IMPORT_API 18 #define DVVAR DV_IMPORT_VAR 19 #endif 20 21 //======================================================================= 22 23 // Forward Declarations 24 25 struct PlasticVisualSettings; 26 struct DrawableMeshImage; 27 28 class PlasticSkeletonDeformation; 29 30 //======================================================================= 31 32 //*********************************************************************************************** 33 // PlasticDeformerData declaration 34 //*********************************************************************************************** 35 36 //! PlasticDeformerData contains all the data needed to perform the deformation 37 //! of a single mesh. 38 struct DVAPI PlasticDeformerData { 39 PlasticDeformer m_deformer; //!< The mesh deformer itself 40 41 std::unique_ptr<double[]> m_so; //!< (owned) Faces' stacking order 42 std::unique_ptr<double[]> m_output; //!< (owned) Output vertex coordinates 43 44 std::vector<int> m_faceHints; //!< Handles' face hints 45 46 public: 47 PlasticDeformerData(); 48 ~PlasticDeformerData(); 49 50 private: 51 // Not copyable 52 53 PlasticDeformerData(const PlasticDeformerData &); 54 PlasticDeformerData &operator=(const PlasticDeformerData &); 55 }; 56 57 //*********************************************************************************************** 58 // PlasticDeformerDataGroup definition 59 //*********************************************************************************************** 60 61 struct DVAPI PlasticDeformerDataGroup { 62 std::unique_ptr<PlasticDeformerData[]> 63 m_datas; //!< (owned) The deformer datas array. One per mesh. 64 std::vector<PlasticHandle> 65 m_handles; //!< Source handles (emanated from skeleton vertices). 66 std::vector<TPointD> 67 m_dstHandles; //!< Corresponding destination handle positions 68 69 int m_compiled; //!< Whether compiled data is present about a certain 70 //! datatype. 71 int m_upToDate; //!< Whether updated data is present about a certain 72 //! datatype. 73 74 double m_outputFrame; //!< The frame of current output values. 75 //!< Value numeric_limits::max can be used to invalidate 76 //!< deformation outputs 77 TAffine m_skeletonAffine; //!< The skeleton affine applied to each handle. 78 //!< In case it changes, the deformation is automatically recompiled. 79 80 double m_soMin, 81 m_soMax; //!< SO min and max across the whole group (useful while drawing 82 //!< due to the unboundedness of the SO parameter) 83 std::vector<std::pair<int, int>> 84 m_sortedFaces; //!< Pairs of face-mesh indices, by sorted stacking order. 85 //!< This is the order that must be followed when drawing faces. 86 public: 87 PlasticDeformerDataGroup(); 88 ~PlasticDeformerDataGroup(); 89 90 private: 91 // Not copyable 92 93 PlasticDeformerDataGroup(const PlasticDeformerDataGroup &); 94 PlasticDeformerDataGroup &operator=(const PlasticDeformerDataGroup &); 95 }; 96 97 //*********************************************************************************************** 98 // PlasticDeformerStorage declaration 99 //*********************************************************************************************** 100 101 //! PlasticDeformerStorage is the global storage class for plastic deformers. 102 /*! 103 PlasticDeformer models a mesh-deformer object that can be used together with 104 texturing to create an interactive image-deformation technique. Direct use 105 of PlasticDeformer instances is discouraged, as they can be considered as 106 technical low-level interfaces to the deformation job. 107 108 \par Rationale 109 110 The crucial reason behind the existance of this class lies in the 111 necessity to cache PlasticDeformer instances to achieve real-time speed in 112 the processing of part of its algorithms. 113 \n\n 114 In this context, caching is all about storing intermediate data so that they 115 are recalculated only when strictly necessary. 116 In PlasticDeformer's case, we can see 3 chained processing stages that need 117 to be calculated before the final result is produced: 118 119 \li <B> Initialization: <\B> A mesh is acquired 120 \li <B> Compilation: <\B> The deformation's source domain data is acquired 121 \li <B> Deformation: <\B> The deformation's destination domain data is 122 acquired 123 124 Each step requires that the previous one has been computed. Obviously when, 125 say, only the deformation's destination data change, there is no need to 126 process 127 the first 2 steps - their cached data remains valid. 128 129 \par Interface 130 131 This class provides the preferential high-level interface to plastic 132 deformers. 133 \n\n 134 The storage caches data about every requested deform specification, that is 135 kept 136 until an explicit release command is issued. A data request is issued with a 137 call 138 to the process() method, which accepts specification of a subset of 139 deform-related 140 data to be returned, skipping unnecessary computations. 141 \n\n 142 The storage requires explicit content invalidation to know that is must 143 recalculate subsequent requests. Invalidation is specific to changes in a 144 PlasticSkeletonDeformation instance, and can be restrained to the destination 145 (deformed) domain, or require more expensive invalidation. 146 147 \par Deformations and Data requests 148 149 Cached data is uniquely associated with pairs of meshImage and deformed 150 skeletons, 151 meaning that the same meshImage can be deformed by multiple skeletons, and 152 viceversa. 153 \n\n 154 A deformer data request needs an affine transform in input, which is intended 155 to 156 map the skeleton deformation on top of the mesh (in mesh coordinates). The 157 storage 158 <I> does not <\I> store a PlasticDeformer instance for each different affine 159 supplied, 160 but rather \a invalidates the old data in case it changes. 161 \n\n 162 The mesh vertex coordinates resulting from a deformation will be stored in the 163 resulting 164 PlasticDeformerData::m_output member of each entry of the output array, one 165 for each mesh 166 of the input meshImage. The returned coordinates are intended in the mesh 167 reference. 168 169 \par Lifetime and Ownership 170 171 This class <B> does not claim ownerhip <\B> of neither the mesh nor the 172 deformation that are 173 specified in a deformer request - and <I> lifetime tracking <\I> of the 174 objects involved in 175 plastic deforming is a burden of callers. 176 \n\n 177 This class requires that the destruction of either a mesh or a deformation be 178 signaled by a 179 call to the appropriate release method in order to enforce the associated 180 deformers destruction. 181 182 \warning No call to the appropriate release method when either a mesh or a 183 deformation which 184 has requested a deformer is destroyed \b will result in a \b leak. 185 */ 186 187 class DVAPI PlasticDeformerStorage { 188 class Imp; 189 std::unique_ptr<Imp> m_imp; 190 191 public: 192 enum DataType { 193 NONE = 0x0, 194 HANDLES = 0x1, // Handles data 195 SO = 0x4, // Stacking Order data 196 MESH = 0x8, // The deformed Mesh 197 198 ALL = HANDLES | SO | MESH 199 }; 200 201 public: 202 PlasticDeformerStorage(); 203 ~PlasticDeformerStorage(); 204 205 static PlasticDeformerStorage *instance(); 206 207 //! This function processes the specified meshImage-deformation pair, 208 //! returning a DataGroup 209 //! with the required data. 210 /*! 211 \note This function \b caches all required data, so that subsequent requests 212 about the same 213 triplet can be sped up considerably in case of cache match. 214 */ 215 const PlasticDeformerDataGroup *process( 216 double frame, const TMeshImage *meshImage, 217 const PlasticSkeletonDeformation *deformation, int skeletonId, 218 const TAffine &deformationToMeshAffine, DataType dataType = ALL); 219 220 //! Performs the specified deformation once, \b without caching data. 221 /*! 222 This method allows the user to perform a single-shot Platic deformation, without 223 dealing with 224 caching issues. 225 226 \note Since caching is disabled, this method is comparably \a slower than its 227 cached counterpart, 228 in case the same deformation is repeatedly invoked. 229 It is meant to be used only in absence of user interaction. 230 231 \warning The returned pointer is owned by the \b caller, and must be manually 232 deleted 233 when no longer needed. 234 */ 235 static const PlasticDeformerDataGroup *processOnce( 236 double frame, const TMeshImage *meshImage, 237 const PlasticSkeletonDeformation *deformation, int skeletonId, 238 const TAffine &deformationToMeshAffine, DataType dataType = ALL); 239 240 //! Similarly to invalidateSkeleton(), for every deformer attached to the 241 //! specified mesh. 242 void invalidateMeshImage(const TMeshImage *meshImage, 243 int recompiledDataType = NONE); 244 245 //! Schedules all stored deformers associated to the specified deformation for 246 //! either re-deformation (stage 3 invalidation) or re-compilation (stage 2 247 //! invalidation). 248 /*! 249 Recompilation should be selected whenever the deformation has sustained source 250 domain 251 changes, such as a vertex addition or removal, or when the \a source skeletal 252 configuration has changed. 253 254 \note Recompilation is typically a slower process than the mere deformers 255 update. 256 Select it explicitly only when it truly needs to be done. 257 */ 258 void invalidateSkeleton(const PlasticSkeletonDeformation *deformation, 259 int skeletonId, int recompiledDataType = NONE); 260 261 //! Similarly to invalidateSkeleton(), for everything attached to the 262 //! specified deformation. 263 void invalidateDeformation(const PlasticSkeletonDeformation *deformation, 264 int recompiledDataType = NONE); 265 266 //! Releases all deformers associated to the specified mesh image. 267 void releaseMeshData(const TMeshImage *meshImage); 268 269 //! Releases all deformers associated to the specified skeletal deformation. 270 void releaseSkeletonData(const PlasticSkeletonDeformation *deformation, 271 int skeletonId); 272 273 //! Releases all deformers associated to the specified skeletal deformation. 274 void releaseDeformationData(const PlasticSkeletonDeformation *deformation); 275 276 //! Releases all deformers, effectively returning the storage to its empty 277 //! state. 278 void clear(); 279 280 private: 281 //! Retrieves the group of deformers (one per mesh in the image) associated to 282 //! the input 283 //! pair, eventually creating one if none did exist. 284 PlasticDeformerDataGroup *deformerData( 285 const TMeshImage *meshImage, 286 const PlasticSkeletonDeformation *deformation, int skeletonId); 287 }; 288 289 #endif // PLASTIDEFORMERSTORAGE_H 290