/****************************************/
/*** Generic Face Compilation Storage ***/
/****************************************/
// Contains tri data with texture data
// Will quad later

#include <ginio.h>
#include <gintex.h>
#include <math.h>

#include "FaceStore.h"
#include "TexGrab.h"
#include "DaveLib.h"
#include "PsxTypes.h"
#include <algorithm>

//***************************************************************************
Vector3 normalise(Vector3 &v)
{
	float sqmag = v.x * v.x + v.y * v.y + v.z * v.z;
	if (sqmag > 0.001f)
	{
		float mag = (float)sqrt( sqmag );
		Vector3 out;

		out.x = v.x / mag;
		out.y = v.y / mag;
		out.z = v.z / mag;

		return out;
	} else
	{
		return v;
	}
}

//***************************************************************************
Vector3 crossProduct( Vector3 &v0, Vector3 &v1, Vector3 &v2 )
{
	Vector3 dv1, dv2;
	Vector3 out;

	dv1.x = v1.x - v0.x;
	dv1.y = v1.y - v0.y;
	dv1.z = v1.z - v0.z;

	dv2.x = v2.x - v0.x;
	dv2.y = v2.y - v0.y;
	dv2.z = v2.z - v0.z;

	out.x = (dv1.z * dv2.y) - (dv1.y * dv2.z);
	out.y = (dv1.x * dv2.z) - (dv1.z * dv2.x);
	out.z = (dv1.y * dv2.x) - (dv1.x * dv2.y);

	out = normalise(out);
	return out;
}

//***************************************************************************
inline float dotProduct( Vector3 &v0, Vector3 &v1 )
{
	float dp = v0.x * v1.x + v0.y * v1.y + v0.z * v1.z;
	return dp;
}

//***************************************************************************
inline bool aprox( float x, float y )
{
	if (fabs(x-y)<0.03)
	{
		return true;
	} else
	{
		return false;
	}
}

//***************************************************************************
inline bool uvaprox( sUV &uv0, sUV &uv1 )
{
	return (aprox(uv0.u, uv1.u) && aprox(uv0.v, uv1.v));
}

//***************************************************************************
CFace	&CFaceStore::AddFace(vector<Vector3> const &P, const sGinTri &T, const sUVTri &uv,GString const &Tex,int ID,bool ProcessTexFlag )
{
//int		ListSize = FaceList.size();
//		FaceList.resize(ListSize+1);
//CFace	&F = FaceList[ListSize];
CFace	F;

		for (int i=0; i<3; i++)
		{
			F.pts[i] = T.p[i];
			F.vis[i] = T.vis[i];
			F.uvs[i] = uv.p[i];
			F.vtx[i] = P[T.p[i]];
// Limit UV's
			if (F.uvs[i].u < 0.f) F.uvs[i].u=0.f;
			if (F.uvs[i].u > 1.f) F.uvs[i].u=1.f;
			if (F.uvs[i].v < 0.f) F.uvs[i].v=0.f;
			if (F.uvs[i].v > 1.f) F.uvs[i].v=1.f;
		}

		F.TexName=Tex;
		F.Mat = -1;
		return(AddFace(F,ProcessTexFlag));
}

//***************************************************************************
CFace	&CFaceStore::AddFace(CFace &F,bool ProcessTexFlag)
{
int		ListSize=FaceList.size();
		FaceList.resize(ListSize+1);

// Process Vtx's
		for (int i=0; i<3; i++)
		{
			F.pts[i]=AddVtx(F.vtx[i]);
		}

		if (ProcessTexFlag && F.Mat==-1)
		{
			F.Mat=AddTex(F.TexName);
		}
		F.Normal = crossProduct( F.vtx[0], F.vtx[1], F.vtx[2] );
		F.Avail = true;

		FaceList[ListSize]=F;
		return(F);
}

//***************************************************************************
void	CFaceStore::AddFaces(vector<CFace> &Faces,bool ProcessTexFlag)
{
int		ListSize=Faces.size();

		for (int i=0 ;i<ListSize ;i++)
		{
			AddFace(Faces[i],ProcessTexFlag);
		}
}

