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