/********************************************************************/
/*   STRIPE: converting a polygonal model to triangle strips    
     Francine Evans, 1996.
     SUNY @ Stony Brook
     Advisors: Steven Skiena and Amitabh Varshney
*/
/********************************************************************/

/*---------------------------------------------------------------------*/
/*   STRIPE: sgi_triang.c
     File contains the routines that do the whole triangulation
     of polygons.
*/
/*---------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "global.h"
#include "output.h"
#include "polverts.h"
#include "sturcts.h"
#include "common.h"
#include "util.h"
#include "init.h"

int Adjacent(int id2,int id1, int *list, int size)
{
	/*	Return the vertex that is adjacent to id1,
		but is not id2, in the list of integers.
	*/

	register int x=0;
	
	while (x < size)
	{
		if (*(list+x) == id1)
		{
			if ((x != (size -1)) && (x != 0))
			{
				if ( *(list+x+1) != id2)
					return *(list+x+1);
				else
					return *(list+x-1);
			}
			else if (x == (size -1))
			{
				if (*(list) != id2)
					return *(list);
				else
					return *(list+x-1);
			}
			else
			{
				if (*(list+size-1) != id2)
					return *(list+size-1);
				else
					return *(list+x+1);
			}
		}
		x++;
	}
	/*   if there are degeneracies */
     return id1;
}


void Rearrange_Index(int *index, int size)
{
	/*	If we are in the middle of a strip we must find the
		edge to start on, which is the last edge that we had
		transmitted.
	*/
	int x,f,y,e1,e2,e3;
 	register int increment = 1;
     int *temp;

	/*	Find where the input edge is in the input list */
	Last_Edge(&e1,&e2,&e3,0);
	for (y = 0; y < size; y++)
	{
		if (*(index+y) == e2)
		{
			if ((y != (size - 1)) && (*(index+y+1) == e3))
				break;
			else if ((y == (size - 1)) && (*(index) == e3))
				break;
               else if ((y != 0) && (*(index+y-1) == e3))
               {
                    increment = -1;
                    break;
               }
               else if ((y==0) && (*(index+size-1) == e3))
               {
                    increment = -1;
                    break;
               }
		}
		if (*(index+y) == e3)
		{
			if ((y != (size - 1)) && (*(index+y+1) == e2))
				break;
			else if ((y == (size - 1)) && (*(index) == e2))
				break;
            else if ((y != 0) && (*(index+y-1) == e2))
            {
                increment = -1;
                break;
            }
            else if ((y==0) && (*(index+size-1) == e2))
            {
                increment = -1;
                break;
            }
		}
		/*	Edge is not here, we are at the beginning */
		if ((y == (size-1)) && (increment != -1))
			return;
	}
	
	/*	Now put the list into a new list, starting with the
		input edge. Increment tells us whether we have to go 
		forward or backward.
	*/
	/*	Was in good position already */
	if ((y == 0) && (increment == 1)) 
		return;
	
     temp = (int *) malloc(sizeof(int) * size);
     memcpy(temp,index,sizeof(int)*size);

	if (increment == 1)
	{
		x=0;
		for (f = y ; f< size; f++)
		{
			*(index+x) = *(temp+f);
			x++;
		}
		/*	Finish the rest of the list */	
		for(f = 0; f < y ; f++)
		{
			*(index+x) = *(temp+f);
			x++;
		}
	}
	else
	{
		x=0;
		for (f = y ; f >= 0; f--)
		{
			*(index+x) = *(temp+f);
			x++;
		}
		/*	Finish the rest of the list */	
		for(f = (size - 1); f > y ; f--)
		{
			*(index+x) = *(temp+f);
			x++;
		}
	}
}

