/**********************************************************************
 *<
	FILE: edmdata.cpp

	DESCRIPTION:  Edit Mesh OSM	data structures

	CREATED BY: Rolf Berteig

	HISTORY: created 1 September, 1995

 *>	Copyright (c) 1994, All Rights Reserved.
 **********************************************************************/
#include "mods.h"
#include "editmesh.h"

// in mods.cpp
extern HINSTANCE hInstance;

float AffectRegionFunction(float dist,float falloff,float pinch,float bubble)
	{
	float u = ((falloff - dist)/falloff);
	float u2 = u*u, s = 1.0f-u;	
	return (3*u*bubble*s + 3*u2*(1.0f-pinch))*s + u*u2;
	}

DWORD GetOtherIndex(Face *f,DWORD v0,DWORD v1)
	{
	for (int i=0; i<3; i++) {
		if (f->v[i]!=v0 && f->v[i]!=v1) return f->v[i];
		}
	// Invalid face
	return 0;
	}

int GetEdgeIndex(Face &f,DWORD v0,DWORD v1)
	{
	int j0, j1;
	for (int i=0; i<3; i++) {
		if (f.v[i]==v0) j0 = i;
		if (f.v[i]==v1) j1 = i;
		}
	switch (j0) {
		case 0: return j1==1?0:2;
		case 1: return j1==2?1:0;
		case 2: return j1==0?2:1;
		default:			
			DebugPrint("Face:%d %d %d   v0:%d  v1:%d\n",
				f.v[0],f.v[1],f.v[2],v0,v1);
			//assert(0);
			return 0;
		}	
	}

BOOL EdgeSelected(Face *faces,BitArray& esel,MEdge *e)
	{
	if (e->f[0] != UNDEFINED) {
		int j = GetEdgeIndex(faces[e->f[0]],e->v[0],e->v[1]);
		if (esel[e->f[0]*3+j]) return TRUE;
		}
	if (e->f[1] != UNDEFINED) {
		int j = GetEdgeIndex(faces[e->f[1]],e->v[0],e->v[1]);
		if (esel[e->f[1]*3+j]) return TRUE;
		}
	return FALSE;
	}


// Ensures that v1->v2 is the order that v1, and v2 appear in f.
void SwapEdgeVerts(Face *f,DWORD& v1,DWORD& v2)
	{
	for ( int i = 0; i < 3; i++ ) {
		if ( f->v[i] == v1 ) {
			for ( int j = 0; j < 3; j++ ) {
				if ( f->v[j] == v2 ) {
					if ( (i==0 && j==2) ||
						 (i==1 && j==0) ||
						 (i==2 && j==1) ) {
						DWORD temp = v1;
						v1 = v2;
						v2 = temp;
						return;
					} else {
						return;
						}
					}
				}
			}
		}
	}


void FlipMeshNormal(Mesh *mesh,DWORD face)
	{
	DWORD vis  = 0;
	if (mesh->faces[face].flags&EDGE_A) vis |= EDGE_A;
	if (mesh->faces[face].flags&EDGE_B) vis |= EDGE_C;
	if (mesh->faces[face].flags&EDGE_C) vis |= EDGE_B;
	DWORD temp = mesh->faces[face].v[0];
	mesh->faces[face].v[0] = mesh->faces[face].v[1];
	mesh->faces[face].v[1] = temp;				
	mesh->faces[face].flags &= ~EDGE_ALL;
	mesh->faces[face].flags |= vis;	
	if (mesh->tvFace) {		
		temp = mesh->tvFace[face].t[0];
		mesh->tvFace[face].t[0] = mesh->tvFace[face].t[1];
		mesh->tvFace[face].t[1] = temp;		
		}
	}


AdjEdgeList::~AdjEdgeList()
	{
	delete[] list;
	}

void AdjEdgeList::AddEdge( DWORD fi, DWORD v0, DWORD v1 )
	{
	if ( v1 < v0 ) { DWORD temp = v0; v0 = v1; v1 = temp; }
	MEdge e, *pe;
	DWORDTab &ae = list[v0];

	// Is it already in the list?
	for ( int i = 0; i < ae.Count(); i++ ) {
		pe = &edges[ae[i]];
		if ( pe->v[0]==v0 && pe->v[1]==v1 ) {
			pe->f[1] = fi;
			return;
			}
		}

	// Add the new edge.
	e.f[0] = fi;
	e.f[1] = UNDEFINED;
	e.v[0] = v0;
	e.v[1] = v1;
	edges.Append(1,&e,10);
	
	DWORD index;
	index = (DWORD)edges.Count()-1;
	list[v0].Append(1,&index,10);
	list[v1].Append(1,&index,10);
	}

AdjEdgeList::AdjEdgeList( Mesh& mesh )
	{
	nverts = mesh.getNumVerts();
	list = new DWORDTab[nverts];
	edges.Resize(mesh.getNumFaces()*3);
	int nf = mesh.getNumFaces();
	for ( int i = 0; i < nf; i++ ) {
		DWORD *v = mesh.faces[i].v;
		if (v[0]!=v[1] &&
			v[0]!=v[2] &&
			v[2]!=v[1]) {
			AddEdge( i, v[0], v[1] );
			AddEdge( i, v[1], v[2] );
			AddEdge( i, v[2], v[0] );
		} else {
#if 0
			DebugPrint("Face %d is degenerate\n",i);
#endif
			}
		}
	edges.Shrink();
	}


