#include "view.h"


/*for LiteFace*/

LiteFace *newLiteFace(vertex,i)
Vertex *vertex;
int i;
{
	LiteFace *p;
	
	p = Malloc(LiteFace,1);
	p->vertex = vertex;
	
	p->first = newIndex(i);
	p->last = p->first;
	p->last->next = p->first;
	p->size = 1;
	p->coeff = NOPLANEQ;
	return(p);
}

void addToFrontLiteFace(poly,i)
LiteFace *poly;
int i;
{
	poly->first = addToFrontIndex(poly->first,i);
	poly->last->next = poly->first;
	++poly->size;
}


void addToBackLiteFace(poly,i)
LiteFace *poly;
int i;
{
	poly->last = addToBackIndex(poly->last,i);
	poly->last->next = poly->first;
	++poly->size;
}



void splitLiteFace(poly,plane,c,ind1,ind2,t,frontP,backP)
/*
  split poly into two between indices ind1 and ind2.
  t is the t value for the intersection.
*/
LiteFace *poly;
PlaneEq *plane;
Classification c;
Index *ind1,*ind2;
REAL t;
LiteFacePtr *frontP,*backP;
{
	Vertex *v;
	Point3D *p1,*p2,*p;
	int k1,k2;
	Index *i1,*i2;
	Classification c1,c2,cn;
	REAL x,y,z,d1,d2;
	LiteFace *theFront,*theBack;
	PlaneEq *pe;
	
	/*get the end points of the split edge*/
	v = VERTEXOfFace(poly);	
	p1 = GETPointFromIndex(v,ind1);	
	p2 = GETPointFromIndex(v,ind2);	
		
	/*and compute the new point - inserting into the vertex list*/
	x = X(*p1) + (X(*p2) - X(*p1))*t;
	y = Y(*p1) + (Y(*p2) - Y(*p1))*t;
	z = Z(*p1) + (Z(*p2) - Z(*p1))*t;
	p = newPoint3D(x,y,z);
	k1 = NEXTFreeVertex(v);
	atPutVertex(v,k1,p);
		
	i2 = ind2;
	if(c==FRONT_BACK) c1 = BACK; else c1 = FRONT;
	c2 = c1;
	/*
	classifyPoint3D(plane,p2,&d2);
	*/
	CLASSIFYPoint3D(plane,(*p2),d2,cn);

	/*this is worked out as if going from FRONT to BACK*/
	/*start off the back face with this point and p2*/
	theBack = newLiteFace(v,k1);
	while(c2 == c1){
		addToBackLiteFace(theBack,INDEX(i2));
		i1 = i2;
		d1 = d2;
		i2 = NEXT(i2);
		p2 = GETPointFromIndex(v,i2);	
		/*
		c2 = addClassification(c2,classifyPoint3D(plane,p2,&d2));
		*/
		CLASSIFYPoint3D(plane,(*p2),d2,cn);
		ADDClassification(c2,cn,c2);
	}
		
	/*here c2 must be BACK_FRONT and the split is between i1, i2*/
	p1 = GETPointFromIndex(v,i1);	
	p2 = GETPointFromIndex(v,i2);				
	t = d1/(d1-d2);
	x = X(*p1) + (X(*p2) - X(*p1))*t;
	y = Y(*p1) + (Y(*p2) - Y(*p1))*t;
	z = Z(*p1) + (Z(*p2) - Z(*p1))*t;
	p = newPoint3D(x,y,z);
	k2 = NEXTFreeVertex(v);
	atPutVertex(v,k2,p);
	addToBackLiteFace(theBack,k2);
		
	theFront = newLiteFace(v,k2);
	while(i2 != ind2){
		addToBackLiteFace(theFront,INDEX(i2));
		i2 = NEXT(i2);
	}
	addToBackLiteFace(theFront,k1);
		
	if(c == FRONT_BACK){
		*frontP = theFront;
		*backP = theBack;
	}
	else{
		*frontP = theBack;
		*backP = theFront;
	}
	
	/*finally give frontP and backP the same plane equation
	   as the original polygon*/
	pe = copyPlaneEqOfFace(poly);
	(*frontP)->coeff = pe;
	pe = copyPlaneEqOfFace(poly);
	(*backP)->coeff = pe;
	/*note - had to make sure that all these pointers are different*/
}


Classification classifyLiteFace(poly,plane,frontP,backP)
/*
  returns the classification of the face with respect
  to the plane. If the classification is CUT then frontP
  and backP are the respective new polygons
*/
LiteFace *poly;
PlaneEq *plane;
LiteFacePtr *frontP,*backP;
{
	Classification c,c1,c2,cn;
	REAL d1,d2;
	register int i,n;
	Index *ind,*ind2,*first,*last;
	Vertex *v;
	Point3D *p;
	REAL t;
	
	*frontP = *backP = NOLITEFACE;
	
	v = VERTEXOfFace(poly);	
		
	/*get the classification for the first point*/
	ind = first = FIRSTOfFace(poly);
	last = LASTOfFace(poly);	
	
	p = GETPointFromIndex(v,first);	
	/*
	c = classifyPoint3D(plane,p,&d1);
	*/
	CLASSIFYPoint3D(plane,(*p),d1,c);
	
	while(ind != last){
		ind2 = NEXT(ind);
		p = GETPointFromIndex(v,ind2);
		/*
		c2 = addClassification(c,classifyPoint3D(plane,p,&d2));
		*/
		CLASSIFYPoint3D(plane,(*p),d2,cn);
		ADDClassification(c,cn,c2);
		if(c2 == FRONT_BACK || c2 == BACK_FRONT) {
			t = d1/(d1-d2);
			splitLiteFace(poly,plane,c2,ind,ind2,t,frontP,backP);
			return(c2);
		}
		else{
			c = c2;
			ind = ind2;
			d1 = d2;
		}
	} 
			
	/*closure - note if the plane intersected this last edge
				then this would have already happened*/
	return(c);
}
			


/*for LiteFaceList*/

LiteFaceList *newLiteFaceList(size)
int size;
{
	LiteFaceList *f;
	int i;
	
	f = Malloc(LiteFaceList,1);
	f->n = 0;
	f->size = size;
	f->face = Malloc(LiteFacePtr,size);
	for(i=0;i<size;++i) *(f->face+i) = NOLITEFACE;
	return(f);
}

void reinitialiseLiteFaceList(facelist)
LiteFaceList *facelist;
{
	register int i;
	facelist->n = 0;
	for(i=0;i<facelist->size;++i) *(facelist->face+i) = NOLITEFACE;
}


LiteFace *atLiteFaceList(f,i)
LiteFaceList *f;
int i;
{
	return(*(f->face+i));
}


void setNextFreeLiteFaceList(f)
LiteFaceList *f;
{
	int i;
	
	i = f->n;
	while(atLiteFaceList(f,i) != NOLITEFACE) ++i;
	f->n = i;
}


void atPutLiteFaceList(f,i,poly)
LiteFaceList *f;
int i;
LiteFacePtr poly;
{
	if(f->n >= f->size){
		printf("Out of space in LiteFaceList\n");
		EXIT;
	}
	*(f->face+i) = poly;
	setNextFreeLiteFaceList(f);
}


Index *makeSetFromLiteFaceList(f)
LiteFaceList *f;
{
	Index *ind,*last;
	register int i;
	
	ind = last = NOINDEX;
	for(i=0; i<NEXTFreeFaceList(f); ++i)
		if(atLiteFaceList(f,i) != NOLITEFACE) appendToIndex(&ind,i,&last);
	return(ind);
}