#include "Painter.h"

SoSeparator* Painter::getShapeSeparator(Mesh* mesh, float deltaX, float deltaY, float scale)
{
	//returns the separator to be added to scene graph (which lets obj be drawn to scr)

	//initialize obj's separator which will be first-filled below
	mesh->sep = new SoSeparator;

	//insert this as the first child 'cos in main i retrieve it as getChild(0) for screen updates so i'm sure it's at the idx 0 even if i do optional addChild()s above such as multiColor
	SoCoordinate3* coords = new SoCoordinate3;
	mesh->sep->addChild(coords); //if i try to access it w/ getChild(1) then no crash occurs but coords are set to weird values so don't do that

	//material
	SoMaterial* mat = new SoMaterial;
	mat->diffuseColor.set1Value(0, mesh->color);
	mat->specularColor.setValue(0.2f, 0.2f, 0.2f); //black was the default
	mat->ambientColor.setValue(0.0f, 0.0f, 0.0f); //default was .2, .2, .2 (dark gray)
	//mat->transparency = 0.5f; //0 makes it completely opaque, the default
	mesh->sep->addChild(mat);
	//a default creaseAngle of 0 (see SoShapeHints) does flat shading and of pi does Gouraud
	SoShapeHints* hints = new SoShapeHints;
//hints->creaseAngle = PI;mesh->sep->addChild(hints); //Gouraud shading
/*hints->shapeType = SoShapeHintsElement::SOLID;
hints->vertexOrdering = SoShapeHintsElement::CLOCKWISE; 
obj->sep->addChild(hints); //front face culling (make COUNTERCLOCKWISE for back face culling); not draw fronts unless visible*/
	
	for (unsigned int v = 0; v < mesh->verts.size(); v++)
		coords->point.set1Value(v, scale*mesh->verts[v]->coords[0]+deltaX, scale*mesh->verts[v]->coords[1]+deltaY, scale*mesh->verts[v]->coords[2]);

	int nt = 0;
	SoIndexedFaceSet* faceSet = new SoIndexedFaceSet;
	for (unsigned int t = 0; t < (int) mesh->tris.size(); t++)
	{
		faceSet->coordIndex.set1Value(0 + 4*nt, mesh->tris[t]->v1i);
		faceSet->coordIndex.set1Value(1 + 4*nt, mesh->tris[t]->v2i);
		faceSet->coordIndex.set1Value(2 + 4*nt, mesh->tris[t]->v3i);
		faceSet->coordIndex.set1Value(3 + 4*nt, -1);
		nt++;
	}
	mesh->sep->addChild(faceSet);

	return mesh->sep;
}