void Delete_From_List(int id,int *list, int *size)
{
	/*	Delete the occurence of id in the list.
		(list has size size)
	*/

	int *temp;
	register int x,y=0;

	temp = (int *) malloc(sizeof(int) * (*size));
	for (x=0; x<(*size); x++)
	{
		if (*(list+x) != id)
		{
			*(temp+y) = *(list+x);
			y++;
		}
	}
	*(temp+y) = -1;
     *size = *size - (*size - y - 1);
	memcpy(list,temp,sizeof(int)*(*size));
}


void Build_SGI_Table(int num_verts,int num_faces)
{
	/*      Build a table that has the polygons sorted by the
	        number of adjacent polygons.
	*/
	int x,y,size,tally=0;
	ListHead *pListHead;
	PF_FACES temp = NULL;

	/* For each face....*/
	for (x=0;x < num_faces;x++)
	{
		pListHead = PolFaces[x];
		temp = ( PF_FACES ) PeekList( pListHead, LISTHEAD, 0 );
		/*   Check each edge of the face and tally the number of adjacent
			polygons to this face. 
		*/                      
		if ( temp != NULL )
		{
			/*      Size of the polygon */
			size = temp->nPolSize;
			if (size != 1)
               {
                    for (y = 0; y< size; y++)
			     {
				     if (y != (size-1))
					     tally += Num_Adj(*(temp->pPolygon+y),*(temp->pPolygon+y+1));
				     else
					     tally += Num_Adj(*(temp->pPolygon),*(temp->pPolygon+(size-1)));
                    }
			
			     /*   Tally is the number of polygons that is adjacent to
				     the current polygon. 
			     */
			     /*      Now put the face in the proper bucket depending on tally. */
			     Add_Sgi_Adj(tally,x);
			     temp = NULL;
			     tally=0;
               }
		}
	}
}


void Triangulate_Quad(int out_edge1,int out_edge2,int in_edge1,
					  int in_edge2,int size,int *index,
					  FILE *output,int reversed,int face_id,
                      int where,int color1,int color2,int color3)
{
	int vertex4,vertex5;
	
	/*	This routine will nonblindly triangulate a quad, meaning
		that there is a definite input and a definite output
		edge that we must adhere to. Reversed will tell the orientation
		of the input edge. (Reversed is -1 is we do not have an input
		edge, in other words we are at the beginning of a strip.)
		Out_edge* is the output edge, and in_edge* is the input edge. 
		Index are the edges of the polygon
		and size is the size of the polygon. Begin is whether we are
		at the start of a new strip.
	*/
	
	/*	If we do not have an input edge, then we can make our input
		edge whatever we like, therefore it will be easier to come
		out on the output edge.
	*/
	if (reversed == -1)
	{
		vertex4 = Adjacent(out_edge1,out_edge2,index,size);
		vertex5 = Get_Other_Vertex(vertex4,out_edge1,out_edge2,index);
		Output_Tri(vertex5,vertex4,out_edge1,output,color1,color2,color3,where);
		Output_Tri(vertex4,out_edge1,out_edge2,output,color1,color2,color3,where);
		return;
	}
	
	/*	These are the 5 cases that we can have for the output edge */
	
	/*  Are they consecutive so that we form a triangle to
		peel off, but cannot use the whole quad?
	*/

	if (in_edge2 == out_edge1) 
	{
		/*	Output the triangle that comes out the correct
			edge last. First output the triangle that comes out
			the wrong edge.
		*/
		vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge2,index);
          Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
          Output_Tri(vertex4,in_edge2,out_edge2,output,color1,color2,color3,where);
		return;
	}
	/*	The next case is where it is impossible to come out the
		edge that we want. So we will have to start a new strip to
		come out on that edge. We will output the one triangle
		that we can, and then start the new strip with the triangle
		that comes out on the edge that we want to come out on.
	*/
	else if (in_edge1 == out_edge1)
	{
		/*	We want to output the first triangle (whose output
			edge is not the one that we want.
			We have to find the vertex that we need, which is
			the other vertex which we do not have.
		*/
		vertex4 = Get_Other_Vertex(in_edge2,in_edge1,out_edge2,index);
		Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where);
		Output_Tri(vertex4,in_edge1,out_edge2,output,color1,color2,color3,where);
		return;
	}
	
	/*	Consecutive cases again, but with the output edge reversed */
	else if (in_edge1 == out_edge2)
	{
		vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
		Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where);
		Output_Tri(vertex4,in_edge1,out_edge1,output,color1,color2,color3,where);
		return;
	}
	else if (in_edge2 == out_edge2)
	{
		vertex4 = Get_Other_Vertex(in_edge1,in_edge2,out_edge1,index);
		Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
		Output_Tri(vertex4,in_edge2,out_edge1,output,color1,color2,color3,where);
		return;
	}

	/*	The final case is where we want to come out the opposite
		edge.
	*/
	else
	{
            if( ((!reversed) && (out_edge1 == (Adjacent(in_edge1,in_edge2,index,size)))) ||
                    ((reversed) && (out_edge2 == (Adjacent(in_edge2,in_edge1,index,size)))))
			{
			/*	We need to know the orientation of the input
				edge, so we know which way to put the diagonal.
                And also the output edge, so that we triangulate
                correctly.
             */
			Output_Tri(in_edge1,in_edge2,out_edge2,output,color1,color2,color3,where);
			Output_Tri(in_edge2,out_edge2,out_edge1,output,color1,color2,color3,where);
		}
		else
		{
			/*      Input and output orientation was reversed, so diagonal will
					be reversed from above.
			*/
			Output_Tri(in_edge1,in_edge2,out_edge1,output,color1,color2,color3,where);
			Output_Tri(in_edge2,out_edge1,out_edge2,output,color1,color2,color3,where);
		}
		return;
	}
}

