1 #include <memory>
2
3 // TnzExt includes
4 #include "ext/plasticskeleton.h"
5 #include "ext/plasticskeletondeformation.h"
6
7 // STD includes
8 #include <limits>
9 #include <map>
10 #include <algorithm>
11
12 // Boost includes
13 #include <boost/multi_index_container.hpp>
14 #include <boost/multi_index/ordered_index.hpp>
15 #include <boost/multi_index/member.hpp>
16
17 // Qt includes
18 #include <QMutex>
19 #include <QMutexLocker>
20
21 #include "ext/plasticdeformerstorage.h"
22
23 //***********************************************************************************************
24 // Storage multi-index map definition
25 //***********************************************************************************************
26
27 namespace {
28
29 typedef PlasticDeformerDataGroup DataGroup;
30
31 //----------------------------------------------------------------------------------
32
33 typedef std::pair<const SkD *, int> DeformedSkeleton;
34
35 //----------------------------------------------------------------------------------
36
37 struct Key {
38 const TMeshImage *m_mi;
39 DeformedSkeleton m_ds;
40
41 std::shared_ptr<DataGroup> m_dataGroup;
42
43 public:
Key__anon3bcd8a1b0111::Key44 Key(const TMeshImage *mi, const SkD *sd, int skelId)
45 : m_mi(mi), m_ds(sd, skelId), m_dataGroup() {}
46
operator <__anon3bcd8a1b0111::Key47 bool operator<(const Key &other) const {
48 return (m_mi < other.m_mi) ||
49 ((!(other.m_mi < m_mi)) && (m_ds < other.m_ds));
50 }
51 };
52
53 //----------------------------------------------------------------------------------
54
55 using namespace boost::multi_index;
56
57 typedef boost::multi_index_container<
58 Key, indexed_by<
59
60 ordered_unique<identity<Key>>,
61 ordered_non_unique<tag<TMeshImage>,
62 member<Key, const TMeshImage *, &Key::m_mi>>,
63 ordered_non_unique<tag<DeformedSkeleton>,
64 member<Key, DeformedSkeleton, &Key::m_ds>>
65
66 >>
67 DeformersSet;
68
69 typedef DeformersSet::nth_index<0>::type DeformersByKey;
70 typedef DeformersSet::index<TMeshImage>::type DeformersByMeshImage;
71 typedef DeformersSet::index<DeformedSkeleton>::type DeformersByDeformedSkeleton;
72
73 } // namespace
74
75 //***********************************************************************************************
76 // Initialization stage functions
77 //***********************************************************************************************
78
79 namespace {
80
initializeSO(PlasticDeformerData & data,const TTextureMeshP & mesh)81 void initializeSO(PlasticDeformerData &data, const TTextureMeshP &mesh) {
82 data.m_so.reset(new double[mesh->facesCount()]);
83 }
84
85 //----------------------------------------------------------------------------------
86
initializeDeformerData(PlasticDeformerData & data,const TTextureMeshP & mesh)87 void initializeDeformerData(PlasticDeformerData &data,
88 const TTextureMeshP &mesh) {
89 initializeSO(data, mesh); // Allocates SO data
90
91 // Also, allocate suitable input-output arrays for the deformation
92 data.m_output.reset(new double[2 * mesh->verticesCount()]);
93 }
94
95 //----------------------------------------------------------------------------------
96
initializeDeformersData(DataGroup * group,const TMeshImage * meshImage)97 void initializeDeformersData(DataGroup *group, const TMeshImage *meshImage) {
98 group->m_datas.reset(new PlasticDeformerData[meshImage->meshes().size()]);
99
100 // Push a PlasticDeformer for each mesh in the image
101 const std::vector<TTextureMeshP> &meshes = meshImage->meshes();
102 int fTotal = 0; // Also count total # of faces
103
104 int m, mCount = meshes.size();
105 for (m = 0; m != mCount; ++m) {
106 fTotal += meshes[m]->facesCount();
107 initializeDeformerData(group->m_datas[m], meshes[m]);
108 }
109
110 // Initialize the vector of sorted faces
111 std::vector<std::pair<int, int>> &sortedFaces = group->m_sortedFaces;
112
113 sortedFaces.reserve(fTotal);
114 for (m = 0; m != mCount; ++m) {
115 const TTextureMesh &mesh = *meshes[m];
116
117 int f, fCount = mesh.facesCount();
118 for (f = 0; f != fCount; ++f) sortedFaces.push_back(std::make_pair(f, m));
119 }
120 }
121
122 } // namespace
123
124 //***********************************************************************************************
125 // Handle processing functions
126 //***********************************************************************************************
127
128 namespace {
129
transformHandles(std::vector<PlasticHandle> & handles,const TAffine & aff)130 void transformHandles(std::vector<PlasticHandle> &handles, const TAffine &aff) {
131 // Transforms handles through deformAff AND applies mi's dpi scale inverse
132 std::vector<PlasticHandle>::size_type h, hCount = handles.size();
133 for (h = 0; h != hCount; ++h) handles[h].m_pos = aff * handles[h].m_pos;
134 }
135
136 //----------------------------------------------------------------------------------
137
transformHandles(std::vector<TPointD> & handles,const TAffine & aff)138 void transformHandles(std::vector<TPointD> &handles, const TAffine &aff) {
139 // Transforms handles through deformAff AND applies mi's dpi scale inverse
140 std::vector<PlasticHandle>::size_type h, hCount = handles.size();
141 for (h = 0; h != hCount; ++h) handles[h] = aff * handles[h];
142 }
143
144 //----------------------------------------------------------------------------------
145
processHandles(DataGroup * group,double frame,const TMeshImage * meshImage,const SkD * sd,int skelId,const TAffine & deformationAffine)146 void processHandles(DataGroup *group, double frame, const TMeshImage *meshImage,
147 const SkD *sd, int skelId,
148 const TAffine &deformationAffine) {
149 assert(sd);
150
151 const PlasticSkeletonP &skeleton = sd->skeleton(skelId);
152
153 if (!skeleton || skeleton->verticesCount() == 0) {
154 group->m_handles.clear();
155 group->m_dstHandles.clear();
156
157 group->m_compiled |= PlasticDeformerStorage::HANDLES;
158 group->m_upToDate |= PlasticDeformerStorage::HANDLES;
159
160 return;
161 }
162
163 int mCount = meshImage->meshes().size();
164
165 if (!(group->m_upToDate & PlasticDeformerStorage::HANDLES)) {
166 // Compile handles if necessary
167 if (!(group->m_compiled & PlasticDeformerStorage::HANDLES)) {
168 // Build and transform handles
169 group->m_handles = skeleton->verticesToHandles();
170 ::transformHandles(group->m_handles, deformationAffine);
171
172 // Prepare a vector for handles' face hints
173 for (int m = 0; m != mCount; ++m)
174 group->m_datas[m].m_faceHints.resize(group->m_handles.size(), -1);
175
176 group->m_compiled |= PlasticDeformerStorage::HANDLES;
177 }
178
179 // Then, build destination handles
180 PlasticSkeleton
181 deformedSkeleton; // NOTE: Could this be moved to the group as well?
182 sd->storeDeformedSkeleton(skelId, frame, deformedSkeleton);
183
184 // Copy deformed skeleton data into input deformation parameters
185 group->m_dstHandles = std::vector<TPointD>(
186 deformedSkeleton.vertices().begin(), deformedSkeleton.vertices().end());
187 ::transformHandles(group->m_dstHandles, deformationAffine);
188
189 group->m_upToDate |= PlasticDeformerStorage::HANDLES;
190 }
191 }
192
193 } // namespace
194
195 //***********************************************************************************************
196 // Stacking Order processing functions
197 //***********************************************************************************************
198
199 namespace {
200
updateHandlesSO(DataGroup * group,const SkD * sd,int skelId,double frame)201 bool updateHandlesSO(DataGroup *group, const SkD *sd, int skelId,
202 double frame) {
203 assert(sd);
204
205 const PlasticSkeletonP &skeleton = sd->skeleton(skelId);
206
207 if (!skeleton || skeleton->verticesCount() == 0) {
208 group->m_soMin = group->m_soMax = 0.0;
209 return false;
210 }
211
212 // Copy SO values to data's handles
213 // Return whether values changed with respect to previous ones
214 bool changed = false;
215
216 assert(group->m_handles.size() == skeleton->verticesCount());
217
218 int h, hCount = group->m_handles.size();
219 {
220 tcg::list<PlasticSkeletonVertex>::iterator vt =
221 skeleton->vertices().begin();
222
223 for (h = 0; h != hCount; ++h, ++vt) {
224 const SkVD *vd = sd->vertexDeformation(vt->name());
225 if (!vd) continue;
226
227 double so = vd->m_params[SkVD::SO]->getValue(frame);
228
229 PlasticHandle &handle = group->m_handles[h];
230 if (handle.m_so != so) {
231 group->m_handles[h].m_so = so;
232 changed = true;
233 }
234 }
235 }
236
237 if (changed) {
238 // Rebuild SO minmax
239 group->m_soMax = -(group->m_soMin = (std::numeric_limits<double>::max)());
240
241 for (h = 0; h != hCount; ++h) {
242 const double &so = group->m_handles[h].m_so;
243
244 group->m_soMin = std::min(group->m_soMin, so);
245 group->m_soMax = std::max(group->m_soMax, so);
246 }
247 }
248
249 return changed;
250 }
251
252 //----------------------------------------------------------------------------------
253
interpolateSO(DataGroup * group,const TMeshImage * meshImage)254 void interpolateSO(DataGroup *group, const TMeshImage *meshImage) {
255 int m, mCount = meshImage->meshes().size();
256
257 if (group->m_handles.size() == 0) {
258 // No handles case, fill in with 0s
259
260 for (m = 0; m != mCount; ++m) {
261 const TTextureMesh &mesh = *meshImage->meshes()[m];
262 PlasticDeformerData &data = group->m_datas[m];
263
264 std::fill(data.m_so.get(), data.m_so.get() + mesh.facesCount(), 0.0);
265 }
266
267 return;
268 }
269
270 // Apply handles' SO values to each mesh
271 for (m = 0; m != mCount; ++m) {
272 const TTextureMesh &mesh = *meshImage->meshes()[m];
273 PlasticDeformerData &data = group->m_datas[m];
274
275 // Interpolate so values
276 std::unique_ptr<double[]> verticesSO(new double[mesh.verticesCount()]);
277
278 ::buildSO(verticesSO.get(), mesh, group->m_handles,
279 &data.m_faceHints.front());
280
281 // Make the mean of each face's vertex values and store that
282 int f, fCount = mesh.facesCount();
283 for (f = 0; f != fCount; ++f) {
284 int v0, v1, v2;
285 mesh.faceVertices(f, v0, v1, v2);
286
287 data.m_so[f] = (verticesSO[v0] + verticesSO[v1] + verticesSO[v2]) / 3.0;
288 }
289 }
290 }
291
292 //----------------------------------------------------------------------------------
293
294 struct FaceLess {
295 const PlasticDeformerDataGroup *m_group;
296
297 public:
FaceLess__anon3bcd8a1b0411::FaceLess298 FaceLess(const PlasticDeformerDataGroup *group) : m_group(group) {}
299
operator ()__anon3bcd8a1b0411::FaceLess300 bool operator()(const std::pair<int, int> &a, const std::pair<int, int> &b) {
301 return (m_group->m_datas[a.second].m_so[a.first] <
302 m_group->m_datas[b.second].m_so[b.first]);
303 }
304 };
305
306 // Must be invoked after updateSO
updateSortedFaces(PlasticDeformerDataGroup * group)307 void updateSortedFaces(PlasticDeformerDataGroup *group) {
308 FaceLess comp(group);
309 std::sort(group->m_sortedFaces.begin(), group->m_sortedFaces.end(), comp);
310 }
311
312 //----------------------------------------------------------------------------------
313
processSO(DataGroup * group,double frame,const TMeshImage * meshImage,const SkD * sd,int skelId,const TAffine & deformationAffine)314 void processSO(DataGroup *group, double frame, const TMeshImage *meshImage,
315 const SkD *sd, int skelId, const TAffine &deformationAffine) {
316 // SO re-interpolate values along the mesh if either:
317 // 1. Recompilation was requested (ie some vertex may have been
318 // added/removed)
319 // 2. OR the value of one of the handle has changed
320
321 bool interpolate = !(group->m_compiled & PlasticDeformerStorage::SO);
322
323 if (!(group->m_upToDate &
324 PlasticDeformerStorage::SO)) // implied by (interpolate == true)
325 {
326 interpolate = updateHandlesSO(group, sd, skelId, frame) ||
327 interpolate; // Order is IMPORTANT
328
329 if (interpolate) {
330 interpolateSO(group, meshImage);
331 updateSortedFaces(group);
332 }
333
334 group->m_compiled |= PlasticDeformerStorage::SO;
335 group->m_upToDate |= PlasticDeformerStorage::SO;
336 }
337 }
338
339 } // namespace
340
341 //***********************************************************************************************
342 // Mesh Deform processing functions
343 //***********************************************************************************************
344
345 namespace {
346
processMesh(DataGroup * group,double frame,const TMeshImage * meshImage,const SkD * sd,int skelId,const TAffine & deformationAffine)347 void processMesh(DataGroup *group, double frame, const TMeshImage *meshImage,
348 const SkD *sd, int skelId, const TAffine &deformationAffine) {
349 if (!(group->m_upToDate & PlasticDeformerStorage::MESH)) {
350 int m, mCount = meshImage->meshes().size();
351
352 if (!(group->m_compiled & PlasticDeformerStorage::MESH)) {
353 for (m = 0; m != mCount; ++m) {
354 const TTextureMeshP &mesh = meshImage->meshes()[m];
355 PlasticDeformerData &data = group->m_datas[m];
356
357 data.m_deformer.initialize(mesh);
358 data.m_deformer.compile(
359 group->m_handles,
360 data.m_faceHints.empty() ? 0 : &data.m_faceHints.front());
361 data.m_deformer.releaseInitializedData();
362 }
363
364 group->m_compiled |= PlasticDeformerStorage::MESH;
365 }
366
367 const TPointD *dstHandlePos =
368 group->m_dstHandles.empty() ? 0 : &group->m_dstHandles.front();
369
370 for (m = 0; m != mCount; ++m) {
371 PlasticDeformerData &data = group->m_datas[m];
372 data.m_deformer.deform(dstHandlePos, data.m_output.get());
373 }
374
375 group->m_upToDate |= PlasticDeformerStorage::MESH;
376 }
377 }
378
379 } // namespace
380
381 //***********************************************************************************************
382 // PlasticDeformerData implementation
383 //***********************************************************************************************
384
PlasticDeformerData()385 PlasticDeformerData::PlasticDeformerData() {}
386
387 //----------------------------------------------------------------------------------
388
~PlasticDeformerData()389 PlasticDeformerData::~PlasticDeformerData() {}
390
391 //***********************************************************************************************
392 // PlasticDeformerDataGroup implementation
393 //***********************************************************************************************
394
PlasticDeformerDataGroup()395 PlasticDeformerDataGroup::PlasticDeformerDataGroup()
396 : m_datas()
397 , m_compiled(PlasticDeformerStorage::NONE)
398 , m_upToDate(PlasticDeformerStorage::NONE)
399 , m_outputFrame((std::numeric_limits<double>::max)())
400 , m_soMin()
401 , m_soMax() {}
402
403 //----------------------------------------------------------------------------------
404
~PlasticDeformerDataGroup()405 PlasticDeformerDataGroup::~PlasticDeformerDataGroup() {}
406
407 //***********************************************************************************************
408 // PlasticDeformerStorage::Imp definition
409 //***********************************************************************************************
410
411 class PlasticDeformerStorage::Imp {
412 public:
413 QMutex m_mutex; //!< Access mutex - needed for thread-safety
414 DeformersSet m_deformers; //!< Set of deformers, ordered by mesh image,
415 //! deformation, and affine.
416
417 public:
Imp()418 Imp() : m_mutex(QMutex::Recursive) {}
419 };
420
421 //***********************************************************************************************
422 // PlasticDeformerStorage implementation
423 //***********************************************************************************************
424
PlasticDeformerStorage()425 PlasticDeformerStorage::PlasticDeformerStorage() : m_imp(new Imp) {}
426
427 //----------------------------------------------------------------------------------
428
~PlasticDeformerStorage()429 PlasticDeformerStorage::~PlasticDeformerStorage() {}
430
431 //----------------------------------------------------------------------------------
432
instance()433 PlasticDeformerStorage *PlasticDeformerStorage::instance() {
434 static PlasticDeformerStorage theInstance;
435 return &theInstance;
436 }
437
438 //----------------------------------------------------------------------------------
439
deformerData(const TMeshImage * meshImage,const PlasticSkeletonDeformation * deformation,int skelId)440 PlasticDeformerDataGroup *PlasticDeformerStorage::deformerData(
441 const TMeshImage *meshImage, const PlasticSkeletonDeformation *deformation,
442 int skelId) {
443 QMutexLocker locker(&m_imp->m_mutex);
444
445 // Search for the corresponding deformation in the storage
446 Key key(meshImage, deformation, skelId);
447
448 DeformersByKey::iterator dt = m_imp->m_deformers.find(key);
449 if (dt == m_imp->m_deformers.end()) {
450 // No deformer was found. Allocate it.
451 key.m_dataGroup = std::make_shared<PlasticDeformerDataGroup>();
452 initializeDeformersData(key.m_dataGroup.get(), meshImage);
453
454 dt = m_imp->m_deformers.insert(key).first;
455 }
456
457 return dt->m_dataGroup.get();
458 }
459
460 //----------------------------------------------------------------------------------
461
process(double frame,const TMeshImage * meshImage,const PlasticSkeletonDeformation * deformation,int skelId,const TAffine & skeletonAffine,DataType dataType)462 const PlasticDeformerDataGroup *PlasticDeformerStorage::process(
463 double frame, const TMeshImage *meshImage,
464 const PlasticSkeletonDeformation *deformation, int skelId,
465 const TAffine &skeletonAffine, DataType dataType) {
466 QMutexLocker locker(&m_imp->m_mutex);
467
468 PlasticDeformerDataGroup *group =
469 deformerData(meshImage, deformation, skelId);
470
471 // On-the-fly checks for data invalidation
472 if (group->m_skeletonAffine != skeletonAffine) {
473 group->m_upToDate = NONE;
474 group->m_compiled = NONE;
475 group->m_skeletonAffine = skeletonAffine;
476 }
477
478 if (group->m_outputFrame != frame) {
479 group->m_upToDate = NONE;
480 group->m_outputFrame = frame;
481 }
482
483 bool doMesh = (dataType & MESH);
484 bool doSO = (dataType & SO) || doMesh;
485 bool doHandles = (bool)dataType;
486
487 // Process data
488 if (doHandles)
489 processHandles(group, frame, meshImage, deformation, skelId,
490 skeletonAffine);
491
492 if (doSO)
493 processSO(group, frame, meshImage, deformation, skelId, skeletonAffine);
494
495 if (doMesh)
496 processMesh(group, frame, meshImage, deformation, skelId, skeletonAffine);
497
498 return group;
499 }
500
501 //----------------------------------------------------------------------------------
502
processOnce(double frame,const TMeshImage * meshImage,const PlasticSkeletonDeformation * deformation,int skelId,const TAffine & skeletonAffine,DataType dataType)503 const PlasticDeformerDataGroup *PlasticDeformerStorage::processOnce(
504 double frame, const TMeshImage *meshImage,
505 const PlasticSkeletonDeformation *deformation, int skelId,
506 const TAffine &skeletonAffine, DataType dataType) {
507 PlasticDeformerDataGroup *group = new PlasticDeformerDataGroup;
508 initializeDeformersData(group, meshImage);
509
510 bool doMesh = (dataType & MESH);
511 bool doSO = (dataType & SO) || doMesh;
512 bool doHandles = (bool)dataType;
513
514 // Process data
515 if (doHandles)
516 processHandles(group, frame, meshImage, deformation, skelId,
517 skeletonAffine);
518
519 if (doSO)
520 processSO(group, frame, meshImage, deformation, skelId, skeletonAffine);
521
522 if (doMesh)
523 processMesh(group, frame, meshImage, deformation, skelId, skeletonAffine);
524
525 return group;
526 }
527
528 //----------------------------------------------------------------------------------
529
invalidateMeshImage(const TMeshImage * meshImage,int recompiledData)530 void PlasticDeformerStorage::invalidateMeshImage(const TMeshImage *meshImage,
531 int recompiledData) {
532 QMutexLocker locker(&m_imp->m_mutex);
533
534 DeformersByMeshImage &deformers = m_imp->m_deformers.get<TMeshImage>();
535
536 DeformersByMeshImage::iterator dBegin(deformers.lower_bound(meshImage));
537 if (dBegin == deformers.end()) return;
538
539 DeformersByMeshImage::iterator dt, dEnd(deformers.upper_bound(meshImage));
540 for (dt = dBegin; dt != dEnd; ++dt) {
541 dt->m_dataGroup->m_outputFrame =
542 (std::numeric_limits<double>::max)(); // Schedule for redeformation
543 if (recompiledData)
544 dt->m_dataGroup->m_compiled &=
545 ~recompiledData; // Schedule for recompilation, too
546 }
547 }
548
549 //----------------------------------------------------------------------------------
550
invalidateSkeleton(const PlasticSkeletonDeformation * deformation,int skelId,int recompiledData)551 void PlasticDeformerStorage::invalidateSkeleton(
552 const PlasticSkeletonDeformation *deformation, int skelId,
553 int recompiledData) {
554 QMutexLocker locker(&m_imp->m_mutex);
555
556 DeformedSkeleton ds(deformation, skelId);
557
558 DeformersByDeformedSkeleton &deformers =
559 m_imp->m_deformers.get<DeformedSkeleton>();
560
561 DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(ds));
562 if (dBegin == deformers.end()) return;
563
564 DeformersByDeformedSkeleton::iterator dt, dEnd(deformers.upper_bound(ds));
565 for (dt = dBegin; dt != dEnd; ++dt) {
566 dt->m_dataGroup->m_outputFrame =
567 (std::numeric_limits<double>::max)(); // Schedule for redeformation
568 if (recompiledData)
569 dt->m_dataGroup->m_compiled &=
570 ~recompiledData; // Schedule for recompilation, too
571 }
572 }
573
574 //----------------------------------------------------------------------------------
575
invalidateDeformation(const PlasticSkeletonDeformation * deformation,int recompiledData)576 void PlasticDeformerStorage::invalidateDeformation(
577 const PlasticSkeletonDeformation *deformation, int recompiledData) {
578 QMutexLocker locker(&m_imp->m_mutex);
579
580 DeformersByDeformedSkeleton &deformers =
581 m_imp->m_deformers.get<DeformedSkeleton>();
582
583 DeformedSkeleton dsBegin(deformation, -(std::numeric_limits<int>::max)()),
584 dsEnd(deformation, (std::numeric_limits<int>::max)());
585
586 DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(dsBegin));
587 DeformersByDeformedSkeleton::iterator dEnd(deformers.upper_bound(dsEnd));
588
589 if (dBegin == dEnd) return;
590
591 for (DeformersByDeformedSkeleton::iterator dt = dBegin; dt != dEnd; ++dt) {
592 dt->m_dataGroup->m_outputFrame =
593 (std::numeric_limits<double>::max)(); // Schedule for redeformation
594 if (recompiledData)
595 dt->m_dataGroup->m_compiled &=
596 ~recompiledData; // Schedule for recompilation, too
597 }
598 }
599
600 //----------------------------------------------------------------------------------
601
releaseMeshData(const TMeshImage * meshImage)602 void PlasticDeformerStorage::releaseMeshData(const TMeshImage *meshImage) {
603 QMutexLocker locker(&m_imp->m_mutex);
604
605 DeformersByMeshImage &deformers = m_imp->m_deformers.get<TMeshImage>();
606
607 DeformersByMeshImage::iterator dBegin(deformers.lower_bound(meshImage));
608 if (dBegin == deformers.end()) return;
609
610 deformers.erase(dBegin, deformers.upper_bound(meshImage));
611 }
612
613 //----------------------------------------------------------------------------------
614
releaseSkeletonData(const SkD * deformation,int skelId)615 void PlasticDeformerStorage::releaseSkeletonData(const SkD *deformation,
616 int skelId) {
617 QMutexLocker locker(&m_imp->m_mutex);
618
619 DeformedSkeleton ds(deformation, skelId);
620
621 DeformersByDeformedSkeleton &deformers =
622 m_imp->m_deformers.get<DeformedSkeleton>();
623
624 DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(ds));
625 if (dBegin == deformers.end()) return;
626
627 deformers.erase(dBegin, deformers.upper_bound(ds));
628 }
629
630 //----------------------------------------------------------------------------------
631
releaseDeformationData(const SkD * deformation)632 void PlasticDeformerStorage::releaseDeformationData(const SkD *deformation) {
633 QMutexLocker locker(&m_imp->m_mutex);
634
635 DeformersByDeformedSkeleton &deformers =
636 m_imp->m_deformers.get<DeformedSkeleton>();
637
638 DeformedSkeleton dsBegin(deformation, -(std::numeric_limits<int>::max)()),
639 dsEnd(deformation, (std::numeric_limits<int>::max)());
640
641 DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(dsBegin));
642 DeformersByDeformedSkeleton::iterator dEnd(deformers.upper_bound(dsEnd));
643
644 if (dBegin == dEnd) return;
645
646 deformers.erase(dBegin, dEnd);
647 }
648
649 //----------------------------------------------------------------------------------
650
clear()651 void PlasticDeformerStorage::clear() {
652 QMutexLocker locker(&m_imp->m_mutex);
653
654 m_imp->m_deformers.clear();
655 }
656