SoSeparator* Painter::get1PointSep(Mesh* mesh, int pnt, float r, float g, float b)
{
	//renders only 1 mesh or voxel pnt arbitrary point

	SoSeparator* pntSep = new SoSeparator;
	//material
	SoMaterial* mat = new SoMaterial;
	mat->diffuseColor.setValue(SbColor(r, g, b));
if (pnt == 137) mat->diffuseColor.setValue(SbColor(0.0f, 1.0f, 0.0f));

	pntSep->addChild(mat);
	SoDrawStyle* style = new SoDrawStyle;
	style->pointSize = 9.0f;
	pntSep->addChild(style);

	//shape
	SoVertexProperty* vp = NULL;
	if (pnt >= 0 && pnt < (int) mesh->verts.size())
	{
		vp = new SoVertexProperty;
		vp->vertex.set1Value(0, mesh->verts[pnt]->coords[0], mesh->verts[pnt]->coords[1], mesh->verts[pnt]->coords[2]);
		//vp->vertex.set1Value(0, mesh->verts[pnt]->MDS[0], mesh->verts[pnt]->MDS[1], mesh->verts[pnt]->MDS[2]);
//vp->vertex.set1Value(0, -33.974422f, -547.348938f, 306.934418f);
	}

	if (vp)
	{
		SoPointSet* pSet = new SoPointSet;
		pSet->numPoints = 1;
		pSet->vertexProperty = vp;
		pntSep->addChild(pSet);
//cout << pnt << " ------> " << mesh->verts[pnt]->matchIdx << endl;
	}

	return pntSep;
}
SoSeparator* Painter::get1PointSep(Mesh* obj, int pnt, bool sketch, float deltaX, float r, float g, float b)
{
	//renders only 1 mesh or sketch pnt


	SoSeparator* pntSep = new SoSeparator;
	//material
	SoMaterial* mat = new SoMaterial;
	mat->diffuseColor.setValue(SbColor(r, g, b));
//if (pnt == 0 || pnt == (int) obj->pnts.size()-1)  mat->diffuseColor.setValue(SbColor(0.0f, 1.0f, 0.0f));
if (pnt == 147) mat->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.0f));

	pntSep->addChild(mat);
	SoDrawStyle* style = new SoDrawStyle;
	style->pointSize = 7.0f;
	pntSep->addChild(style);

	//shape
	SoVertexProperty* vp = NULL;
	if (sketch && pnt >= 0 && pnt < (int) obj->pnts.size())
	{
		vp = new SoVertexProperty;
		vp->vertex.set1Value(0, obj->pnts[pnt]->coords[0], obj->pnts[pnt]->coords[1], obj->z);
//cout << obj->pnts[pnt]->coords[0] << ",,,,,,,,,, " << obj->pnts[pnt]->coords[1] << endl;
	}
	else if (! sketch && pnt >= 0 && pnt < (int) obj->verts.size())
	{
		vp = new SoVertexProperty;
		vp->vertex.set1Value(0, obj->verts[pnt]->coords[0] + deltaX, obj->verts[pnt]->coords[1], obj->verts[pnt]->coords[2]);
	}

	if (vp)
	{
		SoPointSet* pSet = new SoPointSet;
		pSet->numPoints = 1;
		pSet->vertexProperty = vp;
		pntSep->addChild(pSet);
//cout << pnt << " ------> " << mesh->verts[pnt]->matchIdx << endl;
	}

	return pntSep;
}
SoSeparator* Painter::get1PointSep(float x, float y, float z, float r, float g, float b)
{
	//renders only 1 pnt arbitrary point

	SoSeparator* pntSep = new SoSeparator;
	//material
	SoMaterial* mat = new SoMaterial;
	mat->diffuseColor.setValue(SbColor(r, g, b));
	pntSep->addChild(mat);

	SoDrawStyle* style = new SoDrawStyle;
	style->pointSize = 7.0f;
	pntSep->addChild(style);//*/

	//shape
	SoVertexProperty* vp = new SoVertexProperty;
	vp->vertex.set1Value(0, x, y, z);

	SoPointSet* pSet = new SoPointSet;
	pSet->numPoints = 1;
	pSet->vertexProperty = vp;
	pntSep->addChild(pSet);

	return pntSep;
}

SoSeparator* Painter::getSphereSep(Mesh* mesh)
{
	//returns a set of spheres to highlight each mesh.samples[i]

	SoSeparator* spheresSep = new SoSeparator();

	float radius = 1.0f; 

	for (int i = 0; i < (int) mesh->verts.size(); i++)
	{
		//1 sphere for this sample
		SoSeparator* sphere1Sep = new SoSeparator;

		//transformation
		SoTransform* tra = new SoTransform();
		tra->translation.setValue(mesh->verts[i]->coords);
		sphere1Sep->addChild(tra);

		//material
		SoMaterial* ma = new SoMaterial;	
		ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.7f));
		sphere1Sep->addChild(ma);

		//shape
		SoSphere* sph1 = new SoSphere();
		sph1->radius = radius;
		sphere1Sep->addChild(sph1); //whose position is decided by the translation applied above

		spheresSep->addChild(sphere1Sep);
	}
	
	return spheresSep;
}
SoSeparator* Painter::getSphereSep(float x, float y, float z)
{
	//returns a set of spheres to highlight each mesh.samples[i]

	SoSeparator* sphereSep = new SoSeparator();

	//transformation
	SoTransform* tra = new SoTransform();
	tra->translation.setValue(x, y, z);
	sphereSep->addChild(tra);

	//material
	SoMaterial* ma = new SoMaterial;	
	ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.7f));
	sphereSep->addChild(ma);

	//shape
	SoSphere* sph1 = new SoSphere();
	sph1->radius = sphereRadius;
	sphereSep->addChild(sph1); //whose position is decided by the translation applied above
	
	return sphereSep;
}