void Triangulate_Polygon(int out_edge1,int out_edge2,int in_edge1,
						 int in_edge2,int size,int *index,
						 FILE *output,int reversed,int face_id,
                         int where,int color1,int color2,int color3)
{
	/*	We have a polygon that we need to nonblindly triangulate.
		We will recursively try to triangulate it, until we are left
		with a polygon of size 4, which can use the quad routine
		from above. We will be taking off a triangle at a time
		and outputting it. We will have 3 cases similar to the
		cases for the quad above. The inputs to this routine
		are the same as for the quad routine.
	*/

	int vertex4;
	int *temp;

		
	/*	Since we are calling this recursively, we have to check whether
		we are down to the case of the quad.
	*/
	
    if (size == 4)
	{
		Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
							index,output,reversed,face_id,where,color1,color2,color3);
		return;
	}

    
	
	/*	We do not have a specified input edge, and therefore we
		can make it anything we like, as long as we still come out 
		the output edge that we want.
	*/
	if (reversed  == -1)
	{
		/*	Get the vertex for the last triangle, which is
			the one coming out the output edge, before we do
			any deletions to the list. We will be doing this
			bottom up.
		*/
		vertex4 = Adjacent(out_edge1,out_edge2,index,size);
		temp = (int *) malloc(sizeof(int) * size);
		memcpy(temp,index,sizeof(int)*size);
		Delete_From_List(out_edge2,index,&size);
		Triangulate_Polygon(out_edge1,vertex4,in_edge2,
						 vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
		memcpy(index,temp,sizeof(int)*size);
		/*	Lastly do the triangle that comes out the output
			edge.
		*/
		Output_Tri(vertex4,out_edge1,out_edge2,output,color1,color2,color3,where,where);
		return;
	}

	/*	These are the 5 cases that we can have for the output edge */
	
	/*  Are they consecutive so that we form a triangle to
		peel off that comes out the correct output edge, 
		but we cannot use the whole polygon?
	*/
	if (in_edge2 == out_edge1) 
	{
		/*	Output the triangle that comes out the correct
			edge last. First recursively do the rest of the
			polygon.
		*/
		/*	Do the rest of the polygon without the triangle. 
			We will be doing a fan triangulation.
		*/
		/*	Get the vertex adjacent to in_edge1, but is not
			in_edge2.
		*/
		vertex4 = Adjacent(in_edge2,in_edge1,index,size);
		Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where);
		/*	Create a new edgelist without the triangle that
			was just outputted.
		*/
		temp = (int *) malloc(sizeof(int) * size);
		memcpy(temp,index,sizeof(int)*size);
          Delete_From_List(in_edge1,index,&size);
		Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
						vertex4,size-1,index,output,!reversed,face_id,where,color1,color2,color3);
		memcpy(index,temp,sizeof(int)*size);
		return;
	}

	/*	Next case is where it is again consecutive, but the triangle
		formed by the consecutive edges do not come out of the
		correct output edge. For this case, we can not do much to
		keep it sequential. Try and do the fan.
	*/
	else if (in_edge1 == out_edge1)
	{
		/*	Get vertex adjacent to in_edge2, but is not in_edge1 */
		vertex4 = Adjacent(in_edge1,in_edge2,index,size);
		Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where,where);
		/*	Since that triangle goes out of the polygon (the
			output edge of it), we can make our new input edge
			anything we like, so we will try to make it good for
			the strip. (This will be like starting a new strip,
			all so that we can go out the correct output edge.)
		*/
		temp = (int *) malloc(sizeof(int) * size);
		memcpy(temp,index,sizeof(int)*size);
		Delete_From_List(in_edge2,index,&size);
		Triangulate_Polygon(out_edge1,out_edge2,in_edge1,
						vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
		memcpy(index,temp,sizeof(int)*size);
		return;
	}
	/*	Consecutive cases again, but with the output edge reversed */
	else if (in_edge1 == out_edge2)
	{
		/*	Get vertex adjacent to in_edge2, but is not in_edge1 */
		vertex4 = Adjacent(in_edge1,in_edge2,index,size);
		Output_Tri(in_edge2,in_edge1,vertex4,output,color1,color2,color3,where,where);
		temp = (int *) malloc(sizeof(int) * size);
		memcpy(temp,index,sizeof(int)*size);
		Delete_From_List(in_edge2,index,&size);
          Triangulate_Polygon(out_edge1,out_edge2,in_edge1,
						vertex4,size-1,index,output,reversed,face_id,where,color1,color2,color3);
		memcpy(index,temp,sizeof(int)*size);
		return;
	}
	else if (in_edge2 == out_edge2)
	{
		/*	Get vertex adjacent to in_edge2, but is not in_edge1 */
		vertex4 = Adjacent(in_edge2,in_edge1,index,size);
		Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where,where);
		temp = (int *) malloc(sizeof(int) * size);
		memcpy(temp,index,sizeof(int)*size);
		Delete_From_List(in_edge1,index,&size);
          Triangulate_Polygon(out_edge1,out_edge2,vertex4,
						in_edge2,size-1,index,output,reversed,face_id,where,color1,color2,color3);
		memcpy(index,temp,sizeof(int)*size);
		return;
	}

	/*	Else the edge is not consecutive, and it is sufficiently
		far away, for us not to make a conclusion at this time.
		So we can take off a triangle and recursively call this
		function.
	*/
	else
	{
			vertex4 = Adjacent(in_edge2,in_edge1,index,size);
			Output_Tri(in_edge1,in_edge2,vertex4,output,color1,color2,color3,where,where);
			temp = (int *) malloc(sizeof(int) * size);
			memcpy(temp,index,sizeof(int)*size);
			Delete_From_List(in_edge1,index,&size);
               Triangulate_Polygon(out_edge1,out_edge2,in_edge2,
						     vertex4,size-1,index,output,!reversed,face_id,where,color1,color2,color3);
			memcpy(index,temp,sizeof(int)*size);
		     return;
	}
}