int AdjEdgeList::FindEdge(DWORD v0, DWORD v1)
	{
	DWORDTab &ae = list[v0];
	MEdge *pe;

	if (v0 > v1) {
		DWORD temp = v0;
		v0 = v1;
		v1 = temp;
		}

	for (int i = 0; i < ae.Count(); i++) {
		pe = &edges[ae[i]];
		if (pe->v[0]==v0 && pe->v[1]==v1) {			
			return ae[i];
			}
		}
	return -1;
	}

void AdjEdgeList::RemoveEdgeFromVertex(DWORD v,DWORD e)
	{
	DWORDTab &ae = list[v];
	for (int i = 0; i < ae.Count(); i++) {
		if (ae[i] == e) {
			ae.Delete(i,1);
			return;
			}
		}
	}

void AdjEdgeList::AddEdgeToVertex(DWORD v,DWORD e)
	{
	DWORDTab &ae = list[v];
	ae.Append(1,&e);
	}


AdjFaceList::AdjFaceList(Mesh& mesh,AdjEdgeList& el)
	{
	DWORD *v, v0,v1;
	AdjFace aface;

	list.Resize(mesh.getNumFaces());
	for ( DWORD i = 0; i < (DWORD)mesh.getNumFaces(); i++ ) {
		v = mesh.faces[i].v;
		for ( int j = 0; j < 3; j++ ) {
			// The edge I'm looking for:
			v0 = v[j];
			v1 = v[j==2?0:j+1];
			if ( v1 < v0 ) {
				DWORD temp = v0; v0 = v1; v1 = temp;
				}
			DWORDTab& ae = el[v[j]];
			for ( int k = 0; k < ae.Count(); k++ ) {			
				MEdge edge = el.edges[ae[k]];
				if ( edge.v[0] == v0 && edge.v[1] == v1 ) {
					if ( edge.f[0] == i ) {
						aface.f[j] = edge.f[1]; 
					} else { 					
						aface.f[j] = edge.f[0]; 
						}
					break;
					}						
				}
			}
		list.Append(1,&aface);
		}
	}

void FaceClusterList::ClusterID(
		int f, BitArray& fsel, AdjFaceList& adj, DWORD id)
	{
	// Base case: found a nonselected face or a face that has already been IDed.
	if (!fsel[f] || clust[f] == id) return;

	// Set this face's ID.
	clust[f] = id;

	// Set neighbors ID.
	for ( int i = 0; i < 3; i++ ) {
		if (adj[f].f[i] != UNDEFINED) {
			ClusterID(adj[f].f[i],fsel,adj,id);
			}
		}
	}


FaceClusterList::FaceClusterList(BitArray& fsel, AdjFaceList& adj)
	{
	Tab<DWORD> stack;
	count = 0;
	
	// Init cluster id list.
	clust.Resize(fsel.GetSize());
	for (DWORD i = 0; i < (DWORD)fsel.GetSize(); i++) {
		DWORD init = UNDEFINED;
		clust.Append(1,&init);
		}

	for (i = 0; i < (DWORD)fsel.GetSize(); i++) {
		if (fsel[i]) {
			if (clust[i] == UNDEFINED) {				
				
				// Start by pushing this face on the stack
				stack.Append(1,&i,10);

				while (stack.Count()) {
					// Pop a face off the stack
					DWORD f = stack[stack.Count()-1];
					stack.Delete(stack.Count()-1,1);

					// Set the face's cluster ID.
					clust[f] = count;					

					// Push neighbors on the stack
					for (int j=0; j<3; j++) {
						// Adjacent face index
						DWORD af = adj[f].f[j];
						if (af != UNDEFINED) {							
							// If it's selected and we haven't done it yet, push it on the stack
							if (!fsel[af] || clust[af]!=UNDEFINED) continue;
							stack.Append(1,&af,10);
							}
						}
					}
				
				// Move to next ID.
				count++;
				}
			}
		}
#if 0	
	// Recursively ID each face.	
	for (i = 0; i < fsel.GetSize(); i++) {
		if (fsel[i]) {
			if ( clust[i] == UNDEFINED ) {
				ClusterID(i,fsel,adj,count);
				count++;
				}
			}
		}
#endif
	}


void FaceClusterList::ClusterID(
		Mesh *mesh, int f, AdjFaceList& adj, DWORD id, float angle,BOOL useSel)
	{
	// Base case: found a nonselected face or a face that has already been IDed.
	if ((!mesh->faceSel[f]&&useSel) || (clust[f]!=UNDEFINED)) return;

	// Set this face's ID.
	clust[f] = id;

	// Set neighbors ID.
	for (int i = 0; i < 3; i++) {
		if (adj[f].f[i] != UNDEFINED &&
			AngleBetweenFaces(mesh,(DWORD)f,adj[f].f[i]) < angle
			&& angle != 0.0f) {
			ClusterID(mesh,adj[f].f[i],adj,id,angle,useSel);
			}
		}
	}