SoSeparator* Painter::getPointsSep(Mesh* sketch, bool multicolor)
{
	//returns the separator for 2d sketch to be drawn on the xy-plane sitting at z; points are loaded stroke-by-stroke

	SoSeparator* pntsSep = new SoSeparator;

	//material
	SoMaterial* mat = new SoMaterial;
	if (multicolor)
	{
		SbColor colors[10] = {SbColor(0.7f, 0.0f, 0.0f), SbColor(0.0f, 0.0f, 0.0f), SbColor(0.0f, 0.7f, 0.0f), SbColor(0.7f, 0.0f, 0.7f), SbColor(0.0f, 0.0f, 0.7f), SbColor(0.7f, 0.0f, 0.0f), SbColor(0.7f, 0.7f, 0.0f), SbColor(0.2f, 0.3f, 0.4f), SbColor(0.7f, 0.7f, 0.7f), SbColor(0.1f, 0.8f, 0.4f)};
		if (sketch->nOriginalStrokes > 10)
			cout << "WARNING!!!!!!!!!!!! increase size of colors[]\n";
		int i = 0;
		for (int s = 0; s < (int) sketch->strokes.size(); s++)
			if (! sketch->strokes[s]->virtua && ! sketch->strokes[s]->removed)
				for (int p = 0; p < (int) sketch->strokes[s]->pnts.size(); p++)
					mat->diffuseColor.set1Value(i++, colors[s]); //s'th color for stroke s
	}
	else
		mat->diffuseColor.set1Value(0, SbColor(0.0f, 0.7f, 0.0f));
	pntsSep->addChild(mat);
	SoMaterialBinding* materialBinding;
	if (multicolor)
	{
		materialBinding = new SoMaterialBinding; //for 2+ diffuse color usage on the same mesh
		materialBinding->value = SoMaterialBinding::PER_VERTEX_INDEXED;
		pntsSep->addChild(materialBinding);
	}
	SoDrawStyle* style = new SoDrawStyle;
	style->pointSize = 4.0f;
	pntsSep->addChild(style);

	//shape
	SoVertexProperty* vp = new SoVertexProperty;	
	int nAdds = 0;
	for (int s = 0; s < (int) sketch->strokes.size(); s++)
		if (! sketch->strokes[s]->virtua && ! sketch->strokes[s]->removed) //don't duplicate virtual stroke's pnts, which are always 2 and selected from the existing sketch pnts; similarly don't draw removed strokes
			for (int p = 0; p < (int) sketch->strokes[s]->pnts.size(); p++)
			{
//if (mesh->verts[p]->MDS[1] > 547) continue;
//cout<<"hhhhhhhh " << sketch->pnts[ sketch->strokes[s]->pnts[p] ]->strokeID << " &_& " << sketch->pnts[ sketch->strokes[s]->pnts[p] ]->strID << endl;
				//if (s == 5)
				vp->vertex.set1Value(nAdds++, sketch->pnts[ sketch->strokes[s]->pnts[p] ]->coords[0], sketch->pnts[ sketch->strokes[s]->pnts[p] ]->coords[1], sketch->z);
			}
	SoPointSet* pSet = new SoPointSet;
	pSet->numPoints = nAdds;
	pSet->vertexProperty = vp;
	pntsSep->addChild(pSet);

//cout << nAdds << " pnts rendered\n";
	return pntsSep;
}
SoSeparator* Painter::getPointsSep(Mesh* sketch)
{
	//returns the separator for 2d sketch to be drawn on the xy-plane sitting at z; points are loaded directly from pnts[]

	SoSeparator* pntsSep = new SoSeparator;

	//material
	SoMaterial* mat = new SoMaterial;
	mat->diffuseColor.set1Value(0, SbColor(0.0f, 0.7f, 0.0f));
	pntsSep->addChild(mat);
	SoDrawStyle* style = new SoDrawStyle;
	style->pointSize = 4.0f;
	pntsSep->addChild(style);

	//shape
	SoVertexProperty* vp = new SoVertexProperty;	
	int nAdds = 0;
	for (int p = 0; p < (int) sketch->pnts.size(); p++)
		vp->vertex.set1Value(nAdds++, sketch->pnts[p]->coords[0], sketch->pnts[p]->coords[1], sketch->z);
	SoPointSet* pSet = new SoPointSet;
	pSet->numPoints = nAdds;
	pSet->vertexProperty = vp;
	pntsSep->addChild(pSet);

//cout << nAdds << " pnts rendered\n";
	return pntsSep;
}

