Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "plastictool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace PlasticToolLocals;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Undo  definitions
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
namespace {
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
class AnimateValuesUndo final : public TUndo {
Shinya Kitaoka 120a6e
  int m_row, m_col;  //!< Xsheet coordinates
Shinya Kitaoka 120a6e
  int m_v;           //!< Moved vertex
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  SkDKey m_oldValues, m_newValues;  //!< Keyframe values
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Shinya Kitaoka 120a6e
  AnimateValuesUndo(int v) : m_row(::row()), m_col(::column()), m_v(v) {}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Again, not accurate. We should get in the details of SkDF... So, let's say
Shinya Kitaoka 120a6e
  // around 10 kB - max 10k instances in the standard undos pool.
Shinya Kitaoka 473e70
  int getSize() const override { return 10 << 10; }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void redo() const override {
Shinya Kitaoka 120a6e
    PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_v >= 0) l_plasticTool.setSkeletonSelection(m_v);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    l_suspendParamsObservation =
Shinya Kitaoka 120a6e
        true;  // Coalesce params change notifications into one
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    l_plasticTool.deformation()->deleteKeyframe(m_row - 1);
Shinya Kitaoka 120a6e
    l_plasticTool.deformation()->setKeyframe(m_newValues);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    l_suspendParamsObservation = false;
Shinya Kitaoka 120a6e
    l_plasticTool.onChange();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 473e70
  void undo() const override {
Shinya Kitaoka 120a6e
    PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (m_v >= 0) l_plasticTool.setSkeletonSelection(m_v);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    l_suspendParamsObservation =
Shinya Kitaoka 120a6e
        true;  // Coalesce params change notifications into one
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    l_plasticTool.deformation()->deleteKeyframe(
Shinya Kitaoka 120a6e
        m_row - 1);  // Yep. Typical frame/row shift... xD
Shinya Kitaoka 120a6e
    l_plasticTool.deformation()->setKeyframe(m_oldValues);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    l_suspendParamsObservation = false;
Shinya Kitaoka 120a6e
    l_plasticTool.onChange();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
}  // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticTool  functions
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticTool::mouseMove_animate(const TPointD &pos, const TMouseEvent &me) {
Shinya Kitaoka 120a6e
  // Track mouse position
Shinya Kitaoka 120a6e
  m_pos = pos;  // Needs to be done now - ensures m_pos is valid
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_svHigh = m_seHigh = -1;  // Reset highlighted primitives
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_sd) {
Shinya Kitaoka 120a6e
    double d, highlightRadius = getPixelSize() * HIGHLIGHT_DISTANCE;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Look for nearest vertex
Shinya Kitaoka 120a6e
    int v = deformedSkeleton().closestVertex(pos, &d);
Shinya Kitaoka 120a6e
    if (v >= 0 && d < highlightRadius) m_svHigh = v;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticTool::leftButtonDown_animate(const TPointD &pos,
Shinya Kitaoka 120a6e
                                         const TMouseEvent &me) {
Shinya Kitaoka 120a6e
  // Track mouse position
Shinya Kitaoka 120a6e
  m_pressedPos = m_pos = pos;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  setSkeletonSelection(m_svHigh);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_svSel.hasSingleObject()) {
Shinya Kitaoka 120a6e
    // Store original vertex position and keyframe values
Shinya Kitaoka 120a6e
    m_pressedVxsPos =
Shinya Kitaoka 120a6e
        std::vector<tpointd>(1, deformedSkeleton().vertex(m_svSel).P());</tpointd>
Shinya Kitaoka 120a6e
    m_sd->getKeyframeAt(frame(), m_pressedSkDF);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticTool::leftButtonDrag_animate(const TPointD &pos,
Shinya Kitaoka 120a6e
                                         const TMouseEvent &me) {
Shinya Kitaoka 120a6e
  // Track mouse position
Shinya Kitaoka 120a6e
  m_pos = pos;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_sd && m_svSel.hasSingleObject() &&
Shinya Kitaoka 120a6e
      m_svSel > 0)  // Avoid move if vertex is root
Shinya Kitaoka 120a6e
  {
Shinya Kitaoka 120a6e
    l_suspendParamsObservation = true;  // Automatic params notification happen
Shinya Kitaoka 120a6e
    // twice (1 x param) - dealing with it manually
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    double frame = ::frame();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // First, retrieve selected vertex's deformation
Shinya Kitaoka 120a6e
    SkVD *vd = m_sd->vertexDeformation(::skeletonId(), m_svSel);
Shinya Kitaoka 120a6e
    assert(vd);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Move selected branch
Shinya Kitaoka 120a6e
    if (m_keepDistance.getValue()) {
Shinya Kitaoka 120a6e
      ::setKeyframe(vd->m_params[SkVD::ANGLE],
Shinya Kitaoka 120a6e
                    frame);  // Set a keyframe for it. It must be done
Shinya Kitaoka 120a6e
                             // to set the correct function interpolation
Shinya Kitaoka 120a6e
                             // type and other stuff.
Shinya Kitaoka 120a6e
      m_sd->updateAngle(*skeleton(), deformedSkeleton(), frame, m_svSel, pos);
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      ::setKeyframe(vd->m_params[SkVD::ANGLE],
Shinya Kitaoka 120a6e
                    frame);  // Same here. NOTE: Not setting a frame on
Shinya Kitaoka 120a6e
      ::setKeyframe(vd->m_params[SkVD::DISTANCE],
Shinya Kitaoka 120a6e
                    frame);  // vd directly due to SkVD::SO
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_sd->updatePosition(*skeleton(), deformedSkeleton(), frame, m_svSel,
Shinya Kitaoka 120a6e
                           pos);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    l_suspendParamsObservation = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // onChange();                                                     // Due to
Shinya Kitaoka 120a6e
    // a nasty Function Editor dependency,
Shinya Kitaoka 120a6e
    // it's better to call the following directly
Shinya Kitaoka 120a6e
    m_deformedSkeleton.invalidate();
Shinya Kitaoka 120a6e
    invalidate();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticTool::leftButtonUp_animate(const TPointD &pos,
Shinya Kitaoka 120a6e
                                       const TMouseEvent &me) {
Shinya Kitaoka 120a6e
  // Track mouse position
Shinya Kitaoka 120a6e
  m_pos = pos;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (m_svSel.hasSingleObject() && m_dragged) {
Shinya Kitaoka 120a6e
    // Set a keyframe to each skeleton vertex, if that was requested
Shinya Kitaoka 120a6e
    if (m_globalKey.getValue())
Shinya Kitaoka 120a6e
      ::setKeyframe(m_sd, ::frame());  // Already invokes keyframes rebuild
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      stageObject()->updateKeyframes();  // Otherwise, must be explicit
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Add a corresponding undo
Shinya Kitaoka 120a6e
    AnimateValuesUndo *undo = new AnimateValuesUndo(m_svSel);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    undo->m_oldValues = m_pressedSkDF;
Shinya Kitaoka 120a6e
    m_sd->getKeyframeAt(frame(), undo->m_newValues);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // This is needed to refresh the xsheet (there may be new keyframes)
Shinya Kitaoka 120a6e
    TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(false);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // In case one of the vertices is attached (as a hook) to an external
Shinya Kitaoka 120a6e
  // position,
Shinya Kitaoka 120a6e
  // we need to update the whole skeleton according to the updated vertex.
Shinya Kitaoka 120a6e
  updateMatrix();
Shinya Kitaoka 120a6e
  invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticTool::addContextMenuActions_animate(QMenu *menu) {
Shinya Kitaoka 120a6e
  bool ret = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (!m_svSel.isEmpty()) {
Shinya Kitaoka 120a6e
    QAction *setKey = menu->addAction(tr("Set Key"));
Shinya Kitaoka 120a6e
    ret = ret && connect(setKey, SIGNAL(triggered()), &l_plasticTool,
Shinya Kitaoka 120a6e
                         SLOT(setKey_undo()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    QAction *setRestKey = menu->addAction(tr("Set Rest Key"));
Shinya Kitaoka 120a6e
    ret = ret && connect(setRestKey, SIGNAL(triggered()), &l_plasticTool,
Shinya Kitaoka 120a6e
                         SLOT(setRestKey_undo()));
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QAction *setGlobalKey = menu->addAction(tr("Set Global Key"));
Shinya Kitaoka 120a6e
  ret = ret && connect(setGlobalKey, SIGNAL(triggered()), &l_plasticTool,
Shinya Kitaoka 120a6e
                       SLOT(setGlobalKey_undo()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QAction *setGlobalRestKey = menu->addAction(tr("Set Global Rest Key"));
Shinya Kitaoka 120a6e
  ret = ret && connect(setGlobalRestKey, SIGNAL(triggered()), &l_plasticTool,
Shinya Kitaoka 120a6e
                       SLOT(setGlobalRestKey_undo()));
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  menu->addSeparator();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  assert(ret);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticTool::keyFunc_undo(void (PlasticTool::*keyFunc)()) {
Shinya Kitaoka 120a6e
  assert(m_svSel.objects().size() <= 1);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  double frame = ::frame();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  AnimateValuesUndo *undo = new AnimateValuesUndo(m_svSel);
Shinya Kitaoka 120a6e
  m_sd->getKeyframeAt(frame, undo->m_oldValues);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  (this->*keyFunc)();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_sd->getKeyframeAt(frame, undo->m_newValues);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void PlasticTool::draw_animate() {
Shinya Kitaoka 120a6e
  double pixelSize = getPixelSize();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  PlasticSkeleton &deformedSkeleton = this->deformedSkeleton();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Draw deformed skeleton
Shinya Kitaoka 120a6e
  if (m_sd) {
Shinya Kitaoka 120a6e
    drawOnionSkinSkeletons_animate(pixelSize);
Shinya Kitaoka 120a6e
    drawSkeleton(deformedSkeleton, pixelSize);
Shinya Kitaoka 120a6e
    drawSelections(m_sd, deformedSkeleton, pixelSize);
Shinya Kitaoka 120a6e
    drawAngleLimits(m_sd, m_skelId, m_svSel, pixelSize);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  drawHighlights(m_sd, &deformedSkeleton, pixelSize);
Toshihiro Shimizu 890ddd
}