| #include <memory> |
| |
| |
| #include "ext/plasticskeleton.h" |
| #include "ext/plasticskeletondeformation.h" |
| |
| |
| #include <limits> |
| #include <map> |
| #include <algorithm> |
| |
| |
| #include <boost/multi_index_container.hpp> |
| #include <boost/multi_index/ordered_index.hpp> |
| #include <boost/multi_index/member.hpp> |
| |
| |
| #include <QMutex> |
| #include <QMutexLocker> |
| |
| #include "ext/plasticdeformerstorage.h" |
| |
| |
| |
| |
| |
| namespace { |
| |
| typedef PlasticDeformerDataGroup DataGroup; |
| |
| |
| |
| typedef std::pair<const SkD *, int> DeformedSkeleton; |
| |
| |
| |
| struct Key { |
| const TMeshImage *m_mi; |
| DeformedSkeleton m_ds; |
| |
| std::shared_ptr<DataGroup> m_dataGroup; |
| |
| public: |
| Key(const TMeshImage *mi, const SkD *sd, int skelId) |
| : m_mi(mi), m_ds(sd, skelId), m_dataGroup() {} |
| |
| bool operator<(const Key &other) const { |
| return (m_mi < other.m_mi) || |
| ((!(other.m_mi < m_mi)) && (m_ds < other.m_ds)); |
| } |
| }; |
| |
| |
| |
| using namespace boost::multi_index; |
| |
| typedef boost::multi_index_container< |
| Key, indexed_by< |
| |
| ordered_unique<identity<Key>>, |
| ordered_non_unique<tag<TMeshImage>, |
| member<Key, const TMeshImage *, &Key::m_mi>>, |
| ordered_non_unique<tag<DeformedSkeleton>, |
| member<Key, DeformedSkeleton, &Key::m_ds>> |
| |
| >> |
| DeformersSet; |
| |
| typedef DeformersSet::nth_index<0>::type DeformersByKey; |
| typedef DeformersSet::index<TMeshImage>::type DeformersByMeshImage; |
| typedef DeformersSet::index<DeformedSkeleton>::type DeformersByDeformedSkeleton; |
| |
| } |
| |
| |
| |
| |
| |
| namespace { |
| |
| void initializeSO(PlasticDeformerData &data, const TTextureMeshP &mesh) { |
| data.m_so.reset(new double[mesh->facesCount()]); |
| } |
| |
| |
| |
| void initializeDeformerData(PlasticDeformerData &data, |
| const TTextureMeshP &mesh) { |
| initializeSO(data, mesh); |
| |
| |
| data.m_output.reset(new double[2 * mesh->verticesCount()]); |
| } |
| |
| |
| |
| void initializeDeformersData(DataGroup *group, const TMeshImage *meshImage) { |
| group->m_datas.reset(new PlasticDeformerData[meshImage->meshes().size()]); |
| |
| |
| const std::vector<TTextureMeshP> &meshes = meshImage->meshes(); |
| int fTotal = 0; |
| |
| int m, mCount = meshes.size(); |
| for (m = 0; m != mCount; ++m) { |
| fTotal += meshes[m]->facesCount(); |
| initializeDeformerData(group->m_datas[m], meshes[m]); |
| } |
| |
| |
| std::vector<std::pair<int, int>> &sortedFaces = group->m_sortedFaces; |
| |
| sortedFaces.reserve(fTotal); |
| for (m = 0; m != mCount; ++m) { |
| const TTextureMesh &mesh = *meshes[m]; |
| |
| int f, fCount = mesh.facesCount(); |
| for (f = 0; f != fCount; ++f) sortedFaces.push_back(std::make_pair(f, m)); |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| |
| namespace { |
| |
| void transformHandles(std::vector<PlasticHandle> &handles, const TAffine &aff) { |
| |
| std::vector<PlasticHandle>::size_type h, hCount = handles.size(); |
| for (h = 0; h != hCount; ++h) handles[h].m_pos = aff * handles[h].m_pos; |
| } |
| |
| |
| |
| void transformHandles(std::vector<TPointD> &handles, const TAffine &aff) { |
| |
| std::vector<PlasticHandle>::size_type h, hCount = handles.size(); |
| for (h = 0; h != hCount; ++h) handles[h] = aff * handles[h]; |
| } |
| |
| |
| |
| void processHandles(DataGroup *group, double frame, const TMeshImage *meshImage, |
| const SkD *sd, int skelId, |
| const TAffine &deformationAffine) { |
| assert(sd); |
| |
| const PlasticSkeletonP &skeleton = sd->skeleton(skelId); |
| |
| if (!skeleton || skeleton->verticesCount() == 0) { |
| group->m_handles.clear(); |
| group->m_dstHandles.clear(); |
| |
| group->m_compiled |= PlasticDeformerStorage::HANDLES; |
| group->m_upToDate |= PlasticDeformerStorage::HANDLES; |
| |
| return; |
| } |
| |
| int mCount = meshImage->meshes().size(); |
| |
| if (!(group->m_upToDate & PlasticDeformerStorage::HANDLES)) { |
| |
| if (!(group->m_compiled & PlasticDeformerStorage::HANDLES)) { |
| |
| group->m_handles = skeleton->verticesToHandles(); |
| ::transformHandles(group->m_handles, deformationAffine); |
| |
| |
| for (int m = 0; m != mCount; ++m) |
| group->m_datas[m].m_faceHints.resize(group->m_handles.size(), -1); |
| |
| group->m_compiled |= PlasticDeformerStorage::HANDLES; |
| } |
| |
| |
| PlasticSkeleton |
| deformedSkeleton; |
| sd->storeDeformedSkeleton(skelId, frame, deformedSkeleton); |
| |
| |
| group->m_dstHandles = std::vector<TPointD>( |
| deformedSkeleton.vertices().begin(), deformedSkeleton.vertices().end()); |
| ::transformHandles(group->m_dstHandles, deformationAffine); |
| |
| group->m_upToDate |= PlasticDeformerStorage::HANDLES; |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| |
| namespace { |
| |
| bool updateHandlesSO(DataGroup *group, const SkD *sd, int skelId, |
| double frame) { |
| assert(sd); |
| |
| const PlasticSkeletonP &skeleton = sd->skeleton(skelId); |
| |
| if (!skeleton || skeleton->verticesCount() == 0) { |
| group->m_soMin = group->m_soMax = 0.0; |
| return false; |
| } |
| |
| |
| |
| bool changed = false; |
| |
| assert(group->m_handles.size() == skeleton->verticesCount()); |
| |
| int h, hCount = group->m_handles.size(); |
| { |
| tcg::list<PlasticSkeletonVertex>::iterator vt = |
| skeleton->vertices().begin(); |
| |
| for (h = 0; h != hCount; ++h, ++vt) { |
| const SkVD *vd = sd->vertexDeformation(vt->name()); |
| if (!vd) continue; |
| |
| double so = vd->m_params[SkVD::SO]->getValue(frame); |
| |
| PlasticHandle &handle = group->m_handles[h]; |
| if (handle.m_so != so) { |
| group->m_handles[h].m_so = so; |
| changed = true; |
| } |
| } |
| } |
| |
| if (changed) { |
| |
| group->m_soMax = -(group->m_soMin = (std::numeric_limits<double>::max)()); |
| |
| for (h = 0; h != hCount; ++h) { |
| const double &so = group->m_handles[h].m_so; |
| |
| group->m_soMin = std::min(group->m_soMin, so); |
| group->m_soMax = std::max(group->m_soMax, so); |
| } |
| } |
| |
| return changed; |
| } |
| |
| |
| |
| void interpolateSO(DataGroup *group, const TMeshImage *meshImage) { |
| int m, mCount = meshImage->meshes().size(); |
| |
| if (group->m_handles.size() == 0) { |
| |
| |
| for (m = 0; m != mCount; ++m) { |
| const TTextureMesh &mesh = *meshImage->meshes()[m]; |
| PlasticDeformerData &data = group->m_datas[m]; |
| |
| std::fill(data.m_so.get(), data.m_so.get() + mesh.facesCount(), 0.0); |
| } |
| |
| return; |
| } |
| |
| |
| for (m = 0; m != mCount; ++m) { |
| const TTextureMesh &mesh = *meshImage->meshes()[m]; |
| PlasticDeformerData &data = group->m_datas[m]; |
| |
| |
| std::unique_ptr<double[]> verticesSO(new double[mesh.verticesCount()]); |
| |
| ::buildSO(verticesSO.get(), mesh, group->m_handles, |
| &data.m_faceHints.front()); |
| |
| |
| int f, fCount = mesh.facesCount(); |
| for (f = 0; f != fCount; ++f) { |
| int v0, v1, v2; |
| mesh.faceVertices(f, v0, v1, v2); |
| |
| data.m_so[f] = (verticesSO[v0] + verticesSO[v1] + verticesSO[v2]) / 3.0; |
| } |
| } |
| } |
| |
| |
| |
| struct FaceLess { |
| const PlasticDeformerDataGroup *m_group; |
| |
| public: |
| FaceLess(const PlasticDeformerDataGroup *group) : m_group(group) {} |
| |
| bool operator()(const std::pair<int, int> &a, const std::pair<int, int> &b) { |
| return (m_group->m_datas[a.second].m_so[a.first] < |
| m_group->m_datas[b.second].m_so[b.first]); |
| } |
| }; |
| |
| |
| void updateSortedFaces(PlasticDeformerDataGroup *group) { |
| FaceLess comp(group); |
| std::sort(group->m_sortedFaces.begin(), group->m_sortedFaces.end(), comp); |
| } |
| |
| |
| |
| void processSO(DataGroup *group, double frame, const TMeshImage *meshImage, |
| const SkD *sd, int skelId, const TAffine &deformationAffine) { |
| |
| |
| |
| |
| |
| bool interpolate = !(group->m_compiled & PlasticDeformerStorage::SO); |
| |
| if (!(group->m_upToDate & |
| PlasticDeformerStorage::SO)) |
| { |
| interpolate = updateHandlesSO(group, sd, skelId, frame) || |
| interpolate; |
| |
| if (interpolate) { |
| interpolateSO(group, meshImage); |
| updateSortedFaces(group); |
| } |
| |
| group->m_compiled |= PlasticDeformerStorage::SO; |
| group->m_upToDate |= PlasticDeformerStorage::SO; |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| |
| namespace { |
| |
| void processMesh(DataGroup *group, double frame, const TMeshImage *meshImage, |
| const SkD *sd, int skelId, const TAffine &deformationAffine) { |
| if (!(group->m_upToDate & PlasticDeformerStorage::MESH)) { |
| int m, mCount = meshImage->meshes().size(); |
| |
| if (!(group->m_compiled & PlasticDeformerStorage::MESH)) { |
| for (m = 0; m != mCount; ++m) { |
| const TTextureMeshP &mesh = meshImage->meshes()[m]; |
| PlasticDeformerData &data = group->m_datas[m]; |
| |
| data.m_deformer.initialize(mesh); |
| data.m_deformer.compile( |
| group->m_handles, |
| data.m_faceHints.empty() ? 0 : &data.m_faceHints.front()); |
| data.m_deformer.releaseInitializedData(); |
| } |
| |
| group->m_compiled |= PlasticDeformerStorage::MESH; |
| } |
| |
| const TPointD *dstHandlePos = |
| group->m_dstHandles.empty() ? 0 : &group->m_dstHandles.front(); |
| |
| for (m = 0; m != mCount; ++m) { |
| PlasticDeformerData &data = group->m_datas[m]; |
| data.m_deformer.deform(dstHandlePos, data.m_output.get()); |
| } |
| |
| group->m_upToDate |= PlasticDeformerStorage::MESH; |
| } |
| } |
| |
| } |
| |
| |
| |
| |
| |
| PlasticDeformerData::PlasticDeformerData() {} |
| |
| |
| |
| PlasticDeformerData::~PlasticDeformerData() {} |
| |
| |
| |
| |
| |
| PlasticDeformerDataGroup::PlasticDeformerDataGroup() |
| : m_datas() |
| , m_compiled(PlasticDeformerStorage::NONE) |
| , m_upToDate(PlasticDeformerStorage::NONE) |
| , m_outputFrame((std::numeric_limits<double>::max)()) |
| , m_soMin() |
| , m_soMax() {} |
| |
| |
| |
| PlasticDeformerDataGroup::~PlasticDeformerDataGroup() {} |
| |
| |
| |
| |
| |
| class PlasticDeformerStorage::Imp { |
| public: |
| QMutex m_mutex; |
| DeformersSet m_deformers; |
| |
| |
| public: |
| Imp() : m_mutex(QMutex::Recursive) {} |
| }; |
| |
| |
| |
| |
| |
| PlasticDeformerStorage::PlasticDeformerStorage() : m_imp(new Imp) {} |
| |
| |
| |
| PlasticDeformerStorage::~PlasticDeformerStorage() {} |
| |
| |
| |
| PlasticDeformerStorage *PlasticDeformerStorage::instance() { |
| static PlasticDeformerStorage theInstance; |
| return &theInstance; |
| } |
| |
| |
| |
| PlasticDeformerDataGroup *PlasticDeformerStorage::deformerData( |
| const TMeshImage *meshImage, const PlasticSkeletonDeformation *deformation, |
| int skelId) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| |
| Key key(meshImage, deformation, skelId); |
| |
| DeformersByKey::iterator dt = m_imp->m_deformers.find(key); |
| if (dt == m_imp->m_deformers.end()) { |
| |
| key.m_dataGroup = std::make_shared<PlasticDeformerDataGroup>(); |
| initializeDeformersData(key.m_dataGroup.get(), meshImage); |
| |
| dt = m_imp->m_deformers.insert(key).first; |
| } |
| |
| return dt->m_dataGroup.get(); |
| } |
| |
| |
| |
| const PlasticDeformerDataGroup *PlasticDeformerStorage::process( |
| double frame, const TMeshImage *meshImage, |
| const PlasticSkeletonDeformation *deformation, int skelId, |
| const TAffine &skeletonAffine, DataType dataType) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| PlasticDeformerDataGroup *group = |
| deformerData(meshImage, deformation, skelId); |
| |
| |
| if (group->m_skeletonAffine != skeletonAffine) { |
| group->m_upToDate = NONE; |
| group->m_compiled = NONE; |
| group->m_skeletonAffine = skeletonAffine; |
| } |
| |
| if (group->m_outputFrame != frame) { |
| group->m_upToDate = NONE; |
| group->m_outputFrame = frame; |
| } |
| |
| bool doMesh = (dataType & MESH); |
| bool doSO = (dataType & SO) || doMesh; |
| bool doHandles = (bool)dataType; |
| |
| |
| if (doHandles) |
| processHandles(group, frame, meshImage, deformation, skelId, |
| skeletonAffine); |
| |
| if (doSO) |
| processSO(group, frame, meshImage, deformation, skelId, skeletonAffine); |
| |
| if (doMesh) |
| processMesh(group, frame, meshImage, deformation, skelId, skeletonAffine); |
| |
| return group; |
| } |
| |
| |
| |
| const PlasticDeformerDataGroup *PlasticDeformerStorage::processOnce( |
| double frame, const TMeshImage *meshImage, |
| const PlasticSkeletonDeformation *deformation, int skelId, |
| const TAffine &skeletonAffine, DataType dataType) { |
| PlasticDeformerDataGroup *group = new PlasticDeformerDataGroup; |
| initializeDeformersData(group, meshImage); |
| |
| bool doMesh = (dataType & MESH); |
| bool doSO = (dataType & SO) || doMesh; |
| bool doHandles = (bool)dataType; |
| |
| |
| if (doHandles) |
| processHandles(group, frame, meshImage, deformation, skelId, |
| skeletonAffine); |
| |
| if (doSO) |
| processSO(group, frame, meshImage, deformation, skelId, skeletonAffine); |
| |
| if (doMesh) |
| processMesh(group, frame, meshImage, deformation, skelId, skeletonAffine); |
| |
| return group; |
| } |
| |
| |
| |
| void PlasticDeformerStorage::invalidateMeshImage(const TMeshImage *meshImage, |
| int recompiledData) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| DeformersByMeshImage &deformers = m_imp->m_deformers.get<TMeshImage>(); |
| |
| DeformersByMeshImage::iterator dBegin(deformers.lower_bound(meshImage)); |
| if (dBegin == deformers.end()) return; |
| |
| DeformersByMeshImage::iterator dt, dEnd(deformers.upper_bound(meshImage)); |
| for (dt = dBegin; dt != dEnd; ++dt) { |
| dt->m_dataGroup->m_outputFrame = |
| (std::numeric_limits<double>::max)(); |
| if (recompiledData) |
| dt->m_dataGroup->m_compiled &= |
| ~recompiledData; |
| } |
| } |
| |
| |
| |
| void PlasticDeformerStorage::invalidateSkeleton( |
| const PlasticSkeletonDeformation *deformation, int skelId, |
| int recompiledData) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| DeformedSkeleton ds(deformation, skelId); |
| |
| DeformersByDeformedSkeleton &deformers = |
| m_imp->m_deformers.get<DeformedSkeleton>(); |
| |
| DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(ds)); |
| if (dBegin == deformers.end()) return; |
| |
| DeformersByDeformedSkeleton::iterator dt, dEnd(deformers.upper_bound(ds)); |
| for (dt = dBegin; dt != dEnd; ++dt) { |
| dt->m_dataGroup->m_outputFrame = |
| (std::numeric_limits<double>::max)(); |
| if (recompiledData) |
| dt->m_dataGroup->m_compiled &= |
| ~recompiledData; |
| } |
| } |
| |
| |
| |
| void PlasticDeformerStorage::invalidateDeformation( |
| const PlasticSkeletonDeformation *deformation, int recompiledData) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| DeformersByDeformedSkeleton &deformers = |
| m_imp->m_deformers.get<DeformedSkeleton>(); |
| |
| DeformedSkeleton dsBegin(deformation, -(std::numeric_limits<int>::max)()), |
| dsEnd(deformation, (std::numeric_limits<int>::max)()); |
| |
| DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(dsBegin)); |
| DeformersByDeformedSkeleton::iterator dEnd(deformers.upper_bound(dsEnd)); |
| |
| if (dBegin == dEnd) return; |
| |
| for (DeformersByDeformedSkeleton::iterator dt = dBegin; dt != dEnd; ++dt) { |
| dt->m_dataGroup->m_outputFrame = |
| (std::numeric_limits<double>::max)(); |
| if (recompiledData) |
| dt->m_dataGroup->m_compiled &= |
| ~recompiledData; |
| } |
| } |
| |
| |
| |
| void PlasticDeformerStorage::releaseMeshData(const TMeshImage *meshImage) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| DeformersByMeshImage &deformers = m_imp->m_deformers.get<TMeshImage>(); |
| |
| DeformersByMeshImage::iterator dBegin(deformers.lower_bound(meshImage)); |
| if (dBegin == deformers.end()) return; |
| |
| deformers.erase(dBegin, deformers.upper_bound(meshImage)); |
| } |
| |
| |
| |
| void PlasticDeformerStorage::releaseSkeletonData(const SkD *deformation, |
| int skelId) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| DeformedSkeleton ds(deformation, skelId); |
| |
| DeformersByDeformedSkeleton &deformers = |
| m_imp->m_deformers.get<DeformedSkeleton>(); |
| |
| DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(ds)); |
| if (dBegin == deformers.end()) return; |
| |
| deformers.erase(dBegin, deformers.upper_bound(ds)); |
| } |
| |
| |
| |
| void PlasticDeformerStorage::releaseDeformationData(const SkD *deformation) { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| DeformersByDeformedSkeleton &deformers = |
| m_imp->m_deformers.get<DeformedSkeleton>(); |
| |
| DeformedSkeleton dsBegin(deformation, -(std::numeric_limits<int>::max)()), |
| dsEnd(deformation, (std::numeric_limits<int>::max)()); |
| |
| DeformersByDeformedSkeleton::iterator dBegin(deformers.lower_bound(dsBegin)); |
| DeformersByDeformedSkeleton::iterator dEnd(deformers.upper_bound(dsEnd)); |
| |
| if (dBegin == dEnd) return; |
| |
| deformers.erase(dBegin, dEnd); |
| } |
| |
| |
| |
| void PlasticDeformerStorage::clear() { |
| QMutexLocker locker(&m_imp->m_mutex); |
| |
| m_imp->m_deformers.clear(); |
| } |