//***************************************************************************
void	CFaceStore::AddFaces(CFaceStore &Faces,bool ProcessTexFlag)
{
int		ListSize=Faces.GetFaceCount();

		for (int i=0 ;i<ListSize ;i++)
		{
			AddFace(Faces[i],ProcessTexFlag);
		}
}

//***************************************************************************
CFace	&CFaceStore::AddFace(sTriFace &Face,int ID)
{
int		ListSize = FaceList.size();
		FaceList.resize(ListSize+1);
CFace	&F = FaceList[ListSize];

	for (int i=0; i<3; i++)
	{
		F.pts[i] = Face.pts[i];
		F.uvs[i] = Face.uvs[i];
		F.vtx[i] = Face.vtx[i];
// Limit UV's
		if (F.uvs[i].u < 0.f) F.uvs[i].u=0.f;
		if (F.uvs[i].u > 1.f) F.uvs[i].u=1.f;
		if (F.uvs[i].v < 0.f) F.uvs[i].v=0.f;
		if (F.uvs[i].v > 1.f) F.uvs[i].v=1.f;
	}

	F.Mat = Face.Mat;
	F.Normal = crossProduct( F.vtx[0], F.vtx[1], F.vtx[2] );
	F.Avail = true;
	F.ID=ID;
	return(F);
}

//***************************************************************************
//*** Texture Stuff *********************************************************
//***************************************************************************
int		CFaceStore::AddTex(GString const &TexName)
{
static	GString	LastTex;
static	int		LastIdx=-1;
vector<FileInfo> const	&TexList=TexGrab->GetTexInfoList();
int		ListSize=TexList.size();

GString	Filename=TexName;
		Filename.Lower();

		LastTex=Filename;

		for (LastIdx=0; LastIdx<ListSize; LastIdx++)
		{
			GString	const &ListName=TexList[LastIdx].GetActualFileName();
			if (ListName==Filename) return(LastIdx);
		}
// Does file exist
		if (!FindFile(TexName))
			GObject::Error(ERR_FATAL,"Texture not found %s!!\n",TexName);

		TexGrab->AddFile(Filename);
		LastIdx=ListSize;
		return(ListSize);
}

//***************************************************************************
void	CFaceStore::ProcessTextures()
{
// Set Texgrab Defaults		
		TexGrab->ShrinkToFit(true);
		TexGrab->NoSort();

		TexGrab->AnimatedHeadersOnly(true);
		TexGrab->DontOutputBoxes(true);
		TexGrab->AllowRotate(true);
		TexGrab->Process();
}

//***************************************************************************
void	CFaceStore::Process()
{
		Quad();
		BuildOutTriLists();
}

//***************************************************************************
//***************************************************************************
//***************************************************************************
void	CFaceStore::Quad()
{
int		FaceCount=FaceList.size();

		for (int i=0; i<FaceCount; i++)
		{
			TriFaceList.push_back(FaceList[i]);
		}
}