void Triangulate(int out_edge1,int out_edge2,int in_edge1,
				 int in_edge2,int size,int *index,
				 FILE *output,int reversed,int face_id, int where,
                     int color1, int color2,int color3)
{
	/*	We have the info we need to triangulate a polygon */

	if (size == 4)
		Triangulate_Quad(out_edge1,out_edge2,in_edge1,in_edge2,size,
			            index,output,reversed,face_id,where,color1,color2,color3);
	else
		Triangulate_Polygon(out_edge1,out_edge2,in_edge1,in_edge2,size,
			               index,output,reversed,face_id,where,color1,color2,color3);
}

void Non_Blind_Triangulate(int size,int *index,
					  FILE *output,int next_face_id,int face_id,int where,
                           int color1,int color2,int color3)
{
	int id1,id2,id3;
	int nedge1,nedge2;
	int reversed;
	/*	We have a polygon that has to be triangulated and we cannot
		do it blindly, ie we will try to come out on the edge that
		has the least number of adjacencies
	*/

	Last_Edge(&id1,&id2,&id3,0);
	/*	Find the edge that is adjacent to the new face ,
		also return whether the orientation is reversed in the
		face of the input edge, which is id2 and id3.
	*/
	if (next_face_id == -1)
     {
        printf("The face is -1 and the size is %d\n",size);
        exit(0);
     }
    
     reversed = Get_Edge(&nedge1,&nedge2,index,next_face_id,size,id2,id3);
	/*	Do the triangulation */
	
	/*	If reversed is -1, the input edge is not in the polygon, therefore we can have the
		input edge to be anything we like, since we are at the beginning
		of a strip
	*/
	Triangulate(nedge1,nedge2,id2,id3,size,index,output,reversed,
		       face_id, where,color1,color2,color3);
}



