///////////////// vertex normal calculation (taken from max sdk)

#include "miniexp.h"


// Add a normal to the list if the smoothing group bits overlap, 
// otherwise create a new vertex normal in the list
void VNormal::AddNormal(Point3 &n,DWORD s, int facei) {
	if (!(s&smooth) && init) {
		if (next) next->AddNormal(n,s,facei);
		else {
			next = new VNormal(n,s,facei);
		}
	} 
	else {
		norm   += n;
		smooth |= s;
		init    = TRUE;
		faceid = facei;
	}
}

// Retrieves a normal if the smoothing groups overlap or there is 
// only one in the list
Point3 &VNormal::GetNormal(DWORD s, int facei) {

if (smooth&s || !next || faceid==facei) return norm;
	else return next->GetNormal(s,facei);	
}

// Normalize each normal in the list
void VNormal::Normalize() {
	VNormal *ptr = next, *prev = this;
	/*while (ptr) {
		if (ptr->smooth&smooth) {
			norm += ptr->norm;
			prev->next = ptr->next;
			delete ptr;
			ptr = prev->next;
		} 
		else {
			prev = ptr;
			ptr  = ptr->next;
		}
	}*/
	norm = ::Normalize(norm);
	if (next) next->Normalize();
}

void ComputeVertexNormals(Matrix3 nt, Mesh *mesh, Tab<VNormal> &vnorms, Tab<Point3> &fnorms) 
{
	Face *face;	
	Point3 *verts;
	Point3 v0, v1, v2;
	
	face = mesh->faces;	
	verts = mesh->verts;
	vnorms.SetCount(mesh->getNumVerts());
	fnorms.SetCount(mesh->getNumFaces());

	// Compute face and vertex surface normals
	for (int i = 0; i < mesh->getNumVerts(); i++) {
		vnorms[i] = VNormal();
	}	
	for (i = 0; i < mesh->getNumFaces(); i++, face++) {

// Calculate the surface normal
		v0 = verts[face->v[0]] * nt;
		v1 = verts[face->v[1]] * nt;
		v2 = verts[face->v[2]] * nt;
		fnorms[i] = (v1-v0)^(v2-v1);
		if (nt.Parity()) fnorms[i]=-fnorms[i];
		fnorms[i] = Normalize(fnorms[i]);
		for (int j=0; j<3; j++) {		
			vnorms[face->v[j]].AddNormal(fnorms[i],face->smGroup,i);
		}
		
	}
	for (i=0; i < mesh->getNumVerts(); i++) {
		vnorms[i].Normalize();
	}
/*
	// Display the normals in the debug window of the VC++ IDE
	DebugPrint("\n\nVertex Normals ---");

for (i = 0; i < vnorms.Count(); i++) {
		DisplayVertexNormal(vnorms.Addr(i), i, 0);
	}
	DebugPrint("\n\n");
	*/
}

/*
void Utility::DisplayVertexNormal(VNormal *vn, int i, int n) {
	DebugPrint("\nVertex %d Normal %d=(%.1f, %.1f, %.1f)", 
		i, n, vn->norm.x, vn->norm.y, vn->norm.z);
	if (vn->next) DisplayVertexNormal(vn->next, i, n+1);
}
*/