//***************************************************************************
//***************************************************************************
//***************************************************************************
/*
void	CFaceStore::SetupUV(CFace const &In, sTri &Out)
{
vector<sTexOutInfo>	&TexInfo=TexGrab->GetTexInfo();
sTexOutInfo			&ThisTex=TexInfo[In.Mat];
ASSERT(In.Mat<TexInfo.size());

// Uses orig tex size to make sure mapping is corrent on 'shrunk' textures :o)			
int		W = ThisTex.OrigW - 1;
int		H = ThisTex.OrigH - 1;
int		XOfs=0,YOfs=0;

int		uv0[2];
int		uv1[2];
int		uv2[2];

		if (ThisTex.Rotated)
		{
//			uv0[0] = (ThisTex.u + H) - round(In.uvs[0].v * H);
//			uv0[1] = (ThisTex.v + W) - round(In.uvs[0].u * W);
//			uv1[0] = (ThisTex.u + H) - round(In.uvs[1].v * H);
//			uv1[1] = (ThisTex.v + W) - round(In.uvs[1].u * W);
//			uv2[0] = (ThisTex.u + H) - round(In.uvs[2].v * H);
//			uv2[1] = (ThisTex.v + W) - round(In.uvs[2].u * W);

			uv0[0] = (ThisTex.u ) - round(In.uvs[0].v * H);
			uv0[1] = (ThisTex.v ) - round(In.uvs[0].u * W);
			uv1[0] = (ThisTex.u ) - round(In.uvs[1].v * H);
			uv1[1] = (ThisTex.v ) - round(In.uvs[1].u * W);
			uv2[0] = (ThisTex.u ) - round(In.uvs[2].v * H);
			uv2[1] = (ThisTex.v ) - round(In.uvs[2].u * W);

			XOfs=H-((ThisTex.OrigW-ThisTex.h));
			YOfs= +((ThisTex.OrigH-ThisTex.w)-W);
			ASSERT(!"");
		} 
		else
		{
			W=ThisTex.w-1;
			H=ThisTex.h-1;
//			Out.uv0[0] = (ThisTex.u)+		round(In.uvs[0].u * W);
//			Out.uv0[1] = (ThisTex.v + H) -	round(In.uvs[0].v * H);
//			Out.uv1[0] = (ThisTex.u)+		round(In.uvs[1].u * W);
//			Out.uv1[1] = (ThisTex.v + H) -	round(In.uvs[1].v * H);
//			Out.uv2[0] = (ThisTex.u)+		round(In.uvs[2].u * W);
//			Out.uv2[1] = (ThisTex.v + H) -	round(In.uvs[2].v * H);

			uv0[0] = (ThisTex.u) +	round(In.uvs[0].u * W);
			uv0[1] = (ThisTex.v) -	round(In.uvs[0].v * H);
			uv1[0] = (ThisTex.u) +	round(In.uvs[1].u * W);
			uv1[1] = (ThisTex.v) -	round(In.uvs[1].v * H);
			uv2[0] = (ThisTex.u) +	round(In.uvs[2].u * W);
			uv2[1] = (ThisTex.v) -	round(In.uvs[2].v * H);

			XOfs=(ThisTex.OrigW-ThisTex.w);
			YOfs=(ThisTex.OrigH-ThisTex.h)-H;
			XOfs=0;
			YOfs=0;
		}

		Out.uv0[0]=uv0[0]-XOfs; Out.uv0[1]=uv0[1]-YOfs;
		Out.uv1[0]=uv1[0]-XOfs; Out.uv1[1]=uv1[1]-YOfs;
		Out.uv2[0]=uv2[0]-XOfs; Out.uv2[1]=uv2[1]-YOfs;

		Out.TPage=ThisTex.Tpage;
		Out.Clut=ThisTex.Clut;
}
*/
void	CFaceStore::SetupUV(CFace const &In, sTri &Out)
{
vector<sTexOutInfo>	&TexInfo=TexGrab->GetTexInfo();
sTexOutInfo			&ThisTex=TexInfo[In.Mat];
ASSERT(In.Mat<TexInfo.size());

int		uv0[2],uv1[2],uv2[2];
int		XOfs=0,YOfs=0;
			
int		W = ThisTex.w - 1;
int		H = ThisTex.h - 1;

		if (ThisTex.Rotated)
		{
			Out.uv0[0] = (ThisTex.u + H) - round(In.uvs[0].v * H);
			Out.uv0[1] = (ThisTex.v + W) - round(In.uvs[0].u * W);
			Out.uv1[0] = (ThisTex.u + H) - round(In.uvs[1].v * H);
			Out.uv1[1] = (ThisTex.v + W) - round(In.uvs[1].u * W);
			Out.uv2[0] = (ThisTex.u + H) - round(In.uvs[2].v * H);
			Out.uv2[1] = (ThisTex.v + W) - round(In.uvs[2].u * W);
			ASSERT(0==1);
		} 
		else
		{
//			W=ThisTex.OrigW-1;
//			H=ThisTex.OrigH-1;
			if (ThisTex.w!=ThisTex.OrigW) printf("WW");
			if (ThisTex.h!=ThisTex.OrigH) printf("HH");
/*
			uv0[0] = (ThisTex.u)+		round(In.uvs[0].u * W);
			uv0[1] = (ThisTex.v + H) -	round(In.uvs[0].v * H);
			uv1[0] = (ThisTex.u)+		round(In.uvs[1].u * W);
			uv1[1] = (ThisTex.v + H) -	round(In.uvs[1].v * H);
			uv2[0] = (ThisTex.u)+		round(In.uvs[2].u * W);
			uv2[1] = (ThisTex.v + H) -	round(In.uvs[2].v * H);
*/
int			U=ThisTex.u;
int			V=ThisTex.v+H;

			uv0[0] = U +	round(In.uvs[0].u * W);
			uv0[1] = V -	round(In.uvs[0].v * H);
			uv1[0] = U +	round(In.uvs[1].u * W);
			uv1[1] = V -	round(In.uvs[1].v * H);
			uv2[0] = U +	round(In.uvs[2].u * W);
			uv2[1] = V -	round(In.uvs[2].v * H);

//			XOfs=(ThisTex.OrigW-ThisTex.w);
//			XOfs=ThisTex.XOfs;
//			YOfs=H-(ThisTex.OrigH-ThisTex.h);
//			YOfs=H;
		}
		
		Out.uv0[0]=(uv0[0]-XOfs); Out.uv0[1]=(uv0[1]-YOfs);
		Out.uv1[0]=(uv1[0]-XOfs); Out.uv1[1]=(uv1[1]-YOfs);
		Out.uv2[0]=(uv2[0]-XOfs); Out.uv2[1]=(uv2[1]-YOfs);

		Out.TPage=ThisTex.Tpage;
		Out.Clut=ThisTex.Clut;
}