FaceClusterList::FaceClusterList(
		Mesh *mesh, AdjFaceList& adj,float angle,BOOL useSel)
	{
	Tab<DWORD> stack;
	count = 0;
	
	// Init cluster id list.
	clust.SetCount(mesh->getNumFaces());
	for (DWORD i=0; i < (DWORD)mesh->getNumFaces(); i++) clust[i] = UNDEFINED;
	
	for (i = 0; i < (DWORD)mesh->getNumFaces(); i++) {
		if (!useSel || mesh->faceSel[i]) {
			if (clust[i] == UNDEFINED) {				
				
				// Start by pushing this face on the stack
				stack.Append(1,&i,10);

				while (stack.Count()) {
					// Pop a face off the stack
					DWORD f = stack[stack.Count()-1];
					stack.Delete(stack.Count()-1,1);

					// Set the face's cluster ID.
					clust[f] = count;					

					// Push neighbors on the stack
					for (int j=0; j<3; j++) {
						// Adjacent face index
						DWORD af = adj[f].f[j];
						if (af != UNDEFINED) {							
							// If it's selected and we haven't done it yet, push it on the stack
							if ((!mesh->faceSel[af]&&useSel) || (clust[af]!=UNDEFINED)) continue;
							
							// Also, make sure the faces are within angle threshold
							float a = AngleBetweenFaces(mesh,f,af);
							if (a < angle && angle != 0.0f) {
								stack.Append(1,&af,10);
								}
							}
						}
					}
				
				// Move to next ID.
				count++;
				}
			}

		}
#if 0	
	// Recursively ID each face.
	for (i=0; i<mesh->getNumFaces(); i++) {
		if (!useSel || mesh->faceSel[i]) {
			if (clust[i] == UNDEFINED) {
				ClusterID(mesh,i,adj,count,angle,useSel);
				count++;
				}
			}
		}
#endif
	}


 void FaceClusterList::MakeVertCluster(Mesh &mesh,DWORDTab& vclust)
 	{
	DWORD c=UNDEFINED;
	
	vclust.Resize(mesh.getNumVerts());
	for ( int i = 0; i < mesh.getNumVerts(); i++ ) vclust.Append(1,&c);
	
	for ( i = 0; i < mesh.getNumFaces(); i++ ) {
		c = clust[i];
		if ( c != UNDEFINED ) {
			for ( int j = 0; j < 3; j++ ) {
				vclust[mesh.faces[i].v[j]] = c;
				}
			}
		}	
	}


/*-------------------------------------------------------*/


BOOL EdgeClusterList::ClusterID(
		Mesh& mesh, int index, BitArray& esel, AdjEdgeList& adj, DWORD id)
	{
	MEdge *e = &adj.edges[index];
	
	// If the edge is not selected, return
	if (!EdgeSelected(mesh.faces,esel,e)) return FALSE;

	// If this edge has been IDed, return
	int f0, f1, i0, i1;
	f0 = e->f[0];
	f1 = e->f[1];
	if (f0 != UNDEFINED) {
		i0 = GetEdgeIndex(mesh.faces[f0],e->v[0],e->v[1]);
		if (clust[f0*3+i0] != UNDEFINED) return FALSE;
		
		// Set this edges's ID.
		clust[f0*3+i0] = id;
		}
	if (f1 != UNDEFINED) {
		i1 = GetEdgeIndex(mesh.faces[f1],e->v[0],e->v[1]);
		if (clust[f1*3+i1] != UNDEFINED) return FALSE;
		
		// Set this edges's ID.
		clust[f1*3+i1] = id;
		}		

	// Set neighbors ID.
	DWORDTab &el0 = adj.list[e->v[0]];
	for (int i = 0; i < el0.Count(); i++ ) {		
		if (el0[i]==(DWORD)index) continue;
		ClusterID(mesh,el0[i],esel,adj,count);		
		}
	DWORDTab &el1 = adj.list[e->v[1]];
	for (i = 0; i < el1.Count(); i++ ) {		
		if (el1[i]==(DWORD)index) continue;
		ClusterID(mesh,el1[i],esel,adj,count);		
		}
	
	return TRUE;
	}

EdgeClusterList::EdgeClusterList(
		Mesh &mesh, BitArray& esel, AdjEdgeList& adj)
	{
	Tab<DWORD> stack;
	count = 0;
	
	// Init cluster id list.
	clust.SetCount(esel.GetSize());
	for (DWORD i = 0; i < (DWORD)esel.GetSize(); i++) clust[i] = UNDEFINED;			

	for (i=0; i<(DWORD)adj.edges.Count(); i++) {		
		if (EdgeSelected(mesh.faces,esel,&adj.edges[i])) {		
			BOOL done = FALSE;

			// Start by pushing this edge on the stack
			stack.Append(1,&i,10);

			while (stack.Count()) {
				// Pop an edge off the stack
				DWORD ei = stack[stack.Count()-1];
				stack.Delete(stack.Count()-1,1);
				MEdge *e = &adj.edges[ei];

				// ID this edge... continue if it has already been IDed.
				int f0, f1, i0, i1;
				f0 = e->f[0];
				f1 = e->f[1];
				if (f0 != UNDEFINED) {
					i0 = GetEdgeIndex(mesh.faces[f0],e->v[0],e->v[1]);
					if (clust[f0*3+i0] != UNDEFINED) continue;
					
					// Set this edges's ID.
					clust[f0*3+i0] = count;
					}
				if (f1 != UNDEFINED) {
					i1 = GetEdgeIndex(mesh.faces[f1],e->v[0],e->v[1]);
					if (clust[f1*3+i1] != UNDEFINED) continue;
					
					// Set this edges's ID.
					clust[f1*3+i1] = count;
					}		

				// Note that we did ID something
				done = TRUE;

				// Push neighbors on the stack, if they are selected.				
				DWORDTab &el0 = adj.list[e->v[0]];
				for (int j = 0; j < el0.Count(); j++) {		
					if (el0[j]==ei) continue;
					if (!EdgeSelected(mesh.faces,esel, &adj.edges[el0[j]])) continue;
					stack.Append(1,&el0[j],10);
					}
				DWORDTab &el1 = adj.list[e->v[1]];
				for (j = 0; j < el1.Count(); j++ ) {		
					if (el1[j]==ei) continue;
					if (!EdgeSelected(mesh.faces,esel, &adj.edges[el1[j]])) continue;
					stack.Append(1,&el1[j],10);
					}									
				}
			
			// Move to next ID.
			if (done) count++;
			}
		}
#if 0	
	// Recursively ID each edge.
	for (i=0; i<adj.edges.Count(); i++) {	
		MEdge *e = &adj.edges[i];
		if (EdgeSelected(mesh.faces,esel,e)) {
			if (ClusterID(mesh,i,esel,adj,count)) count++;
			}
		}
#endif
	}


