#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <GL/gl.h>   // Header File For The OpenGL32 Library
#include <GL/glu.h>   // Header File For The GLu32 Library
#include <GL/glaux.h>   // Header File For The Glaux Library


static float gong_earth = 7, self_earth = 1, gong_moon = 10, 
           gong_mercury = 200, gong_venus = 4, gong_mars = 80, gong_jupiter = 150,
		   gong_saturn = 60, gong_uranus = 300, gong_neptune = 20, gong_pluto = 110,
           gong_saturn2 = 60, gong_gori = 10; // 행성 위치

static int  R = 10, R1 = 10; 
float eye1=17; // 카메라 초기 설정값
float zoom1=50; //줌 초기 설정값 

GLUquadricObj *obj;

GLuint tex[11]; //텍스쳐 매핑을 위해 그림이 들어갈 공간11개 선언

AUX_RGBImageRec *LoadBMPFile(char *filename) //파일의 이름일때 그림을 불러오게함.
{
	FILE *hFile = NULL;
	if(!filename) return NULL;
		hFile = fopen(filename, "r");
	if(hFile) 
	{
		fclose(hFile);
		return auxDIBImageLoad(filename);
	}   
	return NULL;
}


void loadtexture()
{
	 int i;
	 AUX_RGBImageRec *texRec[11];
	 memset(texRec, 0, sizeof(void *)*11);
   
	 if((texRec[0]=LoadBMPFile("Sun.bmp")) &&  // 그림의 파일을 8비트 단위로 맞춰 넣는다.
		(texRec[1]=LoadBMPFile("Mercury.bmp")) && // texRec[] 각각의 그림파일을 넣는다.
		(texRec[2]=LoadBMPFile("Venus.bmp")) &&
		(texRec[3]=LoadBMPFile("earth.bmp")) &&
		(texRec[4]=LoadBMPFile("Moon.bmp")) &&
		(texRec[5]=LoadBMPFile("Mars.bmp")) &&
		(texRec[6]=LoadBMPFile("Jupiter.bmp")) &&
		(texRec[7]=LoadBMPFile("Saturn.bmp")) &&
		(texRec[8]=LoadBMPFile("Uranus.bmp")) &&
		(texRec[9]=LoadBMPFile("Neptune.bmp")) &&
		(texRec[10]=LoadBMPFile("pluto.bmp"))) 
		{
			glGenTextures(11, &tex[0]);
			for( i=0; i<11; i++) 
			{
			   glBindTexture(GL_TEXTURE_2D, tex[i]);
			   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
			   glTexImage2D(GL_TEXTURE_2D, 0, 3, texRec[i]->sizeX, texRec[i]->sizeY, 0,GL_RGB, GL_UNSIGNED_BYTE,texRec[i]->data);
			}
		}
		for( i=0; i<11; i++) 
		{
			if(texRec[i]) 
			{
				if(texRec[i]->data) free(texRec[i]->data);
				free(texRec[i]);
			} 
		}   
		glEnable(GL_TEXTURE_2D);
		glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
}


void init(void) 
{
	obj = gluNewQuadric();
	loadtexture();
}

void spinDisplay(void)//행성들의 공전 속도
{	
	gong_mercury = gong_mercury + 1.8;
	gong_venus = gong_venus + 1.4; 
	gong_earth = gong_earth + 1.0;
	self_earth = self_earth + 1.0; //자전속도
	gong_moon = gong_moon + 1.5;
	gong_mars = gong_mars + 1.35;      
	gong_jupiter = gong_jupiter + 1.3; 
	gong_saturn = gong_saturn + 1.2; 
	gong_saturn2 = gong_saturn2 + 1.2;
	gong_uranus = gong_uranus + 1.1; 
	gong_neptune = gong_neptune + 0.9; 
	gong_pluto = gong_pluto + 0.8; 
	gong_gori = gong_gori + 1.0;  
	glutPostRedisplay();
}

void renderSphere( float cx, float cy, float cz, float r, int p )