SoSeparator* Painter::getSpheresSep(Mesh* mesh, float deltaX, float deltaY, float scale)
{
	//returns a set of spheres to highlight each mesh.samples[i]

	SoSeparator* spheresSep = new SoSeparator();

	for (int i = 0; i < (int) mesh->samples.size(); i++)
	{
		//1 sphere for this sample
		SoSeparator* sphere1Sep = new SoSeparator;

		//transformation
		SoTransform* tra = new SoTransform();
		tra->translation.setValue(scale*mesh->verts[ mesh->samples[i] ]->coords[0]+deltaX, scale*mesh->verts[ mesh->samples[i] ]->coords[1]+deltaY, scale*mesh->verts[ mesh->samples[i] ]->coords[2]);
		sphere1Sep->addChild(tra);

		//material
		SoMaterial* ma = new SoMaterial;
		if (i == 0)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.0f, 0.0f));
		else if (i == 1)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.7f, 0.0f));
		else if (i == 2)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.7f));
		else if (i == 3)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.0f));
		else if (i == 4)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.7f, 0.0f));
		else if (i == 5)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.0f, 7.0f));
		else if (i == 6)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.2f, 0.4f));
		else
			ma->diffuseColor.setValue(SbColor(0.4f, 0.2f, 0.4f));
		sphere1Sep->addChild(ma);

		//shape
		SoSphere* sph1 = new SoSphere();
		sph1->radius = sphereRadius;
		sphere1Sep->addChild(sph1); //whose position is decided by the translation applied above

		spheresSep->addChild(sphere1Sep);
	}

	return spheresSep;
}
SoSeparator* Painter::getSpheresSepSketch(Mesh* sketch, float deltaX, float deltaY, float scale)
{
	//returns a set of spheres to highlight each mesh.samples[i]

	SoSeparator* spheresSep = new SoSeparator();
	vector< SketchPnt* > ref = (sketch->usePnts ? sketch->pnts : sketch->endpnts);

	bool colorSpheres = false;
	if ((int) sketch->samples.size() > 10)
		sphereRadius /= 1.6f;
	else
		colorSpheres = true;

	for (int i = 0; i < (int) sketch->samples.size(); i++)
	{
		//1 sphere for this sample
		SoSeparator* sphere1Sep = new SoSeparator;

		//transformation
		SoTransform* tra = new SoTransform();
		tra->translation.setValue(scale*ref[ sketch->samples[i] ]->coords[0]+deltaX, scale*ref[ sketch->samples[i] ]->coords[1]+deltaY, scale*ref[ sketch->samples[i] ]->coords[2]);
		sphere1Sep->addChild(tra);

		//material
		SoMaterial* ma = new SoMaterial;
		if (i == 0 && colorSpheres)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.7f));