void EdgeClusterList::MakeVertCluster(Mesh &mesh,DWORDTab& vclust)
 	{
	DWORD c=UNDEFINED;
	
	vclust.Resize(mesh.getNumVerts());
	for (int i=0; i<mesh.getNumVerts(); i++) vclust.Append(1,&c);
	
	for (i = 0; i < mesh.getNumFaces(); i++) {
		for (int j=0; j<3; j++) {			
			c = ID(i,j);
			if (c!=UNDEFINED) {
				vclust[mesh.faces[i].v[j]] = c;
				vclust[mesh.faces[i].v[(j+1)%3]] = c;
				}

			}
		}		
	}


void FaceElementList::AddFacesToElem(
		int face,Mesh &mesh,AdjFaceList& af,DWORD e)
	{
	// Base case: elem is already classified
   	if (face==UNDEFINED || elem[face]!=UNDEFINED) return;

 	elem[face] = e;
	for (int i=0; i<3; i++) {
		AddFacesToElem(af[face].f[i],mesh,af,e);
		}
	}

FaceElementList::FaceElementList(Mesh &mesh,AdjFaceList& af)
	{
	Tab<DWORD> stack;
	count=0;
	elem.SetCount(mesh.getNumFaces());
	for (DWORD i=0; i<(DWORD)mesh.getNumFaces(); i++) elem[i] = UNDEFINED;

	for (i = 0; i < (DWORD)mesh.getNumFaces(); i++) {		
		if (elem[i]==UNDEFINED) {				
			
			// Start by pushing this face on the stack
			stack.Append(1,&i,10);

			while (stack.Count()) {				
				// Pop a face off the stack
				DWORD f = stack[stack.Count()-1];
				stack.Delete(stack.Count()-1,1);

				// Set the face's cluster ID.
				elem[f] = count;					

				// Push neighbors on the stack
				for (int j=0; j<3; j++) {
					// Adjacent face index
					DWORD f2 = af[f].f[j];
					if (f2 != UNDEFINED) {							
						// If we haven't done it yet, push it on the stack
						if (elem[f2]==UNDEFINED) {
							stack.Append(1,&f2,10);
							}
						}
					}
				}
			
			// Move to next ID.
			count++;
			}
		}
	/*
	for (i=0; i<mesh.getNumFaces(); i++) {
		if (elem[i]==UNDEFINED) {
			AddFacesToElem(i,mesh,af,count);
			count++;
			}
		}
	*/
	}

/*-------------------------------------------------------*/

inline Point3 FaceNormal( Mesh& mesh, DWORD fi )
	{
	Face *f = &mesh.faces[fi];
	Point3 v1 = mesh.verts[f->v[1]] - mesh.verts[f->v[0]];
	Point3 v2 = mesh.verts[f->v[2]] - mesh.verts[f->v[1]];
	return v1^v2;
	}

void BuildClusterNormals( Mesh& mesh, FaceClusterList& clust, Point3Tab& normals, Point3Tab& centers )
	{
	Point3 zero(0,0,0), v1, v2;
	BitArray vdone;
	Tab<int> ccount;
	int zr = 0;

	// Init
	normals.Resize(clust.count);
	centers.Resize(clust.count);
	ccount.Resize(clust.count);
	for ( DWORD i = 0; i < clust.count; i++ ) {
		normals.Append(1,&zero);
		centers.Append(1,&zero);
		ccount.Append(1,&zr);
		}
	
	vdone.SetSize(mesh.getNumVerts());
		
	for ( int j = 0; j < mesh.getNumFaces(); j++ ) {		
		if ( clust[j] != UNDEFINED ) {
			// Add this face into its cluster's normal
			Face *f = &mesh.faces[j];
			v1 = mesh.verts[f->v[1]] - mesh.verts[f->v[0]];
			v2 = mesh.verts[f->v[2]] - mesh.verts[f->v[1]];		
			normals[clust[j]] += v1^v2;

			// Add vertices into cluster center.
			for ( int k = 0; k < 3; k++ ) {
				if ( !vdone[f->v[k]] ) {
					centers[clust[j]] += mesh.verts[f->v[k]];
					ccount[clust[j]]  += 1;
					vdone.Set(f->v[k]);
					}
				}
			}
		}
	
	// Normalize the cluster normals and average the centers
	for ( i = 0; i < clust.count; i++ ) {			
		normals[i] = Normalize(normals[i]);
		if ( ccount[i] ) {
			centers[i] /= float(ccount[i]);
			}
		}
	}