{
	int i, j;
	const float PI     = 3.14159265358979f;
	const float TWOPI  = 6.28318530717958f;
	const float PIDIV2 = 1.57079632679489f;

	float theta1 = 0.0;
	float theta2 = 0.0;
	float theta3 = 0.0;

	float ex = 0.0f;
	float ey = 0.0f;
	float ez = 0.0f;

	float px = 0.0f;
	float py = 0.0f;
	float pz = 0.0f;

	// Disallow a negative number for radius.
	if( r < 0 )
		r = -r;

	// Disallow a negative number for precision.
	if( p < 0 )
		p = -p;

	// If the sphere is too small, just render a OpenGL point instead.
	if( p < 4 || r <= 0 ) 
	{
		glBegin( GL_POINTS );
		glVertex3f( cx, cy, cz );
		glEnd();
		return;
	}

    for(i = 0; i < p/2; ++i ) 
	{
        theta1 = i * TWOPI / p - PIDIV2;
        theta2 = (i + 1) * TWOPI / p - PIDIV2;

        glBegin(GL_TRIANGLE_STRIP); 
        {
            for(j = 0; j <= p; ++j )
            {
                theta3 = j * TWOPI / p;

                ex = cos(theta2) * cos(theta3);
                ey = sin(theta2);
                ez = cos(theta2) * sin(theta3);
                px = cx + r * ex;
                py = cy + r * ey;
                pz = cz + r * ez;

                glNormal3f( ex, ey, ez );
                glTexCoord2f( -(j/(float)p) , 2*(i+1)/(float)p );
                glVertex3f( px, py, pz );

                ex = cos(theta1) * cos(theta3);
                ey = sin(theta1);
                ez = cos(theta1) * sin(theta3);
                px = cx + r * ex;
                py = cy + r * ey;
                pz = cz + r * ez;

                glNormal3f( ex, ey, ez );
                glTexCoord2f( -(j/(float)p), 2*i/(float)p );
                glVertex3f( px, py, pz );
            }
        }
        glEnd();
	}
}

void myDisplay(void) //색상,그리기
{	
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glColor3f (1.0, 1.0, 1.0);

	glPushMatrix();
	glRotatef ((GLfloat) R, 1.0, 0.0, 0.0); //커서로 x축 회전 
	glRotatef ((GLfloat) R1, 0.0, 0.0, 1.0); //y축 회전   
	glPushMatrix();

	//태양
	glEnable(GL_TEXTURE_2D);  // 매핑을 사용하기 위해 사용
	glBindTexture(GL_TEXTURE_2D, tex[0]); // tex[0]이 태양
	renderSphere(0.0, 0.0, 0.0, 0.6, 30 ); // x, y, z, 반지름, 정밀도
	glDisable(GL_TEXTURE_2D);  // 매핑을 끝맡칠때 사용

	glPopMatrix();
	glPushMatrix();

	//수성
	glRotatef ((GLfloat) gong_mercury, 0.0, 1.0, 0.0);
	glTranslatef (1.0, 0.0, 0.0);
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[1]); 
	renderSphere(0.0, 0.0, 0.0, 0.13, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//수성궤도
	glColor3ub(0, 100, 200);
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 1.0, 1.01, 100, 1);// 궤도 좌표(위치)

	glPopMatrix();
	glPushMatrix();

	//금성
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_venus, 0.0, 1.0, 0.0);
	glTranslatef (1.5, 0.0, 0.0);	
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[2]); 
	renderSphere(0.0, 0.0, 0.0, 0.22, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//금성궤도
	glColor3ub(0, 100, 200);
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 1.5, 1.51, 100, 1);	

	glPopMatrix();
	glPushMatrix();
	//지구
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_earth, 0.0, 1.0, 0.0);
	glTranslatef (2.2, 0.0, 0.0);
	glRotatef ((GLfloat) self_earth, 0.0, 1.0, 0.0);	
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[3]); 
	renderSphere(0.0, 0.0, 0.0, 0.2, 30 ); 
	glDisable(GL_TEXTURE_2D);  	
	
	//달
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_moon, 0.0, 1.0, 0.0);
	glTranslatef (0.4, 0.0, 0.0);	
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[4]); 
	renderSphere(0.0, 0.0, 0.0, 0.07, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//달궤도
	glColor3ub(180, 180, 180);
	glRotatef ((GLfloat) gong_gori, 0.0, 1.0, 0.0);
	glTranslatef (2.2, 0.0, 0.1);
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 0.4, 0.41, 100, 1);		

	glPopMatrix();
	glPushMatrix();

	//지구궤도
	glColor3ub(0, 100, 200);		
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 2.2, 2.21, 100, 1);

	glPopMatrix();
	glPushMatrix();

	//화성
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_mars, 0.0, 1.0, 0.0);
	glTranslatef (3.0, 0.0, 0.0);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, tex[5]);
	renderSphere(0.0, 0.0, 0.0, 0.16, 30 );
	glDisable(GL_TEXTURE_2D);

	glPopMatrix();
	glPushMatrix();

	//화성궤도	
	glColor3ub(0, 100, 200);	
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 3.0, 3.01, 100, 1);
	glPopMatrix();

	glPushMatrix();      

	//목성
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_jupiter, 0.0, 1.0, 0.0);
	glTranslatef (3.8, 0.0, 0.0);	
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[6]); 
	renderSphere(0.0, 0.0, 0.0, 0.3, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//목성궤도	
	glColor3ub(0, 100, 200);	
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 3.8, 3.81, 100, 1);
	
	glPopMatrix();
	glPushMatrix();

	//토성
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_saturn, 0.0, 1.0, 0.0);	
	glTranslatef (4.6, 0.0, 0.0);	
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[7]); 
	renderSphere(0.0, 0.0, 0.0, 0.25, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//토성궤도
	glColor3ub(0, 100, 200);	
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 4.6, 4.61, 100, 1);

	glPopMatrix();
	glPushMatrix();	
	
	//토성고리
	glColor3ub(60,60,60);
	glRotatef ((GLfloat) gong_saturn2, 0.0, 1.0, 0.0);
	glTranslatef (4.6, 0.0, 0.0); 
	glRotatef (45.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 0.29, 0.39, 100, 1); 

	glPopMatrix();
	glPushMatrix();

	//천왕성
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_uranus, 0.0, 1.0, 0.0);
	glTranslatef (5.4, 0.0, 0.0);	
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[8]); 
	renderSphere(0.0, 0.0, 0.0, 0.23, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//천왕성궤도	
	glColor3ub(0, 100, 200);	
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 5.4, 5.41, 100, 1);	

	glPopMatrix();
	glPushMatrix();

	//해왕성
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_neptune, 0.0, 1.0, 0.0);
	glTranslatef (6.2, 0.0, 0.0);	
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[9]); 
	renderSphere(0.0, 0.0, 0.0, 0.21, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//해왕성궤도
	glColor3ub(0, 100, 200);	
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 6.2, 6.21, 100, 1);

	glPopMatrix();
	glPushMatrix();

	//명왕성
	glColor3f (1.0, 1.0, 1.0);
	glRotatef ((GLfloat) gong_pluto, 0.0, 1.0, 0.0);
	glTranslatef (7.0, 0.0, 0.0);
	glEnable(GL_TEXTURE_2D);  
	glBindTexture(GL_TEXTURE_2D, tex[10]); 
	renderSphere(0.0, 0.0, 0.0, 0.20, 30 ); 
	glDisable(GL_TEXTURE_2D);  

	glPopMatrix();
	glPushMatrix();

	//명왕성궤도	
	glColor3ub(0, 100, 200);	
	glRotatef (90.0, 1.0, 0.0, 0.0);
	gluDisk(obj, 7, 7.01, 100, 1);	

	glPopMatrix();
	glPopMatrix();

	glutSwapBuffers();
}

