//*****************************************************************************************
// Disclaimer, Authorship and License
/*
	This code has been written to serve as a learning tool for the course MAE 410-574, 
	Virtual Reality Applications and Research, Spring 2007.
	
	Large parts of the code has been adapted from the examples given in the OpenGL 
	Programming Guide by Woo et. al and also from Computer Graphics Using OpenGL by FS Hill
	Some parts of the code has also been adapted from various resources available through 
	out the internet.I thank all those whose code and resources I have used to write these 
	examples. You may use this code for any non-commerical purpose. Feel free to include 
	and use parts of this code for your own application, but remember that this code is not
	entirely bug free, use it at your own risk.If you plan on using the code for your any 
	academic purpose please drop me an email. I would like to attach a link to your course 
	from my home page.

	The Author of this code is Govindarajan Srimathveeravalli, Dept. of Mech and Aero Eng. ,
	University at Buffalo.
*/
//******************************************************************************************
// Below given code demonstrates how to generate a simple Bezier curve using evaluators 
// from OpenGL. Click on points in the screen choosing the control points, right click to
// finish and draw the curve.
//
// Try the following.
// 1. Play around with the curve, we know that since the curves are Bezier, they will always
//    pass throught the start and end. See if other properties of Bezier curves (convexity,
//    linearity etc.) can be simulated using a good choice of points.

#include <iostream>
#include <stdlib.h>
#include <math.h>
#include <glut.h>


typedef struct 
{
	float x;
	float y;
	float z;
}point;

bool doOnce = true;

const int numPoints = 100;
unsigned int numClicks = 0;
point pointSet[ numPoints ];
unsigned int oldIndex = 0;

// pass lineType 1 for line_strip and 2 for line_loop
void drawLine( void )
{	

	glLineWidth( 3.0 );
	glBegin( GL_LINE_STRIP );
		// for number of clicks occured draw lines
		for( unsigned int i=0; i<numClicks; i++)
		{
			glColor3f( 1., 0., 0. );
			glVertex3f( pointSet[i].x, pointSet[i].y, pointSet[i].z );
		}
	glEnd();
	
	glPointSize( 10.0 );
	glColor3f( 0., 1., 0. );

	glBegin( GL_POINTS );
		// for number of clicks occured draw lines
		for( unsigned int i=0; i<numClicks; i++)
			glVertex3f( pointSet[i].x, pointSet[i].y, pointSet[i].z );
	glEnd();

	glutSwapBuffers();
}

void mouseClickFunc( int button, int state, int x, int y )
{
	
	if( doOnce )
	{
		if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
		{
			pointSet[ numClicks ].x = x;
			pointSet[ numClicks ].y = y;
			pointSet[ numClicks ].z = 0.;
			numClicks++;
			std::cout << x << "  " << y  << "\n";
		}
		else if( button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN )
			doOnce = false;
	}
	glutPostRedisplay();
}


void reshape( int w, int h)
{
	
	glViewport( 0., 0., w, h );
	glutPostRedisplay();
}

void display( )
{
	// Clear the background before drawing
	glClear( GL_COLOR_BUFFER_BIT );

	// Coloring
	glColor3f( 1., 0., 0. );

	drawLine();

	glColor3f( 0., 0., 1. );

	// Draw the bezier curve here
	if( !doOnce )
	{
		float controlPoints [100][3];

		for( unsigned int i=0; i<numClicks; i++)
		{
			controlPoints[i][0] = pointSet[i].x;
			controlPoints[i][1] = pointSet[i].y;
			controlPoints[i][2] = pointSet[i].z;
		}
		
		// Here we enable use of a bezier curve., parameters below initialize the curve
		// the actual coordinates of the curve are calculated from 
		glMap1f( GL_MAP1_VERTEX_3, 0., 1., 3, numClicks , &controlPoints[0][0] );
		glEnable( GL_MAP1_VERTEX_3 );
		
		glLineWidth( 7.0 );
		glBegin( GL_LINE_STRIP );
			for( unsigned int i=0; i<50; i++)
				glEvalCoord1f( (GLfloat)i/50 );
		glEnd();
	}

	// Ensure all drawing commands are executed
	glutSwapBuffers( );
}

void init( )
{
	// Set the background 
	glClearColor( 1., 1., 1. , 0. );

	glMatrixMode( GL_PROJECTION );
	glLoadIdentity( );

	gluOrtho2D( 0, 640., 480. , 0.  );
}

int main(int argc, char* argv[])
{

	// Initialize a window with command line arguments
	glutInit( &argc, argv );
	// Provide window with buffering, coloring information
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
	// Position and Size the window
	glutInitWindowPosition( 50, 50 );
	glutInitWindowSize( 540, 480 );
	// Create the window with the given features with a 'suitable title'
	glutCreateWindow( "Bezier Curve" );

	// do some initialization like setting up background color, camera, projection type etc.
	init( );

	// Assign a display 'callback function'
	glutDisplayFunc( display );

	// The reshape function is called everytime the window is relocated or resized ! duh
	glutReshapeFunc( reshape );

	// adding a function to handle mouse clicks
	glutMouseFunc( mouseClickFunc );
	// Enter the graphics loop
	glutMainLoop( );

	return 0;
}


