//*****************************************************************************************
// 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.
*/
//******************************************************************************************

// Let us consider 1 A.U (distance from sun to earth) to be 10 units on screen
// The sun sits at the origin (0,0,0). The size of the solar system till neptune is
// 30 A.U (total size of 300 units from one side, 600 on both.
// For simplicity sake all planets are assumed to lie on the XZ plane
// Also, we assume earth to be of one PU equal to 1 unit (in reality it is closer to 
// .008 units (units being km here )
// First of all we demonstrate how to independently manage the transformation of various
// objects using push and pop.
// Then we look at how to perform two or more transformations on a given body at a time,
// i.e. rotation and revolution, the rotation in this case not about an axis about the origin
// but some arbitrary axis.
//
// Try the following
// 1. Why does Jupiter  seem to move slower than the rest ? Is there any problem with the transformations set up ?
// 2. Change the viewing parameters on the glFrustum, experiment and determine the effect
//    of each parameter.
// 3. A simple fly through of the scene can be made by making the parameters in gluLookAt into
//    variables and changing them using the keyboard.
// 4. The sun, is obviously missing from the whole set up. Add a sun, add an appropriate light
//    at that point. Will adding an ambient light for the whole set up through glLightModelfv
//    a good idea ?
// 5. Add coments visiting systems, (they follow a rather elongated ellipitical path, their path
//    within the system is seemingly parabolic.
// 6. Each planet has a charachteristic color and luminosity. Try adding this feature using glMaterials



#include "stdafx.h"
#include <glut.h>
#include <math.h>
#include <ctime>


time_t hold_time;

float whereAmI[3] = { 0., 15., 0. };

float earthAt = 0.;

void keyboard( unsigned char key, int x, int y )
{
	switch( key )
	{
	case 'e':
		{
			glEnable(GL_CLIP_PLANE1);
		} break;
	case 'd':
		{
			glDisable(GL_CLIP_PLANE1);
		} break;
	}
	glutSwapBuffers();
}

void idle( void )
{
	
	earthAt += .01;
	glutPostRedisplay();
}

void drawCircle( float rad )
{
	float angle =  0.;
	glColor3f( 1., 1., 1. );
	glLineWidth( 3. );
	glBegin( GL_LINE_LOOP );
		for( unsigned int i = 0; i<100; i++ )
		{
			angle = 2*3.14*i/100;
			glVertex3f( rad*cos(angle), 0., rad*sin(angle) );
		}
	glEnd();
}

void drawAxes()
{
	glBegin( GL_LINES );
		glColor3f( 1., 0., 0. );
		glVertex3f( -350., 0., 0. );
		glVertex3f( 350., 0., 0. );
	glEnd();

	glBegin( GL_LINES );
		glColor3f( 0., 1., 0. );
		glVertex3f( 0., -100., 0. );
		glVertex3f( 0., 100., 0. );
	glEnd();

	glBegin( GL_LINES );
		glColor3f( 0., 0., 1. );
		glVertex3f( 0., 0., -350. );
		glVertex3f( 0., 0., 350. );
	glEnd();
}

void reshape( int w, int h )
{

	glViewport( 0, 0, w, h);
	// reshape to keep the size of the world a constant "square" aspect ratio
	//if( w < h )
	//	glViewport( 0, 0, w, w);
	//else
	//	glViewport( 0, 0, h, h);

	glMatrixMode( GL_PROJECTION );
	glLoadIdentity();
	glFrustum( -.4, .4, -.3, .3, .5, 2500 ); 
	// uncomment to see how gluperspective (defining it almost like a camera, works)
	//gluPerspective( 120., 1., 0., 2500. ); // fov, aspect ratio, near and far Z
	glMatrixMode( GL_MODELVIEW );

	glutPostRedisplay();
}