//ma->diffuseColor.setValue(SbColor(0.7f, 0.7f, 0.0f));
		else if (i == 1 && colorSpheres)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.0f));
		else if (i == 2 && colorSpheres)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.7f, 0.0f));
		else if (i == 3 && colorSpheres)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.0f, 0.7f));
		else if (i == 4 && colorSpheres)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.7f, 0.0f));
		else if (i == 5)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.0f, 0.0f));
		else if (i == 6)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.2f, 0.4f));
		else
			ma->diffuseColor.setValue(SbColor(0.4f, 0.2f, 0.4f));


//if (i > 1) continue;
/*if (ref[ sketch->samples[i] ]->idx == 21) ma->diffuseColor.setValue(SbColor(0.7f, 0.7f, 0.7f)); //gray
if (ref[ sketch->samples[i] ]->idx == 160) ma->diffuseColor.setValue(SbColor(0.5f, 0.5f, 1.0f)); //light blue
if (ref[ sketch->samples[i] ]->idx == 2617) ma->diffuseColor.setValue(SbColor(1.0f, 0.5f, 0.75f)); //pink
if (ref[ sketch->samples[i] ]->idx == 0) ma->diffuseColor.setValue(SbColor(1.0f, 1.0f, 0.0f)); //yellow*/

		sphere1Sep->addChild(ma);

		//shape
		SoSphere* sph1 = new SoSphere();
		sph1->radius = sphereRadius;
		sphere1Sep->addChild(sph1); //whose position is decided by the translation applied above

		spheresSep->addChild(sphere1Sep);
	}

	return spheresSep;
}

SoSeparator* Painter::getMatchingLinesSep(Mesh* sketch, Mesh* mesh, float deltaX, float deltaY, float scale)
{
	//returns the lines going from mesh1's i to correspondence(i) in mesh2

	SoSeparator* linesSep = new SoSeparator(), * allLinesSep = new SoSeparator();
	vector< SketchPnt* > ref = (sketch->usePnts ? sketch->pnts : sketch->endpnts);

	//material
	SoMaterial* ma = new SoMaterial;
	ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.0f));
	linesSep->addChild(ma);
//SoDrawStyle* style = new SoDrawStyle; style->lineWidth = 1.5f; linesSep->addChild(style); //thick lines for scrshot

	SoIndexedLineSet* lines = new SoIndexedLineSet;
	SoCoordinate3* co = new SoCoordinate3;	
	int lc = 0; //line counter
	for (int b = 0; b < (int) mesh->samples.size(); b++)
	{
		int corresp = mesh->verts[ mesh->samples[b] ]->matchIdx;
		if (corresp == -1)
			continue; //no match for this mesh1.samples in mesh2 at all

		SbVec3f from = scale*mesh->verts[ mesh->samples[b] ]->coords + SbVec3f(deltaX, deltaY, 0.0f);
		co->point.set1Value(2*lc, from);
		SbVec3f to = SbVec3f(ref[corresp]->coords[0], ref[corresp]->coords[1], sketch->z);
		co->point.set1Value(2*lc + 1, to);
		lines->coordIndex.set1Value(3*lc, 2*lc);
		lines->coordIndex.set1Value(3*lc + 1, 2*lc + 1);
		lines->coordIndex.set1Value(3*lc++ + 2, -1); //end this line with -1
	}
	linesSep->addChild(co); linesSep->addChild(lines);
	allLinesSep->addChild(linesSep);

//allLinesSep->addChild( get1LineSep(SbColor(0.9f, 0.0f, 0.9f), mesh1->verts[ mesh1->bestMatchG ]->coords, scale*mesh2->verts[corresp]->coords + SbVec3f(deltaX, 0.0f, 0.0f)) );

	return allLinesSep;
}

