#include	<GL\glut.h> 
#include	<iostream.h>
#include	<stdio.h>
#include	<windows.h>

#define	MAX			101
#define NORMAL		1
#define HERMITE		101

GLsizei		h=600, w=800;			//크기
int			count = 0;
int			display = NORMAL;
int			index = -1;
double		pt[MAX][3];
double		v[3];

void		myHermite();
void		myHermiteCalculate(double *v, int i, int j);
void		myNormal();
void		myPoint();

void myDisplay()
{ 
	glClear(GL_COLOR_BUFFER_BIT);

	myPoint();

	if(display==NORMAL) myNormal();		
	else if(display==HERMITE) myHermite();

	glutSwapBuffers();
}

void myPoint()
{
	int	w = 10;

	glColor3f(0.0f,0.5f,0.0f);
	glPointSize(10.0);
	glBegin(GL_POINTS);
	for(int i=0; i<count; i++) 
		glVertex2i(pt[i][0], pt[i][1]);
	glEnd();

	glColor3f(1.0f,1.0f,1.0f);       //좌표범위지정
	if(index>=0 && index<=count) 
	{
		glBegin(GL_LINE_LOOP);
			glVertex2i(pt[index][0]-w,pt[index][1]-w);
			glVertex2i(pt[index][0]+w,pt[index][1]-w);
			glVertex2i(pt[index][0]+w,pt[index][1]+w);
			glVertex2i(pt[index][0]-w,pt[index][1]+w);
		glEnd();
	}
}

void myNormal()
{
	glColor3f(0.0f,1.0f,0.0f);
	glBegin(GL_LINE_STRIP);
	{
		for(int i=0;i<count;i++)
			glVertex2d(pt[i][0],pt[i][1]);
	}
	glEnd();
}


void myHermite()
{
	glBegin(GL_LINE_STRIP);
	for(int i=0; i<count-1; i++) 
	{
		for(int j=0;j<MAX;j++)
		{
			myHermiteCalculate(v,i,j);
			glVertex2d(v[0], v[1]);
		}
	}
	glEnd();
}

void myHermiteCalculate(double *v, int i, int j)
{
	double t, ldx, ldy, rdx, rdy;
	
	t = (double)j/MAX;

	if(i==0) 
	{
		ldx = pt[i+1][0] - pt[i][0];
		ldy = pt[i+1][1] - pt[i][1];
	}	
	else 
	{
		ldx = pt[i+1][0] - pt[i-1][0];
		ldy = pt[i+1][1] - pt[i-1][1];
	}

	if(i==count-2) 
	{
		rdx = pt[i+1][0] - pt[i][0];
		rdy = pt[i+1][1] - pt[i][1];
	}
	else 
	{
		rdx = pt[i+2][0] - pt[i][0];
		rdy = pt[i+2][1] - pt[i][1];
	}

	v[0] = ( ( 2 * t * t * t) - (3 * t * t) + 1 ) *   pt[ i ][0] +
		   ( (-2 * t * t * t) + (3 * t * t)     ) *   pt[i+1][0] +
		   ( ( t * t * t    ) - (2 * t * t) + t ) *   ( ldx ) +
		   ( ( t * t * t    ) - (t * t)         ) *   ( rdx );

	v[1] = ( ( 2 * t * t * t) - (3 * t * t) + 1 ) *   pt[ i ][1] +
		   ( (-2 * t * t * t) + (3 * t * t)     ) *   pt[i+1][1] +
		   ( ( t * t * t    ) - (2 * t * t) + t ) *   ( ldy ) +
		   ( ( t * t * t    ) - (t * t)         ) *   ( rdy );
}

void printandassign(int x, int y)
{
	pt[count][0] = x;
	pt[count][1] = y;

	cout<<endl;
	for(int i=0;i<=count;i++)
		cout<< i <<"-> ("<< pt[i][0] <<", "<< pt[i][1] <<")"<<endl;

	count++;
}


void myReshape(GLsizei w, GLsizei h)
{

	glClearColor (0.0f, 0.0f, 0.5f, 0.0f);
	gluOrtho2D(0,(float)w,0,(float)h);
	glMatrixMode(GL_MODELVIEW); 

}

void clrscr()
{
  HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
  COORD coord = {0, 0};
  DWORD count;

  CONSOLE_SCREEN_BUFFER_INFO csbi;

  GetConsoleScreenBufferInfo(hStdOut, &csbi);

  FillConsoleOutputCharacter(hStdOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, coord, &count);

}

void myMouse(int btn, int state, int x, int y)
{
	x = x;
	y = h-y;
			
	if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN && index==-1)
	{  
		if(count<MAX) 
			printandassign(x,y);
	}
	myDisplay();
}

/* 좌표 클릭 */
void myMotionFunc(int x, int y)
{
	pt[index][0] = x;
	pt[index][1] = h-y;

	glutPostRedisplay();
}

/* 좌표선택 이동 */
void myPassiveMotionFunc(int x, int y)
{
	for(int i=0;i<=count;i++)
	{
		if(x>(pt[i][0]-5) && x<(pt[i][0]+5) && (h-y)>pt[i][1]-5 && (h-y)<pt[i][1]+5) 
		{
			index = i;
			break;
		}
	}
	if(i>count) 
		index=-1;

	myDisplay();
}

void myDeletePoint()
{
	if(index==-1||count==0)
		return;
	
	for(int i=index;i<count-1;i++)
	{
		pt[i][0] = pt[i+1][0];
		pt[i][1] = pt[i+1][1];
		pt[i][2] = pt[i+1][2];
	}

	count--;
	index=-1;
}

void rightMenu(int id)
{
	if(id==1)
	{
		display = NORMAL;
		glutPostRedisplay();
	}
	else if(id==2)
	{
		display = HERMITE;
		glutPostRedisplay();
	}
	else if(id==3)
	{
		myDeletePoint();
		glutPostRedisplay();
	}
	else if(id==4)
	{
		count=0;
		clrscr();
		glutPostRedisplay();
	}
	else if(id==5)
		exit(1);
}

void main() 
{ 
	glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);  
	glutInitWindowSize(w,h); 
	glutCreateWindow("cubic"); 

	glutMouseFunc(myMouse);						
	glutDisplayFunc(myDisplay);			
	glutReshapeFunc(myReshape);
	glutPassiveMotionFunc(myPassiveMotionFunc);  
	glutMotionFunc(myMotionFunc);

	glutCreateMenu(rightMenu);
	glutAddMenuEntry("Normal Line",1);
	glutAddMenuEntry("Cubic Hermite Interpolation",2);
	glutAddMenuEntry("Delete Point",3);
	glutAddMenuEntry("Clear Screen",4);
	glutAddMenuEntry("Quit",5);
	glutAttachMenu(GLUT_RIGHT_BUTTON);

	glutMainLoop(); 
}