//***************************************************************************
void	CFaceStore::SetupUV(CFace const &In, sQuad &Out)
{
vector<sTexOutInfo>	&TexInfo=TexGrab->GetTexInfo();
sTexOutInfo			&ThisTex=TexInfo[In.Mat];

int		W = ThisTex.w - 1;
int		H = ThisTex.h - 1;

		if (ThisTex.Rotated)
		{
			Out.uv0[0] = (ThisTex.u + H) - round(In.uvs[0].v * H);
			Out.uv0[1] = (ThisTex.v + W) - round(In.uvs[0].u * W);
			Out.uv1[0] = (ThisTex.u + H) - round(In.uvs[1].v * H);
			Out.uv1[1] = (ThisTex.v + W) - round(In.uvs[1].u * W);
			Out.uv2[0] = (ThisTex.u + H) - round(In.uvs[2].v * H);
			Out.uv2[1] = (ThisTex.v + W) - round(In.uvs[2].u * W);
			Out.uv3[0] = (ThisTex.u + H) - round(In.uvs[3].v * H);
			Out.uv3[1] = (ThisTex.v + W) - round(In.uvs[3].u * W);
		} 
		else
		{
			Out.uv0[0] = (ThisTex.u)+		round(In.uvs[0].u * W);
			Out.uv0[1] = (ThisTex.v + H) -	round(In.uvs[0].v * H);
			Out.uv1[0] = (ThisTex.u)+		round(In.uvs[1].u * W);
			Out.uv1[1] = (ThisTex.v + H) -	round(In.uvs[1].v * H);
			Out.uv2[0] = (ThisTex.u)+		round(In.uvs[2].u * W);
			Out.uv2[1] = (ThisTex.v + H) -	round(In.uvs[2].v * H);
			Out.uv3[0] = (ThisTex.u)+		round(In.uvs[3].u * W);
			Out.uv3[1] = (ThisTex.v + H) -	round(In.uvs[3].v * H);
		}

		Out.TPage=ThisTex.Tpage;
		Out.Clut=ThisTex.Clut;
}



//***************************************************************************
int		CFaceStore::AddVtx(Vector3 &InVtx)
{
int		ListSize=OutVtxList.size();
sVtx	ThisVtx;

		ThisVtx.vx=round(InVtx.x*Scale);
		ThisVtx.vy=round(InVtx.y*Scale);
		ThisVtx.vz=round(InVtx.z*Scale);

		for (int i=0; i<ListSize; i++)
		{
			if (OutVtxList[i]==ThisVtx) return(i);
		}

		OutVtxList.push_back(ThisVtx);
		return(ListSize);
}