typedef DWORD EdgeSeg[2];
typedef Tab<EdgeSeg> EdgeSegTab;

void BuildClusterNormals(
		Mesh& mesh, EdgeClusterList& clust, Point3Tab& normals, Point3Tab& centers)
	{
	EdgeSegTab *cedge = new EdgeSegTab[clust.count];

	// Build a list of edges for each cluster
	for (int i=0; i<mesh.getNumFaces(); i++) {
		for (int j=0; j<3; j++) {
			if (clust.ID(i,j)!=UNDEFINED) {
				EdgeSeg es = {mesh.faces[i].v[j],mesh.faces[i].v[(j+1)%3]};
				cedge[clust.ID(i,j)].Append(1,&es,5);
				}
			}
		}

	normals.SetCount(clust.count);
	centers.SetCount(clust.count);
	
	for (i=0; i<(int)clust.count; i++) {
		centers[i] = Point3(0,0,0);
		normals[i] = Point3(0,0,0);
		
		// Compute centers
		for (int j=0; j<cedge[i].Count(); j++) {
			centers[i] += mesh.verts[cedge[i][j][0]];
			centers[i] += mesh.verts[cedge[i][j][1]];
			}
		centers[i] /= float(cedge[i].Count()*2);

		// Compute the normal by constructing to radial segments from
		// the cluster center to the two end of an edge. Average these
		// normals for all edges
		for (j=0; j<cedge[i].Count(); j++) {
			Point3 v0 = mesh.verts[cedge[i][j][0]] - centers[i];
			Point3 v1 = mesh.verts[cedge[i][j][1]] - centers[i];
			Point3 n = v0^v1;
			if (DotProd(n,normals[i]) < 0.0f) {
				normals[i] += -n;
			} else {
				normals[i] += n;
				}
			}
		normals[i] = Normalize(normals[i]);
		}

	delete[] cedge;

#if 0
	Point3 zero(0,0,0), v1, v2;
	Tab<int> ccount;
	int zr = 0;

	// Init
	normals.Resize(clust.count);
	centers.Resize(clust.count);
	ccount.Resize(clust.count);
	for (DWORD i = 0; i < clust.count; i++) {
		normals.Append(1,&zero);
		centers.Append(1,&zero);
		ccount.Append(1,&zr);
		}	
	

	for (i=0; i<(DWORD)mesh.getNumFaces(); i++) {
		for (int j=0; j<3; j++) {
			if (clust.ID(i,j)!=UNDEFINED) {
				// Add this face into its cluster's normal
				Face *f = &mesh.faces[i];
				v1 = mesh.verts[f->v[1]] - mesh.verts[f->v[0]];
				v2 = mesh.verts[f->v[2]] - mesh.verts[f->v[1]];		
				normals[clust.ID(i,j)] += v1^v2;

				// Add vertices into center
				centers[clust.ID(i,j)] += mesh.verts[f->v[j]];
				centers[clust.ID(i,j)] += mesh.verts[f->v[(j+1)%3]];
				ccount[clust.ID(i,j)]  += 2;
				}
			}		
		}
	
	// Normalize the cluster normals and average the centers
	for (i = 0; i < clust.count; i++) {
		normals[i] = Normalize(normals[i]);
		if (ccount[i]) {
			centers[i] /= float(ccount[i]);
			}
		}
#endif
	}



void BuildAverageNormals( Mesh& mesh, Point3Tab& normals )
	{
	Point3 init(0,0,0),v1,v2, n;
	Face *f;

	normals.Delete(0,normals.Count());
	normals.Resize(mesh.getNumVerts());
	for ( int i = 0; i < mesh.getNumVerts(); i++ ) normals.Append(1,&init);
	
	// Add each face normal into the faces vertex normal
	for ( i = 0; i < mesh.getNumFaces(); i++ ) {		
		f = &mesh.faces[i];
		n = FaceNormal(mesh,i);
		normals[f->v[0]] += n;
		normals[f->v[1]] += n;
		normals[f->v[2]] += n;
		}
	
	// Normalize
	for ( i = 0; i < normals.Count(); i++ ) {
		normals[i] = Normalize(normals[i]);
		}
	}


// Constructs an arbitrary matrix such that
// Z axis = the given normal.
// X axis = a vector in the XY plane perpidicular to Z axis
// Y axis = Z axis cross X axis
void MatrixFromNormal( Point3& normal, Matrix3& mat )
	{
	Point3 vx;
	vx.z = .0f;
	vx.x = -normal.y;
	vx.y = normal.x;	
	if ( vx.x == .0f && vx.y == .0f ) {
		vx.x = 1.0f;
		}
	mat.SetRow(0,vx);
	mat.SetRow(1,normal^vx);
	mat.SetRow(2,normal);
	mat.SetTrans(Point3(0,0,0));
	mat.NoScale();
	}

static int whichEdge(Face *f, DWORD a, DWORD b) {
	DWORD *v = f->getAllVerts();
	if (a==v[0]) {
		if (b==v[1]) return 0;
		if (b==v[2]) return 2;	
		} 
	else 
	if (a==v[1]) {
		if (b==v[0]) return 0;
		if (b==v[2]) return 1;	
		}
	// a = v[2]
	if (b==v[0]) return 2;
	if (b==v[1]) return 1;	
	return 0;
	}

