| |
| |
|
|
| #include "tundo.h" |
| |
| |
| #include "ext/plasticdeformerstorage.h" |
| |
| |
| #include "toonz/txshcell.h" |
| #include "toonz/txshsimplelevel.h" |
| #include "toonz/txsheethandle.h" |
| #include "toonz/stage.h" |
| |
| |
| #include "tcg/tcg_point_ops.h" |
| #include "tcg/tcg_algorithm.h" |
| #include "tcg/tcg_function_types.h" |
| #include "tcg/tcg_iterator_ops.h" |
| |
| #include "plastictool.h" |
| |
| using namespace PlasticToolLocals; |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| TPointD closestMeshVertexPos(const TPointD &pos, double *distance = 0) |
| { |
| const TXshCell &imageCell = TTool::getImageCell(); |
| |
| TXshSimpleLevel *sl = imageCell.getSimpleLevel(); |
| assert(sl); |
| |
| TMeshImageP mi(TTool::getImage(false)); |
| assert(mi); |
| |
| |
| |
| |
| |
| const TPointD &dpi = sl->getDpi(imageCell.getFrameId()); |
| assert(dpi.x > 0.0 && dpi.y > 0.0); |
| |
| |
| const TPointD pos_mesh(pos.x * (dpi.x / Stage::inch), pos.y * (dpi.y / Stage::inch)); |
| |
| |
| const std::pair<double, PlasticTool::MeshIndex> &closest = |
| PlasticToolLocals::closestVertex(*mi, pos_mesh); |
| |
| const TPointD &vxPos_mesh = mi->meshes()[closest.second.m_meshIdx]->vertex(closest.second.m_idx).P(); |
| |
| if (distance) |
| *distance = std::min(Stage::inch / dpi.x, Stage::inch / dpi.y) * closest.first; |
| |
| |
| return TPointD(vxPos_mesh.x * (Stage::inch / dpi.x), vxPos_mesh.y * (Stage::inch / dpi.y)); |
| } |
| |
| |
| |
| TPointD closestSkeletonVertexPos(const TPointD &pos) |
| { |
| struct locals { |
| static inline double dist2(const TPointD &pos, const PlasticSkeletonVertex &vx) |
| { |
| return tcg::point_ops::dist2(pos, vx.P()); |
| } |
| }; |
| |
| const PlasticSkeletonP &skeleton = l_plasticTool.skeleton(); |
| if (!skeleton || skeleton->empty()) |
| return TConsts::napd; |
| |
| const PlasticSkeleton::vertices_container &vertices = skeleton->vertices(); |
| |
| return tcg::min_transform(vertices.begin(), vertices.end(), |
| tcg::bind1st(&locals::dist2, pos)) |
| ->P(); |
| } |
| |
| } |
| |
| |
| |
| |
| |
| namespace |
| { |
| |
| class VertexUndo : public TUndo |
| { |
| protected: |
| int m_row, m_col; |
| |
| int m_v, m_vParent; |
| PlasticSkeletonVertex m_vx; |
| |
| std::vector<int> m_children; |
| |
| public: |
| VertexUndo() : m_row(::row()), m_col(::column()), m_v(-1), m_vParent(-1) {} |
| |
| int getSize() const { return sizeof(*this); } |
| |
| void storeChildren(const PlasticSkeleton &skeleton, const PlasticSkeletonVertex &vx) |
| { |
| m_children.clear(); |
| |
| |
| PlasticSkeletonVertex::edges_const_iterator et, eEnd(vx.edgesEnd()); |
| for (et = vx.edgesBegin(); et != eEnd; ++et) { |
| int vChild = skeleton.edge(*et).vertex(1); |
| if (vChild == vx.getIndex()) |
| continue; |
| |
| m_children.push_back(vChild); |
| } |
| } |
| |
| void addVertex() |
| { |
| assert(m_vx.edges().empty()); |
| |
| |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| const PlasticSkeletonP &skeleton = l_plasticTool.skeleton(); |
| TCG_ASSERT(skeleton || m_vParent < 0, return ); |
| |
| |
| l_plasticTool.setSkeletonSelection(m_vParent); |
| l_plasticTool.addVertex(m_vx); |
| |
| |
| assert(l_plasticTool.skeletonVertexSelection().hasSingleObject()); |
| m_v = l_plasticTool.skeletonVertexSelection(); |
| } |
| |
| void insertVertex() |
| { |
| if (m_children.empty()) { |
| addVertex(); |
| return; |
| } |
| |
| assert(m_vx.edges().empty()); |
| |
| TCG_ASSERT(m_vParent >= 0, return ); |
| |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| const PlasticSkeletonP &skeleton = l_plasticTool.skeleton(); |
| TCG_ASSERT(skeleton, return ); |
| |
| |
| l_plasticTool.insertVertex(m_vx, m_vParent, m_children); |
| |
| |
| assert(l_plasticTool.skeletonVertexSelection().hasSingleObject()); |
| m_v = l_plasticTool.skeletonVertexSelection(); |
| } |
| |
| void removeVertex() |
| { |
| TCG_ASSERT(m_v >= 0, return ); |
| |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| const PlasticSkeletonP &skeleton = l_plasticTool.skeleton(); |
| TCG_ASSERT(skeleton, return ); |
| |
| |
| { |
| const PlasticSkeletonVertex &vx = skeleton->vertex(m_v); |
| |
| m_vParent = vx.parent(); |
| m_vx = PlasticSkeletonVertex(vx.P()); |
| |
| storeChildren(*skeleton, vx); |
| } |
| |
| |
| if (m_v > 0) { |
| l_plasticTool.setSkeletonSelection(m_v); |
| l_plasticTool.removeVertex(); |
| } else |
| l_plasticTool.removeSkeleton(::skeletonId()); |
| } |
| }; |
| |
| |
| |
| class AddVertexUndo : public VertexUndo |
| { |
| public: |
| AddVertexUndo(int vParent, const PlasticSkeletonVertex &vx) |
| { |
| m_vParent = vParent, m_vx = vx; |
| assert(m_vx.edges().empty()); |
| } |
| |
| void redo() const { const_cast<AddVertexUndo &>(*this).VertexUndo::addVertex(); } |
| void undo() const { const_cast<AddVertexUndo &>(*this).VertexUndo::removeVertex(); } |
| }; |
| |
| |
| |
| class RemoveVertexUndo : public VertexUndo |
| { |
| public: |
| RemoveVertexUndo(int v) |
| { |
| assert(v >= 0); |
| m_v = v; |
| } |
| |
| void redo() const { const_cast<RemoveVertexUndo &>(*this).VertexUndo::removeVertex(); } |
| void undo() const { const_cast<RemoveVertexUndo &>(*this).VertexUndo::insertVertex(); } |
| }; |
| |
| |
| |
| class InsertVertexUndo : public VertexUndo |
| { |
| public: |
| InsertVertexUndo(int e, const PlasticSkeletonVertex &vx) |
| { |
| const PlasticSkeleton &skeleton = *l_plasticTool.skeleton(); |
| const PlasticSkeleton::edge_type &ed = skeleton.edge(e); |
| |
| m_vParent = ed.vertex(0), m_vx = vx; |
| std::vector<int>(1, ed.vertex(1)).swap(m_children); |
| } |
| |
| void redo() const |
| { |
| const_cast<InsertVertexUndo &>(*this).VertexUndo::insertVertex(); |
| } |
| |
| void undo() const |
| { |
| TCG_ASSERT(!m_children.empty(), return ); |
| |
| const_cast<InsertVertexUndo &>(*this).VertexUndo::removeVertex(); |
| } |
| }; |
| |
| |
| |
| class AddSkeletonUndo : public TUndo |
| { |
| protected: |
| int m_row, m_col; |
| |
| int m_skelId; |
| PlasticSkeletonP m_skeleton; |
| |
| public: |
| AddSkeletonUndo(int skelId, const PlasticSkeletonP &skeletonCopy) |
| : m_row(::row()), m_col(::column()), m_skelId(skelId), m_skeleton(skeletonCopy) {} |
| |
| |
| |
| |
| int getSize() const { return 1 << 20; } |
| |
| void redo() const |
| { |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| l_plasticTool.addSkeleton(m_skelId, new PlasticSkeleton(*m_skeleton)); |
| ::invalidateXsheet(); |
| } |
| |
| void undo() const |
| { |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| l_plasticTool.removeSkeleton(m_skelId); |
| } |
| }; |
| |
| |
| |
| class RemoveSkeletonUndo : public AddSkeletonUndo |
| { |
| public: |
| RemoveSkeletonUndo(int skelId) : AddSkeletonUndo(skelId, l_plasticTool.skeleton()) {} |
| |
| void redo() const { AddSkeletonUndo::undo(); } |
| void undo() const { AddSkeletonUndo::redo(); } |
| }; |
| |
| |
| |
| class RemoveSkeletonUndo_WithKeyframes : public RemoveSkeletonUndo |
| { |
| mutable std::vector<TDoubleKeyframe> m_skelIdsKeyframes; |
| |
| public: |
| RemoveSkeletonUndo_WithKeyframes(int skelId) : RemoveSkeletonUndo(skelId) {} |
| |
| void redo() const |
| { |
| |
| const SkDP &sd = l_plasticTool.deformation(); |
| TCG_ASSERT(sd, return ); |
| |
| const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam(); |
| if (skelIdsParam->getKeyframeCount() > 0) { |
| double frame; |
| |
| for (int k = 0; k >= 0; k = skelIdsParam->getNextKeyframe(frame)) { |
| const TDoubleKeyframe &kf = skelIdsParam->getKeyframe(k); |
| frame = kf.m_frame; |
| |
| if (m_skelId == (int)kf.m_value) { |
| m_skelIdsKeyframes.push_back(kf); |
| skelIdsParam->deleteKeyframe(frame); |
| } |
| } |
| } |
| |
| RemoveSkeletonUndo::redo(); |
| } |
| |
| void undo() const |
| { |
| l_plasticTool.touchDeformation(); |
| |
| |
| const SkDP &sd = l_plasticTool.deformation(); |
| assert(sd); |
| |
| const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam(); |
| |
| std::vector<TDoubleKeyframe>::iterator kt, kEnd(m_skelIdsKeyframes.end()); |
| for (kt = m_skelIdsKeyframes.begin(); kt != kEnd; ++kt) |
| skelIdsParam->setKeyframe(*kt); |
| |
| m_skelIdsKeyframes.clear(); |
| |
| RemoveSkeletonUndo::undo(); |
| } |
| }; |
| |
| |
| |
| class SetSkeletonIdUndo : public TUndo |
| { |
| int m_row, m_col; |
| |
| int m_skelId; |
| mutable TDoubleKeyframe m_oldKf; |
| mutable bool m_added1stKeyframe; |
| |
| public: |
| SetSkeletonIdUndo(int skelId) |
| : m_row(::row()), m_col(::column()), m_skelId(skelId) {} |
| |
| int getSize() const { return sizeof(*this); } |
| |
| void redo() const |
| { |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| const SkDP &sd = l_plasticTool.deformation(); |
| TCG_ASSERT(sd, return ); |
| |
| const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam(); |
| double frame = ::frame(); |
| |
| m_oldKf = skelIdsParam->getKeyframeAt(frame); |
| m_added1stKeyframe = false; |
| |
| if (frame > 0.0 && (skelIdsParam->getKeyframeCount() == 0 || |
| skelIdsParam->getKeyframe(0).m_frame >= frame)) { |
| |
| TDoubleKeyframe kf(frame - 1.0, skelIdsParam->getDefaultValue()); |
| kf.m_type = TDoubleKeyframe::Constant; |
| |
| skelIdsParam->setKeyframe(kf); |
| m_added1stKeyframe = true; |
| } |
| |
| TDoubleKeyframe kf(frame, m_skelId); |
| kf.m_type = TDoubleKeyframe::Constant; |
| |
| skelIdsParam->setKeyframe(kf); |
| |
| |
| } |
| |
| void undo() const |
| { |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| const SkDP &sd = l_plasticTool.deformation(); |
| TCG_ASSERT(sd, return ); |
| |
| const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam(); |
| |
| if (m_oldKf.m_isKeyframe) |
| skelIdsParam->setKeyframe(m_oldKf); |
| else |
| skelIdsParam->deleteKeyframe(m_oldKf.m_frame); |
| |
| if (m_added1stKeyframe) { |
| const TDoubleKeyframe &kf = skelIdsParam->getKeyframe(0); |
| |
| assert(kf.m_value == skelIdsParam->getDefaultValue()); |
| if (kf.m_value == skelIdsParam->getDefaultValue()) |
| skelIdsParam->deleteKeyframe(kf.m_frame); |
| } |
| } |
| }; |
| |
| |
| |
| class MoveVertexUndo_Build : public TUndo |
| { |
| int m_row, m_col; |
| |
| std::vector<int> m_vIdxs; |
| std::vector<TPointD> m_origVxsPos; |
| TPointD m_posShift; |
| |
| public: |
| MoveVertexUndo_Build( |
| const std::vector<int> &vIdxs, |
| const std::vector<TPointD> &origVxsPos, |
| const TPointD &posShift) |
| : m_row(::row()), m_col(::column()), m_vIdxs(vIdxs), m_origVxsPos(origVxsPos), m_posShift(posShift) |
| { |
| assert(m_vIdxs.size() == m_origVxsPos.size()); |
| } |
| |
| int getSize() const { return int(sizeof(*this) + m_vIdxs.size() * (sizeof(int) + 2 * sizeof(TPointD))); } |
| |
| void redo() const |
| { |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| l_plasticTool.setSkeletonSelection(m_vIdxs); |
| l_plasticTool.moveVertex_build(m_origVxsPos, m_posShift); |
| |
| ::stageObject()->invalidate(); |
| l_plasticTool.invalidate(); |
| } |
| |
| void undo() const |
| { |
| PlasticTool::TemporaryActivation tempActivate(m_row, m_col); |
| |
| l_plasticTool.setSkeletonSelection(m_vIdxs); |
| l_plasticTool.moveVertex_build(m_origVxsPos, TPointD()); |
| |
| ::stageObject()->invalidate(); |
| l_plasticTool.invalidate(); |
| } |
| }; |
| |
| } |
| |
| |
| |
| |
| |
| void PlasticTool::mouseMove_build(const TPointD &pos, const TMouseEvent &me) |
| { |
| |
| m_pos = pos; |
| |
| m_svHigh = m_seHigh = -1; |
| |
| double d, highlightRadius = getPixelSize() * HIGHLIGHT_DISTANCE; |
| |
| const PlasticSkeletonP &skeleton = this->skeleton(); |
| if (skeleton) { |
| |
| |
| |
| int v = skeleton->closestVertex(pos, &d); |
| if (v >= 0 && d < highlightRadius) |
| m_svHigh = v; |
| else { |
| |
| int e = skeleton->closestEdge(pos, &d); |
| if (e >= 0 && d < highlightRadius) |
| m_seHigh = e; |
| } |
| } |
| |
| if (m_svHigh < 0 && m_seHigh < 0) { |
| |
| |
| if (m_snapToMesh.getValue()) { |
| const TPointD &mvPos = ::closestMeshVertexPos(pos, &d); |
| |
| if (d < highlightRadius) |
| m_pos = mvPos; |
| } |
| } |
| |
| invalidate(); |
| } |
| |
| |
| |
| void PlasticTool::leftButtonDown_build(const TPointD &pos, const TMouseEvent &me) |
| { |
| |
| m_pressedPos = m_pos = pos; |
| |
| |
| { |
| const PlasticSkeletonP &skel = skeleton(); |
| |
| if (m_svHigh >= 0) { |
| PlasticVertexSelection vSel(me.isShiftPressed() ? PlasticVertexSelection(branchSelection(m_svHigh)) : PlasticVertexSelection(m_svHigh)); |
| |
| if (me.isCtrlPressed()) |
| toggleSkeletonSelection(vSel); |
| else if (!m_svSel.contains(vSel)) |
| setSkeletonSelection(vSel); |
| } else if (m_seHigh >= 0) { |
| |
| TUndo *op = new InsertVertexUndo(m_seHigh, PlasticSkeletonVertex( |
| projection(*skel, m_seHigh, m_pos))); |
| TUndoManager::manager()->add(op); |
| |
| op->redo(); |
| } else if (!skel || skel->empty() || m_svSel.hasSingleObject()) { |
| |
| if (m_snapToMesh.getValue()) { |
| double d, highlightRadius = getPixelSize() * HIGHLIGHT_DISTANCE; |
| |
| const TPointD &mvPos = ::closestMeshVertexPos(pos, &d); |
| |
| if (d < highlightRadius) |
| m_pos = mvPos; |
| } |
| |
| |
| TUndo *op = new AddVertexUndo(m_svSel, PlasticSkeletonVertex(m_pos)); |
| TUndoManager::manager()->add(op); |
| |
| op->redo(); |
| |
| assert(skeleton()); |
| } else |
| setSkeletonSelection(-1); |
| } |
| |
| |
| if (!m_svSel.isEmpty()) { |
| struct locals { |
| static TPointD vertexPos(const PlasticSkeleton &skel, int v) |
| { |
| return skel.vertex(v).P(); |
| } |
| }; |
| |
| const PlasticSkeletonP &skel = skeleton(); |
| assert(skel); |
| |
| |
| if (m_svSel.hasSingleObject()) |
| m_pressedPos = skel->vertex(m_svSel).P(); |
| |
| |
| m_pressedVxsPos = std::vector<TPointD>( |
| tcg::make_cast_it(m_svSel.objects().begin(), tcg::bind1st(&locals::vertexPos, *skel)), |
| tcg::make_cast_it(m_svSel.objects().end(), tcg::bind1st(&locals::vertexPos, *skel))); |
| } |
| |
| invalidate(); |
| } |
| |
| |
| |
| void PlasticTool::leftButtonDrag_build(const TPointD &pos, const TMouseEvent &me) |
| { |
| |
| if (m_snapToMesh.getValue()) { |
| const TPointD &mvPos = ::closestMeshVertexPos(pos), |
| &svPos = ::closestSkeletonVertexPos(mvPos); |
| |
| if (tcg::point_ops::dist(mvPos, svPos) > getPixelSize()) |
| m_pos = mvPos; |
| } |
| else |
| m_pos = pos; |
| |
| moveVertex_build(m_pressedVxsPos, m_pos - m_pressedPos); |
| invalidate(); |
| } |
| |
| |
| |
| void PlasticTool::leftButtonUp_build(const TPointD &pos, const TMouseEvent &me) |
| { |
| |
| if (m_snapToMesh.getValue()) { |
| const TPointD &mvPos = ::closestMeshVertexPos(pos), |
| &svPos = ::closestSkeletonVertexPos(mvPos); |
| |
| if (tcg::point_ops::dist(mvPos, svPos) > getPixelSize()) |
| m_pos = mvPos; |
| } else |
| m_pos = pos; |
| |
| if (!m_svSel.isEmpty() && m_dragged) { |
| TUndoManager::manager()->add(new MoveVertexUndo_Build( |
| m_svSel.objects(), m_pressedVxsPos, m_pos - m_pressedPos)); |
| |
| ::stageObject()->invalidate(); |
| invalidate(); |
| } |
| } |
| |
| |
| |
| void PlasticTool::addContextMenuActions_build(QMenu *menu) |
| { |
| bool ret = true; |
| |
| if (!m_svSel.isEmpty()) { |
| QAction *deleteVertex = menu->addAction(tr("Delete Vertex")); |
| ret = ret && connect(deleteVertex, SIGNAL(triggered()), &l_plasticTool, SLOT(deleteSelectedVertex_undo())); |
| |
| menu->addSeparator(); |
| } |
| |
| assert(ret); |
| } |
| |
| |
| |
| void PlasticTool::moveVertex_build(const std::vector<TPointD> &origVxsPos, const TPointD &posShift) |
| { |
| if (!m_svSel.isEmpty()) { |
| const PlasticSkeletonP &skeleton = this->skeleton(); |
| |
| |
| int v, vCount = int(m_svSel.objects().size()); |
| for (v = 0; v != vCount; ++v) |
| skeleton->moveVertex(m_svSel.objects()[v], origVxsPos[v] + posShift); |
| |
| |
| PlasticDeformerStorage::instance()->invalidateSkeleton( |
| m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL); |
| |
| if (m_mode.getIndex() == ANIMATE_IDX) |
| storeDeformation(); |
| } |
| } |
| |
| |
| |
| void PlasticTool::addVertex(const PlasticSkeletonVertex &vx) |
| { |
| touchSkeleton(); |
| const PlasticSkeletonP &skeleton = this->skeleton(); |
| |
| l_suspendParamsObservation = true; |
| |
| assert(m_svSel.isEmpty() || m_svSel.hasSingleObject()); |
| setSkeletonSelection(skeleton->addVertex(vx, m_svSel)); |
| |
| l_suspendParamsObservation = false; |
| onChange(); |
| |
| |
| |
| |
| |
| |
| TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged(); |
| PlasticDeformerStorage::instance()->invalidateSkeleton( |
| m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL); |
| } |
| |
| |
| |
| void PlasticTool::insertVertex(const PlasticSkeletonVertex &vx, |
| int parent, const std::vector<int> &children) |
| { |
| const PlasticSkeletonP &skeleton = this->skeleton(); |
| assert(skeleton); |
| |
| l_suspendParamsObservation = true; |
| |
| setSkeletonSelection(skeleton->insertVertex(vx, parent, children)); |
| |
| l_suspendParamsObservation = false; |
| onChange(); |
| |
| TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged(); |
| PlasticDeformerStorage::instance()->invalidateSkeleton( |
| m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL); |
| } |
| |
| |
| |
| void PlasticTool::insertVertex(const PlasticSkeletonVertex &vx, int e) |
| { |
| const PlasticSkeletonP &skeleton = this->skeleton(); |
| assert(skeleton); |
| |
| const PlasticSkeleton::edge_type &ed = skeleton->edge(e); |
| insertVertex(vx, ed.vertex(0), std::vector<int>(1, skeleton->edge(e).vertex(1))); |
| } |
| |
| |
| |
| void PlasticTool::removeVertex() |
| { |
| const PlasticSkeletonP &skeleton = this->skeleton(); |
| assert(skeleton && m_svSel.hasSingleObject() && m_svSel > 0); |
| |
| l_suspendParamsObservation = true; |
| |
| skeleton->removeVertex(m_svSel); |
| PlasticDeformerStorage::instance()->invalidateSkeleton( |
| m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL); |
| |
| l_suspendParamsObservation = false; |
| onChange(); |
| |
| clearSkeletonSelections(); |
| |
| |
| |
| TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged(); |
| |
| |
| stageObject()->updateKeyframes(); |
| } |
| |
| |
| |
| int PlasticTool::addSkeleton(const PlasticSkeletonP &skeleton) |
| { |
| assert(TTool::isEnabled()); |
| |
| touchDeformation(); |
| |
| int skelId; |
| { |
| if (m_sd->empty()) |
| skelId = 1; |
| else { |
| |
| SkD::skelId_iterator st, sEnd; |
| m_sd->skeletonIds(st, sEnd); |
| |
| for (skelId = 1; st != sEnd && skelId == *st; ++skelId, ++st) |
| ; |
| } |
| } |
| |
| addSkeleton(skelId, skeleton); |
| return skelId; |
| } |
| |
| |
| |
| void PlasticTool::addSkeleton(int skelId, const PlasticSkeletonP &skeleton) |
| { |
| assert(TTool::isEnabled()); |
| |
| touchDeformation(); |
| m_sd->attach(skelId, skeleton.getPointer()); |
| |
| emit skelIdsListChanged(); |
| } |
| |
| |
| |
| void PlasticTool::removeSkeleton(int skelId) |
| { |
| |
| clearSkeletonSelections(); |
| |
| if (m_sd) { |
| m_sd->detach(skelId); |
| if (m_sd->empty()) |
| stageObject()->setPlasticSkeletonDeformation(PlasticSkeletonDeformationP()); |
| |
| ::invalidateXsheet(); |
| emit skelIdsListChanged(); |
| } |
| } |
| |
| |
| |
| void PlasticTool::deleteSelectedVertex_undo() |
| { |
| if (m_svSel.isEmpty()) |
| return; |
| |
| TUndoManager *manager = TUndoManager::manager(); |
| |
| if (m_svSel.contains(0)) { |
| TUndo *op = new RemoveSkeletonUndo(::skeletonId()); |
| manager->add(op); |
| |
| op->redo(); |
| } else { |
| typedef PlasticVertexSelection::objects_container objects_container; |
| |
| objects_container vertexIdxs = m_svSel.objects(); |
| |
| manager->beginBlock(); |
| { |
| objects_container::const_iterator vit, viEnd = vertexIdxs.end(); |
| for (vit = vertexIdxs.begin(); vit != viEnd; ++vit) { |
| TUndo *op = new RemoveVertexUndo(*vit); |
| manager->add(op); |
| |
| op->redo(); |
| } |
| } |
| manager->endBlock(); |
| } |
| } |
| |
| |
| |
| int PlasticTool::addSkeleton_undo(const PlasticSkeletonP &skeleton) |
| { |
| int skelId; |
| |
| TUndoManager *manager = TUndoManager::manager(); |
| manager->beginBlock(); |
| { |
| skelId = l_plasticTool.addSkeleton(skeleton); |
| assert(l_plasticTool.deformation()); |
| |
| TUndo *addUndo = new AddSkeletonUndo(skelId, new PlasticSkeleton(*skeleton)); |
| manager->add(addUndo); |
| |
| TUndo *setIdUndo = new SetSkeletonIdUndo(skelId); |
| manager->add(setIdUndo); |
| |
| setIdUndo->redo(); |
| } |
| manager->endBlock(); |
| |
| ::invalidateXsheet(); |
| return skelId; |
| } |
| |
| |
| |
| void PlasticTool::addSkeleton_undo(int skelId, const PlasticSkeletonP &skeleton) |
| { |
| TUndoManager *manager = TUndoManager::manager(); |
| manager->beginBlock(); |
| { |
| l_plasticTool.addSkeleton(skelId, skeleton); |
| assert(l_plasticTool.deformation()); |
| |
| TUndo *addUndo = new AddSkeletonUndo(skelId, new PlasticSkeleton(*skeleton)); |
| manager->add(addUndo); |
| |
| TUndo *setIdUndo = new SetSkeletonIdUndo(skelId); |
| manager->add(setIdUndo); |
| |
| setIdUndo->redo(); |
| } |
| manager->endBlock(); |
| |
| ::invalidateXsheet(); |
| } |
| |
| |
| |
| void PlasticTool::removeSkeleton_undo(int skelId) |
| { |
| TUndo *op = new RemoveSkeletonUndo(skelId); |
| TUndoManager::manager()->add(op); |
| |
| op->redo(); |
| } |
| |
| |
| |
| void PlasticTool::removeSkeleton_withKeyframes_undo(int skelId) |
| { |
| TUndo *op = new RemoveSkeletonUndo_WithKeyframes(skelId); |
| TUndoManager::manager()->add(op); |
| |
| op->redo(); |
| } |
| |
| |
| |
| void PlasticTool::editSkelId_undo(int skelId) |
| { |
| TUndo *op = new SetSkeletonIdUndo(skelId); |
| TUndoManager::manager()->add(op); |
| |
| op->redo(); |
| } |
| |
| |
| |
| void PlasticTool::draw_build() |
| { |
| double pixelSize = getPixelSize(); |
| |
| |
| const PlasticSkeletonP &skeleton = this->skeleton(); |
| if (skeleton) { |
| drawOnionSkinSkeletons_build(pixelSize); |
| drawSkeleton(*skeleton, pixelSize); |
| drawSelections(m_sd, *skeleton, pixelSize); |
| } |
| |
| drawHighlights(m_sd, skeleton.getPointer(), pixelSize); |
| |
| if (!skeleton || skeleton->vertices().empty() || |
| (m_svSel.hasSingleObject() && m_svHigh < 0 && m_seHigh < 0)) { |
| |
| drawSquare(m_pos, HANDLE_SIZE * pixelSize); |
| } |
| } |
| |