void myReshape (int width, int height)
{
	glViewport (0, 0, (GLsizei) width, (GLsizei) height); 
	glMatrixMode (GL_PROJECTION);
	glLoadIdentity ();
	gluPerspective(zoom1, (GLfloat) width/(GLfloat) height, 5.0, 50.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	gluLookAt (0.0, 0.0, eye1, 0.0, 0.0, 0.0, 0.0, 0.1, 0.0);
}

void myMouse(int button, int state, int x, int y) //마우스 버튼 조작
{
	switch (button) 
	{
		case GLUT_LEFT_BUTTON:
			if (state == GLUT_DOWN)
				glutIdleFunc(spinDisplay); //왼쪽 버튼 회전 시작
		 break;

		case GLUT_RIGHT_BUTTON:       //오른쪽 버튼 멈춤
			if (state == GLUT_DOWN)
				glutIdleFunc(NULL);
		 break;

		default:
			break;
	}
}

void myKeyboard (int key, int x, int y) //키보드 버튼 조작
{
   
	switch (key)
	{
		case GLUT_KEY_PAGE_DOWN :// 줌 확대
			zoom1 = zoom1 + 1.0;
			myReshape (800,600);
			glutPostRedisplay();
			break;

		case GLUT_KEY_PAGE_UP :// 줌 축소
			zoom1 = zoom1 - 1.0;
			myReshape (800,600);
			glutPostRedisplay();
			break;

		case GLUT_KEY_UP ://x축 회전
			R = R + 5;
			glutPostRedisplay();
			break;

		case GLUT_KEY_DOWN ://x축 회전
			R = R - 5;
			glutPostRedisplay();
			break;

		case GLUT_KEY_LEFT ://y축 회전
			R1 = R1 + 5;
			glutPostRedisplay();
			break;

		case GLUT_KEY_RIGHT ://y축 회전
			R1 = R1 - 5;
			glutPostRedisplay();
			break;

		case 27:
			exit(0);
			break;

		default:
			break;
	}
}

 

int main(int argc, char** argv)
{
	glutInit(&argc, argv);
	glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize (800,600);
	glutInitWindowPosition (0, 0);
	glutCreateWindow ("Space");
	init();
	glutDisplayFunc(myDisplay); 
	glutReshapeFunc(myReshape);
	glutMouseFunc(myMouse);
	glutSpecialFunc(myKeyboard);
	glutMainLoop();
	return 0;
}