inline BOOL FacesCoplanar(Mesh& mesh,DWORD f0, DWORD f1, float thresh)
	{
	Point3 n0 =  Normalize(FaceNormal(mesh,f0));
	Point3 n1 =  Normalize(FaceNormal(mesh,f1));	
	float dp = DotProd(n0,n1);
	if ( dp > float(1) ) {
		return TRUE;
		}
	if ( dp < float(-1) ) {
		return FALSE;
		}
	float angle = float(acos(dp));
	return fabs(angle) < fabs(DegToRad(thresh));
	}

float AngleBetweenFaces(Mesh *mesh,DWORD f0, DWORD f1)
	{
	if (f0==UNDEFINED || f1==UNDEFINED) return DegToRad(180);
	Point3 n0 =  Normalize(FaceNormal(*mesh,f0));
	Point3 n1 =  Normalize(FaceNormal(*mesh,f1));	
	float dp = DotProd(n0,n1);
	if (dp > float(1)) {
		return 0.0f;
		}
	if (dp < float(-1)) {
		return DegToRad(180);
		}
	return float(acos(dp));	
	}

static void BuildPoly(
		Mesh& mesh,
		AdjFaceList &al,
		DWORD f,
		DWORDTab& sel,
		BitArray& fdone,
		float thresh)
	{
	if ( !fdone[f] ) {
		fdone.Set(f);
		sel.Append(1,&f,10);
		for ( int i = 0; i < 3; i++ ) {
			if (al[f].f[i]!=UNDEFINED && !mesh.faces[f].getEdgeVis(i)) {
				Face *face = &mesh.faces[al[f].f[i]];
				DWORD v0 = mesh.faces[f].v[i];
				DWORD v1 = mesh.faces[f].v[i==2?0:i+1];
				if ( !face->getEdgeVis(whichEdge(face,v0,v1)) ) {
					if ( FacesCoplanar(mesh,f,al[f].f[i],thresh) ) {
						BuildPoly(mesh,al,al[f].f[i],sel,fdone,thresh);
						} 
					}
				}
			}
		}
	}

void PolyFromFace(
		Mesh& mesh,AdjFaceList &al,
		DWORD f,DWORDTab& sel,float thresh)
	{
	BitArray fdone;
 	Tab<DWORD> stack;

	fdone.SetSize(mesh.getNumFaces());
				
	// Start by pushing this face on the stack
	stack.Append(1,&f,10);

	while (stack.Count()) {
		// Pop a face off the stack
		DWORD f = stack[stack.Count()-1];
		stack.Delete(stack.Count()-1,1);

		// Add this face to the list and mark it as done.
		fdone.Set(f);
		sel.Append(1,&f,10);

		// Push neighbors on the stack
		for (int i=0; i<3; i++) {
			// Adjacent face index
			DWORD af = al[f].f[i];
			
			// If it's been done, then continue;
			if (af==UNDEFINED || fdone[af]) continue;

			// It must be adjacent across hidden edges and within
			// the threshold angle.
			if (!mesh.faces[f].getEdgeVis(i)) {				
				Face *face = &mesh.faces[af];
				DWORD v0 = mesh.faces[f].v[i];
				DWORD v1 = mesh.faces[f].v[i==2?0:i+1];
				if (!face->getEdgeVis(whichEdge(face,v0,v1))) {
					if (FacesCoplanar(mesh,f,af,thresh)) {
						stack.Append(1,&af,10);
						} 
					}				
				}
			}
		}
		
	//BuildPoly(mesh,al,f,sel,fdone,thresh);
	}

/*-------------------------------------------------------*/


void SelectElementFromFace(
		Mesh &mesh, AdjFaceList &al,
		DWORD f, BitArray &set, BitArray &fdone)
	{		
	if (fdone[f]) return;
	Tab<DWORD> stack;

	// Start by pushing this face on the stack
	stack.Append(1,&f,10);

	while (stack.Count()) {
		// Pop a face off the stack
		DWORD f = stack[stack.Count()-1];
		stack.Delete(stack.Count()-1,1);

		// Do this face and mark it as done.
		fdone.Set(f);
		set.Set(f);

		// Push neighbors on the stack
		for (int i=0; i<3; i++) {
			// Adjacent face index
			DWORD af = al[f].f[i];
		
			// Make sure it hasn't been done.
			if (af!=UNDEFINED && !fdone[af]) {
				stack.Append(1,&af,10);
				}
			}
		}
	/*
	if (!fdone[f]) {
		// Do it
		fdone.Set(f);
		set.Set(f);
		
		// Do all adjacents
		for (int i=0; i<3; i++) {
			if (al[f].f[i]!=UNDEFINED) {				
				SelectElementFromFace(
					mesh,al,al[f].f[i],set,fdone);
				}
			}
		}
	*/
	}


/*-------------------------------------------------------*/

int MEdge::EdgeIndex(Face *faces,int side)
	{
	assert(f[side]!=UNDEFINED);	
	return GetEdgeIndex(faces[f[side]],v[0],v[1]);
	}

BOOL MEdge::Selected(Face *faces,BitArray &esel)
	{
	if (f[0]!=UNDEFINED) {
		int i = EdgeIndex(faces,0);
		if (esel[f[0]*3+i]) return TRUE;
		}	
	if (f[1]!=UNDEFINED) {
		int i = EdgeIndex(faces,1);
		if (esel[f[1]*3+i]) return TRUE;
		}	
	return FALSE;
	}