void Blind_Triangulate(int size, int *index, FILE *output,
				   BOOL begin, int where ,int color1,int color2,
                       int color3)
{
	/*	save sides in temp array, we need it so we know
		about swaps.
	*/
	int mode, decreasing,increasing,e1,e2,e3;
	int x = 0;
	BOOL flag = FALSE;

	/*	Rearrange the index list so that the input edge is first
	*/
	if (!begin)
		Rearrange_Index(index,size);
	
	/*	We are given a polygon of more than 3 sides
		and want to triangulate it. We will output the
		triangles to the output file.
	*/
	
    /*	Find where the input edge is in the input list */
	Last_Edge(&e1,&e2,&e3,0);
     if (( (!begin) && (*(index) == e2) ) || (begin))
     {
	    Output_Tri(*(index+0),*(index+1),*(index+size-1),output,color1,color2,color3,where,where);
        /*	If we have a quad, (chances are yes), then we know that
	   	     we can just add one diagonal and be done. (divide the
		     quad into 2 triangles.
        */
        if (size == 4)
        {
		    Output_Tri(*(index+1),*(index+size-1),*(index+2),output,color1,color2,color3,where,where);
              return;
        }
        increasing = 1;
        mode = 1;

    }
    else if (!begin)
    {
        Output_Tri(*(index+1),*(index+0),*(index+size-1),output,color1,color2,color3,where,where);
        if (size == 4)
        {
            Output_Tri(*(index+0),*(index+size-1),*(index+2),output,color1,color2,color3,where,where);
            return;
        }
        Output_Tri(*(index+0),*(index+size-1),*(index+2),output,color1,color2,color3,where,where);
        increasing = 2;
        mode = 0;
    }
    if (size != 4)
    {
		/*	We do not have a quad, we have something bigger. */
		decreasing = size - 1;		
		do
		{
			/*	Will be alternating diagonals, so we will be increasing
				and decreasing around the polygon.
			*/
			if (mode)
			{
				Output_Tri(*(index+increasing),*(index+decreasing),*(index+increasing+1),output,color1,color2,color3,where,where);
				increasing++;
			}
			else
			{
				Output_Tri(*(index+decreasing),*(index+increasing),*(index+decreasing-1),output,color1,color2,color3,where,where);
                    decreasing--;
               }
			mode = !mode;
		} while ((decreasing - increasing) >= 2);

	}
}