//***************************************************************************
void	CFaceStore::BuildOutTriLists()
{
int		FaceCount=TriFaceList.size();

		OutTriList.resize(FaceCount);

		for (int i=0; i<FaceCount; i++)
		{
			CFace	&InFace=TriFaceList[i];
			sTri	&OutFace=OutTriList[i];

			OutFace.P0=InFace.pts[0];
			OutFace.P1=InFace.pts[1];
			OutFace.P2=InFace.pts[2];
// Materials and other shit
			SetupUV(InFace,OutFace);
		}

}

//***************************************************************************
void	CFaceStore::BuildOutQuadList()
{
/*
int		FaceCount=QuadFaceList.size();
		OutQuadList.resize(FaceCount);
		for (int i=0; i<FaceCount; i++)
		{
			CFace	&InFace=QuadFaceList[i];
			sQuad	&OutFace=OutQuadList[i];

			OutFace.P0=AddVtx(InFace.vtx[0]*Scale);
			OutFace.P1=AddVtx(InFace.vtx[1]*Scale);
			OutFace.P2=AddVtx(InFace.vtx[2]*Scale);
			OutFace.P3=AddVtx(InFace.vtx[3]*Scale);

// Materials and other shit
			SetupUV(InFace,OutFace);
		}
*/
}

//***************************************************************************
//***************************************************************************
//***************************************************************************
int		CFaceStore::WriteTriList(FILE *File,vector<sTri> &List)
{
int		ListSize=List.size();
int		Pos=ftell(File);

		for (int i=0; i<ListSize; i++)
		{
			sTri	ThisTri=List[i];
			fwrite(&ThisTri,1,sizeof(sTri),File);
		}
		return(Pos);
}

//***************************************************************************
int		CFaceStore::WriteQuadList(FILE *File,vector<sQuad> &List)
{
int		ListSize=List.size();
int		Pos=ftell(File);

		for (int i=0; i<ListSize; i++)
		{
			sQuad	&ThisQuad=List[i];
			fwrite(&ThisQuad,1,sizeof(sQuad),File);
		}
		return(Pos);
}

//***************************************************************************
int		CFaceStore::WriteVtxList(FILE *File,vector<sVtx> &List)
{
int		ListSize=List.size();
int		Pos=ftell(File);

		for (int i=0; i<ListSize; i++)
		{
			sVtx	&ThisVtx=List[i];
			fwrite(&ThisVtx,1,sizeof(sVtx),File);
		}
		return(Pos);
}

//***************************************************************************
//***************************************************************************
//***************************************************************************
//***************************************************************************
//***************************************************************************
//***************************************************************************
//***************************************************************************
#if	0	// quadding stuff
bool CFaceStore::CanConnect( int f0, int f1 )
{
	CFace &F0 = FaceList[f0];
	CFace &F1 = FaceList[f1];

	// check ID's match (used for nodes, weights)
	if (F0.ID!=F1.ID) return false;

	// check materials match
	if (F0.Mat != F1.Mat) return false;

	// check normals
	float dp = dotProduct( F0.Normal, F1.Normal );
	if (dp < 0.98f)
		return false;

	// check pnt connections
	bool found = false;
	int  chkp00 ;
	int  chkp01 ;
	int  chkp10 ;
	int  chkp11 ;
	for (int i=0; i<3 && !found; i++)
	{
		int npi = (i + 1)%3;
		for (int j=0; j<3 && !found; j++)
		{
			int npj = (j + 1)%3;
			if (F0.pts[i] == F1.pts[npj] && F0.pts[npi] == F1.pts[j])
			{
				chkp00 = i;
				chkp01 = npi;
				chkp10 = j;
				chkp11 = npj;
				found = true;
			}
		}
	}

	if (found)
	{
		// check uv
		return (uvaprox(F0.uvs[chkp00], F1.uvs[chkp11]) && uvaprox(F0.uvs[chkp01], F1.uvs[chkp10]));
	}

	return false;
}