Point3 MEdge::Center(Point3 *verts)
	{
	return (verts[v[0]] + verts[v[1]])/2.0f;
	}

BOOL MEdge::AFaceSelected(BitArray &fsel)
	{
	if (f[0]!=UNDEFINED) {
		if (fsel[f[0]]) return TRUE;
		}
	if (f[1]!=UNDEFINED) {
		if (fsel[f[1]]) return TRUE;
		}
	return FALSE;
	}

Point3 MEdge::ButterFlySubdivide(
		Mesh *mesh,AdjFaceList *af,float tens)
	{
	Point3 a, b, c, d, ee, ff, gg, hh;
	Face *f0, *f1;
	int edge;
	DWORD n0, n1, fi;

	if (f[0]!=UNDEFINED) {
		f0 = &mesh->faces[f[0]];
	} else {
		return Center(mesh->verts);
		}
	if (f[1]!=UNDEFINED) {
		f1 = &mesh->faces[f[1]];
	} else {
		return Center(mesh->verts);
		}

#if 0	
	if (f0->v[0]==f0->v[1] ||
		f0->v[1]==f0->v[2] ||
		f0->v[0]==f0->v[2]) {

		DebugPrint("Face:%d v[0]:%d v[1]:%d v[2]:%d\n",
					f[0],f0->v[0],f0->v[1],f0->v[2]);
		}

	if (f1->v[0]==f1->v[1] ||
		f1->v[1]==f1->v[2] ||
		f1->v[0]==f1->v[2]) {

		DebugPrint("Face:%d v[0]:%d v[1]:%d v[2]:%d\n",
					f[1],f1->v[0],f1->v[1],f1->v[2]);
		}
#endif

	n0 = GetOtherIndex(f0,v[0],v[1]);
	n1 = GetOtherIndex(f1,v[0],v[1]);

	a = mesh->verts[v[0]];
	b = mesh->verts[v[1]];
	c = mesh->verts[n0];
	d = mesh->verts[n1];
	
	edge = GetEdgeIndex(*f0,n0,v[1]);
	fi = (*af)[f[0]].f[edge];
	if (fi!=UNDEFINED) {		
		ff = mesh->verts[GetOtherIndex(&mesh->faces[fi],n0,v[1])];
	} else {
		ff = b;
		}
	
	edge = GetEdgeIndex(*f0,n0,v[0]);
	fi = (*af)[f[0]].f[edge];
	if (fi!=UNDEFINED) {		
		hh = mesh->verts[GetOtherIndex(&mesh->faces[fi],n0,v[0])];
	} else {
		hh = a;
		}

	edge = GetEdgeIndex(*f1,n1,v[1]);
	fi = (*af)[f[1]].f[edge];
	if (fi!=UNDEFINED) {		
		ee = mesh->verts[GetOtherIndex(&mesh->faces[fi],n1,v[1])];
	} else {
		ee = b;
		}

	edge = GetEdgeIndex(*f1,n1,v[0]);
	fi = (*af)[f[1]].f[edge];
	if (fi!=UNDEFINED) {		
		gg = mesh->verts[GetOtherIndex(&mesh->faces[fi],n1,v[0])];
	} else {
		gg = a;
		}

	return 0.5f*(a+b) + 2.0f*tens*(c+d) - tens*(ee+ff+gg+hh);	
	}

/*-------------------------------------------------------*/

EMTempData::~EMTempData()
	{
	if (adjList) delete adjList;
	if (faceAdjList) delete faceAdjList;
	if (faceCluster) delete faceCluster;
	if (edgeCluster) delete edgeCluster;
	if (vertCluster) delete vertCluster;
	if (cnormals) delete cnormals;
	if (ccenters) delete ccenters;
	if (vnormals) delete vnormals;
	if (mesh) delete mesh;
	}

EMTempData::EMTempData(EditMeshMod *m,EditMeshData *md)
	{
	adjList     = NULL;
	faceAdjList = NULL;
	faceCluster = NULL;
	edgeCluster = NULL;
	vertCluster = NULL;
	cnormals    = NULL;
	ccenters    = NULL;
	mesh = NULL;
	alValid.SetEmpty();
	meshValid.SetEmpty();
	meshData = md;
	mod = m;
	vnormals = NULL;
	lockInvalidate = FALSE;
	}

void EMTempData::Invalidate(DWORD part,BOOL meshValid)
	{
	if (lockInvalidate) return;

	if ( !meshValid ) {
		delete mesh;
		mesh = NULL;
		}
	if ( part & PART_TOPO ) {
		if ( adjList ) delete adjList;
		adjList = NULL;
		if ( faceAdjList ) delete faceAdjList;
		faceAdjList = NULL;
		if ( faceCluster ) delete faceCluster;
		faceCluster = NULL;
		if ( edgeCluster ) delete edgeCluster;
		edgeCluster = NULL;
		if ( vertCluster ) delete vertCluster;
		vertCluster = NULL;
		if ( cnormals ) delete cnormals;
		cnormals = NULL;
		if ( ccenters ) delete ccenters;
		ccenters = NULL;
		if ( vnormals ) delete vnormals;
		vnormals = NULL;
		}
	if ( part & PART_GEOM ) {
		if ( cnormals ) delete cnormals;
		cnormals = NULL;
		if ( ccenters ) delete ccenters;
		ccenters = NULL;
		if ( vnormals ) delete vnormals;
		vnormals = NULL;
		}
	if ( part & PART_SELECT ) {
		if ( faceCluster ) delete faceCluster;
		faceCluster = NULL;
		if ( edgeCluster ) delete edgeCluster;
		edgeCluster = NULL;
		if ( vertCluster ) delete vertCluster;
		vertCluster = NULL;
		if ( cnormals ) delete cnormals;
		cnormals = NULL;
		if ( ccenters ) delete ccenters;
		ccenters = NULL;
		}
	}

