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