//***************************************************************************
int CFaceStore::GetUnconnectedPoint(int f0, int f1, int &f0p0, int &f0p1 )
{
	CFace &F0 = FaceList[f0];
	CFace &F1 = FaceList[f1];

	for (int i=0; i<3; i++)
	{
		int npi = (i + 1)%3;
		for (int j=0; j<3; j++)
		{
			int npj = (j + 1)%3;
			if (F0.pts[i] == F1.pts[npj] && F0.pts[npi] == F1.pts[j])
			{
				int cp = (j+2) % 3;
				f0p0 = F0.pts[i];
				f0p1 = F0.pts[npi];
				return cp;
			}
		}
	}

	return -1;
}

//***************************************************************************
int CFaceStore::CountFacesAttached ( int f )
{
	int count = 0;
	int c = FaceList.size();

	for (int i=0; i<c; i++)
	{
		if (FaceList[i].avail && i!=f)
		{
			if (CanConnect(f, i))
			{
				count ++;
			}
		}
	}
	
	return count;
}

//***************************************************************************
void CFaceStore::FollowFace( int id, CFace &F )
{
	int minF = -1;
	int minC = 9999;
	int c = FaceList.size();
	for (int i=0; i<c; i++)
	{
		if (FaceList[i].avail && id != i && CanConnect(id, i))
		{
			int fec = CountFacesAttached( i );
			if (fec < minC)
			{
				minF = i;
				minC = fec;
			}
		}
	}

	CFace &nf = FaceList[minF];

	int ptc = F.pts.size();
	int v0, v1;
	int unc = GetUnconnectedPoint( id, minF, v0, v1);

	for (int j=0; j<ptc; j++) if (F.pts[j] == v1) break;

	
	if (j != (ptc-1))
	{
		int idx = (j+1)%ptc;
		vector<int>::iterator pb, pe, pm;
		vector<sUV>::iterator ub, ue, um;
		vector<Vector3>::iterator vb, ve, vm;
		pb = F.pts.begin();	pe = F.pts.end();
		ub = F.uvs.begin();	ue = F.uvs.end();
		vb = F.vtx.begin();	ve = F.vtx.end();

		pm = pb + idx;
		um = ub + idx;
		vm = vb + idx;

		rotate(pb, pm, pe);
		rotate(ub, um, ue);
		rotate(vb, vm, ve);
	}

	for (j=0; j<ptc; j++) if (F.pts[j] == v0)	break;

	if (j != (ptc-2))
	{
		int idx = (j+1)%ptc;
		vector<int>::iterator pb, pe, pm;
		vector<sUV>::iterator ub, ue, um;
		vector<Vector3>::iterator vb, ve, vm;
		pb = F.pts.begin();	pe = F.pts.end()-1;
		ub = F.uvs.begin();	ue = F.uvs.end()-1;
		vb = F.vtx.begin();	ve = F.vtx.end()-1;

		pm = pb + idx;
		um = ub + idx;
		vm = vb + idx;

		rotate(pb, pm, pe);
		rotate(ub, um, ue);
		rotate(vb, vm, ve);
	}

	F.pts.resize(ptc+1);
	F.vtx.resize(ptc+1);
	F.uvs.resize(ptc+1);

	F.pts[ptc] = nf.pts[unc];
	F.vtx[ptc] = nf.vtx[unc];
	F.uvs[ptc] = nf.uvs[unc];
	nf.avail = false;

	if (minC && MaxStrip>F.pts.size()) FollowFace( minF, F );
}

//***************************************************************************
bool	CFaceStore::GetFace( CFace &F )
{
int		minF = -1;
int		minC = 9999;
int		c = FaceList.size();

	for (int i=0; i<c; i++)
		{
		if (FaceList[i].avail)
			{
			int fec = CountFacesAttached( i );
			if (fec < minC)
				{
				minF = i;
				minC = fec;
				}
			}
		}

	if (minF == -1)
		return false;

	F.Mat = FaceList[minF].Mat;
	F.pts = FaceList[minF].pts;
	F.uvs = FaceList[minF].uvs;
	F.vtx = FaceList[minF].vtx;
	FaceList[minF].avail = false;
	F.Normal= FaceList[minF].Normal;
	F.ID= FaceList[minF].ID;

	if (minC && MaxStrip>F.pts.size()) FollowFace( minF, F );

	return true;
}

