Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzExt includes
Toshihiro Shimizu 890ddd
#include "ext/plasticdeformerstorage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/txshcell.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/stage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_point_ops.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_algorithm.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_function_types.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_iterator_ops.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
//    Local namespace  stuff
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TPointD closestMeshVertexPos(const TPointD &pos, double *distance = 0)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const TXshCell &imageCell = TTool::getImageCell();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TXshSimpleLevel *sl = imageCell.getSimpleLevel();
Toshihiro Shimizu 890ddd
	assert(sl);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TMeshImageP mi(TTool::getImage(false));
Toshihiro Shimizu 890ddd
	assert(mi);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve *level* dpi
Toshihiro Shimizu 890ddd
	// NOTE: This is different than current IMAGE's dpi. An image is actually displayed with
Toshihiro Shimizu 890ddd
	//       its level owner's dpi, RATHER than its own.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TPointD &dpi = sl->getDpi(imageCell.getFrameId());
Toshihiro Shimizu 890ddd
	assert(dpi.x > 0.0 && dpi.y > 0.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Cast pos to image coordinates
Toshihiro Shimizu 890ddd
	const TPointD pos_mesh(pos.x * (dpi.x / Stage::inch), pos.y * (dpi.y / Stage::inch));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve the closest vertex to pos_mesh
Toshihiro Shimizu 890ddd
	const std::pair<double, plastictool::meshindex=""> &closest =</double,>
Toshihiro Shimizu 890ddd
		PlasticToolLocals::closestVertex(*mi, pos_mesh);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TPointD &vxPos_mesh = mi->meshes()[closest.second.m_meshIdx]->vertex(closest.second.m_idx).P();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (distance)
Toshihiro Shimizu 890ddd
		*distance = tmin(Stage::inch / dpi.x, Stage::inch / dpi.y) * closest.first;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Cast it back to world coordinates
Toshihiro Shimizu 890ddd
	return TPointD(vxPos_mesh.x * (Stage::inch / dpi.x), vxPos_mesh.y * (Stage::inch / dpi.y));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TPointD closestSkeletonVertexPos(const TPointD &pos)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		static inline double dist2(const TPointD &pos, const PlasticSkeletonVertex &vx)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return tcg::point_ops::dist2(pos, vx.P());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skeleton = l_plasticTool.skeleton();
Toshihiro Shimizu 890ddd
	if (!skeleton || skeleton->empty())
Toshihiro Shimizu 890ddd
		return TConsts::napd;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const PlasticSkeleton::vertices_container &vertices = skeleton->vertices();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return tcg::min_transform(vertices.begin(), vertices.end(),
Toshihiro Shimizu 890ddd
							  tcg::bind1st(&locals::dist2, pos))
Toshihiro Shimizu 890ddd
		->P();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
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 VertexUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
protected:
Toshihiro Shimizu 890ddd
	int m_row, m_col; //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_v, m_vParent;			//!< Indices of the added vertex and its parent
Toshihiro Shimizu 890ddd
	PlasticSkeletonVertex m_vx; //!< Added vertex
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<int> m_children; //!< Children of the vertex to insert</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	VertexUndo() : m_row(::row()), m_col(::column()), m_v(-1), m_vParent(-1) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return sizeof(*this); } // sizeof this is roughly ok
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void storeChildren(const PlasticSkeleton &skeleton, const PlasticSkeletonVertex &vx)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_children.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Traverse vx's edges and build its children table
Toshihiro Shimizu 890ddd
		PlasticSkeletonVertex::edges_const_iterator et, eEnd(vx.edgesEnd());
Toshihiro Shimizu 890ddd
		for (et = vx.edgesBegin(); et != eEnd; ++et) {
Toshihiro Shimizu 890ddd
			int vChild = skeleton.edge(*et).vertex(1);
Toshihiro Shimizu 890ddd
			if (vChild == vx.getIndex())
Toshihiro Shimizu 890ddd
				continue;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_children.push_back(vChild);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void addVertex()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		assert(m_vx.edges().empty());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Load the right skeleton by moving to the stored xsheet pos
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skeleton = l_plasticTool.skeleton();
Toshihiro Shimizu 890ddd
		TCG_ASSERT(skeleton || m_vParent < 0, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Perform addition
Toshihiro Shimizu 890ddd
		l_plasticTool.setSkeletonSelection(m_vParent);
Toshihiro Shimizu 890ddd
		l_plasticTool.addVertex(m_vx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Store data to invert the operation
Toshihiro Shimizu 890ddd
		assert(l_plasticTool.skeletonVertexSelection().hasSingleObject());
Toshihiro Shimizu 890ddd
		m_v = l_plasticTool.skeletonVertexSelection();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void insertVertex()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (m_children.empty()) {
Toshihiro Shimizu 890ddd
			addVertex();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		assert(m_vx.edges().empty());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TCG_ASSERT(m_vParent >= 0, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skeleton = l_plasticTool.skeleton();
Toshihiro Shimizu 890ddd
		TCG_ASSERT(skeleton, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Perform insertion
Toshihiro Shimizu 890ddd
		l_plasticTool.insertVertex(m_vx, m_vParent, m_children);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Store data to invert the operation
Toshihiro Shimizu 890ddd
		assert(l_plasticTool.skeletonVertexSelection().hasSingleObject());
Toshihiro Shimizu 890ddd
		m_v = l_plasticTool.skeletonVertexSelection();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void removeVertex()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TCG_ASSERT(m_v >= 0, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skeleton = l_plasticTool.skeleton();
Toshihiro Shimizu 890ddd
		TCG_ASSERT(skeleton, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Store data to invert the operation
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const PlasticSkeletonVertex &vx = skeleton->vertex(m_v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_vParent = vx.parent();
Toshihiro Shimizu 890ddd
			m_vx = PlasticSkeletonVertex(vx.P());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			storeChildren(*skeleton, vx);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Perform removal
Toshihiro Shimizu 890ddd
		if (m_v > 0) {
Toshihiro Shimizu 890ddd
			l_plasticTool.setSkeletonSelection(m_v);
Toshihiro Shimizu 890ddd
			l_plasticTool.removeVertex();
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			l_plasticTool.removeSkeleton(::skeletonId());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class AddVertexUndo : public VertexUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	AddVertexUndo(int vParent, const PlasticSkeletonVertex &vx)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_vParent = vParent, m_vx = vx;
Toshihiro Shimizu 890ddd
		assert(m_vx.edges().empty());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const { const_cast<addvertexundo &="">(*this).VertexUndo::addVertex(); }</addvertexundo>
Toshihiro Shimizu 890ddd
	void undo() const { const_cast<addvertexundo &="">(*this).VertexUndo::removeVertex(); }</addvertexundo>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class RemoveVertexUndo : public VertexUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	RemoveVertexUndo(int v)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		assert(v >= 0);
Toshihiro Shimizu 890ddd
		m_v = v;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const { const_cast<removevertexundo &="">(*this).VertexUndo::removeVertex(); }</removevertexundo>
Toshihiro Shimizu 890ddd
	void undo() const { const_cast<removevertexundo &="">(*this).VertexUndo::insertVertex(); }</removevertexundo>
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class InsertVertexUndo : public VertexUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	InsertVertexUndo(int e, const PlasticSkeletonVertex &vx)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const PlasticSkeleton &skeleton = *l_plasticTool.skeleton();
Toshihiro Shimizu 890ddd
		const PlasticSkeleton::edge_type &ed = skeleton.edge(e);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_vParent = ed.vertex(0), m_vx = vx;
Toshihiro Shimizu 890ddd
		std::vector<int>(1, ed.vertex(1)).swap(m_children);</int>
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const_cast<insertvertexundo &="">(*this).VertexUndo::insertVertex();</insertvertexundo>
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TCG_ASSERT(!m_children.empty(), return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const_cast<insertvertexundo &="">(*this).VertexUndo::removeVertex();</insertvertexundo>
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class AddSkeletonUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
protected:
Toshihiro Shimizu 890ddd
	int m_row, m_col; //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_skelId;				 //!< The added skeleton's id
Toshihiro Shimizu 890ddd
	PlasticSkeletonP m_skeleton; //!< A COPY of the added skeleton
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	AddSkeletonUndo(int skelId, const PlasticSkeletonP &skeletonCopy)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_skelId(skelId), m_skeleton(skeletonCopy) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// This is not correct... it's tough to build the right one! We're like storing the whole
Toshihiro Shimizu 890ddd
	// cleared deformation! So, I guess 1 MB (100 of these in the standard undos pool)
Toshihiro Shimizu 890ddd
	// is a reasonable estimate...
Toshihiro Shimizu 890ddd
	int getSize() const { return 1 << 20; }
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
		l_plasticTool.addSkeleton(m_skelId, new PlasticSkeleton(*m_skeleton));
Toshihiro Shimizu 890ddd
		::invalidateXsheet();
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
		l_plasticTool.removeSkeleton(m_skelId);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class RemoveSkeletonUndo : public AddSkeletonUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	RemoveSkeletonUndo(int skelId) : AddSkeletonUndo(skelId, l_plasticTool.skeleton()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const { AddSkeletonUndo::undo(); }
Toshihiro Shimizu 890ddd
	void undo() const { AddSkeletonUndo::redo(); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class RemoveSkeletonUndo_WithKeyframes : public RemoveSkeletonUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	mutable std::vector<tdoublekeyframe> m_skelIdsKeyframes; //!< Skeleton Ids param curve keyframes</tdoublekeyframe>
Toshihiro Shimizu 890ddd
															 //!< for m_skelId
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	RemoveSkeletonUndo_WithKeyframes(int skelId) : RemoveSkeletonUndo(skelId) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		// Erase all keyframes corresponding to m_skelId from sd's skeleton ids curve
Toshihiro Shimizu 890ddd
		const SkDP &sd = l_plasticTool.deformation();
Toshihiro Shimizu 890ddd
		TCG_ASSERT(sd, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam();
Toshihiro Shimizu 890ddd
		if (skelIdsParam->getKeyframeCount() > 0) {
Toshihiro Shimizu 890ddd
			double frame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			for (int k = 0; k >= 0; k = skelIdsParam->getNextKeyframe(frame)) {
Toshihiro Shimizu 890ddd
				const TDoubleKeyframe &kf = skelIdsParam->getKeyframe(k);
Toshihiro Shimizu 890ddd
				frame = kf.m_frame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (m_skelId == (int)kf.m_value) {
Toshihiro Shimizu 890ddd
					m_skelIdsKeyframes.push_back(kf);
Toshihiro Shimizu 890ddd
					skelIdsParam->deleteKeyframe(frame);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		RemoveSkeletonUndo::redo(); // Invalidates the xsheet
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		l_plasticTool.touchDeformation(); // Skeleton removal could have destroyed the sd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore saved keyframes to sd's skelIdsParam curve
Toshihiro Shimizu 890ddd
		const SkDP &sd = l_plasticTool.deformation();
Toshihiro Shimizu 890ddd
		assert(sd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::vector<tdoublekeyframe>::iterator kt, kEnd(m_skelIdsKeyframes.end());</tdoublekeyframe>
Toshihiro Shimizu 890ddd
		for (kt = m_skelIdsKeyframes.begin(); kt != kEnd; ++kt)
Toshihiro Shimizu 890ddd
			skelIdsParam->setKeyframe(*kt);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_skelIdsKeyframes.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		RemoveSkeletonUndo::undo(); // Invalidates the xsheet
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class SetSkeletonIdUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_row, m_col; //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_skelId;					 //!< The new skeleton id value
Toshihiro Shimizu 890ddd
	mutable TDoubleKeyframe m_oldKf; //!< Old keyframe values for skelIds parameter
Toshihiro Shimizu 890ddd
	mutable bool m_added1stKeyframe; //!< Whether the redo() added the first skelIds keyframe
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SetSkeletonIdUndo(int skelId)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_skelId(skelId) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return sizeof(*this); }
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
		const SkDP &sd = l_plasticTool.deformation();
Toshihiro Shimizu 890ddd
		TCG_ASSERT(sd, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam();
Toshihiro Shimizu 890ddd
		double frame = ::frame();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_oldKf = skelIdsParam->getKeyframeAt(frame);
Toshihiro Shimizu 890ddd
		m_added1stKeyframe = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (frame > 0.0 && (skelIdsParam->getKeyframeCount() == 0 ||
Toshihiro Shimizu 890ddd
							skelIdsParam->getKeyframe(0).m_frame >= frame)) {
Toshihiro Shimizu 890ddd
			// Put a keyframe at the previous cell to preserve values before current frame
Toshihiro Shimizu 890ddd
			TDoubleKeyframe kf(frame - 1.0, skelIdsParam->getDefaultValue());
Toshihiro Shimizu 890ddd
			kf.m_type = TDoubleKeyframe::Constant;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			skelIdsParam->setKeyframe(kf);
Toshihiro Shimizu 890ddd
			m_added1stKeyframe = true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TDoubleKeyframe kf(frame, m_skelId);
Toshihiro Shimizu 890ddd
		kf.m_type = TDoubleKeyframe::Constant;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		skelIdsParam->setKeyframe(kf);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// No need to invoke PlasticTool::storeSkeletonId() - automatic through 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
		const SkDP &sd = l_plasticTool.deformation();
Toshihiro Shimizu 890ddd
		TCG_ASSERT(sd, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const TDoubleParamP &skelIdsParam = sd->skeletonIdsParam();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_oldKf.m_isKeyframe)
Toshihiro Shimizu 890ddd
			skelIdsParam->setKeyframe(m_oldKf);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			skelIdsParam->deleteKeyframe(m_oldKf.m_frame);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_added1stKeyframe) {
Toshihiro Shimizu 890ddd
			const TDoubleKeyframe &kf = skelIdsParam->getKeyframe(0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			assert(kf.m_value == skelIdsParam->getDefaultValue());
Toshihiro Shimizu 890ddd
			if (kf.m_value == skelIdsParam->getDefaultValue())
Toshihiro Shimizu 890ddd
				skelIdsParam->deleteKeyframe(kf.m_frame);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class MoveVertexUndo_Build : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_row, m_col; //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<int> m_vIdxs;		   //!< Moved vertices</int>
Toshihiro Shimizu 890ddd
	std::vector<tpointd> m_origVxsPos; //!< Original vertex positions</tpointd>
Toshihiro Shimizu 890ddd
	TPointD m_posShift;				   //!< Vertex positions shift
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	MoveVertexUndo_Build(
Toshihiro Shimizu 890ddd
		const std::vector<int> &vIdxs,</int>
Toshihiro Shimizu 890ddd
		const std::vector<tpointd> &origVxsPos,</tpointd>
Toshihiro Shimizu 890ddd
		const TPointD &posShift)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_vIdxs(vIdxs), m_origVxsPos(origVxsPos), m_posShift(posShift)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		assert(m_vIdxs.size() == m_origVxsPos.size());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return int(sizeof(*this) + m_vIdxs.size() * (sizeof(int) + 2 * sizeof(TPointD))); }
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
		l_plasticTool.setSkeletonSelection(m_vIdxs);
Toshihiro Shimizu 890ddd
		l_plasticTool.moveVertex_build(m_origVxsPos, m_posShift);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		::stageObject()->invalidate(); // Should be a TStageObject's implementation detail ...
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
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
		l_plasticTool.setSkeletonSelection(m_vIdxs);
Toshihiro Shimizu 890ddd
		l_plasticTool.moveVertex_build(m_origVxsPos, TPointD());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		::stageObject()->invalidate(); // Should be a TStageObject's implementation detail ...
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
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_build(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
	double d, highlightRadius = getPixelSize() * HIGHLIGHT_DISTANCE;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
	if (skeleton) {
Toshihiro Shimizu 890ddd
		// Search nearest skeleton entities
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Look for nearest vertex
Toshihiro Shimizu 890ddd
		int v = skeleton->closestVertex(pos, &d);
Toshihiro Shimizu 890ddd
		if (v >= 0 && d < highlightRadius)
Toshihiro Shimizu 890ddd
			m_svHigh = v;
Toshihiro Shimizu 890ddd
		else {
Toshihiro Shimizu 890ddd
			// Look for nearest edge
Toshihiro Shimizu 890ddd
			int e = skeleton->closestEdge(pos, &d);
Toshihiro Shimizu 890ddd
			if (e >= 0 && d < highlightRadius)
Toshihiro Shimizu 890ddd
				m_seHigh = e;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_svHigh < 0 && m_seHigh < 0) {
Toshihiro Shimizu 890ddd
		// No highlighted skeleton primitive. Mouse position may be
Toshihiro Shimizu 890ddd
		// a candidate for vertex addition - snap to mesh if required
Toshihiro Shimizu 890ddd
		if (m_snapToMesh.getValue()) {
Toshihiro Shimizu 890ddd
			const TPointD &mvPos = ::closestMeshVertexPos(pos, &d); // No need to check against closest skeleton vertex,
Toshihiro Shimizu 890ddd
																	// since vertex highlighting kicks in at the same time
Toshihiro Shimizu 890ddd
			if (d < highlightRadius)								// the snapping would take place.
Toshihiro Shimizu 890ddd
				m_pos = mvPos;
Toshihiro Shimizu 890ddd
		}
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::leftButtonDown_build(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
	// Update selections
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skel = skeleton();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_svHigh >= 0) {
Toshihiro Shimizu 890ddd
			PlasticVertexSelection vSel(me.isShiftPressed() ? PlasticVertexSelection(branchSelection(m_svHigh)) : PlasticVertexSelection(m_svHigh));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (me.isCtrlPressed())
Toshihiro Shimizu 890ddd
				toggleSkeletonSelection(vSel);
Toshihiro Shimizu 890ddd
			else if (!m_svSel.contains(vSel))
Toshihiro Shimizu 890ddd
				setSkeletonSelection(vSel);
Toshihiro Shimizu 890ddd
		} else if (m_seHigh >= 0) {
Toshihiro Shimizu 890ddd
			// Insert a vertex in the edge
Toshihiro Shimizu 890ddd
			TUndo *op = new InsertVertexUndo(m_seHigh, PlasticSkeletonVertex(
Toshihiro Shimizu 890ddd
														   projection(*skel, m_seHigh, m_pos)));
Toshihiro Shimizu 890ddd
			TUndoManager::manager()->add(op);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			op->redo();
Toshihiro Shimizu 890ddd
		} else if (!skel || skel->empty() || m_svSel.hasSingleObject()) {
Toshihiro Shimizu 890ddd
			// Snap to mesh if required
Toshihiro Shimizu 890ddd
			if (m_snapToMesh.getValue()) {
Toshihiro Shimizu 890ddd
				double d, highlightRadius = getPixelSize() * HIGHLIGHT_DISTANCE;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				const TPointD &mvPos = ::closestMeshVertexPos(pos, &d); // Again, no need to check against closest
Toshihiro Shimizu 890ddd
																		// skeleton vertex.
Toshihiro Shimizu 890ddd
				if (d < highlightRadius)
Toshihiro Shimizu 890ddd
					m_pos = mvPos;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Add a new vertex
Toshihiro Shimizu 890ddd
			TUndo *op = new AddVertexUndo(m_svSel, PlasticSkeletonVertex(m_pos));
Toshihiro Shimizu 890ddd
			TUndoManager::manager()->add(op);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			op->redo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			assert(skeleton());
Toshihiro Shimizu 890ddd
		} else
Toshihiro Shimizu 890ddd
			setSkeletonSelection(-1);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Start move vertex operation
Toshihiro Shimizu 890ddd
	if (!m_svSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		struct locals {
Toshihiro Shimizu 890ddd
			static TPointD vertexPos(const PlasticSkeleton &skel, int v)
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				return skel.vertex(v).P();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skel = skeleton();
Toshihiro Shimizu 890ddd
		assert(skel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Adjust mouse press to the selected skeleton vertex, if necessary
Toshihiro Shimizu 890ddd
		if (m_svSel.hasSingleObject())
Toshihiro Shimizu 890ddd
			m_pressedPos = skel->vertex(m_svSel).P();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Store original vertex positions
Toshihiro Shimizu 890ddd
		m_pressedVxsPos = std::vector<tpointd>(</tpointd>
Toshihiro Shimizu 890ddd
			tcg::make_cast_it(m_svSel.objects().begin(), tcg::bind1st(&locals::vertexPos, *skel)),
Toshihiro Shimizu 890ddd
			tcg::make_cast_it(m_svSel.objects().end(), tcg::bind1st(&locals::vertexPos, *skel)));
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_build(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Track mouse position
Toshihiro Shimizu 890ddd
	if (m_snapToMesh.getValue()) {
Toshihiro Shimizu 890ddd
		const TPointD &mvPos = ::closestMeshVertexPos(pos),
Toshihiro Shimizu 890ddd
					  &svPos = ::closestSkeletonVertexPos(mvPos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (tcg::point_ops::dist(mvPos, svPos) > getPixelSize()) // 1) If said distance is sub-pixel, the user
Toshihiro Shimizu 890ddd
			m_pos = mvPos;										 //    just cannot see the assignment - so it's not safe.
Toshihiro Shimizu 890ddd
	}															 // 2) The moveVertex_build() below manipulates m_pos
Toshihiro Shimizu 890ddd
	else														 //    (not how m_pressedPos is subtracted), so !=
Toshihiro Shimizu 890ddd
		m_pos = pos;											 //    is not a choice.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	moveVertex_build(m_pressedVxsPos, m_pos - m_pressedPos);
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::leftButtonUp_build(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Track mouse position
Toshihiro Shimizu 890ddd
	if (m_snapToMesh.getValue()) {
Toshihiro Shimizu 890ddd
		const TPointD &mvPos = ::closestMeshVertexPos(pos),
Toshihiro Shimizu 890ddd
					  &svPos = ::closestSkeletonVertexPos(mvPos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (tcg::point_ops::dist(mvPos, svPos) > getPixelSize()) // Same as above
Toshihiro Shimizu 890ddd
			m_pos = mvPos;
Toshihiro Shimizu 890ddd
	} else
Toshihiro Shimizu 890ddd
		m_pos = pos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_svSel.isEmpty() && m_dragged) {
Toshihiro Shimizu 890ddd
		TUndoManager::manager()->add(new MoveVertexUndo_Build(
Toshihiro Shimizu 890ddd
			m_svSel.objects(), m_pressedVxsPos, m_pos - m_pressedPos));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		::stageObject()->invalidate(); // Should be a TStageObject's implementation detail ...
Toshihiro Shimizu 890ddd
		invalidate();				   // .. it's that it caches placement data and we must
Toshihiro Shimizu 890ddd
	}								   // invalidate it. Gross. Can't we do anything about it?
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::addContextMenuActions_build(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 *deleteVertex = menu->addAction(tr("Delete Vertex"));
Toshihiro Shimizu 890ddd
		ret = ret && connect(deleteVertex, SIGNAL(triggered()), &l_plasticTool, SLOT(deleteSelectedVertex_undo()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		menu->addSeparator();
Toshihiro Shimizu 890ddd
	}
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::moveVertex_build(const std::vector<tpointd> &origVxsPos, const TPointD &posShift)</tpointd>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_svSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Move selected vertices
Toshihiro Shimizu 890ddd
		int v, vCount = int(m_svSel.objects().size());
Toshihiro Shimizu 890ddd
		for (v = 0; v != vCount; ++v)
Toshihiro Shimizu 890ddd
			skeleton->moveVertex(m_svSel.objects()[v], origVxsPos[v] + posShift);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Deformation must be recompiled
Toshihiro Shimizu 890ddd
		PlasticDeformerStorage::instance()->invalidateSkeleton(
Toshihiro Shimizu 890ddd
			m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_mode.getIndex() == ANIMATE_IDX)
Toshihiro Shimizu 890ddd
			storeDeformation(); // Rebuild deformed skeleton - default values have changed
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::addVertex(const PlasticSkeletonVertex &vx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	touchSkeleton();
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_suspendParamsObservation = true; // Some vertex parameters change during insert
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(m_svSel.isEmpty() || m_svSel.hasSingleObject()); // Could there be no parent (inserting the root)
Toshihiro Shimizu 890ddd
	setSkeletonSelection(skeleton->addVertex(vx, m_svSel));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_suspendParamsObservation = false;
Toshihiro Shimizu 890ddd
	onChange(); // Update once after add
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// NOTE: Root addition does NOT currently add channels, so the above onChange() is
Toshihiro Shimizu 890ddd
	// quite necessary to cover that case too!
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Xsheet change notification is necessary to inform the Function Editor that new
Toshihiro Shimizu 890ddd
	// channels (the vertex deformation ones) have been introduced
Toshihiro Shimizu 890ddd
	TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
	PlasticDeformerStorage::instance()->invalidateSkeleton(
Toshihiro Shimizu 890ddd
		m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::insertVertex(const PlasticSkeletonVertex &vx,
Toshihiro Shimizu 890ddd
							   int parent, const std::vector<int> &children)</int>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
	assert(skeleton);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_suspendParamsObservation = true; // Some vertex parameters change during insert.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	setSkeletonSelection(skeleton->insertVertex(vx, parent, children));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_suspendParamsObservation = false;
Toshihiro Shimizu 890ddd
	onChange(); // Update once after insertion
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
	PlasticDeformerStorage::instance()->invalidateSkeleton(
Toshihiro Shimizu 890ddd
		m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::insertVertex(const PlasticSkeletonVertex &vx, int e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
	assert(skeleton);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const PlasticSkeleton::edge_type &ed = skeleton->edge(e);
Toshihiro Shimizu 890ddd
	insertVertex(vx, ed.vertex(0), std::vector<int>(1, skeleton->edge(e).vertex(1)));</int>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::removeVertex()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
	assert(skeleton && m_svSel.hasSingleObject() && m_svSel > 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_suspendParamsObservation = true; // Some vertex parameters change during removal.
Toshihiro Shimizu 890ddd
									   // We need to avoid updating WHILE removing.
Toshihiro Shimizu 890ddd
	skeleton->removeVertex(m_svSel);
Toshihiro Shimizu 890ddd
	PlasticDeformerStorage::instance()->invalidateSkeleton(
Toshihiro Shimizu 890ddd
		m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::ALL);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_suspendParamsObservation = false;
Toshihiro Shimizu 890ddd
	onChange();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	clearSkeletonSelections(); // Remove mesh references - could be invalidated...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Xsheet change notification is necessary to inform the Function Editor that some
Toshihiro Shimizu 890ddd
	// channels (the vertex deformation ones) have been removed
Toshihiro Shimizu 890ddd
	TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged(); // NOTE: This COULD invoke invalidate()...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Rebuild the stage object's keyframes table
Toshihiro Shimizu 890ddd
	stageObject()->updateKeyframes();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int PlasticTool::addSkeleton(const PlasticSkeletonP &skeleton)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(TTool::isEnabled());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	touchDeformation();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int skelId;
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (m_sd->empty())
Toshihiro Shimizu 890ddd
			skelId = 1;
Toshihiro Shimizu 890ddd
		else {
Toshihiro Shimizu 890ddd
			// Get the first unused skeleton id in m_sd
Toshihiro Shimizu 890ddd
			SkD::skelId_iterator st, sEnd;
Toshihiro Shimizu 890ddd
			m_sd->skeletonIds(st, sEnd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			for (skelId = 1; st != sEnd && skelId == *st; ++skelId, ++st)
Toshihiro Shimizu 890ddd
				;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	addSkeleton(skelId, skeleton);
Toshihiro Shimizu 890ddd
	return skelId;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::addSkeleton(int skelId, const PlasticSkeletonP &skeleton)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(TTool::isEnabled());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	touchDeformation();
Toshihiro Shimizu 890ddd
	m_sd->attach(skelId, skeleton.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	emit skelIdsListChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::removeSkeleton(int skelId)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Remove the entire deformation
Toshihiro Shimizu 890ddd
	clearSkeletonSelections();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_sd) {
Toshihiro Shimizu 890ddd
		m_sd->detach(skelId);
Toshihiro Shimizu 890ddd
		if (m_sd->empty())
Toshihiro Shimizu 890ddd
			stageObject()->setPlasticSkeletonDeformation(PlasticSkeletonDeformationP());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		::invalidateXsheet(); // Updates m_sd
Toshihiro Shimizu 890ddd
		emit skelIdsListChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::deleteSelectedVertex_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_svSel.isEmpty())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TUndoManager *manager = TUndoManager::manager();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_svSel.contains(0)) {
Toshihiro Shimizu 890ddd
		TUndo *op = new RemoveSkeletonUndo(::skeletonId());
Toshihiro Shimizu 890ddd
		manager->add(op);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		op->redo();
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		typedef PlasticVertexSelection::objects_container objects_container;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		objects_container vertexIdxs = m_svSel.objects(); // Each undo will reset the vertex selection,
Toshihiro Shimizu 890ddd
														  // so we need a copy
Toshihiro Shimizu 890ddd
		manager->beginBlock();
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			objects_container::const_iterator vit, viEnd = vertexIdxs.end();
Toshihiro Shimizu 890ddd
			for (vit = vertexIdxs.begin(); vit != viEnd; ++vit) {
Toshihiro Shimizu 890ddd
				TUndo *op = new RemoveVertexUndo(*vit);
Toshihiro Shimizu 890ddd
				manager->add(op);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				op->redo();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		manager->endBlock();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int PlasticTool::addSkeleton_undo(const PlasticSkeletonP &skeleton)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int skelId;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TUndoManager *manager = TUndoManager::manager();
Toshihiro Shimizu 890ddd
	manager->beginBlock();
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		skelId = l_plasticTool.addSkeleton(skeleton);
Toshihiro Shimizu 890ddd
		assert(l_plasticTool.deformation());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TUndo *addUndo = new AddSkeletonUndo(skelId, new PlasticSkeleton(*skeleton));
Toshihiro Shimizu 890ddd
		manager->add(addUndo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TUndo *setIdUndo = new SetSkeletonIdUndo(skelId);
Toshihiro Shimizu 890ddd
		manager->add(setIdUndo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		setIdUndo->redo();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	manager->endBlock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	::invalidateXsheet();
Toshihiro Shimizu 890ddd
	return skelId;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::addSkeleton_undo(int skelId, const PlasticSkeletonP &skeleton)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TUndoManager *manager = TUndoManager::manager();
Toshihiro Shimizu 890ddd
	manager->beginBlock();
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		l_plasticTool.addSkeleton(skelId, skeleton);
Toshihiro Shimizu 890ddd
		assert(l_plasticTool.deformation());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TUndo *addUndo = new AddSkeletonUndo(skelId, new PlasticSkeleton(*skeleton));
Toshihiro Shimizu 890ddd
		manager->add(addUndo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TUndo *setIdUndo = new SetSkeletonIdUndo(skelId);
Toshihiro Shimizu 890ddd
		manager->add(setIdUndo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		setIdUndo->redo();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	manager->endBlock();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	::invalidateXsheet();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::removeSkeleton_undo(int skelId)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TUndo *op = new RemoveSkeletonUndo(skelId);
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(op);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	op->redo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::removeSkeleton_withKeyframes_undo(int skelId)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TUndo *op = new RemoveSkeletonUndo_WithKeyframes(skelId);
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(op);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	op->redo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::editSkelId_undo(int skelId)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TUndo *op = new SetSkeletonIdUndo(skelId);
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(op);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	op->redo();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::draw_build()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double pixelSize = getPixelSize();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Draw original skeleton
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
	if (skeleton) {
Toshihiro Shimizu 890ddd
		drawOnionSkinSkeletons_build(pixelSize);
Toshihiro Shimizu 890ddd
		drawSkeleton(*skeleton, pixelSize);
Toshihiro Shimizu 890ddd
		drawSelections(m_sd, *skeleton, pixelSize);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	drawHighlights(m_sd, skeleton.getPointer(), pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!skeleton || skeleton->vertices().empty() ||
Toshihiro Shimizu 890ddd
		(m_svSel.hasSingleObject() && m_svHigh < 0 && m_seHigh < 0)) {
Toshihiro Shimizu 890ddd
		// Draw a handle at current mouse pos (will add a vertex)
Toshihiro Shimizu 890ddd
		drawSquare(m_pos, HANDLE_SIZE * pixelSize);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}