Mesh *EMTempData::GetMesh(TimeValue t)
	{
	if ( meshValid.InInterval(t) && mesh ) {
		return mesh;
	} else {
		meshData->SetFlag(EMD_UPDATING_CACHE,TRUE);
		lockInvalidate = TRUE;
		mod->NotifyDependents(Interval(t,t), 
			PART_GEOM|SELECT_CHANNEL|PART_SUBSEL_TYPE|
			PART_DISPLAY|PART_TOPO,
		    REFMSG_MOD_EVAL);
		lockInvalidate = FALSE;
		assert(	meshValid.InInterval(t) && mesh );
		meshData->SetFlag(EMD_UPDATING_CACHE,FALSE);
		if ( vnormals ) delete vnormals;
		vnormals = NULL;
		return mesh;
		}
	}

AdjEdgeList *EMTempData::AdjList(TimeValue t)
	{
	GetMesh(t);
	if ( !alValid.InInterval(t) && adjList ) {
		delete adjList;
		adjList = NULL;
		if ( faceAdjList ) {
			delete faceAdjList;
			faceAdjList = NULL;
			}
		if ( faceCluster ) {
			delete faceCluster;
			faceCluster = NULL;
			}
		if ( edgeCluster ) {
			delete edgeCluster;
			edgeCluster = NULL;
			}
		if ( vertCluster ) {
			delete vertCluster;
			vertCluster = NULL;
			}
		if ( cnormals ) {
			delete cnormals;
			cnormals = NULL;
			}
		if ( ccenters ) {
			delete ccenters;
			ccenters = NULL;
			}
		}
	if ( !adjList ) {
		adjList = new AdjEdgeList(*mesh);
		alValid = meshValid;
		}
	return adjList;
	}

AdjFaceList *EMTempData::FaceAdjList(TimeValue t)
	{
	GetMesh(t);
	AdjList(t);
	if ( !faceAdjList ) {
		faceAdjList = new AdjFaceList(*mesh,*adjList);
		}
	return faceAdjList;
	}

FaceClusterList *EMTempData::FaceCluster(TimeValue t)
	{
	GetMesh(t);
	FaceAdjList(t);
	if ( !faceCluster ) {
		faceCluster = new FaceClusterList(mesh->faceSel,*faceAdjList);
		}
	return faceCluster;
	}

EdgeClusterList *EMTempData::EdgeCluster(TimeValue t)
	{
	GetMesh(t);
	AdjList(t);
	if (!edgeCluster) {
		edgeCluster = new EdgeClusterList(*mesh,mesh->edgeSel,*adjList);
		}
	return edgeCluster;
	}

Point3Tab *EMTempData::ClustNormals(TimeValue t)
	{
	GetMesh(t);
	if ( !cnormals ) {
		cnormals = new Point3Tab;
		ccenters = new Point3Tab;
		
		if (mod->selLevel==EM_EDGE) {
			EdgeCluster(t);
			BuildClusterNormals(*mesh,*edgeCluster,*cnormals,*ccenters);
		} else {
			FaceCluster(t);
			BuildClusterNormals(*mesh,*faceCluster,*cnormals,*ccenters);
			}
		}
	return cnormals;
	}

Point3Tab *EMTempData::ClustCenters(TimeValue t)
	{
	ClustNormals(t);
	return ccenters;
	}

Point3Tab *EMTempData::VertNormals(TimeValue t)
	{
	GetMesh(t);
	if ( !vnormals ) {
		vnormals = new Point3Tab;
		BuildAverageNormals(*mesh,*vnormals);
		}
	return vnormals;
	}

DWORDTab *EMTempData::VertCluster(TimeValue t)
	{
	GetMesh(t);	
	if (!vertCluster) {
		vertCluster = new DWORDTab;		
		if (mod->selLevel==EM_EDGE) {
			EdgeCluster(t);
			edgeCluster->MakeVertCluster(*mesh,*vertCluster);
		} else {		
			FaceCluster(t);
			faceCluster->MakeVertCluster(*mesh,*vertCluster);
			}
		}
	return vertCluster;
	}

BOOL EMTempData::MeshCached(TimeValue t)
	{
	return (meshValid.InInterval(t) && mesh);
	}

void EMTempData::UpdateCache(TriObject *triOb)
	{
	if ( mesh ) delete mesh;
	mesh = new Mesh(triOb->mesh);

	meshValid = FOREVER;
	
	// These are the chanels we care about.
	meshValid &= triOb->ChannelValidity(0,GEOM_CHAN_NUM);
	meshValid &= triOb->ChannelValidity(0,TOPO_CHAN_NUM);
	meshValid &= triOb->ChannelValidity(0,SELECT_CHAN_NUM);
	meshValid &= triOb->ChannelValidity(0,SUBSEL_TYPE_CHAN_NUM);
	meshValid &= triOb->ChannelValidity(0,DISP_ATTRIB_CHAN_NUM);	
	meshValid &= triOb->ChannelValidity(0,TEXMAP_CHAN_NUM);
	}