/*****************************************************************************/
/*****************************************************************************/
/*****************************************************************************/
void	CFaceStore::QuadGetPnts(CFace &F,int *Join0,int *Join1,int *Pnt)
{
		if (!F.vis[0])
			{
			*Join0=	F.pts[0];
			*Join1=	F.pts[1];
			*Pnt=	2;
			}
		else
		if (!F.vis[1])
			{
			*Join0=	F.pts[1];
			*Join1=	F.pts[2];
			*Pnt=	0;
			}
		else
			{
			*Join0=	F.pts[2];
			*Join1=	F.pts[0];
			*Pnt=	1;
			}
}

//***************************************************************************
int		CFaceStore::QuadGetAttached(int FaceNo)
{
CFace	ThisFace=FaceList[FaceNo];
int		Vis=ThisFace.vis[0]+ThisFace.vis[1]+ThisFace.vis[2];
		if (Vis==7) return(0);	// Pure Tri
int		FaceCount=FaceList.size();
int		J00,J01,P0;
int		J10,J11,P1;

		QuadGetPnts(ThisFace,&J00,&J01,&P0);
	
		for (int Loop=FaceNo+1;Loop<FaceCount;Loop++)
			{
			CFace	&cFace=FaceList[Loop];
			if (cFace.avail)
				{
				if (ThisFace.Normal.x==cFace.Normal.x &&
					ThisFace.Normal.y==cFace.Normal.y &&
					ThisFace.Normal.z==cFace.Normal.z)
					{
					if (ThisFace.Mat==cFace.Mat && ThisFace.ID==cFace.ID)
						{
						QuadGetPnts(cFace,&J10,&J11,&P1);
						if ((J00==J10 && J01==J11) || (J00==J11 && J01==J10)) return(Loop);
						}
					}
				}
			}

	return(0);
}

//***************************************************************************
void CFaceStore::OrderPnts( CFace &F ,int unc)
{
int	idx;
	if (!F.vis[0]) idx=2;
	if (!F.vis[1]) idx=0;
	if (!F.vis[2]) idx=1;

	{
		vector<int>::iterator pb, pe, pm;
		vector<sUV>::iterator ub, ue, um;
		vector<Vector3>::iterator vb, ve, vm;
		pb = F.pts.begin();	pe = F.pts.end();
		ub = F.uvs.begin();	ue = F.uvs.end();
		vb = F.vtx.begin();	ve = F.vtx.end();

		pm = pb + idx;
		um = ub + idx;
		vm = vb + idx;

		rotate(pb, pm, pe);
		rotate(ub, um, ue);
		rotate(vb, vm, ve);
	}

}

//***************************************************************************
void	CFaceStore::Quad(vector<CFace> &TriList,vector<CFace> &QuadList)
{
int	FaceCount=FaceList.size();

	if (MaxStrip==4)
	{
//vector<CFace> ThisTriList;
	for (int Loop=0;Loop<FaceCount;Loop++)
	{
		if (FaceList[Loop].avail)
		{
			int	Att=QuadGetAttached(Loop);
			if (Att)
			{
				CFace &F=FaceList[Loop];
				CFace &NF=FaceList[Att];
				int	J0,J1,P;
				QuadGetPnts(NF,&J0,&J1,&P);
				FaceList[Loop].avail=FaceList[Att].avail=false;
				OrderPnts(F,P);
				F.pts.push_back(NF.pts[P]);
				F.vtx.push_back(NF.vtx[P]);
				F.uvs.push_back(NF.uvs[P]);
				QuadList.push_back(F);
			}
		}
	}

// Strip remaining tris
//	for (Loop=0;Loop<FaceCount;Loop++)
//		{
//		if (FaceList[Loop].avail) ThisTriList.push_back(FaceList[Loop]);
//		}

		bool strips = true;
		while (strips)
			{
			CFace f;
			strips = GetFace( f );
			if (strips)
				{
				if (f.pts.size() == 3)
					TriList.push_back(f); 
				else
					QuadList.push_back(f); 
				}
			}
//		printf("Quaded %i extra\n",ThisTriList.size()-TriList.size());
		}
	else
		{	// No quadding, copy direct
		for (int Loop=0;Loop<FaceCount;Loop++) TriList.push_back(FaceList[Loop]);
		}
}
#endif