SoSeparator* Painter::getStrokesSepSketch(Mesh* sketch)
{
	//returns the lines going from virtual strokes' endpnts' (blue) and actual strokes' endpnts (red)

	if ((int) sketch->samples.size() > 10)
		return new SoSeparator(); //for some weird reason sketch-only view w/ uniform dense sampling sucks if this function is enabled; so disable it

	SoSeparator* linesSep = new SoSeparator(), * lines2Sep = new SoSeparator(), * allLinesSep = new SoSeparator();

	//////////////////////// virtuals in blue ////////////////////////
	//material
	SoMaterial* ma = new SoMaterial;
	ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 1.0f));
	linesSep->addChild(ma);
SoDrawStyle* style = new SoDrawStyle; style->lineWidth = 8.5f; linesSep->addChild(style); //thick lines for scrshot
	SoIndexedLineSet* lines = new SoIndexedLineSet;
	SoCoordinate3* co = new SoCoordinate3;	
	int lc = 0; //line counter
	for (int s = 0; s < (int) sketch->strokes.size(); s++)
	{
		if (sketch->strokes[s]->removed || ! sketch->strokes[s]->virtua)
			continue;
		int i = sketch->strokes[s]->v1i, j = sketch->strokes[s]->v2i;
		SbVec3f from = SbVec3f(sketch->pnts[i]->coords[0], sketch->pnts[i]->coords[1], sketch->z);
		co->point.set1Value(2*lc, from);
		SbVec3f to = SbVec3f(sketch->pnts[j]->coords[0], sketch->pnts[j]->coords[1], sketch->z);
		co->point.set1Value(2*lc + 1, to);
		lines->coordIndex.set1Value(3*lc, 2*lc);
		lines->coordIndex.set1Value(3*lc + 1, 2*lc + 1);
		lines->coordIndex.set1Value(3*lc++ + 2, -1); //end this line with -1
	}
	if (lc > 0)
	{
		linesSep->addChild(co); linesSep->addChild(lines);
		allLinesSep->addChild(linesSep);
	}
	//////////////////////// actuals in red ////////////////////////
	SoMaterial* ma2 = new SoMaterial;
	ma2->diffuseColor.setValue(SbColor(1.0f, 0.0f, 0.0f));
	lines2Sep->addChild(ma2);
SoDrawStyle* style2 = new SoDrawStyle; style2->lineWidth = 4.5f; lines2Sep->addChild(style2); //thick lines for scrshot
	SoIndexedLineSet* lines2 = new SoIndexedLineSet;
	SoCoordinate3* co2 = new SoCoordinate3;	
	lc = 0; //line counter
	for (int s = 0; s < (int) sketch->strokes.size(); s++)
	{
		if (sketch->strokes[s]->removed || sketch->strokes[s]->virtua)
			continue;
		int i = sketch->strokes[s]->v1i, j = sketch->strokes[s]->v2i;
		SbVec3f from = SbVec3f(sketch->pnts[i]->coords[0], sketch->pnts[i]->coords[1], sketch->z);
		co2->point.set1Value(2*lc, from);
		SbVec3f to = SbVec3f(sketch->pnts[j]->coords[0], sketch->pnts[j]->coords[1], sketch->z);
		co2->point.set1Value(2*lc + 1, to);
		lines2->coordIndex.set1Value(3*lc, 2*lc);
		lines2->coordIndex.set1Value(3*lc + 1, 2*lc + 1);
		lines2->coordIndex.set1Value(3*lc++ + 2, -1); //end this line with -1
	}
	if (lc > 0)
	{
		lines2Sep->addChild(co2); lines2Sep->addChild(lines2);
		allLinesSep->addChild(lines2Sep);
	}
