Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "plastictool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzTools includes
Toshihiro Shimizu 890ddd
#include "tw/keycodes.h" // Obsolete by now... still currently used though
Toshihiro Shimizu 890ddd
#include "tooloptionscontrols.h"
Toshihiro Shimizu 890ddd
#include "tools/toolcommandids.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzQt includes
Toshihiro Shimizu 890ddd
#include "toonzqt/selection.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/tselectionhandle.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/dvmimedata.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/dvdialog.h"
Toshihiro Shimizu 890ddd
#include "toonzqt/selectioncommandids.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzLib includes
Toshihiro Shimizu 890ddd
#include "toonz/tframehandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tcolumnhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/txsheethandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tobjecthandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tonionskinmaskhandle.h"
Toshihiro Shimizu 890ddd
#include "toonz/tstageobject.h"
Toshihiro Shimizu 890ddd
#include "toonz/doubleparamcmd.h"
Toshihiro Shimizu 890ddd
#include "toonz/palettecontroller.h"
Toshihiro Shimizu 890ddd
#include "toonz/txshsimplelevel.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzExt includes
Toshihiro Shimizu 890ddd
#include "ext/plasticskeleton.h"
Toshihiro Shimizu 890ddd
#include "ext/plasticdeformerstorage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
#include "tfunctorinvoker.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// Qt includes
Toshihiro Shimizu 890ddd
#include <qapplication></qapplication>
Toshihiro Shimizu 890ddd
#include <qstring></qstring>
Toshihiro Shimizu 890ddd
#include <qtoolbar></qtoolbar>
Toshihiro Shimizu 890ddd
#include <qpushbutton></qpushbutton>
Toshihiro Shimizu 890ddd
#include <qlabel></qlabel>
Toshihiro Shimizu 890ddd
#include <qclipboard></qclipboard>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// tcg includes
Toshihiro Shimizu 890ddd
#include "tcg/tcg_macros.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_point_ops.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_list.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
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
static const double l_dmax = (std::numeric_limits<double>::max)();</double>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticToolLocals namespace
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace PlasticToolLocals;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace PlasticToolLocals
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticTool l_plasticTool;
Toshihiro Shimizu 890ddd
bool l_suspendParamsObservation = false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TPointD projection(const PlasticSkeleton &skeleton, int e, const TPointD &pos)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const PlasticSkeleton::edge_type &ed = skeleton.edge(e);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TPointD &p0 = skeleton.vertex(ed.vertex(0)).P();
Toshihiro Shimizu 890ddd
	const TPointD &p1 = skeleton.vertex(ed.vertex(1)).P();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return tcg::point_ops::projection(pos, p0, tcg::point_ops::direction(p0, p1));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double frame()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return TTool::getApplication()->getCurrentFrame()->getFrame();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int row() { return int(frame()) + 1; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int column()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return TTool::getApplication()->getCurrentColumn()->getColumnIndex();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void setCell(int row, int col)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TTool::Application *app = TTool::getApplication();
Toshihiro Shimizu 890ddd
	app->getCurrentFrame()->setCurrentFrame(row);
Toshihiro Shimizu 890ddd
	app->getCurrentColumn()->setColumnIndex(col);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TXshColumn *xshColumn()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Toshihiro Shimizu 890ddd
	return xsh->getColumn(column());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TStageObject *stageObject()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Toshihiro Shimizu 890ddd
	return xsh->getStageObject(TStageObjectId::ColumnId(column()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
const TXshCell &xshCell()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TXsheet *xsh = TTool::getApplication()->getCurrentXsheet()->getXsheet();
Toshihiro Shimizu 890ddd
	return xsh->getCell(frame(), column());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int skeletonId()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TStageObject *obj = stageObject();
Toshihiro Shimizu 890ddd
	const PlasticSkeletonDeformationP &def = obj->getPlasticSkeletonDeformation();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return def ? def->skeletonId(obj->paramsTime(frame())) : 1; // 1 (not -1) is intended.
Toshihiro Shimizu 890ddd
} // Means '' (empty string)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
double sdFrame() { return stageObject()->paramsTime(frame()); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void setKeyframe(TDoubleParamP ¶m, double frame)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!param->isKeyframe(frame)) {
Toshihiro Shimizu 890ddd
		KeyframeSetter setter(param.getPointer(), -1, false); // Not placing undos through this setter
Toshihiro Shimizu 890ddd
		setter.createKeyframe(frame);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void setKeyframe(SkVD *vd, double frame)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// vd->setKeyframe(frame);                          // Nope. In fact...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Keyframe set is performed with a special tool that is NOT AVAILABLE in TnzExt
Toshihiro Shimizu 890ddd
	// (thus, not available to m_sd). It deals with specifying the correct interpolation
Toshihiro Shimizu 890ddd
	// type (by user preference, which is TnzLib stuff), etc...
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Traverse vd's parameters. In case they don't have a keyframe at current frame, add one.
Toshihiro Shimizu 890ddd
	for (int p = 0; p < SkVD::PARAMS_COUNT; ++p)
Toshihiro Shimizu 890ddd
		setKeyframe(vd->m_params[p], frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void setKeyframe(const PlasticSkeletonDeformationP &sd, double frame)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// NOTE: The skeleton ids parameter is NOT affected
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SkD::vd_iterator vdt, vdEnd;
Toshihiro Shimizu 890ddd
	sd->vertexDeformations(vdt, vdEnd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (; vdt != vdEnd; ++vdt)
Toshihiro Shimizu 890ddd
		setKeyframe((*vdt).second, frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void invalidateXsheet()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TTool::getApplication()->getCurrentXsheet()->notifyXsheetChanged();
Toshihiro Shimizu 890ddd
	stageObject()->updateKeyframes();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_plasticTool.storeDeformation();
Toshihiro Shimizu 890ddd
	l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace PlasticToolLocals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Mime  definitions
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct PlasticSkeletonPMime : public DvMimeData {
Toshihiro Shimizu 890ddd
	PlasticSkeletonP m_skeleton;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	PlasticSkeletonPMime(const PlasticSkeletonP &skeleton)
Toshihiro Shimizu 890ddd
		: m_skeleton(skeleton) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual DvMimeData *clone() const { return new PlasticSkeletonPMime(m_skeleton); }
Toshihiro Shimizu 890ddd
	virtual void releaseData() { m_skeleton = PlasticSkeletonP(); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct SkDPMime : public DvMimeData {
Toshihiro Shimizu 890ddd
	SkDP m_sd;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SkDPMime(const SkDP &sd) : m_sd(sd) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	virtual DvMimeData *clone() const { return new SkDPMime(m_sd); }
Toshihiro Shimizu 890ddd
	virtual void releaseData() { m_sd = SkDP(); }
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Undo  definitions
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// NOTE: Some of the following UNDOs have complex and dynamic contents, and I don't want to
Toshihiro Shimizu 890ddd
//       trace their size thoroughly. So, I'll follow this guideline: given the standard
Toshihiro Shimizu 890ddd
//       100 MB undos pool, how many undos of one specific type I'd want the pool to be able
Toshihiro Shimizu 890ddd
//       to store?
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class SetVertexNameUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_row, m_col; //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
	int m_v;		  //!< Changed vertex
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	mutable QString m_oldName, m_newName; //!< Vertex names
Toshihiro Shimizu 890ddd
	mutable SkVD m_oldVd;				  //!< Old Vertex deformation (SHARE-OWNED, rather than CLONED)
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SetVertexNameUndo(int v, const QString &newName)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_v(v), m_newName(newName)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skeleton = l_plasticTool.skeleton();
Toshihiro Shimizu 890ddd
		const PlasticSkeletonVertex &vx = skeleton->vertex(v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_oldName = vx.name();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return sizeof(*this); } // sizeof this is roughly ok
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
		// Store the vertex deformation before it's released (possibly destroyed)
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 SkVD *vd = sd->vertexDeformation(m_oldName);
Toshihiro Shimizu 890ddd
			TCG_ASSERT(vd, return );
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_oldVd = *vd;
Toshihiro Shimizu 890ddd
		}
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_plasticTool.setVertexName(m_newName);
Toshihiro Shimizu 890ddd
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
		const SkDP &sd = l_plasticTool.deformation();
Toshihiro Shimizu 890ddd
		TCG_ASSERT(sd, return );
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_plasticTool.setVertexName(m_oldName);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore the vertex deformation.
Toshihiro Shimizu 890ddd
		SkVD *vd = sd->vertexDeformation(m_oldName);
Toshihiro Shimizu 890ddd
		assert(vd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		*vd = m_oldVd;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		::invalidateXsheet();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class PasteDeformationUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_col;			   //!< Affected column
Toshihiro Shimizu 890ddd
	SkDP m_oldSd, m_newSd; //!< The skeleton deformations
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	PasteDeformationUndo(const SkDP &newSd)
Toshihiro Shimizu 890ddd
		: m_col(column()), m_oldSd(stageObject()->getPlasticSkeletonDeformation()), m_newSd(newSd) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return 1 << 20; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TTool::getApplication()->getCurrentColumn()->setColumnIndex(m_col);
Toshihiro Shimizu 890ddd
		stageObject()->setPlasticSkeletonDeformation(m_newSd);
Toshihiro Shimizu 890ddd
		::invalidateXsheet();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TTool::getApplication()->getCurrentColumn()->setColumnIndex(m_col);
Toshihiro Shimizu 890ddd
		stageObject()->setPlasticSkeletonDeformation(m_oldSd);
Toshihiro Shimizu 890ddd
		::invalidateXsheet();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticTool::TemporaryActivation  implementation
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticTool::TemporaryActivation::TemporaryActivation(int row, int col)
Toshihiro Shimizu 890ddd
	: m_activate(!l_plasticTool.isActive())
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_activate)
Toshihiro Shimizu 890ddd
		l_plasticTool.onActivate();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	::setCell(row, col);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticTool::TemporaryActivation::~TemporaryActivation()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_activate)
Toshihiro Shimizu 890ddd
		l_plasticTool.onDeactivate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticToolOptionsBox::SkelIdComboBox  definition
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class PlasticToolOptionsBox::SkelIdsComboBox : public QComboBox
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SkelIdsComboBox(QWidget *parent = 0) : QComboBox(parent)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		updateSkeletonsList();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void updateSkeletonsList();
Toshihiro Shimizu 890ddd
	void updateCurrentSkeleton();
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::SkelIdsComboBox::updateSkeletonsList()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const SkDP &sd = l_plasticTool.deformation();
Toshihiro Shimizu 890ddd
	if (!sd)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QStringList skeletonsList;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SkD::skelId_iterator st, sEnd;
Toshihiro Shimizu 890ddd
	sd->skeletonIds(st, sEnd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (; st != sEnd; ++st)
Toshihiro Shimizu 890ddd
		skeletonsList.push_back(QString::number(*st));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QComboBox::insertItems(0, skeletonsList);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	updateCurrentSkeleton();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::SkelIdsComboBox::updateCurrentSkeleton()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setCurrentIndex(findText(QString::number(::skeletonId())));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticToolOptionsBox  implementation
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticToolOptionsBox::PlasticToolOptionsBox(QWidget *parent, TTool *tool, TPaletteHandle *pltHandle)
Toshihiro Shimizu 890ddd
	: GenericToolOptionsBox(parent, tool, pltHandle, PlasticTool::MODES_COUNT), m_tool(tool), m_subToolbars(new GenericToolOptionsBox *[PlasticTool::MODES_COUNT])
Toshihiro Shimizu 890ddd
//, m_subToolbarActions(new QAction*[PlasticTool::MODES_COUNT])
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		static inline QWidget *newSpace(QWidget *parent = 0)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			QWidget *space = new QWidget(parent);
Toshihiro Shimizu 890ddd
			space->setFixedWidth(TOOL_OPTIONS_LEFT_MARGIN);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return space;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Create Mesh button
Toshihiro Shimizu 890ddd
	QPushButton *meshifyButton = new QPushButton(tr("Create Mesh"));
Toshihiro Shimizu 890ddd
	// Add skeleton id-related widgets
Toshihiro Shimizu 890ddd
	QLabel *skelIdLabel = new QLabel(tr("Skeleton:"));
Toshihiro Shimizu 890ddd
	m_skelIdComboBox = new SkelIdsComboBox;
Toshihiro Shimizu 890ddd
	m_addSkelButton = new QPushButton("+");	// Connected in the show event
Toshihiro Shimizu 890ddd
	m_removeSkelButton = new QPushButton("-"); // Connected in the show event
Toshihiro Shimizu 890ddd
	// Add sub-options for each mode group
Toshihiro Shimizu 890ddd
	for (int m = 0; m != PlasticTool::MODES_COUNT; ++m)
Toshihiro Shimizu 890ddd
		m_subToolbars[m] = new GenericToolOptionsBox(0, tool, pltHandle, m);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	meshifyButton->setFixedHeight(20);
Toshihiro Shimizu 890ddd
	QAction *meshifyAction = CommandManager::instance()->getAction("A_ToolOption_Meshify");
Toshihiro Shimizu 890ddd
	meshifyButton->addAction(meshifyAction);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	skelIdLabel->setFixedHeight(20);
Toshihiro Shimizu 890ddd
	m_skelIdComboBox->setFixedWidth(50);
Toshihiro Shimizu 890ddd
	m_addSkelButton->setFixedSize(20, 20);
Toshihiro Shimizu 890ddd
	m_removeSkelButton->setFixedSize(20, 20);
Toshihiro Shimizu 890ddd
	for (int m = 0; m != PlasticTool::MODES_COUNT; ++m)
Toshihiro Shimizu 890ddd
		m_subToolbars[m]->setContentsMargins(0, 0, 0, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	/*- Layout -*/
Toshihiro Shimizu 890ddd
	// Add created widgets to the toolbar (in reverse order since we're inserting at 0)
Toshihiro Shimizu 890ddd
	m_layout->insertWidget(0, m_removeSkelButton);
Toshihiro Shimizu 890ddd
	m_layout->insertWidget(0, m_addSkelButton);
Toshihiro Shimizu 890ddd
	m_layout->insertWidget(0, m_skelIdComboBox);
Toshihiro Shimizu 890ddd
	m_layout->insertWidget(0, skelIdLabel);
Toshihiro Shimizu 890ddd
	m_layout->insertWidget(0, locals::newSpace(this));
Toshihiro Shimizu 890ddd
	m_layout->insertWidget(0, meshifyButton);
Toshihiro Shimizu 890ddd
	m_layout->insertWidget(0, locals::newSpace(this));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int m = 0; m != PlasticTool::MODES_COUNT; ++m)
Toshihiro Shimizu 890ddd
		m_layout->insertWidget(m_layout->count() - 1, m_subToolbars[m], 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool ret = true;
Toshihiro Shimizu 890ddd
	ret = ret && connect(meshifyButton, SIGNAL(clicked()), meshifyAction, SLOT(trigger()));
Toshihiro Shimizu 890ddd
	assert(ret);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Add Animation mode fields corresponding to vertex properties
Toshihiro Shimizu 890ddd
	GenericToolOptionsBox *animateOptionsBox = m_subToolbars[PlasticTool::ANIMATE_IDX];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Adjust some specific controls first
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		ToolOptionTextField *minAngleField = static_cast<tooloptiontextfield *="">(</tooloptiontextfield>
Toshihiro Shimizu 890ddd
			animateOptionsBox->control("minAngle"));
Toshihiro Shimizu 890ddd
		assert(minAngleField);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		minAngleField->setFixedWidth(40);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		ToolOptionTextField *maxAngleField = static_cast<tooloptiontextfield *="">(</tooloptiontextfield>
Toshihiro Shimizu 890ddd
			animateOptionsBox->control("maxAngle"));
Toshihiro Shimizu 890ddd
		assert(maxAngleField);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		maxAngleField->setFixedWidth(40);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Distance
Toshihiro Shimizu 890ddd
	ToolOptionParamRelayField *distanceField = new ToolOptionParamRelayField(
Toshihiro Shimizu 890ddd
		&l_plasticTool, &l_plasticTool.m_distanceRelay);
Toshihiro Shimizu 890ddd
	distanceField->setGlobalKey(&l_plasticTool.m_globalKey, &l_plasticTool.m_relayGroup);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QLabel *distanceLabel = new QLabel(tr("Distance"));
Toshihiro Shimizu 890ddd
	distanceLabel->setFixedHeight(20);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Angle
Toshihiro Shimizu 890ddd
	ToolOptionParamRelayField *angleField = new ToolOptionParamRelayField(
Toshihiro Shimizu 890ddd
		&l_plasticTool, &l_plasticTool.m_angleRelay);
Toshihiro Shimizu 890ddd
	angleField->setGlobalKey(&l_plasticTool.m_globalKey, &l_plasticTool.m_relayGroup);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QLabel *angleLabel = new QLabel(tr("Angle"));
Toshihiro Shimizu 890ddd
	angleLabel->setFixedHeight(20);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// SO
Toshihiro Shimizu 890ddd
	ToolOptionParamRelayField *soField = new ToolOptionParamRelayField(
Toshihiro Shimizu 890ddd
		&l_plasticTool, &l_plasticTool.m_soRelay);
Toshihiro Shimizu 890ddd
	soField->setGlobalKey(&l_plasticTool.m_globalKey, &l_plasticTool.m_relayGroup);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QLabel *soLabel = new QLabel(tr("SO"));
Toshihiro Shimizu 890ddd
	soLabel->setFixedHeight(20);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QHBoxLayout *animateLayout = animateOptionsBox->hLayout();
Toshihiro Shimizu 890ddd
	animateLayout->insertWidget(0, soField);
Toshihiro Shimizu 890ddd
	animateLayout->insertWidget(0, soLabel);
Toshihiro Shimizu 890ddd
	animateLayout->insertWidget(0, angleField);
Toshihiro Shimizu 890ddd
	animateLayout->insertWidget(0, angleLabel);
Toshihiro Shimizu 890ddd
	animateLayout->insertWidget(0, distanceField);
Toshihiro Shimizu 890ddd
	animateLayout->insertWidget(0, distanceLabel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	onPropertyChanged();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::showEvent(QShowEvent *se)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool ret = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ret = ret && connect(&l_plasticTool, SIGNAL(skelIdsListChanged()), SLOT(onSkelIdsListChanged()));
Toshihiro Shimizu 890ddd
	ret = ret && connect(&l_plasticTool, SIGNAL(skelIdChanged()), SLOT(onSkelIdChanged()));
Toshihiro Shimizu 890ddd
	ret = ret && connect(m_skelIdComboBox, SIGNAL(activated(int)), SLOT(onSkelIdEdited()));
Toshihiro Shimizu 890ddd
	ret = ret && connect(m_addSkelButton, SIGNAL(released()), SLOT(onAddSkeleton()));
Toshihiro Shimizu 890ddd
	ret = ret && connect(m_removeSkelButton, SIGNAL(released()), SLOT(onRemoveSkeleton()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(ret);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_skelIdComboBox->updateSkeletonsList();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::hideEvent(QHideEvent *he)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	disconnect(&l_plasticTool, 0, this, 0);
Toshihiro Shimizu 890ddd
	disconnect(m_skelIdComboBox, 0, this, 0);
Toshihiro Shimizu 890ddd
	disconnect(m_addSkelButton, 0, this, 0);
Toshihiro Shimizu 890ddd
	disconnect(m_removeSkelButton, 0, this, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::onPropertyChanged()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Fetch current mode index
Toshihiro Shimizu 890ddd
	TPropertyGroup *pGroup = m_tool->getProperties(PlasticTool::MODES_COUNT);
Toshihiro Shimizu 890ddd
	assert(pGroup);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TEnumProperty *prop = dynamic_cast<tenumproperty *="">(pGroup->getProperty("mode"));</tenumproperty>
Toshihiro Shimizu 890ddd
	assert(prop);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int mode = prop->getIndex();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Show the specified mode options, hide all the others
Toshihiro Shimizu 890ddd
	for (int m = 0; m != PlasticTool::MODES_COUNT; ++m)
Toshihiro Shimizu 890ddd
		m_subToolbars[m]->setVisible(m == mode);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::onSkelIdsListChanged()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_skelIdComboBox->updateSkeletonsList();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::onSkelIdChanged()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_skelIdComboBox->updateCurrentSkeleton();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::onSkelIdEdited()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int skelId = m_skelIdComboBox->currentText().toInt();
Toshihiro Shimizu 890ddd
	if (skelId == ::skeletonId())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!l_plasticTool.deformation())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	l_plasticTool.editSkelId_undo(skelId);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::onAddSkeleton()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (l_plasticTool.isEnabled())
Toshihiro Shimizu 890ddd
		l_plasticTool.addSkeleton_undo(new PlasticSkeleton);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticToolOptionsBox::onRemoveSkeleton()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (l_plasticTool.isEnabled() && l_plasticTool.deformation())
Toshihiro Shimizu 890ddd
		l_plasticTool.removeSkeleton_withKeyframes_undo(::skeletonId());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticTool  implementation
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticTool::PlasticTool()
Toshihiro Shimizu 890ddd
	: TTool(T_Plastic), m_skelId(-(std::numeric_limits<int>::max)()), m_propGroup(new TPropertyGroup[MODES_COUNT + 1]), m_mode("mode"), m_vertexName("vertexName", L""), m_interpolate("interpolate", false), m_snapToMesh("snapToMesh", false), m_thickness("Thickness", 1, 100, 5), m_rigidValue("rigidValue"), m_globalKey("globalKeyframe", true), m_keepDistance("keepDistance", true), m_minAngle("minAngle", L""), m_maxAngle("maxAngle", L""), m_distanceRelay("distanceRelay"), m_angleRelay("angleRelay"), m_soRelay("soRelay"), m_skelIdRelay("skelIdRelay"), m_pressedPos(TConsts::napd), m_dragged(false), m_svHigh(-1), m_seHigh(-1), m_mvHigh(-1), m_meHigh(-1), m_rigidityPainter(createRigidityPainter()), m_showSkeletonOS(true), m_recompileOnMouseRelease(false)</int>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// And now, a little trick about tool binding
Toshihiro Shimizu 890ddd
	bind(TTool::AllImages);  // Attach the tool to all types :)
Toshihiro Shimizu 890ddd
	bind(TTool::MeshLevels); // But disable it for all but meshes :0
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// This little trick is needed to associate the tool to common levels (the toolbar must appear), in
Toshihiro Shimizu 890ddd
	// order to make them meshable.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Bind properties to the appropriate property group (needed by the automatic toolbar builder)
Toshihiro Shimizu 890ddd
	m_propGroup[MODES_COUNT].bind(m_mode);
Toshihiro Shimizu 890ddd
	m_propGroup[MODES_COUNT].bind(m_vertexName);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_propGroup[RIGIDITY_IDX].bind(m_thickness);
Toshihiro Shimizu 890ddd
	m_propGroup[RIGIDITY_IDX].bind(m_rigidValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_propGroup[BUILD_IDX].bind(m_interpolate);
Toshihiro Shimizu 890ddd
	m_propGroup[BUILD_IDX].bind(m_snapToMesh);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_propGroup[ANIMATE_IDX].bind(m_globalKey);
Toshihiro Shimizu 890ddd
	m_propGroup[ANIMATE_IDX].bind(m_keepDistance);
Toshihiro Shimizu 890ddd
	m_propGroup[ANIMATE_IDX].bind(m_minAngle);
Toshihiro Shimizu 890ddd
	m_propGroup[ANIMATE_IDX].bind(m_maxAngle);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_relayGroup.bind(m_distanceRelay);
Toshihiro Shimizu 890ddd
	m_relayGroup.bind(m_angleRelay);
Toshihiro Shimizu 890ddd
	m_relayGroup.bind(m_soRelay);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_mode.setId("SkeletonMode");
Toshihiro Shimizu 890ddd
	m_vertexName.setId("VertexName");
Toshihiro Shimizu 890ddd
	m_interpolate.setId("Interpolate");
Toshihiro Shimizu 890ddd
	m_snapToMesh.setId("SnapToMesh");
Toshihiro Shimizu 890ddd
	m_thickness.setId("Thickness");
Toshihiro Shimizu 890ddd
	m_rigidValue.setId("RigidValue");
Toshihiro Shimizu 890ddd
	m_globalKey.setId("GlobalKey");
Toshihiro Shimizu 890ddd
	m_keepDistance.setId("KeepDistance");
Toshihiro Shimizu 890ddd
	m_minAngle.setId("MinAngle");
Toshihiro Shimizu 890ddd
	m_maxAngle.setId("MaxAngle");
Toshihiro Shimizu 890ddd
	m_distanceRelay.setId("DistanceRelay");
Toshihiro Shimizu 890ddd
	m_angleRelay.setId("AngleRelay");
Toshihiro Shimizu 890ddd
	m_soRelay.setId("SoRelay");
Toshihiro Shimizu 890ddd
	m_skelIdRelay.setId("SkelIdRelay");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Attach to selections
Toshihiro Shimizu 890ddd
	m_svSel.setView(this);
Toshihiro Shimizu 890ddd
	m_mvSel.setView(this), m_meSel.setView(this);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticTool::~PlasticTool()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_sd)
Toshihiro Shimizu 890ddd
		m_sd->removeObserver(this);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
TTool::ToolType PlasticTool::getToolType() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
	case RIGIDITY_IDX:
Toshihiro Shimizu 890ddd
		return TTool::LevelWriteTool;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE BUILD_IDX : case ANIMATE_IDX : return TTool::ColumnTool;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(false);
Toshihiro Shimizu 890ddd
	return TTool::GenericTool;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::updateTranslation()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_mode.setQStringName(tr("Mode:"));
Toshihiro Shimizu 890ddd
	m_mode.deleteAllValues();
Toshihiro Shimizu 890ddd
	m_mode.addValue(tr("Edit Mesh").toStdWString());
Toshihiro Shimizu 890ddd
	m_mode.addValue(tr("Paint Rigid").toStdWString());
Toshihiro Shimizu 890ddd
	m_mode.addValue(tr("Build Skeleton").toStdWString());
Toshihiro Shimizu 890ddd
	m_mode.addValue(tr("Animate").toStdWString());
Toshihiro Shimizu 890ddd
	m_mode.setIndex(BUILD_IDX);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_vertexName.setQStringName(tr("Vertex Name:"));
Toshihiro Shimizu 890ddd
	m_interpolate.setQStringName(tr("Allow Stretching"));
Toshihiro Shimizu 890ddd
	m_snapToMesh.setQStringName(tr("Snap To Mesh"));
Toshihiro Shimizu 890ddd
	m_thickness.setQStringName(tr("Thickness"));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_rigidValue.setQStringName("");
Toshihiro Shimizu 890ddd
	m_rigidValue.deleteAllValues();
Toshihiro Shimizu 890ddd
	m_rigidValue.addValue(tr("Rigid").toStdWString());
Toshihiro Shimizu 890ddd
	m_rigidValue.addValue(tr("Flex").toStdWString());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_globalKey.setQStringName(tr("Global Key"));
Toshihiro Shimizu 890ddd
	m_keepDistance.setQStringName(tr("Keep Distance"));
Toshihiro Shimizu 890ddd
	m_minAngle.setQStringName(tr("Angle Bounds"));
Toshihiro Shimizu 890ddd
	m_maxAngle.setQStringName("");
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ToolOptionsBox *PlasticTool::createOptionsBox()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Create the options box
Toshihiro Shimizu 890ddd
	TPaletteHandle *currPalette = TTool::getApplication()->getPaletteController()->getCurrentLevelPalette();
Toshihiro Shimizu 890ddd
	PlasticToolOptionsBox *optionsBox = new PlasticToolOptionsBox(0, this, currPalette);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Connect it to receive m_mode notifications
Toshihiro Shimizu 890ddd
	m_mode.addListener(optionsBox);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return optionsBox;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticSkeletonP PlasticTool::skeleton() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return m_sd ? m_sd->skeleton(::sdFrame()) : PlasticSkeletonP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticSkeleton &PlasticTool::deformedSkeleton()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef tcg::function
Toshihiro Shimizu 890ddd
						  &PlasticTool::updateDeformedSkeleton> Func;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return m_deformedSkeleton(tcg::bind1st(Func(), *this));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::touchSkeleton()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	touchDeformation();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int skelId = ::skeletonId();
Toshihiro Shimizu 890ddd
	if (!m_sd->skeleton(skelId)) {
Toshihiro Shimizu 890ddd
		m_sd->attach(skelId, new PlasticSkeleton);
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::touchDeformation()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_sd)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Store a new deformation in the column's stage object
Toshihiro Shimizu 890ddd
	stageObject()->setPlasticSkeletonDeformation(new PlasticSkeletonDeformation);
Toshihiro Shimizu 890ddd
	storeDeformation(); // Builds the deformed skeleton too
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::storeDeformation()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const SkDP &sd = stageObject()->getPlasticSkeletonDeformation();
Toshihiro Shimizu 890ddd
	if (m_sd != sd) {
Toshihiro Shimizu 890ddd
		clearSkeletonSelections();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_sd) {
Toshihiro Shimizu 890ddd
			m_sd->removeObserver(this);
Toshihiro Shimizu 890ddd
			m_skelIdRelay.setParam(TDoubleParamP());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Store the deformation, retrieving it from current column stage object
Toshihiro Shimizu 890ddd
		m_sd = sd;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (m_sd) {
Toshihiro Shimizu 890ddd
			m_sd->addObserver(this);
Toshihiro Shimizu 890ddd
			m_skelIdRelay.setParam(m_sd->skeletonIdsParam());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_skelIdRelay.notifyListeners();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	storeSkeletonId();
Toshihiro Shimizu 890ddd
	if (m_mode.getIndex() == ANIMATE_IDX)
Toshihiro Shimizu 890ddd
		m_deformedSkeleton.invalidate(); // Store the deformed skeleton too
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::storeSkeletonId()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int skelId = m_sd ? m_sd->skeletonIdsParam()->getValue(::sdFrame()) : -(std::numeric_limits<int>::max)();</int>
Toshihiro Shimizu 890ddd
	if (m_skelId != skelId) {
Toshihiro Shimizu 890ddd
		m_skelId = skelId;
Toshihiro Shimizu 890ddd
		clearSkeletonSelections();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		emit skelIdChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::updateDeformedSkeleton(PlasticSkeleton &deformedSkeleton)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_sd)
Toshihiro Shimizu 890ddd
		m_sd->storeDeformedSkeleton(::skeletonId(), ::sdFrame(), deformedSkeleton);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		deformedSkeleton.clear();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onFrameSwitched()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	storeSkeletonId();
Toshihiro Shimizu 890ddd
	storeMeshImage();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case ANIMATE_IDX:
Toshihiro Shimizu 890ddd
		m_deformedSkeleton.invalidate();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Update the relays' current frame
Toshihiro Shimizu 890ddd
	double frame = ::sdFrame();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_distanceRelay.frame() = frame;
Toshihiro Shimizu 890ddd
	m_angleRelay.frame() = frame;
Toshihiro Shimizu 890ddd
	m_soRelay.frame() = frame;
Toshihiro Shimizu 890ddd
	m_skelIdRelay.frame() = frame;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_distanceRelay.notifyListeners();
Toshihiro Shimizu 890ddd
	m_angleRelay.notifyListeners();
Toshihiro Shimizu 890ddd
	m_soRelay.notifyListeners();
Toshihiro Shimizu 890ddd
	m_skelIdRelay.notifyListeners();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onColumnSwitched()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
	case BUILD_IDX:
Toshihiro Shimizu 890ddd
	case RIGIDITY_IDX:
Toshihiro Shimizu 890ddd
		m_pvs.m_showOriginalColumn = xshColumn();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	storeDeformation();
Toshihiro Shimizu 890ddd
	storeMeshImage();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onXsheetChanged()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	onColumnSwitched();
Toshihiro Shimizu 890ddd
	TTool::updateEnabled(); // Current cell may no longer be a mesh one (or viceversa),
Toshihiro Shimizu 890ddd
} // so tool enabled status must be updated.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onChange()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Since parameters are typically coupled, we could pass multiple, consecutive times in
Toshihiro Shimizu 890ddd
	// this notification function. We have to employ counter-measures to prevent multiple
Toshihiro Shimizu 890ddd
	// calls from affecting performance.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	static bool refresh = false; // Accessible from locals since static
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		struct RefreshFunctor : public TFunctorInvoker::BaseFunctor {
Toshihiro Shimizu 890ddd
			void operator()()
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				refresh = false;
Toshihiro Shimizu 890ddd
				l_plasticTool.storeSkeletonId(); // Calls ::sdFrame()
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				// This is needed to repaint the xsheet (not automatic otherwise)
Toshihiro Shimizu 890ddd
				TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(false);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		};
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Using invalidate/update and delayed invocation to prevent multiple calls to ::sdFrame()
Toshihiro Shimizu 890ddd
	m_deformedSkeleton.invalidate();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!refresh) {
Toshihiro Shimizu 890ddd
		refresh = true;
Toshihiro Shimizu 890ddd
		QMetaObject::invokeMethod(TFunctorInvoker::instance(), "invoke", Qt::QueuedConnection,
Toshihiro Shimizu 890ddd
								  Q_ARG(void *, new locals::RefreshFunctor));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Passing through Qt's event system to compress repaints in a single one
Toshihiro Shimizu 890ddd
	TTool::Viewer *viewer = getViewer();
Toshihiro Shimizu 890ddd
	if (viewer)					 // This goes through paintEvent(),
Toshihiro Shimizu 890ddd
		viewer->invalidateAll(); // \a unlike TTool::invalidate()
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onChange(const TParamChange &pc)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (l_suspendParamsObservation)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	onChange();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onSetViewer()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Viewer *viewer = getViewer();
Toshihiro Shimizu 890ddd
	if (viewer) {
Toshihiro Shimizu 890ddd
		PlasticVisualSettings &pvs = viewer->visualSettings().m_plasticVisualSettings;
Toshihiro Shimizu 890ddd
		pvs = m_pvs;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Force options if needed
Toshihiro Shimizu 890ddd
		if (m_mode.getIndex() == RIGIDITY_IDX)
Toshihiro Shimizu 890ddd
			pvs.m_drawRigidity = true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onActivate()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool ret;
Toshihiro Shimizu 890ddd
	ret = connect(TTool::m_application->getCurrentFrame(), SIGNAL(frameSwitched()), this, SLOT(onFrameSwitched())), assert(ret);
Toshihiro Shimizu 890ddd
	ret = connect(TTool::m_application->getCurrentColumn(), SIGNAL(columnIndexSwitched()), this, SLOT(onColumnSwitched())), assert(ret);
Toshihiro Shimizu 890ddd
	ret = connect(TTool::m_application->getCurrentXsheet(), SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged())), assert(ret);
Toshihiro Shimizu 890ddd
	ret = connect(TTool::m_application->getCurrentXsheet(), SIGNAL(xsheetSwitched()), this, SLOT(onXsheetChanged())), assert(ret);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	onSetViewer();
Toshihiro Shimizu 890ddd
	onColumnSwitched();
Toshihiro Shimizu 890ddd
	onFrameSwitched();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	setActive(true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onDeactivate()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setActive(false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool ret;
Toshihiro Shimizu 890ddd
	ret = disconnect(TTool::m_application->getCurrentFrame(), SIGNAL(frameSwitched()), this, SLOT(onFrameSwitched())), assert(ret);
Toshihiro Shimizu 890ddd
	ret = disconnect(TTool::m_application->getCurrentColumn(), SIGNAL(columnIndexSwitched()), this, SLOT(onColumnSwitched())), assert(ret);
Toshihiro Shimizu 890ddd
	ret = disconnect(TTool::m_application->getCurrentXsheet(), SIGNAL(xsheetChanged()), this, SLOT(onXsheetChanged())), assert(ret);
Toshihiro Shimizu 890ddd
	ret = disconnect(TTool::m_application->getCurrentXsheet(), SIGNAL(xsheetSwitched()), this, SLOT(onXsheetChanged())), assert(ret);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	Viewer *viewer = getViewer();
Toshihiro Shimizu 890ddd
	if (viewer)
Toshihiro Shimizu 890ddd
		viewer->visualSettings().m_plasticVisualSettings = PlasticVisualSettings();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_sd = PlasticSkeletonDeformationP();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onEnter()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onLeave()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Clear visualization vars
Toshihiro Shimizu 890ddd
	m_pos = TConsts::napd;
Toshihiro Shimizu 890ddd
	m_svHigh = m_seHigh = -1;
Toshihiro Shimizu 890ddd
	m_mvHigh = m_meHigh = MeshIndex();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onSelectionChanged()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	SkVD *vd = 0;
Toshihiro Shimizu 890ddd
	if (m_sd && m_svSel.hasSingleObject()) {
Toshihiro Shimizu 890ddd
		int skelId = ::skeletonId();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const PlasticSkeleton::vertex_type &vx = m_sd->skeleton(skelId)->vertex(m_svSel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_vertexName.setValue(vx.name().toStdWString());
Toshihiro Shimizu 890ddd
		m_interpolate.setValue(vx.m_interpolate);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_minAngle.setValue((vx.m_minAngle == -l_dmax) ? L"" : QString::number(vx.m_minAngle).toStdWString());
Toshihiro Shimizu 890ddd
		m_maxAngle.setValue((vx.m_maxAngle == l_dmax) ? L"" : QString::number(vx.m_maxAngle).toStdWString());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		vd = m_sd->vertexDeformation(skelId, m_svSel);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		m_vertexName.setValue(L"");
Toshihiro Shimizu 890ddd
		m_interpolate.setValue(false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_minAngle.setValue(L"");
Toshihiro Shimizu 890ddd
		m_maxAngle.setValue(L"");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Attach or detach relays depending on selected vertex's parameters
Toshihiro Shimizu 890ddd
	m_soRelay.setParam(vd ? vd->m_params[SkVD::SO] : TDoubleParamP());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (vd && m_svSel.hasSingleObject() && m_svSel.objects().front() > 0) {
Toshihiro Shimizu 890ddd
		m_distanceRelay.setParam(vd->m_params[SkVD::DISTANCE]);
Toshihiro Shimizu 890ddd
		m_angleRelay.setParam(vd->m_params[SkVD::ANGLE]);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		m_distanceRelay.setParam(TDoubleParamP());
Toshihiro Shimizu 890ddd
		m_angleRelay.setParam(TDoubleParamP());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_vertexName.notifyListeners();
Toshihiro Shimizu 890ddd
	m_interpolate.notifyListeners();
Toshihiro Shimizu 890ddd
	m_minAngle.notifyListeners();
Toshihiro Shimizu 890ddd
	m_maxAngle.notifyListeners();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_distanceRelay.notifyListeners();
Toshihiro Shimizu 890ddd
	m_angleRelay.notifyListeners();
Toshihiro Shimizu 890ddd
	m_soRelay.notifyListeners();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::enableCommands()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (TSelection::getCurrent() == &m_svSel)
Toshihiro Shimizu 890ddd
		m_svSel.enableCommand(this, MI_Clear, &PlasticTool::deleteSelectedVertex_undo);
Toshihiro Shimizu 890ddd
	else if (TSelection::getCurrent() == &m_meSel) {
Toshihiro Shimizu 890ddd
		m_meSel.enableCommand(this, MI_Clear, &PlasticTool::collapseEdge_mesh_undo);
Toshihiro Shimizu 890ddd
		m_meSel.enableCommand(this, MI_Insert, &PlasticTool::splitEdge_mesh_undo);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setSkeletonSelection(const PlasticVertexSelection &vSel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (vSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		m_svSel.selectNone();
Toshihiro Shimizu 890ddd
		m_svSel.makeNotCurrent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(m_sd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_svSel.skeletonId() = m_skelId;
Toshihiro Shimizu 890ddd
	m_svSel.setObjects(vSel.objects());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_svSel.notifyView();
Toshihiro Shimizu 890ddd
	m_svSel.makeCurrent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Okay, the following is cheap - we have to update the Function Editor (specifically)
Toshihiro Shimizu 890ddd
	// since current vertex is shown in a special color. We know that the same happens for
Toshihiro Shimizu 890ddd
	// the current stage object, so... we'll attach there.
Toshihiro Shimizu 890ddd
	TTool::getApplication()->getCurrentObject()->notifyObjectIdChanged(false); // Carry on, you've seen nothing ;)
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::toggleSkeletonSelection(const PlasticVertexSelection &addition)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const std::vector<int> &storedIdxs = m_svSel.objects();</int>
Toshihiro Shimizu 890ddd
	const std::vector<int> &addedIdxs = addition.objects();</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Build new selection
Toshihiro Shimizu 890ddd
	std::vector<int> selectedIdxs;</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_svSel.contains(addition)) {
Toshihiro Shimizu 890ddd
		std::set_difference(
Toshihiro Shimizu 890ddd
			storedIdxs.begin(), storedIdxs.end(),
Toshihiro Shimizu 890ddd
			addedIdxs.begin(), addedIdxs.end(),
Toshihiro Shimizu 890ddd
			std::back_inserter(selectedIdxs));
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		std::set_union(
Toshihiro Shimizu 890ddd
			storedIdxs.begin(), storedIdxs.end(),
Toshihiro Shimizu 890ddd
			addedIdxs.begin(), addedIdxs.end(),
Toshihiro Shimizu 890ddd
			std::back_inserter(selectedIdxs));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	setSkeletonSelection(selectedIdxs);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::clearSkeletonSelections()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_svHigh = m_seHigh = -1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_svSel.selectNone();
Toshihiro Shimizu 890ddd
	m_svSel.makeNotCurrent();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
PlasticVertexSelection PlasticTool::branchSelection(int vIdx) const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		static void addBranch(const PlasticSkeleton &skeleton, int v, std::vector<int> &branch)</int>
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			branch.push_back(v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const PlasticSkeletonVertex &vx = skeleton.vertex(v);
Toshihiro Shimizu 890ddd
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 child = skeleton.edge(*et).vertex(1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (v != child)							// The edge to parent is in the list
Toshihiro Shimizu 890ddd
					addBranch(skeleton, child, branch); // I wonder if it's ensured to be always at begin?
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(skeleton());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<int> selectedIdxs;</int>
Toshihiro Shimizu 890ddd
	locals::addBranch(*skeleton(), vIdx, selectedIdxs);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return selectedIdxs;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::copySkeleton()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_sd)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skel = m_sd->skeleton(::skeletonId());
Toshihiro Shimizu 890ddd
	if (!skel)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Copy a CLONE of currently addressed skeleton in the app clipboard
Toshihiro Shimizu 890ddd
	QMimeData *data = new PlasticSkeletonPMime(new PlasticSkeleton(*skel));
Toshihiro Shimizu 890ddd
	QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::pasteSkeleton_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const PlasticSkeletonPMime *data = dynamic_cast<const *="" plasticskeletonpmime="">(</const>
Toshihiro Shimizu 890ddd
		QApplication::clipboard()->mimeData());
Toshihiro Shimizu 890ddd
	if (!data)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	PlasticSkeletonP newSkeleton(new PlasticSkeleton(*data->m_skeleton));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	touchDeformation();
Toshihiro Shimizu 890ddd
	assert(m_sd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int skelId = ::skeletonId();
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &oldSkel = m_sd->skeleton(skelId);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (oldSkel && !oldSkel->empty()) {
Toshihiro Shimizu 890ddd
		// In case there exists a not-empty skeleton, add a NEW skeleton
Toshihiro Shimizu 890ddd
		addSkeleton_undo(newSkeleton);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		TUndoManager *manager = TUndoManager::manager();
Toshihiro Shimizu 890ddd
		manager->beginBlock();
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			removeSkeleton_undo(skelId); // No problem - it's eventually empty
Toshihiro Shimizu 890ddd
			addSkeleton_undo(skelId, newSkeleton.getPointer());
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
void PlasticTool::copyDeformation()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_sd)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Copy a reference to currently addressed skeleton in the app clipboard
Toshihiro Shimizu 890ddd
	QMimeData *data = new SkDPMime(m_sd);
Toshihiro Shimizu 890ddd
	QApplication::clipboard()->setMimeData(data, QClipboard::Clipboard);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::pasteDeformation_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const SkDPMime *data = dynamic_cast<const *="" skdpmime="">(QApplication::clipboard()->mimeData());</const>
Toshihiro Shimizu 890ddd
	if (!data)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Given a skeleton, attempt to assign it to the current stage object
Toshihiro Shimizu 890ddd
	TStageObject *obj = ::stageObject();
Toshihiro Shimizu 890ddd
	assert(obj);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const PlasticSkeletonDeformationP &oldSd = obj->getPlasticSkeletonDeformation();
Toshihiro Shimizu 890ddd
	if (oldSd) {
Toshihiro Shimizu 890ddd
		// A skeleton already exists. Ask the user if it has to be replaced.
Toshihiro Shimizu 890ddd
		bool replace = DVGui::MsgBox(
Toshihiro Shimizu 890ddd
						   tr("A group of skeletons already exists for current column. Replacing it will also substitute any existing vertex animation.\n\nDo you want to continue?"),
Toshihiro Shimizu 890ddd
						   tr("Ok"), tr("Cancel")) == 1;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!replace)
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Clone the whole skeleton deformation (skeleton itself included)
Toshihiro Shimizu 890ddd
	SkDP newSd(new PlasticSkeletonDeformation(*data->m_sd));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Insert the undo and perform the op
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(new PasteDeformationUndo(newSd));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	obj->setPlasticSkeletonDeformation(newSd);
Toshihiro Shimizu 890ddd
	::invalidateXsheet();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setKey()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_svSel.hasSingleObject());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SkVD *vd = m_sd->vertexDeformation(::skeletonId(), m_svSel);
Toshihiro Shimizu 890ddd
	double frame = ::frame();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (vd->isFullKeyframe(frame))
Toshihiro Shimizu 890ddd
		vd->deleteKeyframe(frame);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		::setKeyframe(vd, frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setGlobalKey()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		inline static bool isFullKeyframe(const SkDP &sd, double frame)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			SkD::vd_iterator vdt, vdEnd;
Toshihiro Shimizu 890ddd
			sd->vertexDeformations(vdt, vdEnd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			for (; vdt != vdEnd; ++vdt)
Toshihiro Shimizu 890ddd
				if (!(*vdt).second->isFullKeyframe(frame))
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double frame = ::frame();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (locals::isFullKeyframe(m_sd, frame))
Toshihiro Shimizu 890ddd
		m_sd->deleteKeyframe(frame);
Toshihiro Shimizu 890ddd
	else
Toshihiro Shimizu 890ddd
		::setKeyframe(m_sd, frame);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setRestKey()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	assert(m_svSel.hasSingleObject());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SkVD *vd = m_sd->vertexDeformation(::skeletonId(), m_svSel);
Toshihiro Shimizu 890ddd
	double frame = ::frame();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (int p = 0; p != SkVD::PARAMS_COUNT; ++p)
Toshihiro Shimizu 890ddd
		vd->m_params[p]->setValue(frame, vd->m_params[p]->getDefaultValue());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setGlobalRestKey()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	double frame = ::frame();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	SkD::vd_iterator vdt, vdEnd;
Toshihiro Shimizu 890ddd
	m_sd->vertexDeformations(vdt, vdEnd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	for (; vdt != vdEnd; ++vdt) {
Toshihiro Shimizu 890ddd
		SkVD *vd = (*vdt).second;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		for (int p = 0; p != SkVD::PARAMS_COUNT; ++p)
Toshihiro Shimizu 890ddd
			vd->m_params[p]->setValue(frame, vd->m_params[p]->getDefaultValue());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setKey_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	keyFunc_undo(&PlasticTool::setKey);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setGlobalKey_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	keyFunc_undo(&PlasticTool::setGlobalKey);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setRestKey_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	keyFunc_undo(&PlasticTool::setRestKey);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setGlobalRestKey_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	keyFunc_undo(&PlasticTool::setGlobalRestKey);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setVertexName(QString &name)
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
	// Update the selected vertex's name
Toshihiro Shimizu 890ddd
	while (!m_sd->skeleton(::skeletonId())->setVertexName(m_svSel, name))
Toshihiro Shimizu 890ddd
		name += "_";
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_vertexName.setValue(name.toStdWString());
Toshihiro Shimizu 890ddd
	m_vertexName.notifyListeners(); // NOTE: This should NOT invoke this function recursively
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Re-store the deformed skeleton. This is necessary since any follow-up vertex
Toshihiro Shimizu 890ddd
	// manipulation must refer the correct vd name.
Toshihiro Shimizu 890ddd
	m_deformedSkeleton.invalidate();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	PlasticDeformerStorage::instance()->invalidateSkeleton(
Toshihiro Shimizu 890ddd
		m_sd.getPointer(), ::skeletonId(), PlasticDeformerStorage::NONE);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::mouseMove(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Discriminate mode
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
		mouseMove_mesh(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE BUILD_IDX : mouseMove_build(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE RIGIDITY_IDX : mouseMove_rigidity(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE ANIMATE_IDX : mouseMove_animate(pos, me);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::leftButtonDown(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
		leftButtonDown_mesh(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE BUILD_IDX : leftButtonDown_build(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE RIGIDITY_IDX : leftButtonDown_rigidity(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE ANIMATE_IDX : leftButtonDown_animate(pos, me);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::leftButtonDrag(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Track dragging status
Toshihiro Shimizu 890ddd
	m_dragged = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
		leftButtonDrag_mesh(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE BUILD_IDX : leftButtonDrag_build(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE RIGIDITY_IDX : leftButtonDrag_rigidity(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE ANIMATE_IDX : leftButtonDrag_animate(pos, me);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::leftButtonUp(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
		leftButtonUp_mesh(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE BUILD_IDX : leftButtonUp_build(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE RIGIDITY_IDX : leftButtonUp_rigidity(pos, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE ANIMATE_IDX : leftButtonUp_animate(pos, me);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_pressedPos = TConsts::napd;
Toshihiro Shimizu 890ddd
	m_pressedVxsPos.clear();
Toshihiro Shimizu 890ddd
	m_dragged = false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::addContextMenuItems(QMenu *menu)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool ret = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Add global actions
Toshihiro Shimizu 890ddd
	if (m_sd && m_sd->skeleton(::skeletonId())) {
Toshihiro Shimizu 890ddd
		QAction *copySkeleton = menu->addAction(tr("Copy Skeleton"));
Toshihiro Shimizu 890ddd
		ret = ret && connect(copySkeleton, SIGNAL(triggered()), &l_plasticTool, SLOT(copySkeleton()));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (dynamic_cast<const *="" plasticskeletonpmime="">(QApplication::clipboard()->mimeData())) {</const>
Toshihiro Shimizu 890ddd
		QAction *pasteSkeleton = menu->addAction(tr("Paste Skeleton"));
Toshihiro Shimizu 890ddd
		ret = ret && connect(pasteSkeleton, SIGNAL(triggered()), &l_plasticTool, SLOT(pasteSkeleton_undo()));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	menu->addSeparator(); // Separate actions type
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Add editing actions
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
		addContextMenuActions_mesh(menu);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE BUILD_IDX : addContextMenuActions_build(menu);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE RIGIDITY_IDX : addContextMenuActions_rigidity(menu);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE ANIMATE_IDX : addContextMenuActions_animate(menu);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Add view actions
Toshihiro Shimizu 890ddd
	QAction *showMesh = menu->addAction(tr("Show Mesh"));
Toshihiro Shimizu 890ddd
	showMesh->setCheckable(true);
Toshihiro Shimizu 890ddd
	showMesh->setChecked(m_pvs.m_drawMeshesWireframe);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ret = ret && connect(showMesh, SIGNAL(triggered(bool)), &l_plasticTool, SLOT(onShowMeshToggled(bool)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QAction *showRigidity = menu->addAction(tr("Show Rigidity"));
Toshihiro Shimizu 890ddd
	showRigidity->setCheckable(true);
Toshihiro Shimizu 890ddd
	showRigidity->setChecked(m_pvs.m_drawRigidity);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ret = ret && connect(showRigidity, SIGNAL(triggered(bool)), &l_plasticTool, SLOT(onShowRigidityToggled(bool)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QAction *showSO = menu->addAction(tr("Show SO"));
Toshihiro Shimizu 890ddd
	showSO->setCheckable(true);
Toshihiro Shimizu 890ddd
	showSO->setChecked(m_pvs.m_drawSO);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ret = ret && connect(showSO, SIGNAL(triggered(bool)), &l_plasticTool, SLOT(onShowSOToggled(bool)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QAction *showSkeletonOS = menu->addAction(tr("Show Skeleton Onion Skin"));
Toshihiro Shimizu 890ddd
	showSkeletonOS->setCheckable(true);
Toshihiro Shimizu 890ddd
	showSkeletonOS->setChecked(m_showSkeletonOS);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	ret = ret && connect(showSkeletonOS, SIGNAL(triggered(bool)), &l_plasticTool, SLOT(onShowSkelOSToggled(bool)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(ret);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	menu->addSeparator(); // Separate from common view options
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::reset()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// NOTE: This is an inherited virtual. Please leave it even if it's empty.
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool PlasticTool::onPropertyChanged(std::string propertyName)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		static bool alreadyContainsVertexName(const PlasticSkeleton &skel, const QString &name)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			tcg::list<plasticskeletonvertex>::const_iterator vt, vEnd(skel.vertices().end());</plasticskeletonvertex>
Toshihiro Shimizu 890ddd
			for (vt = skel.vertices().begin(); vt != vEnd; ++vt)
Toshihiro Shimizu 890ddd
				if (vt->name() == name)
Toshihiro Shimizu 890ddd
					return true;
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static int vdCount(const SkDP &sd, const QString &name)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			SkD::vx_iterator vxBegin, vxEnd;
Toshihiro Shimizu 890ddd
			sd->vdSkeletonVertices(name, vxBegin, vxEnd);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return std::distance(vxBegin, vxEnd);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (propertyName == "mode") {
Toshihiro Shimizu 890ddd
		switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
		case MESH_IDX:
Toshihiro Shimizu 890ddd
		case BUILD_IDX:
Toshihiro Shimizu 890ddd
		case RIGIDITY_IDX:
Toshihiro Shimizu 890ddd
			m_pvs.m_showOriginalColumn = xshColumn();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			CASE ANIMATE_IDX:
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				m_pvs.m_showOriginalColumn = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (m_svSel.objects().size() > 1)
Toshihiro Shimizu 890ddd
					setSkeletonSelection(-1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				storeDeformation(); // Rebuild deformed skeleton
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_mode.notifyListeners(); // You thought that was automatic, eh? BTW, this means
Toshihiro Shimizu 890ddd
								  // we're requesting toolbars to update options visibility
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		onSetViewer(); // Store m_pvs in the viewer's visual settings
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
	} else if (propertyName == "vertexName") {
Toshihiro Shimizu 890ddd
		if (m_sd && m_svSel >= 0) {
Toshihiro Shimizu 890ddd
			// Update the selected vertex's name
Toshihiro Shimizu 890ddd
			QString newName(QString::fromStdWString(m_vertexName.getValue()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const PlasticSkeletonP skeleton = this->skeleton();
Toshihiro Shimizu 890ddd
			assert(skeleton);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const QString &oldName = skeleton->vertex(m_svSel).name();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			bool doRename = true;
Toshihiro Shimizu 890ddd
			if (oldName != newName &&
Toshihiro Shimizu 890ddd
				!locals::alreadyContainsVertexName(*skeleton, newName) &&
Toshihiro Shimizu 890ddd
				m_sd->vertexDeformation(newName) &&
Toshihiro Shimizu 890ddd
				locals::vdCount(m_sd, oldName) == 1)
Toshihiro Shimizu 890ddd
				doRename = (DVGui::MsgBox(tr("The previous vertex name will be discarded, and all associated keys will be lost.\n\nDo you want to proceed?"),
Toshihiro Shimizu 890ddd
										  QObject::tr("Ok"), QObject::tr("Cancel")) == 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (doRename) {
Toshihiro Shimizu 890ddd
				TUndo *undo = new SetVertexNameUndo(m_svSel, newName);
Toshihiro Shimizu 890ddd
				TUndoManager::manager()->add(undo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				undo->redo();
Toshihiro Shimizu 890ddd
			} else {
Toshihiro Shimizu 890ddd
				m_vertexName.setValue(oldName.toStdWString());
Toshihiro Shimizu 890ddd
				m_vertexName.notifyListeners();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else if (propertyName == "interpolate") {
Toshihiro Shimizu 890ddd
		if (m_sd && m_svSel >= 0) {
Toshihiro Shimizu 890ddd
			// Set interpolation property to the associated skeleton vertex
Toshihiro Shimizu 890ddd
			int skelId = ::skeletonId();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_sd->skeleton(skelId)->vertex(m_svSel).m_interpolate =
Toshihiro Shimizu 890ddd
				m_interpolate.getValue();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_interpolate.notifyListeners(); // NOTE: This should NOT invoke this function recursively
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			PlasticDeformerStorage::instance()->invalidateSkeleton(
Toshihiro Shimizu 890ddd
				m_sd.getPointer(), skelId, PlasticDeformerStorage::ALL);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else if (propertyName == "minAngle") {
Toshihiro Shimizu 890ddd
		if (m_sd && m_svSel >= 0) {
Toshihiro Shimizu 890ddd
			// Set maxAngle property to the associated skeleton vertex
Toshihiro Shimizu 890ddd
			int skelId = ::skeletonId();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			bool ok;
Toshihiro Shimizu 890ddd
			double value = QString::fromStdWString(m_minAngle.getValue()).toDouble(&ok);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!ok)
Toshihiro Shimizu 890ddd
				value = -l_dmax, m_minAngle.setValue(L"");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_sd->skeleton(skelId)->vertex(m_svSel).m_minAngle = value;
Toshihiro Shimizu 890ddd
			if (m_mode.getIndex() == ANIMATE_IDX)
Toshihiro Shimizu 890ddd
				deformedSkeleton().vertex(m_svSel).m_minAngle = value;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_minAngle.notifyListeners(); // NOTE: This should NOT invoke this function recursively
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else if (propertyName == "maxAngle") {
Toshihiro Shimizu 890ddd
		if (m_sd && m_svSel >= 0) {
Toshihiro Shimizu 890ddd
			// Set maxAngle property to the associated skeleton vertex
Toshihiro Shimizu 890ddd
			int skelId = ::skeletonId();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			bool ok;
Toshihiro Shimizu 890ddd
			double value = QString::fromStdWString(m_maxAngle.getValue()).toDouble(&ok);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (!ok)
Toshihiro Shimizu 890ddd
				value = l_dmax, m_maxAngle.setValue(L"");
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_sd->skeleton(skelId)->vertex(m_svSel).m_maxAngle = value;
Toshihiro Shimizu 890ddd
			if (m_mode.getIndex() == ANIMATE_IDX)
Toshihiro Shimizu 890ddd
				deformedSkeleton().vertex(m_svSel).m_maxAngle = value;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			m_maxAngle.notifyListeners(); // NOTE: This should NOT invoke this function recursively
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onShowMeshToggled(bool on)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_pvs.m_drawMeshesWireframe = on;
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onShowSOToggled(bool on)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_pvs.m_drawSO = on;
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onShowRigidityToggled(bool on)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_pvs.m_drawRigidity = on;
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::onShowSkelOSToggled(bool on)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_showSkeletonOS = on;
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Drawing functions
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace PlasticToolLocals
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawSquare(const TPointD &pos, double radius)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glBegin(GL_LINE_LOOP);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x - radius, pos.y - radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x + radius, pos.y - radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x + radius, pos.y + radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x - radius, pos.y + radius);
Toshihiro Shimizu 890ddd
	glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawFullSquare(const TPointD &pos, double radius)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glBegin(GL_QUADS);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x - radius, pos.y - radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x + radius, pos.y - radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x + radius, pos.y + radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x - radius, pos.y + radius);
Toshihiro Shimizu 890ddd
	glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawFilledSquare(const TPointD &pos, double radius)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glBegin(GL_QUADS);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x - radius, pos.y - radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x + radius, pos.y - radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x + radius, pos.y + radius);
Toshihiro Shimizu 890ddd
	glVertex2d(pos.x - radius, pos.y + radius);
Toshihiro Shimizu 890ddd
	glEnd();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawHandle(const TPointD &pos, double radius, const TPixel32 &color)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glColor4ub(0, 0, 0, color.m); // Black border
Toshihiro Shimizu 890ddd
	glLineWidth(4.0f);
Toshihiro Shimizu 890ddd
	drawSquare(pos, radius);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	glColor4ub(color.r, color.g, color.b, color.m);
Toshihiro Shimizu 890ddd
	glLineWidth(2.0f);
Toshihiro Shimizu 890ddd
	drawSquare(pos, radius);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawFilledHandle(const TPointD &pos, double radius, double pixelSize, const TPixel32 &color)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glColor4ub(0, 0, 0, color.m);
Toshihiro Shimizu 890ddd
	drawFilledSquare(pos, radius + pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	glColor4ub(color.r, color.g, color.b, color.m);
Toshihiro Shimizu 890ddd
	drawFilledSquare(pos, radius);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void drawText(const TPointD &pos, const QString &text, double fontScale)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Get the world-to-window affine
Toshihiro Shimizu 890ddd
	double matrix[16];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	glGetDoublev(GL_MODELVIEW_MATRIX, matrix);
Toshihiro Shimizu 890ddd
	TAffine worldToWindowAff(
Toshihiro Shimizu 890ddd
		matrix[0], matrix[4], matrix[12],
Toshihiro Shimizu 890ddd
		matrix[1], matrix[5], matrix[13]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Push the window reference
Toshihiro Shimizu 890ddd
	glPushMatrix();
Toshihiro Shimizu 890ddd
	glLoadIdentity();
Toshihiro Shimizu 890ddd
	glScaled(fontScale, fontScale, 1.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	tglDrawText(TScale(1.0 / fontScale) * worldToWindowAff * pos, text.toStdWString());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Bottom-left fixed text version
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// double origin = 10.0 / fontScale
Toshihiro Shimizu 890ddd
	// tglDrawText(TPointD(origin, origin), text.toStdWString());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	glPopMatrix();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace PlasticToolLocals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::drawHighlights(const SkDP &sd, const PlasticSkeleton *skeleton, double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glColor3f(1.0f, 0.0f, 0.0f); // Red
Toshihiro Shimizu 890ddd
	glLineWidth(1.0f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Vertex highlights
Toshihiro Shimizu 890ddd
	if (m_svHigh >= 0) {
Toshihiro Shimizu 890ddd
		double handleRadius = HIGHLIGHTED_HANDLE_SIZE * pixelSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const PlasticSkeleton::vertex_type &vx = skeleton->vertex(m_svHigh);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int hookNumber = sd->hookNumber(vx.name());
Toshihiro Shimizu 890ddd
		assert(hookNumber >= 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			glPushAttrib(GL_LINE_BIT);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glEnable(GL_LINE_STIPPLE);
Toshihiro Shimizu 890ddd
			glLineStipple(1, 0xCCCC);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			drawSquare(vx.P(), handleRadius);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glPopAttrib();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		drawText(vx.P() + TPointD(2.0 * handleRadius, 2.0 * handleRadius),
Toshihiro Shimizu 890ddd
				 QString("(%1) ").arg(hookNumber) + vx.name(), 1.7);
Toshihiro Shimizu 890ddd
	} else if (m_seHigh >= 0) {
Toshihiro Shimizu 890ddd
		// Draw a handle at the projection of current mouse position towards the highlighted edge
Toshihiro Shimizu 890ddd
		double handleRadius = HANDLE_SIZE * pixelSize;
Toshihiro Shimizu 890ddd
		drawSquare(projection(*skeleton, m_seHigh, m_pos), handleRadius);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::drawSelections(const SkDP &sd, const PlasticSkeleton &skeleton, double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glColor3f(1.0f, 0.0f, 0.0f); // Red
Toshihiro Shimizu 890ddd
	glLineWidth(1.0f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double handleRadius = SELECTED_HANDLE_SIZE * pixelSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_svSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		typedef PlasticVertexSelection::objects_container objects_container;
Toshihiro Shimizu 890ddd
		const objects_container &vIdxs = m_svSel.objects();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Draw a handle square for each selected vertex
Toshihiro Shimizu 890ddd
		objects_container::const_iterator vst, vsEnd = vIdxs.end();
Toshihiro Shimizu 890ddd
		for (vst = vIdxs.begin(); vst != vsEnd; ++vst)
Toshihiro Shimizu 890ddd
			drawSquare(skeleton.vertex(*vst).P(), handleRadius);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Draw vertex descriptions (only in the single selection case - to avoid text pollution)
Toshihiro Shimizu 890ddd
		if (vIdxs.size() == 1) {
Toshihiro Shimizu 890ddd
			const PlasticSkeleton::vertex_type &vx = skeleton.vertex(m_svSel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int hookNumber = sd->hookNumber(vx.name());
Toshihiro Shimizu 890ddd
			assert(hookNumber >= 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			drawText(vx.P() + TPointD(2.0 * handleRadius, 2.0 * handleRadius),
Toshihiro Shimizu 890ddd
					 QString("(%1) ").arg(hookNumber) + vx.name(), 1.7);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::drawSkeleton(const PlasticSkeleton &skel, double pixelSize, UCHAR alpha)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		inline static void drawLine(const TPointD &p0, const TPointD &p1)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			glVertex2d(p0.x, p0.y);
Toshihiro Shimizu 890ddd
			glVertex2d(p1.x, p1.y);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const tcg::list<plasticskeleton::vertex_type> &vertices = skel.vertices();</plasticskeleton::vertex_type>
Toshihiro Shimizu 890ddd
	if (vertices.size() > 0) {
Toshihiro Shimizu 890ddd
		// Draw edges
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const tcg::list<plasticskeleton::edge_type> &edges = skel.edges();</plasticskeleton::edge_type>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			tcg::list<plasticskeleton::edge_type>::const_iterator et, eEnd(edges.end());</plasticskeleton::edge_type>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glColor4ub(0, 0, 0, alpha);
Toshihiro Shimizu 890ddd
			glLineWidth(4.0f); // Black border
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				for (et = edges.begin(); et != eEnd; ++et)
Toshihiro Shimizu 890ddd
					locals::drawLine(skel.vertex(et->vertex(0)).P(), skel.vertex(et->vertex(1)).P());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			glEnd();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glColor4ub(250, 184, 70, alpha);
Toshihiro Shimizu 890ddd
			glLineWidth(2.0f); // Yellow/Orange-ish line center
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				for (et = edges.begin(); et != eEnd; ++et)
Toshihiro Shimizu 890ddd
					locals::drawLine(skel.vertex(et->vertex(0)).P(), skel.vertex(et->vertex(1)).P());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			glEnd();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Draw vertices
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const TPixel32 magenta(255, 0, 255, alpha);
Toshihiro Shimizu 890ddd
			const TPixel32 yellow(255, 255, 0, alpha);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double handleRadius = HANDLE_SIZE * pixelSize;
Toshihiro Shimizu 890ddd
			float intHandleThick = 2.0f, extHandleThick = 4.0f;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Draw root
Toshihiro Shimizu 890ddd
			drawFilledHandle(vertices.begin()->P(), handleRadius, pixelSize, magenta);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Draw remaining vertices
Toshihiro Shimizu 890ddd
			tcg::list<plasticskeleton::vertex_type>::const_iterator vt(vertices.begin()), vEnd(vertices.end());</plasticskeleton::vertex_type>
Toshihiro Shimizu 890ddd
			if (vt != vEnd) {
Toshihiro Shimizu 890ddd
				for (vt = ++vertices.begin(); vt != vEnd; ++vt)
Toshihiro Shimizu 890ddd
					drawHandle(vt->P(), handleRadius, vt->m_interpolate ? magenta : yellow);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::drawOnionSkinSkeletons_build(double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!(m_showSkeletonOS && m_sd))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const OnionSkinMask &os = TTool::getApplication()->getCurrentOnionSkin()->getOnionSkinMask();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<int> osRows;</int>
Toshihiro Shimizu 890ddd
	int currentRow = ::row();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	os.getAll(currentRow, osRows);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TStageObject *obj = ::stageObject();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Sieve osRows' associated skeleton ids first
Toshihiro Shimizu 890ddd
	std::map<int, uchar=""> skelAlphas;</int,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int r, rCount = int(osRows.size());
Toshihiro Shimizu 890ddd
	for (r = 0; r != rCount; ++r) {
Toshihiro Shimizu 890ddd
		assert(osRows[r] != currentRow);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double sdFrame = obj->paramsTime(double(osRows[r] - 1));
Toshihiro Shimizu 890ddd
		int skelId = m_sd->skeletonId(sdFrame);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UCHAR &skelAlpha = skelAlphas[skelId];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UCHAR alpha = 255 - UCHAR(255.0 * OnionSkinMask::getOnionSkinFade(osRows[r] - currentRow));
Toshihiro Shimizu 890ddd
		skelAlpha = tmax(skelAlpha, alpha);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::map<int, uchar="">::iterator st, sEnd(skelAlphas.end());</int,>
Toshihiro Shimizu 890ddd
	for (st = skelAlphas.begin(); st != sEnd; ++st) {
Toshihiro Shimizu 890ddd
		const PlasticSkeletonP &skel = m_sd->skeleton(st->first);
Toshihiro Shimizu 890ddd
		drawSkeleton(*skel, pixelSize, st->second);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::drawOnionSkinSkeletons_animate(double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!(m_showSkeletonOS && m_sd))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const OnionSkinMask &os = TTool::getApplication()->getCurrentOnionSkin()->getOnionSkinMask();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<int> osRows;</int>
Toshihiro Shimizu 890ddd
	int currentRow = ::row();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	os.getAll(currentRow, osRows);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TStageObject *obj = ::stageObject();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int r, rCount = int(osRows.size());
Toshihiro Shimizu 890ddd
	for (r = 0; r != rCount; ++r) {
Toshihiro Shimizu 890ddd
		assert(osRows[r] != currentRow);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		double sdFrame = obj->paramsTime(double(osRows[r] - 1));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PlasticSkeleton skel;
Toshihiro Shimizu 890ddd
		m_sd->storeDeformedSkeleton(m_sd->skeletonId(sdFrame), sdFrame, skel);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		UCHAR alpha = 255 - 255.0 * OnionSkinMask::getOnionSkinFade(abs(osRows[r] - currentRow));
Toshihiro Shimizu 890ddd
		drawSkeleton(skel, pixelSize, alpha);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::drawAngleLimits(const SkDP &sd, int skelId, int v, double pixelSize)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct {
Toshihiro Shimizu 890ddd
		PlasticTool *m_this;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void drawAnnulusArc(const TPointD ¢er, double angleStart, double angleEnd,
Toshihiro Shimizu 890ddd
							double radiusA, double radiusB, double pixelSize)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			double angleDelta = acos(1.0 - pixelSize / tmax(radiusA, radiusB)) *
Toshihiro Shimizu 890ddd
								((angleStart <= angleEnd) ? 1.0 : -1.0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int a, aCount = tcg::numeric_ops::grow(fabs((angleEnd - angleStart) / angleDelta));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glBegin(GL_QUAD_STRIP);
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				for (a = 0; a != aCount; ++a) {
Toshihiro Shimizu 890ddd
					double angle = angleStart + a * angleDelta;
Toshihiro Shimizu 890ddd
					TPointD direction(cos(angle), sin(angle));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					tglVertex(center + radiusA * direction);
Toshihiro Shimizu 890ddd
					tglVertex(center + radiusB * direction);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				TPointD direction(cos(angleEnd), sin(angleEnd));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				tglVertex(center + radiusA * direction);
Toshihiro Shimizu 890ddd
				tglVertex(center + radiusB * direction);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			glEnd();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void drawLimit(const SkDP &sd, int skelId, int v,
Toshihiro Shimizu 890ddd
					   double angleLimit, double pixelSize)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			const PlasticSkeleton &skel = *sd->skeleton(skelId);
Toshihiro Shimizu 890ddd
			const PlasticSkeleton &defSkel = m_this->deformedSkeleton();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const PlasticSkeletonVertex &vx = skel.vertex(v);
Toshihiro Shimizu 890ddd
			const PlasticSkeletonVertex &defVx = defSkel.vertex(v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int vParent = vx.parent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const PlasticSkeletonVertex &vxParent = skel.vertex(vParent);
Toshihiro Shimizu 890ddd
			const PlasticSkeletonVertex &defVxParent = defSkel.vertex(vParent);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Build directions
Toshihiro Shimizu 890ddd
			int vGrandParent = vxParent.parent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			TPointD dirFromParent(vx.P() - vxParent.P()),
Toshihiro Shimizu 890ddd
				dirFromGrandParent(1, 0),
Toshihiro Shimizu 890ddd
				dirFromDeformedGrandParent(1, 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (vGrandParent >= 0) {
Toshihiro Shimizu 890ddd
				const PlasticSkeletonVertex &vxGrandParent = skel.vertex(vGrandParent),
Toshihiro Shimizu 890ddd
											&defVxGrandParent = defSkel.vertex(vGrandParent);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				dirFromGrandParent = vxParent.P() - vxGrandParent.P();
Toshihiro Shimizu 890ddd
				dirFromDeformedGrandParent = defVxParent.P() - defVxGrandParent.P();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Retrieve angular data
Toshihiro Shimizu 890ddd
			double angleShift = sd->vertexDeformation(skelId, v)->m_params[SkVD::ANGLE]->getValue(::frame());
Toshihiro Shimizu 890ddd
			double defaultAngleValue = tcg::consts::rad_to_deg * tcg::point_ops::angle(
Toshihiro Shimizu 890ddd
																	 dirFromGrandParent, dirFromParent);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Convert to radians
Toshihiro Shimizu 890ddd
			double currentBranchAngle_rad = tcg::point_ops::rad(dirFromDeformedGrandParent);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double currentAngle_rad = currentBranchAngle_rad + tcg::consts::deg_to_rad * (angleShift + defaultAngleValue);
Toshihiro Shimizu 890ddd
			double limitDirection_rad = currentBranchAngle_rad + tcg::consts::deg_to_rad * (angleLimit + defaultAngleValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glColor4ub(0, 0, 255, 128);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Draw limit lines
Toshihiro Shimizu 890ddd
			if (angleShift - 180.0 <= angleLimit && angleLimit <= angleShift + 180.0) {
Toshihiro Shimizu 890ddd
				TPointD limitDirection(cos(limitDirection_rad), sin(limitDirection_rad));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
				{
Toshihiro Shimizu 890ddd
					tglVertex(defVxParent.P());
Toshihiro Shimizu 890ddd
					tglVertex(defVxParent.P() + 1e4 * limitDirection);
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
				glEnd();
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Draw limit annulus arc
Toshihiro Shimizu 890ddd
			angleLimit = tcrop(angleLimit, angleShift - 180.0, angleShift + 180.0);
Toshihiro Shimizu 890ddd
			limitDirection_rad = currentBranchAngle_rad + tcg::consts::deg_to_rad * (angleLimit + defaultAngleValue);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			double radius = tcg::point_ops::dist(defVx.P(), defVxParent.P()) * 0.25;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			drawAnnulusArc(defVxParent.P(), limitDirection_rad, currentAngle_rad,
Toshihiro Shimizu 890ddd
						   radius - 5.0 * pixelSize, radius + 5.0 * pixelSize, pixelSize);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} locals = {this};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Dismiss no-ops
Toshihiro Shimizu 890ddd
	const PlasticSkeletonP &skel = sd->skeleton(skelId);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!skel || v < 0)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Ensure we're editing a vertex with an existing parent
Toshihiro Shimizu 890ddd
	if (m_dragged) {
Toshihiro Shimizu 890ddd
		const PlasticSkeletonVertex &vx = skel->vertex(v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int vParent = vx.parent();
Toshihiro Shimizu 890ddd
		if (vParent >= 0) {
Toshihiro Shimizu 890ddd
			// Draw angular limits
Toshihiro Shimizu 890ddd
			if (vx.m_minAngle != -l_dmax)
Toshihiro Shimizu 890ddd
				locals.drawLimit(sd, skelId, v, vx.m_minAngle, pixelSize);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (vx.m_maxAngle != l_dmax)
Toshihiro Shimizu 890ddd
				locals.drawLimit(sd, skelId, v, vx.m_maxAngle, pixelSize);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::draw()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	glPushAttrib(GL_LINE_BIT | GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	glEnable(GL_BLEND);
Toshihiro Shimizu 890ddd
	glEnable(GL_LINE_SMOOTH);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	switch (m_mode.getIndex()) {
Toshihiro Shimizu 890ddd
	case MESH_IDX:
Toshihiro Shimizu 890ddd
		draw_mesh();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE BUILD_IDX : draw_build();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE RIGIDITY_IDX : draw_rigidity();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		CASE ANIMATE_IDX : draw_animate();
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	glPopAttrib();
Toshihiro Shimizu 890ddd
}