void display( )
{
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	glLoadIdentity();

	// Uncomment to look at "different camera location"
	//glTranslatef( -60, 30., 0. );
	//glRotatef( 90., 0., 1.0, 0.);
	// Comment the code to change to "location" of the camera and to set it at it's default locn
	gluLookAt( -60., 30., 0., 196., 0., 0., 0., 1., 0. );
	
	// Draw the coordinate axes.
	glDisable( GL_LIGHTING );
	drawAxes();
	glEnable( GL_LIGHTING );

	// draw out the paths for each of the planets

	// mercury @ .4 AU
	glColor3f( 1., 0., 0. );
	drawCircle( 4. );
	glPushMatrix();
		glTranslatef( 4.*cos(earthAt/0.25), 0., 4.*sin(earthAt/0.25) );
		glRotatef( earthAt/59, 0., 1., 0. );
		glutSolidSphere( 0.4, 15, 15 );
	glPopMatrix();
	
	// Venus @ .7 AU
	glColor3f( 0., 1., 0. );
	drawCircle( 7. );
	glPushMatrix();
		glTranslatef( 7.*cos(earthAt/0.61), 0.,  7.*sin(earthAt/0.61) );
		glRotatef( earthAt/243, 0., 1., 0. );
		glutSolidSphere( 1., 15, 15 );
	glPopMatrix();
	
	// Earth @ 1. AU
	drawCircle( 10. );
	glPushMatrix();
		glTranslatef( 10.*cos(earthAt), 0., 10.*sin(earthAt) );
		glRotatef( earthAt, 0., 1., 0. );
		glutSolidSphere( 1. , 15, 15 );
	glPopMatrix();	

	// Moon at 3 AU (random, not accurate)
	glPushMatrix();
		glTranslatef( 10*cos(earthAt), 0., 10*sin(earthAt));
		glRotatef( earthAt*12, 0., 1., 0. );
		glTranslatef( 3., 0., 0. );
		glRotatef( earthAt, 0., 1., 0. );
		glutSolidSphere( 0.25, 15, 15 );
	glPopMatrix();

	// Mars @  1.5 AU
	drawCircle( 15. );
	glPushMatrix();
		glTranslatef( 15.*cos(earthAt/1.8), 0., 15.*sin(earthAt/1.8));
		glRotatef( earthAt, 0., 1., 0. );
		glutSolidSphere( 0.5, 15, 15 );
	glPopMatrix();
	
	// Jupiter 5.2 AU
	drawCircle( 52. );
	glPushMatrix();
		// since this is a fairly large object we can try "two different ways" of
		// getting it to move
		glTranslatef( 52.*cos(earthAt/12), 0.,  52.*sin(earthAt/12) );
		glRotatef( earthAt*3, 0., 1., 0. );
		//glRotatef( earthAt/12, 0., 1., 0. );
		//glTranslatef( 52., 0., 0. );
		glutSolidSphere( 12., 15, 15 );
	glPopMatrix();
	
	// Saturn 9.5 AU
	drawCircle( 95. );
	glPushMatrix();
		//glTranslatef (-1.25, 3.0, 0.0);
		glTranslatef( 95.*cos(earthAt/30), 0., 95.*sin(earthAt/30) );
		glRotatef( earthAt*2, 0., 1., 0. );
		glutSolidSphere( 10.5, 15, 15 );
	glPopMatrix();
	
	// Uranus 19.6 AU
	drawCircle( 196. );
	glPushMatrix();
		glTranslatef( 196.*cos(earthAt/84), 0., 196.*sin(earthAt/84) );
		glRotatef( earthAt*2.5, 0., 1., 0. );
		glutSolidSphere( 4.25 , 15, 15 );
	glPopMatrix();

	// Nepture 30 AU
	glColor3f( 0., 0., 1. );
	drawCircle( 300. );
	glPushMatrix();
		glTranslatef( 300.*cos(earthAt/165), 0.,  300.*sin(earthAt/165) );
		glRotatef( earthAt*2.5, 0., 1., 0. );
		glutSolidSphere( 4.25, 15, 15 );
	glPopMatrix();

	glutSwapBuffers();
}

void init( )
{
	glClearColor( 0., 0., 0., 0. );

	glShadeModel( GL_SMOOTH );
	//glShadeModel( GL_FLAT );

	// Some material and enabling the first light
	GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
    GLfloat mat_shininess[] = { 50.0 };
    GLfloat light_position[] = { 0.0, 1.0, 0.0, 0.0 };

	// Lets do just half of the whole view!
	GLdouble plane1[4] = { 1., 0., 0., 0. };
	glClipPlane( GL_CLIP_PLANE1, plane1);

    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glDepthFunc(GL_LEQUAL);
    glEnable(GL_DEPTH_TEST);
}

int main(int argc, char* argv[])
{
	glutInit( &argc, argv );
	glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
	glutInitWindowSize( 640, 480 );
	glutInitWindowPosition( 50, 50 );
	glutCreateWindow( "Solar System" );

	init();

	glutDisplayFunc( display );

	glutReshapeFunc( reshape );

	glutIdleFunc( idle );

	glutKeyboardFunc( keyboard );

	glutMainLoop();

	return 0;
}