//allLinesSep->addChild( get1LineSep(SbColor(0.9f, 0.0f, 0.9f), mesh1->verts[ mesh1->bestMatchG ]->coords, scale*mesh2->verts[corresp]->coords + SbVec3f(deltaX, 0.0f, 0.0f)) );

	return allLinesSep;
}
SoSeparator* Painter::getStrokeSep(Mesh* sketch, int strokeID)
{
	//returns the points of strokes[strokeID], which may be an actual or virtual stroke

	SoSeparator* pntsSep = new SoSeparator;
	if (strokeID >= (int) sketch->strokes.size())//sketch->strokes[strokeID]->removed)
		return pntsSep; //draw nothing

	//material
	SoMaterial* mat = new SoMaterial;
	mat->diffuseColor.set1Value(0, SbColor(0.0f, 0.7f, 0.7f));
	pntsSep->addChild(mat);
	SoDrawStyle* style = new SoDrawStyle;
	style->pointSize = 6.0f;
	pntsSep->addChild(style);

	//shape
	SoVertexProperty* vp = new SoVertexProperty;	
	int nAdds = 0;
	for (int p = 0; p < (int) sketch->strokes[strokeID]->pnts.size(); p++)
		vp->vertex.set1Value(nAdds++, sketch->pnts[ sketch->strokes[strokeID]->pnts[p] ]->coords[0], sketch->pnts[ sketch->strokes[strokeID]->pnts[p] ]->coords[1], sketch->z);
	SoPointSet* pSet = new SoPointSet;
	pSet->numPoints = nAdds;
	pSet->vertexProperty = vp;
	pntsSep->addChild(pSet);

	return pntsSep;
}

SoSeparator* Painter::getMatchingSpheresSep(Mesh* sketch, Mesh* mesh, float deltaX, float deltaY, float scale)
{
	//returns a set of spheres to highlight matching mesh.samples[i] w/ same color

	SoSeparator* spheresSep = new SoSeparator();
	vector< SketchPnt* > ref = (sketch->usePnts ? sketch->pnts : sketch->endpnts);

	for (int i = 0; i < (int) mesh->samples.size(); i++)
	{
		if (mesh->verts[ mesh->samples[i] ]->matchIdx == -1)
			continue; //do nothing for this unmatched sample

		//1 sphere for this sample
		SoSeparator* sphere1Sep = new SoSeparator;
		//transformation
		SoTransform* tra = new SoTransform();
		tra->translation.setValue(scale*mesh->verts[ mesh->samples[i] ]->coords[0]+deltaX, scale*mesh->verts[ mesh->samples[i] ]->coords[1]+deltaY, scale*mesh->verts[ mesh->samples[i] ]->coords[2]);
		sphere1Sep->addChild(tra);
		//material
		SoMaterial* ma = new SoMaterial;
		if (i == 0)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.7f));
		else if (i == 1)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.0f, 0.0f));
		else if (i == 2)
			ma->diffuseColor.setValue(SbColor(0.0f, 0.7f, 0.0f));
		else if (i == 3)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.0f, 0.7f));
		else if (i == 4)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.7f, 0.0f));
		else if (i == 5)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.0f, 0.0f));
		else if (i == 6)
			ma->diffuseColor.setValue(SbColor(0.7f, 0.2f, 0.4f));
		else
			ma->diffuseColor.setValue(SbColor(0.4f, 0.2f, 0.4f));
		sphere1Sep->addChild(ma);
		//shape
		SoSphere* sph1 = new SoSphere();
		sph1->radius = sphereRadius * 1.25f;
		sphere1Sep->addChild(sph1); //whose position is decided by the translation applied above

		//another sphere w/ the same color for the matching sample on mesh2
		SoSeparator* sphere2Sep = new SoSeparator;
		//transformation
		SoTransform* tra2 = new SoTransform();
		tra2->translation.setValue(ref[ mesh->verts[ mesh->samples[i] ]->matchIdx ]->coords[0], ref[ mesh->verts[ mesh->samples[i] ]->matchIdx ]->coords[1], sketch->z);
		sphere2Sep->addChild(tra2);
		//material
		sphere2Sep->addChild(ma);
		//shape
		SoSphere* sph2 = new SoSphere();
		sph2->radius = sphereRadius * 1.25f;
		sphere2Sep->addChild(sph2); //whose position is decided by the translation applied above

		spheresSep->addChild(sphere1Sep);
		spheresSep->addChild(sphere2Sep);
	}

	return spheresSep;
}
