Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzCore includes
Toshihiro Shimizu 890ddd
#include "tmeshimage.h"
Toshihiro Shimizu 890ddd
#include "tgl.h"
Toshihiro Shimizu 890ddd
#include "tundo.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// TnzExt includes
Toshihiro Shimizu 890ddd
#include "ext/plasticdeformerstorage.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// 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_iterator_ops.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_function_types.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_deleter_types.h"
Toshihiro Shimizu 890ddd
#include "tcg/tcg_unique_ptr.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// boost includes
Toshihiro Shimizu 890ddd
#include <boost unordered_set.hpp=""></boost>
Toshihiro Shimizu 890ddd
#include <boost unordered_map.hpp=""></boost>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace tcg::bgl;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <boost breadth_first_search.hpp="" graph=""></boost>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
// STD includes
Toshihiro Shimizu 890ddd
#include <stack></stack>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "plastictool.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace PlasticToolLocals;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Local namespace  stuff
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
typedef PlasticTool::MeshIndex MeshIndex;
Toshihiro Shimizu 890ddd
typedef TTextureMesh::vertex_type vertex_type;
Toshihiro Shimizu 890ddd
typedef TTextureMesh::edge_type edge_type;
Toshihiro Shimizu 890ddd
typedef TTextureMesh::face_type face_type;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool borderEdge(const TTextureMesh &mesh, int e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return (mesh.edge(e).facesCount() < 2);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool borderVertex(const TTextureMesh &mesh, int v)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const TTextureVertex &vx = mesh.vertex(v);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	tcg::vertex_traits<ttexturevertex>::edges_const_iterator et, eEnd(vx.edgesEnd());</ttexturevertex>
Toshihiro Shimizu 890ddd
	for (et = vx.edgesBegin(); et != eEnd; ++et) {
Toshihiro Shimizu 890ddd
		if (borderEdge(mesh, *et))
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool testSwapEdge(const TTextureMesh &mesh, int e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return (mesh.edge(e).facesCount() == 2);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool testCollapseEdge(const TTextureMesh &mesh, int e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct Locals {
Toshihiro Shimizu 890ddd
		const TTextureMesh &m_mesh;
Toshihiro Shimizu 890ddd
		int m_e;
Toshihiro Shimizu 890ddd
		const TTextureMesh::edge_type &m_ed;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool testTrianglesCount()
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			// There must be at least one remanining triangle
Toshihiro Shimizu 890ddd
			return (m_mesh.facesCount() > m_ed.facesCount());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool testBoundary()
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			// Must not join two non-adjacent boundary vertices
Toshihiro Shimizu 890ddd
			return (!borderVertex(m_mesh, m_ed.vertex(0)) ||
Toshihiro Shimizu 890ddd
					!borderVertex(m_mesh, m_ed.vertex(1)) ||
Toshihiro Shimizu 890ddd
					borderEdge(m_mesh, m_e));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		bool testAdjacency()
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			// See TriMesh<>::collapseEdge()
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Retrieve allowed adjacent vertices
Toshihiro Shimizu 890ddd
			int f, fCount = m_ed.facesCount();
Toshihiro Shimizu 890ddd
			int allowedV[6], *avt, *avEnd = allowedV + 3 * fCount;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			for (f = 0, avt = allowedV; f != fCount; ++f, avt += 3)
Toshihiro Shimizu 890ddd
				m_mesh.faceVertices(m_ed.face(f), avt[0], avt[1], avt[2]);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Test adjacent vertices
Toshihiro Shimizu 890ddd
			int v0 = m_ed.vertex(0), v1 = m_ed.vertex(1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const vertex_type &vx0 = m_mesh.vertex(v0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			tcg::vertex_traits<vertex_type>::edges_const_iterator et, eEnd = vx0.edgesEnd();</vertex_type>
Toshihiro Shimizu 890ddd
			for (et = vx0.edgesBegin(); et != eEnd; ++et) {
Toshihiro Shimizu 890ddd
				int otherV = m_mesh.edge(*et).otherVertex(v0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (m_mesh.edgeInciding(v1, otherV) >= 0) {
Toshihiro Shimizu 890ddd
					// Adjacent vertex - must be found in the allowed list
Toshihiro Shimizu 890ddd
					if (std::find(allowedV, avEnd, otherV) == avEnd)
Toshihiro Shimizu 890ddd
						return false;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} locals = {mesh, e, mesh.edge(e)};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return (locals.testTrianglesCount() &&
Toshihiro Shimizu 890ddd
			locals.testBoundary() &&
Toshihiro Shimizu 890ddd
			locals.testAdjacency());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticToolLocals  stuff
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace PlasticToolLocals
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct Closer {
Toshihiro Shimizu 890ddd
	const TTextureMesh &m_mesh;
Toshihiro Shimizu 890ddd
	TPointD m_pos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double dist2(const TTextureMesh::vertex_type &a)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return tcg::point_ops::dist2<tpointd>(a.P(), m_pos);</tpointd>
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	double dist2(const TTextureMesh::edge_type &a)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const TTextureMesh::vertex_type &avx0 = m_mesh.vertex(a.vertex(0)),
Toshihiro Shimizu 890ddd
										&avx1 = m_mesh.vertex(a.vertex(1));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return sq(tcg::point_ops::segDist<tpointd>(avx0.P(), avx1.P(), m_pos));</tpointd>
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool operator()(const TTextureMesh::vertex_type &a,
Toshihiro Shimizu 890ddd
					const TTextureMesh::vertex_type &b)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (dist2(a) < dist2(b));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool operator()(const TTextureMesh::edge_type &a,
Toshihiro Shimizu 890ddd
					const TTextureMesh::edge_type &b)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		return (dist2(a) < dist2(b));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
std::pair<double, int=""> closestVertex(const TTextureMesh &mesh, const TPointD &pos)</double,>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Closer closer = {mesh, pos};
Toshihiro Shimizu 890ddd
	int vIdx = int(std::min_element(mesh.vertices().begin(), mesh.vertices().end(), closer).index());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return std::make_pair(closer.dist2(mesh.vertex(vIdx)), vIdx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
std::pair<double, int=""> closestEdge(const TTextureMesh &mesh, const TPointD &pos)</double,>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	Closer closer = {mesh, pos};
Toshihiro Shimizu 890ddd
	int eIdx = int(std::min_element(mesh.edges().begin(), mesh.edges().end(), closer).index());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return std::make_pair(closer.dist2(mesh.edge(eIdx)), eIdx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
std::pair<double, meshindex=""> closestVertex(const TMeshImage &mi, const TPointD &pos)</double,>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::pair<double, meshindex=""> closest((std::numeric_limits<double>::max)(), MeshIndex());</double></double,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TMeshImage::meshes_container &meshes = mi.meshes();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TMeshImage::meshes_container::const_iterator mt, mEnd = meshes.end();
Toshihiro Shimizu 890ddd
	for (mt = meshes.begin(); mt != mEnd; ++mt) {
Toshihiro Shimizu 890ddd
		const std::pair<double, int=""> &candidateIdx = closestVertex(**mt, pos);</double,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::pair<double, meshindex=""> candidate(</double,>
Toshihiro Shimizu 890ddd
			candidateIdx.first, MeshIndex(mt - meshes.begin(), candidateIdx.second));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (candidate < closest)
Toshihiro Shimizu 890ddd
			closest = candidate;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return closest;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
std::pair<double, meshindex=""> closestEdge(const TMeshImage &mi, const TPointD &pos)</double,>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::pair<double, meshindex=""> closest((std::numeric_limits<double>::max)(), MeshIndex());</double></double,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TMeshImage::meshes_container &meshes = mi.meshes();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TMeshImage::meshes_container::const_iterator mt, mEnd = meshes.end();
Toshihiro Shimizu 890ddd
	for (mt = meshes.begin(); mt != mEnd; ++mt) {
Toshihiro Shimizu 890ddd
		const std::pair<double, int=""> &candidateIdx = closestEdge(**mt, pos);</double,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		std::pair<double, meshindex=""> candidate(</double,>
Toshihiro Shimizu 890ddd
			candidateIdx.first, MeshIndex(mt - meshes.begin(), candidateIdx.second));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (candidate < closest)
Toshihiro Shimizu 890ddd
			closest = candidate;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return closest;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Cut Mesh  operation
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct EdgeCut {
Toshihiro Shimizu 890ddd
	int m_vIdx; //!< Vertex index to cut from.
Toshihiro Shimizu 890ddd
	int m_eIdx; //!< Edge index to cut.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	EdgeCut(int vIdx, int eIdx)
Toshihiro Shimizu 890ddd
		: m_vIdx(vIdx), m_eIdx(eIdx) {}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
struct VertexOccurrence {
Toshihiro Shimizu 890ddd
	int m_count;			  //!< Number of times a vertex occurs.
Toshihiro Shimizu 890ddd
	int m_adjacentEdgeIdx[2]; //!< Edge indexes of which a vertex is endpoint.
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool buildEdgeCuts(const TMeshImage &mi, const PlasticTool::MeshSelection &edgesSelection,
Toshihiro Shimizu 890ddd
				   int &meshIdx, std::vector<edgecut> &edgeCuts)</edgecut>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef PlasticTool::MeshSelection::objects_container edges_container;
Toshihiro Shimizu 890ddd
	typedef PlasticTool::MeshIndex MeshIndex;
Toshihiro Shimizu 890ddd
	typedef boost::unordered_map<int, vertexoccurrence=""> VertexOccurrencesMap;</int,>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static bool differentMesh(const MeshIndex &a, const MeshIndex &b)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return (a.m_meshIdx != b.m_meshIdx);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static int testSingleMesh(const edges_container &edges)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			assert(!edges.empty());
Toshihiro Shimizu 890ddd
			return (std::find_if(
Toshihiro Shimizu 890ddd
						edges.begin(), edges.end(), tcg::bind2nd(&differentMesh, edges.front())) == edges.end())
Toshihiro Shimizu 890ddd
					   ? edges.front().m_meshIdx
Toshihiro Shimizu 890ddd
					   : -1;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static bool testNoBoundaryEdge(
Toshihiro Shimizu 890ddd
			const TTextureMesh &mesh, const edges_container &edges)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			edges_container::const_iterator et, eEnd = edges.end();
Toshihiro Shimizu 890ddd
			for (et = edges.begin(); et != eEnd; ++et)
Toshihiro Shimizu 890ddd
				if (::borderEdge(mesh, et->m_idx))
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static bool buildVertexOccurrences(
Toshihiro Shimizu 890ddd
			const TTextureMesh &mesh, const edges_container &edges,
Toshihiro Shimizu 890ddd
			VertexOccurrencesMap &vertexOccurrences)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			// Calculate vertex occurrences as edge endpoints
Toshihiro Shimizu 890ddd
			edges_container::const_iterator et, eEnd = edges.end();
Toshihiro Shimizu 890ddd
			for (et = edges.begin(); et != eEnd; ++et) {
Toshihiro Shimizu 890ddd
				const edge_type &ed = mesh.edge(et->m_idx);
Toshihiro Shimizu 890ddd
				int v0 = ed.vertex(0), v1 = ed.vertex(1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				VertexOccurrence &vo0 = vertexOccurrences[v0],
Toshihiro Shimizu 890ddd
								 &vo1 = vertexOccurrences[v1];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (vo0.m_count > 1 || vo1.m_count > 1)
Toshihiro Shimizu 890ddd
					return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				vo0.m_adjacentEdgeIdx[vo0.m_count++] =
Toshihiro Shimizu 890ddd
					vo1.m_adjacentEdgeIdx[vo1.m_count++] = et->m_idx;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static bool buildEdgeCuts(
Toshihiro Shimizu 890ddd
			const TTextureMesh &mesh, const edges_container &edges,
Toshihiro Shimizu 890ddd
			std::vector<edgecut> &edgeCuts)</edgecut>
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			VertexOccurrencesMap vertexOccurrences;
Toshihiro Shimizu 890ddd
			if (!buildVertexOccurrences(mesh, edges, vertexOccurrences))
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Build endpoints (exactly 2)
Toshihiro Shimizu 890ddd
			int endPoints[2];
Toshihiro Shimizu 890ddd
			int epCount = 0;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			VertexOccurrencesMap::iterator ot, oEnd = vertexOccurrences.end();
Toshihiro Shimizu 890ddd
			for (ot = vertexOccurrences.begin(); ot != oEnd; ++ot) {
Toshihiro Shimizu 890ddd
				if (ot->second.m_count == 1) {
Toshihiro Shimizu 890ddd
					if (epCount > 1)
Toshihiro Shimizu 890ddd
						return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					endPoints[epCount++] = ot->first;
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (epCount != 2)
Toshihiro Shimizu 890ddd
				return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Pick the first endpoint on the boundary, if any (otherwise, just pick one)
Toshihiro Shimizu 890ddd
			int *ept, *epEnd = endPoints + 2;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			ept = std::find_if(endPoints, epEnd, tcg::bind1st(&borderVertex, mesh));
Toshihiro Shimizu 890ddd
			if (ept == epEnd) {
Toshihiro Shimizu 890ddd
				// There is no boundary endpoint
Toshihiro Shimizu 890ddd
				if (edges.size() < 2) // We should not cut the mesh on a
Toshihiro Shimizu 890ddd
					return false;	 // single edge - no vertex to duplicate!
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				ept = endPoints;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Build the edge cuts list, expanding the edges selection from
Toshihiro Shimizu 890ddd
			// the chosen endpoint
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			edgeCuts.push_back(EdgeCut( // Build the first EdgeCut separately
Toshihiro Shimizu 890ddd
				*ept, vertexOccurrences[*ept].m_adjacentEdgeIdx[0]));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int e, eCount = int(edges.size()); // Build the remaining ones
Toshihiro Shimizu 890ddd
			for (e = 1; e != eCount; ++e) {
Toshihiro Shimizu 890ddd
				const EdgeCut &lastCut = edgeCuts.back();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				int vIdx = mesh.edge(lastCut.m_eIdx).otherVertex(lastCut.m_vIdx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				const int(&adjEdges)[2] = vertexOccurrences[vIdx].m_adjacentEdgeIdx;
Toshihiro Shimizu 890ddd
				int eIdx = (adjEdges[0] == lastCut.m_eIdx) ? adjEdges[1] : adjEdges[0];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				edgeCuts.push_back(EdgeCut(vIdx, eIdx));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const edges_container &edges = edgesSelection.objects();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Trivial early bailouts
Toshihiro Shimizu 890ddd
	if (edges.empty())
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Selected edges must lie on the same mesh
Toshihiro Shimizu 890ddd
	meshIdx = locals::testSingleMesh(edges);
Toshihiro Shimizu 890ddd
	if (meshIdx < 0)
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const TTextureMesh &mesh = *mi.meshes()[meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// No selected edge must be on the boundary
Toshihiro Shimizu 890ddd
	return (locals::testNoBoundaryEdge(mesh, edges) &&
Toshihiro Shimizu 890ddd
			locals::buildEdgeCuts(mesh, edges, edgeCuts));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
inline bool testCutMesh(const TMeshImage &mi, const PlasticTool::MeshSelection &edgesSelection)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	std::vector<edgecut> edgeCuts;</edgecut>
Toshihiro Shimizu 890ddd
	int meshIdx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return buildEdgeCuts(mi, edgesSelection, meshIdx, edgeCuts);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void slitMesh(TTextureMesh &mesh, int e) //! Opens a slit along the specified edge index.
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TTextureMesh::edge_type &ed = mesh.edge(e);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(ed.facesCount() == 2);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Duplicate the edge and pass one face to the duplicate
Toshihiro Shimizu 890ddd
	TTextureMesh::edge_type edDup(ed.vertex(0), ed.vertex(1));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int f = ed.face(1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	edDup.addFace(f);
Toshihiro Shimizu 890ddd
	ed.eraseFace(ed.facesBegin() + 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int eDup = mesh.addEdge(edDup);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Alter the face to host the duplicate
Toshihiro Shimizu 890ddd
	TTextureMesh::face_type &fc = mesh.face(f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	(fc.edge(0) == e) ? fc.setEdge(0, eDup) : (fc.edge(1) == e) ? fc.setEdge(1, eDup) : fc.setEdge(2, eDup);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
/*!
Toshihiro Shimizu 890ddd
  \brief    Duplicates a mesh edge-vertex pair (the 'cut') and separates their
Toshihiro Shimizu 890ddd
            connections to adjacent mesh primitives.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
  \remark   The starting vertex is supposed to be on the mesh boundary.
Toshihiro Shimizu 890ddd
  \remark   Edges with a single neighbouring face can be duplicated, too.
Toshihiro Shimizu 890ddd
*/
Toshihiro Shimizu 890ddd
void cutEdge(TTextureMesh &mesh, const EdgeCut &edgeCut)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static void transferEdge(
Toshihiro Shimizu 890ddd
			TTextureMesh &mesh, int e, int vFrom, int vTo)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			edge_type &ed = mesh.edge(e);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			vertex_type &vxFrom = mesh.vertex(vFrom),
Toshihiro Shimizu 890ddd
						&vxTo = mesh.vertex(vTo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			(ed.vertex(0) == vFrom) ? ed.setVertex(0, vTo) : ed.setVertex(1, vTo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			vxTo.addEdge(e);
Toshihiro Shimizu 890ddd
			vxFrom.eraseEdge(std::find(vxFrom.edges().begin(), vxFrom.edges().end(), e));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static void transferFace(
Toshihiro Shimizu 890ddd
			TTextureMesh &mesh, int eFrom, int eTo)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			edge_type &edFrom = mesh.edge(eFrom),
Toshihiro Shimizu 890ddd
					  &edTo = mesh.edge(eTo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			int f = mesh.edge(eFrom).face(1);
Toshihiro Shimizu 890ddd
			{
Toshihiro Shimizu 890ddd
				face_type &fc = mesh.face(f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				(fc.edge(0) == eFrom) ? fc.setEdge(0, eTo) : (fc.edge(1) == eFrom) ? fc.setEdge(1, eTo) : fc.setEdge(2, eTo);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				edTo.addFace(f);
Toshihiro Shimizu 890ddd
				edFrom.eraseFace(edFrom.facesBegin() + 1);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int vOrig = edgeCut.m_vIdx,
Toshihiro Shimizu 890ddd
		eOrig = edgeCut.m_eIdx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Create a new vertex at the same position of the original
Toshihiro Shimizu 890ddd
	int vDup = mesh.addVertex(vertex_type(mesh.vertex(vOrig).P()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int e = eOrig;
Toshihiro Shimizu 890ddd
	if (mesh.edge(e).facesCount() == 2) {
Toshihiro Shimizu 890ddd
		// Duplicate the cut edge
Toshihiro Shimizu 890ddd
		e = mesh.addEdge(edge_type(vDup, mesh.edge(eOrig).otherVertex(vOrig)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Transfer one face from the original to the duplicate
Toshihiro Shimizu 890ddd
		locals::transferFace(mesh, eOrig, e);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		// Transfer the original edge to the duplicate vertex
Toshihiro Shimizu 890ddd
		locals::transferEdge(mesh, eOrig, vOrig, vDup);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Edges adjacent to the original vertex that are also adjacent
Toshihiro Shimizu 890ddd
	// to the transferred face above must be transferred too
Toshihiro Shimizu 890ddd
	int f = mesh.edge(e).face(0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	while (f >= 0) {
Toshihiro Shimizu 890ddd
		// Retrieve the next edge to transfer
Toshihiro Shimizu 890ddd
		int otherE = mesh.otherFaceEdge(f, mesh.edge(e).otherVertex(vDup));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// NOTE: Not "mesh.edgeInciding(vOrig, mesh.otherFaceVertex(f, e))" in the calculation
Toshihiro Shimizu 890ddd
		//       of otherE. This is required since by transferring each edge at a time,
Toshihiro Shimizu 890ddd
		//       we're 'breaking' faces up - f is adjacent to both vOrig AND vDup!
Toshihiro Shimizu 890ddd
		//
Toshihiro Shimizu 890ddd
		//       The chosen calculation, instead, just asks for the one edge which does
Toshihiro Shimizu 890ddd
		//       not have a specific vertex in common to the 2 other edges in the face.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		locals::transferEdge(mesh, otherE, vOrig, vDup);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Update e and f
Toshihiro Shimizu 890ddd
		e = otherE;
Toshihiro Shimizu 890ddd
		f = mesh.edge(otherE).otherFace(f);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
namespace locals_
Toshihiro Shimizu 890ddd
{						// Need to use a named namespace due to
Toshihiro Shimizu 890ddd
						// a known gcc 4.2 bug with compiler-generated
Toshihiro Shimizu 890ddd
struct VertexesRecorder // copy constructors.
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	boost::unordered_set<int> &m_examinedVertexes;</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	typedef boost::on_examine_vertex event_filter;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	VertexesRecorder(boost::unordered_set<int> &examinedVertexes)</int>
Toshihiro Shimizu 890ddd
		: m_examinedVertexes(examinedVertexes) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void operator()(int v, const TTextureMesh &)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_examinedVertexes.insert(v);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{ //
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void splitUnconnectedMesh(TMeshImage &mi, int meshIdx)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
		static void buildConnectedComponent(
Toshihiro Shimizu 890ddd
			const TTextureMesh &mesh, boost::unordered_set<int> &vertexes)</int>
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			// Prepare BFS algorithm
Toshihiro Shimizu 890ddd
			tcg::unique_ptr<uchar, tcg::freer=""> colorMapP(</uchar,>
Toshihiro Shimizu 890ddd
				(UCHAR *)calloc(mesh.vertices().nodesCount(), sizeof(UCHAR)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			locals_::VertexesRecorder vertexesRecorder(vertexes);
Toshihiro Shimizu 890ddd
			std::stack<int> verticesQueue;</int>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			// Launch it
Toshihiro Shimizu 890ddd
			boost::breadth_first_visit(mesh, int(mesh.vertices().begin().index()),
Toshihiro Shimizu 890ddd
									   verticesQueue, boost::make_bfs_visitor(vertexesRecorder), colorMapP.get());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Retrieve the list of vertexes in the first connected component
Toshihiro Shimizu 890ddd
	TTextureMesh &origMesh = *mi.meshes()[meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	boost::unordered_set<int> firstComponent;</int>
Toshihiro Shimizu 890ddd
	locals::buildConnectedComponent(origMesh, firstComponent);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (firstComponent.size() == origMesh.verticesCount())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// There are (exactly) 2 connected components. Just duplicate the mesh
Toshihiro Shimizu 890ddd
	// and keep/delete found vertexes.
Toshihiro Shimizu 890ddd
	TTextureMeshP dupMeshPtr(new TTextureMesh(origMesh));
Toshihiro Shimizu 890ddd
	TTextureMesh &dupMesh = *dupMeshPtr;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TTextureMesh::vertices_container &vertices = origMesh.vertices();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TTextureMesh::vertices_container::iterator vt, vEnd = vertices.end();
Toshihiro Shimizu 890ddd
	for (vt = vertices.begin(); vt != vEnd;) {
Toshihiro Shimizu 890ddd
		int v = int(vt.index());
Toshihiro Shimizu 890ddd
		++vt;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (firstComponent.count(v))
Toshihiro Shimizu 890ddd
			dupMesh.removeVertex(v);
Toshihiro Shimizu 890ddd
		else
Toshihiro Shimizu 890ddd
			origMesh.removeVertex(v);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	dupMesh.squeeze();
Toshihiro Shimizu 890ddd
	origMesh.squeeze();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	mi.meshes().push_back(dupMeshPtr);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void splitMesh(TMeshImage &mi, int meshIdx, int lastBoundaryVertex)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Retrieve a cutting edge with a single adjacent face - cutting that
Toshihiro Shimizu 890ddd
	// will just duplicate the vertex and separate the mesh in 2 connected
Toshihiro Shimizu 890ddd
	// components
Toshihiro Shimizu 890ddd
	TTextureMesh &mesh = *mi.meshes()[meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int e;
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const vertex_type &lbVx = mesh.vertex(lastBoundaryVertex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		vertex_type::edges_const_iterator et =
Toshihiro Shimizu 890ddd
			std::find_if(lbVx.edgesBegin(), lbVx.edgesEnd(), tcg::bind1st(&borderEdge, mesh));
Toshihiro Shimizu 890ddd
		assert(et != lbVx.edgesEnd());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		e = *et;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	cutEdge(mesh, EdgeCut(lastBoundaryVertex, e));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// At this point, separate the 2 resulting connected components
Toshihiro Shimizu 890ddd
	// in 2 separate meshes (if necessary)
Toshihiro Shimizu 890ddd
	splitUnconnectedMesh(mi, meshIdx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool cutMesh(TMeshImage &mi, const PlasticTool::MeshSelection &edgesSelection)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct locals {
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static int lastVertex(
Toshihiro Shimizu 890ddd
			const TTextureMesh &mesh, const std::vector<edgecut> &edgeCuts)</edgecut>
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return mesh.edge(edgeCuts.back().m_eIdx)
Toshihiro Shimizu 890ddd
				.otherVertex(edgeCuts.back().m_vIdx);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static int lastBoundaryVertex(
Toshihiro Shimizu 890ddd
			const TTextureMesh &mesh, const std::vector<edgecut> &edgeCuts)</edgecut>
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			int v = lastVertex(mesh, edgeCuts);
Toshihiro Shimizu 890ddd
			return ::borderVertex(mesh, v) ? v : -1;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	}; // locals
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<edgecut> edgeCuts;</edgecut>
Toshihiro Shimizu 890ddd
	int meshIdx;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!::buildEdgeCuts(mi, edgesSelection, meshIdx, edgeCuts))
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TTextureMesh &mesh = *mi.meshes()[meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int lastBoundaryVertex = locals::lastBoundaryVertex(mesh, edgeCuts);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Slit the mesh on the first edge, in case the cuts do not start
Toshihiro Shimizu 890ddd
	// on the mesh boundary
Toshihiro Shimizu 890ddd
	std::vector<edgecut>::iterator ecBegin = edgeCuts.begin();</edgecut>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!::borderVertex(mesh, ecBegin->m_vIdx)) {
Toshihiro Shimizu 890ddd
		::slitMesh(mesh, ecBegin->m_eIdx);
Toshihiro Shimizu 890ddd
		++ecBegin;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Cut edges, in the order specified by edgeCuts
Toshihiro Shimizu 890ddd
	std::for_each(ecBegin, edgeCuts.end(),
Toshihiro Shimizu 890ddd
				  tcg::bind1st(&cutEdge, mesh));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Finally, the mesh could have been split in 2 - we need to separate
Toshihiro Shimizu 890ddd
	// the pieces if needed
Toshihiro Shimizu 890ddd
	if (lastBoundaryVertex >= 0)
Toshihiro Shimizu 890ddd
		splitMesh(mi, meshIdx, lastBoundaryVertex);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    Undo  definitions
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
namespace
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class MoveVertexUndo_Mesh : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_row, m_col; //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::vector<meshindex> m_vIdxs;	//!< Moved vertices</meshindex>
Toshihiro Shimizu 890ddd
	std::vector<tpointd> m_origVxsPos; //!< Original vertex positions</tpointd>
Toshihiro Shimizu 890ddd
	TPointD m_posShift;				   //!< Vertex positions shift
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	MoveVertexUndo_Mesh(
Toshihiro Shimizu 890ddd
		const std::vector<meshindex> &vIdxs,</meshindex>
Toshihiro Shimizu 890ddd
		const std::vector<tpointd> &origVxsPos,</tpointd>
Toshihiro Shimizu 890ddd
		const TPointD &posShift)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_vIdxs(vIdxs), m_origVxsPos(origVxsPos), m_posShift(posShift)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		assert(m_vIdxs.size() == m_origVxsPos.size());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return int(sizeof(*this) + m_vIdxs.size() * (sizeof(int) + 2 * sizeof(TPointD))); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.setMeshVertexesSelection(m_vIdxs);
Toshihiro Shimizu 890ddd
		l_plasticTool.moveVertex_mesh(m_origVxsPos, m_posShift);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged(); // IMPORTANT: In particular, sets the level's
Toshihiro Shimizu 890ddd
	}										//            dirty flag, so Toonz knows it has
Toshihiro Shimizu 890ddd
											//            to be saved!
Toshihiro Shimizu 890ddd
	void undo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.setMeshVertexesSelection(m_vIdxs);
Toshihiro Shimizu 890ddd
		l_plasticTool.moveVertex_mesh(m_origVxsPos, TPointD());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class SwapEdgeUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_row, m_col;			 //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
	mutable MeshIndex m_edgeIdx; //!< Edge index
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SwapEdgeUndo(const MeshIndex &edgeIdx)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_edgeIdx(edgeIdx) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return sizeof(*this); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const TMeshImageP &mi = TMeshImageP(TTool::getImage(true));
Toshihiro Shimizu 890ddd
		assert(mi);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Perform swap
Toshihiro Shimizu 890ddd
		TTextureMesh &mesh = *mi->meshes()[m_edgeIdx.m_meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_edgeIdx.m_idx = mesh.swapEdge(m_edgeIdx.m_idx);
Toshihiro Shimizu 890ddd
		assert(m_edgeIdx.m_idx >= 0);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Invalidate any deformer associated with mi
Toshihiro Shimizu 890ddd
		PlasticDeformerStorage::instance()->releaseMeshData(mi.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Update tool selection
Toshihiro Shimizu 890ddd
		l_plasticTool.setMeshEdgesSelection(m_edgeIdx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void undo() const { redo(); } // Operation is idempotent (indices
Toshihiro Shimizu 890ddd
								  // are perfectly restored, too)
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class TTextureMeshUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
protected:
Toshihiro Shimizu 890ddd
	int m_row, m_col; //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int m_meshIdx;					 //!< Mesh index in the image at stored xsheet coords
Toshihiro Shimizu 890ddd
	mutable TTextureMesh m_origMesh; //!< Copy of the original mesh
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	TTextureMeshUndo(int meshIdx)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_meshIdx(meshIdx) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Let's say 1MB each - storing the mesh is costly
Toshihiro Shimizu 890ddd
	int getSize() const { return 1 << 20; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TMeshImageP getMeshImage() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const TMeshImageP &mi = TMeshImageP(TTool::getImage(true));
Toshihiro Shimizu 890ddd
		assert(mi);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return mi;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class CollapseEdgeUndo : public TTextureMeshUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_eIdx; //!< Collapsed edge index
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	CollapseEdgeUndo(const MeshIndex &edgeIdx)
Toshihiro Shimizu 890ddd
		: TTextureMeshUndo(edgeIdx.m_meshIdx), m_eIdx(edgeIdx.m_idx) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const TMeshImageP &mi = getMeshImage();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Store the original mesh
Toshihiro Shimizu 890ddd
		TTextureMesh &mesh = *mi->meshes()[m_meshIdx];
Toshihiro Shimizu 890ddd
		m_origMesh = mesh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Collapse
Toshihiro Shimizu 890ddd
		mesh.collapseEdge(m_eIdx);
Toshihiro Shimizu 890ddd
		mesh.squeeze();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Invalidate any cached deformer associated with the modified mesh image
Toshihiro Shimizu 890ddd
		PlasticDeformerStorage::instance()->releaseMeshData(mi.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Refresh the tool
Toshihiro Shimizu 890ddd
		l_plasticTool.clearMeshSelections();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged();
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 TMeshImageP &mi = getMeshImage();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore the original mesh
Toshihiro Shimizu 890ddd
		TTextureMesh &mesh = *mi->meshes()[m_meshIdx];
Toshihiro Shimizu 890ddd
		mesh = m_origMesh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PlasticDeformerStorage::instance()->releaseMeshData(mi.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore selection
Toshihiro Shimizu 890ddd
		l_plasticTool.setMeshEdgesSelection(MeshIndex(m_meshIdx, m_eIdx));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class SplitEdgeUndo : public TTextureMeshUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_eIdx; //!< Split edge index
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	SplitEdgeUndo(const MeshIndex &edgeIdx)
Toshihiro Shimizu 890ddd
		: TTextureMeshUndo(edgeIdx.m_meshIdx), m_eIdx(edgeIdx.m_idx) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void redo() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		PlasticTool::TemporaryActivation tempActivate(m_row, m_col);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		const TMeshImageP &mi = getMeshImage();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Store the original mesh
Toshihiro Shimizu 890ddd
		TTextureMesh &mesh = *mi->meshes()[m_meshIdx];
Toshihiro Shimizu 890ddd
		m_origMesh = mesh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Split
Toshihiro Shimizu 890ddd
		mesh.splitEdge(m_eIdx);
Toshihiro Shimizu 890ddd
		//mesh.squeeze();                                                     // There should be no need to squeeze
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		assert(mesh.vertices().size() == mesh.vertices().nodesCount()); //
Toshihiro Shimizu 890ddd
		assert(mesh.edges().size() == mesh.edges().nodesCount());		//
Toshihiro Shimizu 890ddd
		assert(mesh.faces().size() == mesh.faces().nodesCount());		//
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PlasticDeformerStorage::instance()->releaseMeshData(mi.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.clearMeshSelections();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged();
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 TMeshImageP &mi = getMeshImage();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore the original mesh
Toshihiro Shimizu 890ddd
		TTextureMesh &mesh = *mi->meshes()[m_meshIdx];
Toshihiro Shimizu 890ddd
		mesh = m_origMesh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PlasticDeformerStorage::instance()->releaseMeshData(mi.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore selection
Toshihiro Shimizu 890ddd
		l_plasticTool.setMeshEdgesSelection(MeshIndex(m_meshIdx, m_eIdx));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//==============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class CutEdgesUndo : public TUndo
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int m_row, m_col;		 //!< Xsheet coordinates
Toshihiro Shimizu 890ddd
	TMeshImageP m_origImage; //!< Clone of the original image
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	PlasticTool::MeshSelection m_edgesSelection; //!< Selection to operate on
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	CutEdgesUndo(const PlasticTool::MeshSelection &edgesSelection)
Toshihiro Shimizu 890ddd
		: m_row(::row()), m_col(::column()), m_origImage(TTool::getImage(false)->cloneImage()), m_edgesSelection(edgesSelection) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int getSize() const { return 1 << 20; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	bool do_() const
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		TMeshImageP mi = TTool::getImage(true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (::cutMesh(*mi, m_edgesSelection)) {
Toshihiro Shimizu 890ddd
			PlasticDeformerStorage::instance()->releaseMeshData(mi.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			l_plasticTool.clearMeshSelections();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
			l_plasticTool.notifyImageChanged();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	}
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
		bool ret = do_();
Toshihiro Shimizu 890ddd
		(void)ret;
Toshihiro Shimizu 890ddd
		assert(ret);
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
		TMeshImageP mi = TTool::getImage(true);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore the original image
Toshihiro Shimizu 890ddd
		*mi = *m_origImage;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		PlasticDeformerStorage::instance()->releaseMeshData(mi.getPointer());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Restore selection
Toshihiro Shimizu 890ddd
		l_plasticTool.setMeshEdgesSelection(m_edgesSelection);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		l_plasticTool.invalidate();
Toshihiro Shimizu 890ddd
		l_plasticTool.notifyImageChanged();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
} // namespace
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
//    PlasticTool  functions
Toshihiro Shimizu 890ddd
//****************************************************************************************
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::storeMeshImage()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	TMeshImageP mi = getImage(false);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (mi != m_mi) {
Toshihiro Shimizu 890ddd
		m_mi = mi;
Toshihiro Shimizu 890ddd
		clearMeshSelections();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setMeshSelection(MeshSelection &target, const MeshSelection &newSel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (newSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		target.selectNone();
Toshihiro Shimizu 890ddd
		target.makeNotCurrent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	target.setObjects(newSel.objects());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	target.notifyView();
Toshihiro Shimizu 890ddd
	target.makeCurrent();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::toggleMeshSelection(MeshSelection &target, const MeshSelection &addition)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	typedef MeshSelection::objects_container objects_container;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	const objects_container &storedIdxs = target.objects();
Toshihiro Shimizu 890ddd
	const objects_container &addedIdxs = addition.objects();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Build new selection
Toshihiro Shimizu 890ddd
	objects_container selectedIdxs;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (target.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
	setMeshSelection(target, selectedIdxs);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::clearMeshSelections()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_mvHigh = m_meHigh = MeshIndex();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_mvSel.selectNone();
Toshihiro Shimizu 890ddd
	m_mvSel.makeNotCurrent();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_meSel.selectNone();
Toshihiro Shimizu 890ddd
	m_meSel.makeNotCurrent();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setMeshVertexesSelection(const MeshSelection &vSel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setMeshSelection(m_meSel, MeshSelection()), setMeshSelection(m_mvSel, vSel);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::toggleMeshVertexesSelection(const MeshSelection &vSel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setMeshSelection(m_meSel, MeshSelection()), toggleMeshSelection(m_mvSel, vSel);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::setMeshEdgesSelection(const MeshSelection &eSel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setMeshSelection(m_meSel, eSel), setMeshSelection(m_mvSel, MeshSelection());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::toggleMeshEdgesSelection(const MeshSelection &eSel)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	toggleMeshSelection(m_meSel, eSel), setMeshSelection(m_mvSel, MeshSelection());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::mouseMove_mesh(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Track mouse position
Toshihiro Shimizu 890ddd
	m_pos = pos; // Needs to be done now - ensures m_pos is valid
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_mvHigh = MeshIndex(); // Reset highlighted primitives
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_mi) {
Toshihiro Shimizu 890ddd
		// Look for nearest primitive
Toshihiro Shimizu 890ddd
		std::pair<double, meshindex=""> closestVertex = ::closestVertex(*m_mi, pos),</double,>
Toshihiro Shimizu 890ddd
									 closestEdge = ::closestEdge(*m_mi, pos);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// Discriminate on fixed metric
Toshihiro Shimizu 890ddd
		const double hDistSq = sq(getPixelSize() * MESH_HIGHLIGHT_DISTANCE);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_mvHigh = m_meHigh = MeshIndex();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (closestEdge.first < hDistSq)
Toshihiro Shimizu 890ddd
			m_meHigh = closestEdge.second;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (closestVertex.first < hDistSq)
Toshihiro Shimizu 890ddd
			m_mvHigh = closestVertex.second, m_meHigh = MeshIndex();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(!(m_mvHigh && m_meHigh)); // Vertex and edge highlights are mutually exclusive
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::leftButtonDown_mesh(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct Locals {
Toshihiro Shimizu 890ddd
		PlasticTool *m_this;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void updateSelection(MeshSelection &sel, const MeshIndex &idx, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			if (idx) {
Toshihiro Shimizu 890ddd
				MeshSelection newSel(idx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				if (me.isCtrlPressed())
Toshihiro Shimizu 890ddd
					m_this->toggleMeshSelection(sel, newSel);
Toshihiro Shimizu 890ddd
				else if (!sel.contains(newSel))
Toshihiro Shimizu 890ddd
					m_this->setMeshSelection(sel, newSel);
Toshihiro Shimizu 890ddd
			} else
Toshihiro Shimizu 890ddd
				m_this->setMeshSelection(sel, MeshSelection());
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		static TPointD vertexPos(const TMeshImage &mi, const MeshIndex &meshIdx)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			return mi.meshes()[meshIdx.m_meshIdx]->vertex(meshIdx.m_idx).P();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	} locals = {this};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Track mouse position
Toshihiro Shimizu 890ddd
	m_pressedPos = m_pos = pos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Update selection
Toshihiro Shimizu 890ddd
	locals.updateSelection(m_mvSel, m_mvHigh, me);
Toshihiro Shimizu 890ddd
	locals.updateSelection(m_meSel, m_meHigh, me);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Store original vertex positions
Toshihiro Shimizu 890ddd
	if (!m_mvSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		m_pressedVxsPos = std::vector<tpointd>(</tpointd>
Toshihiro Shimizu 890ddd
			tcg::make_cast_it(m_mvSel.objects().begin(), tcg::bind1st(&Locals::vertexPos, *m_mi)),
Toshihiro Shimizu 890ddd
			tcg::make_cast_it(m_mvSel.objects().end(), tcg::bind1st(&Locals::vertexPos, *m_mi)));
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Redraw selections
Toshihiro Shimizu 890ddd
	invalidate();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::leftButtonDrag_mesh(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Track mouse position
Toshihiro Shimizu 890ddd
	m_pos = pos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_mvSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		moveVertex_mesh(m_pressedVxsPos, pos - m_pressedPos);
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::leftButtonUp_mesh(const TPointD &pos, const TMouseEvent &me)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	// Track mouse position
Toshihiro Shimizu 890ddd
	m_pos = pos;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (m_dragged && !m_mvSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		TUndoManager::manager()->add(new MoveVertexUndo_Mesh(
Toshihiro Shimizu 890ddd
			m_mvSel.objects(), m_pressedVxsPos, pos - m_pressedPos));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		invalidate();
Toshihiro Shimizu 890ddd
		notifyImageChanged(); // Sets the level's dirty flag      -.-'
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::addContextMenuActions_mesh(QMenu *menu)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	bool ret = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_meSel.isEmpty()) {
Toshihiro Shimizu 890ddd
		if (m_meSel.hasSingleObject()) {
Toshihiro Shimizu 890ddd
			const MeshIndex &mIdx = m_meSel.objects().front();
Toshihiro Shimizu 890ddd
			const TTextureMesh &mesh = *m_mi->meshes()[mIdx.m_meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (::testSwapEdge(mesh, mIdx.m_idx)) {
Toshihiro Shimizu 890ddd
				QAction *swapEdge = menu->addAction(tr("Swap Edge"));
Toshihiro Shimizu 890ddd
				ret = ret && connect(swapEdge, SIGNAL(triggered()), &l_plasticTool, SLOT(swapEdge_mesh_undo()));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			if (::testCollapseEdge(mesh, mIdx.m_idx)) {
Toshihiro Shimizu 890ddd
				QAction *collapseEdge = menu->addAction(tr("Collapse Edge"));
Toshihiro Shimizu 890ddd
				ret = ret && connect(collapseEdge, SIGNAL(triggered()), &l_plasticTool, SLOT(collapseEdge_mesh_undo()));
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			QAction *splitEdge = menu->addAction(tr("Split Edge"));
Toshihiro Shimizu 890ddd
			ret = ret && connect(splitEdge, SIGNAL(triggered()), &l_plasticTool, SLOT(splitEdge_mesh_undo()));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (::testCutMesh(*m_mi, m_meSel)) {
Toshihiro Shimizu 890ddd
			QAction *cutEdges = menu->addAction(tr("Cut Mesh"));
Toshihiro Shimizu 890ddd
			ret = ret && connect(cutEdges, SIGNAL(triggered()), &l_plasticTool, SLOT(cutEdges_mesh_undo()));
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		menu->addSeparator();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(ret);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::moveVertex_mesh(
Toshihiro Shimizu 890ddd
	const std::vector<tpointd> &origVxsPos, const TPointD &posShift)</tpointd>
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (m_mvSel.isEmpty() || !m_mi)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	assert(origVxsPos.size() == m_mvSel.objects().size());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Move selected vertices
Toshihiro Shimizu 890ddd
	TMeshImageP mi = getImage(true);
Toshihiro Shimizu 890ddd
	assert(m_mi == mi);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int v, vCount = int(m_mvSel.objects().size());
Toshihiro Shimizu 890ddd
	for (v = 0; v != vCount; ++v) {
Toshihiro Shimizu 890ddd
		const MeshIndex &meshIndex = m_mvSel.objects()[v];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		TTextureMesh &mesh = *mi->meshes()[meshIndex.m_meshIdx];
Toshihiro Shimizu 890ddd
		mesh.vertex(meshIndex.m_idx).P() = origVxsPos[v] + posShift;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Mesh must be recompiled
Toshihiro Shimizu 890ddd
	PlasticDeformerStorage::instance()->invalidateMeshImage(
Toshihiro Shimizu 890ddd
		mi.getPointer(), PlasticDeformerStorage::MESH);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::swapEdge_mesh_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!(m_mi && m_meSel.hasSingleObject()))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Test current edge swapability
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const MeshIndex &eIdx = m_meSel.objects().front();
Toshihiro Shimizu 890ddd
		const TTextureMesh &mesh = *m_mi->meshes()[eIdx.m_meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!::testSwapEdge(mesh, eIdx.m_idx))
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Perform operation
Toshihiro Shimizu 890ddd
	std::auto_ptr<tundo> undo(new SwapEdgeUndo(m_meSel.objects().front()));</tundo>
Toshihiro Shimizu 890ddd
	undo->redo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(undo.release());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::collapseEdge_mesh_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!(m_mi && m_meSel.hasSingleObject()))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Test collapsibility of current edge
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		const MeshIndex &eIdx = m_meSel.objects().front();
Toshihiro Shimizu 890ddd
		const TTextureMesh &mesh = *m_mi->meshes()[eIdx.m_meshIdx];
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		if (!::testCollapseEdge(mesh, eIdx.m_idx))
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Perform operation
Toshihiro Shimizu 890ddd
	std::auto_ptr<tundo> undo(new CollapseEdgeUndo(m_meSel.objects().front()));</tundo>
Toshihiro Shimizu 890ddd
	undo->redo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(undo.release());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::splitEdge_mesh_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!(m_mi && m_meSel.hasSingleObject()))
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::auto_ptr<tundo> undo(new SplitEdgeUndo(m_meSel.objects().front()));</tundo>
Toshihiro Shimizu 890ddd
	undo->redo();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	TUndoManager::manager()->add(undo.release());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::cutEdges_mesh_undo()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_mi)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	std::auto_ptr<cutedgesundo> undo(new CutEdgesUndo(m_meSel.objects()));</cutedgesundo>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (undo->do_())
Toshihiro Shimizu 890ddd
		TUndoManager::manager()->add(undo.release());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void PlasticTool::draw_mesh()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	struct Locals {
Toshihiro Shimizu 890ddd
		PlasticTool *m_this;
Toshihiro Shimizu 890ddd
		double m_pixelSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void drawLine(const TPointD &a, const TPointD &b)
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			glVertex2d(a.x, a.y);
Toshihiro Shimizu 890ddd
			glVertex2d(b.x, b.y);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void drawVertexSelections()
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			typedef MeshSelection::objects_container objects_container;
Toshihiro Shimizu 890ddd
			const objects_container &objects = m_this->m_mvSel.objects();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glColor3ub(255, 0, 0); // Red
Toshihiro Shimizu 890ddd
			glLineWidth(1.0f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			const double hSize = MESH_SELECTED_HANDLE_SIZE * m_pixelSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			objects_container::const_iterator vt, vEnd = objects.end();
Toshihiro Shimizu 890ddd
			for (vt = objects.begin(); vt != vEnd; ++vt) {
Toshihiro Shimizu 890ddd
				const TTextureVertex &vx = m_this->m_mi->meshes()[vt->m_meshIdx]
Toshihiro Shimizu 890ddd
											   ->vertex(vt->m_idx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				::drawFullSquare(vx.P(), hSize);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void drawEdgeSelections()
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			typedef MeshSelection::objects_container objects_container;
Toshihiro Shimizu 890ddd
			const objects_container &objects = m_this->m_meSel.objects();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glColor3ub(0, 0, 255); // Blue
Toshihiro Shimizu 890ddd
			glLineWidth(2.0f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			objects_container::const_iterator et, eEnd = objects.end();
Toshihiro Shimizu 890ddd
			for (et = objects.begin(); et != eEnd; ++et) {
Toshihiro Shimizu 890ddd
				const TTextureVertex
Toshihiro Shimizu 890ddd
					&vx0 = m_this->m_mi->meshes()[et->m_meshIdx]->edgeVertex(et->m_idx, 0),
Toshihiro Shimizu 890ddd
					&vx1 = m_this->m_mi->meshes()[et->m_meshIdx]->edgeVertex(et->m_idx, 1);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				drawLine(vx0.P(), vx1.P());
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			glEnd();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void drawVertexHighlights()
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			if (m_this->m_mvHigh) {
Toshihiro Shimizu 890ddd
				const MeshIndex &vHigh = m_this->m_mvHigh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				const TTextureMesh::vertex_type &vx =
Toshihiro Shimizu 890ddd
					m_this->m_mi->meshes()[vHigh.m_meshIdx]->vertex(vHigh.m_idx);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				glColor3ub(255, 0, 0); // Red
Toshihiro Shimizu 890ddd
				glLineWidth(1.0f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				const double hSize = MESH_HIGHLIGHTED_HANDLE_SIZE * m_pixelSize;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				::drawSquare(vx.P(), hSize);
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		void drawEdgeHighlights()
Toshihiro Shimizu 890ddd
		{
Toshihiro Shimizu 890ddd
			if (m_this->m_meHigh) {
Toshihiro Shimizu 890ddd
				const MeshIndex &eHigh = m_this->m_meHigh;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
				const TTextureMesh::vertex_type
Toshihiro Shimizu 890ddd
					&vx0 = m_this->m_mi->meshes()[eHigh.m_meshIdx]->edgeVertex(eHigh.m_idx, 0),
Toshihiro Shimizu 890ddd
					&vx1 = m_this->m_mi->meshes()[eHigh.m_meshIdx]->edgeVertex(eHigh.m_idx, 1);
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
					glColor3ub(0, 0, 255); // Blue
Toshihiro Shimizu 890ddd
					glLineWidth(1.0f);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					glBegin(GL_LINES);
Toshihiro Shimizu 890ddd
					drawLine(vx0.P(), vx1.P());
Toshihiro Shimizu 890ddd
					glEnd();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
					glPopAttrib();
Toshihiro Shimizu 890ddd
				}
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	} locals = {this, getPixelSize()};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// The selected mesh image is already drawn by the stage
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// Draw additional overlays
Toshihiro Shimizu 890ddd
	if (m_mi) {
Toshihiro Shimizu 890ddd
		locals.drawVertexSelections();
Toshihiro Shimizu 890ddd
		locals.drawEdgeSelections();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		locals.drawVertexHighlights();
Toshihiro Shimizu 890ddd
		locals.drawEdgeHighlights();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}