#include <time.h>
#include <stdio.h>
#include <gl/glut.h>
#include <gl/glaux.h>
#include <windows.h>
#include <math.h>

#define GL_PI 3.1415f

#define MODE_OBJECT 1
#define MODE_LIGHT  2


static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;
static GLfloat zDistance = -100.0f;

static GLfloat xRot2 = 0.0f;
static GLfloat yRot2 = 0.0f;
static GLfloat zDistance2 = -100.0f;

static GLfloat pendulumAng = 0.0f;
static GLfloat pendulumStep = 1.2f;

static GLfloat fHourAngle = 0.0f;
static GLfloat fMinAngle = 0.0f;
static GLfloat fSecAngle = 0.0f;

static GLuint	textureID;
static AUX_RGBImageRec * texRec;

GLfloat  lightPos[] = { 20.0f, 20.0f, 130.0f, 0.0f };
GLfloat  specular[] = { 1.0f, 1.0f, 1.0f, 1.0f};
GLfloat  specref[] =  { 1.0f, 1.0f, 1.0f, 1.0f };
GLfloat  ambientLight[] = { 0.5f, 0.5f, 0.5f, 1.0f};
GLfloat  spotDir[] = { 0.0f, 0.0f, -1.0f };

int iMode=1;

void ProcessMenu(int value)
{
  switch(value)
  {
     case 1:
         iMode = MODE_OBJECT;
          break;
      case 2:
         iMode = MODE_LIGHT;
         break;
  }
    glutPostRedisplay();
}

void SetupRC()
{
	// 조명값 및 좌표값
	glShadeModel(GL_SMOOTH);
	glEnable(GL_DEPTH_TEST);  // 은면제거
	glEnable(GL_LIGHTING); // 조명 효과를 준다.
	glEnable(GL_TEXTURE_2D); //2D 텍스쳐
	

	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight	); 

	glLightfv(GL_LIGHT0,GL_DIFFUSE,ambientLight); 
    glLightfv(GL_LIGHT0,GL_SPECULAR,specular);
    glLightfv(GL_LIGHT0,GL_POSITION,lightPos);   
	glLightf(GL_LIGHT0,GL_SPOT_CUTOFF,50.0f);    
	glEnable(GL_LIGHT0); 		         
	glEnable(GL_COLOR_MATERIAL);                 
	glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
    
	// All materials hereafter have full specular reflectivity
	glMaterialfv(GL_FRONT, GL_SPECULAR,specref);
    glMateriali(GL_FRONT, GL_SHININESS,128);


	glFrontFace(GL_CCW);      //add
	
	// 텍스쳐 설정 
	texRec = auxDIBImageLoad("texture.bmp");
	glGenTextures(1, &textureID);
	glBindTexture(GL_TEXTURE_2D, textureID);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);


	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, texRec->sizeX, texRec->sizeY, 
		0, GL_RGB, GL_UNSIGNED_BYTE, texRec->data); 

	// 검은색 배경으로 초기화한다. 
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f );
	


}

void TimerFunc(int value)
{
	//현재시간을 얻기위하여 time 구조체 이용
	time_t timeStr;
	tm	*pTime;
	GLubyte ubHour = 0;
	GLubyte ubMin = 0;
	GLubyte ubSec = 0;

	time(&timeStr);
	pTime = localtime(&timeStr);
	// 시계바늘 각도 
	ubHour = (GLubyte)(pTime->tm_hour%12);
	ubMin = (GLubyte)pTime->tm_min;
	ubSec = (GLubyte)(pTime->tm_sec);

	// 시계 바늘 
	fSecAngle = 360 - (6.0f * (GLfloat)ubSec);
	fMinAngle = 360 - (6.0f * (GLfloat)ubMin);
	fHourAngle = 360 - (30.0f * (GLfloat)ubHour + 0.5f * (GLfloat)ubMin);

	// 시계추 흔들리는 각 변경
	pendulumAng += pendulumStep;

	// 좌우 30도 반경안에서 흔들리게 한다.
	if (pendulumStep > 0 && pendulumAng >= 29.0f)
		pendulumStep *= -1.0f;
	if (pendulumStep < 0 && pendulumAng <= -29.0f)
		pendulumStep *= -1.0f;

	glutPostRedisplay();
	glutTimerFunc(15,TimerFunc, 1);
}

//Perspective
void ChangeSize(int w, int h)
{

	GLfloat fAspect;

	glViewport(0,0,w,h);

	fAspect = (GLfloat)w/(GLfloat)h;

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	gluPerspective(47.0f,fAspect,1.0f, 400.0f);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glTranslatef(0.0f,10.0f, -20.0f); //add 
}	

void RenderScene()
{	
	GLfloat x,y,angle;

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	

	glPushMatrix();
	glTranslatef(0.0f,0.0f, zDistance);
	glRotatef(xRot, 1.0f, 0.0f, 0.0f);
	glRotatef(yRot, 0.0f, 1.0f, 0.0f);

	glPushMatrix();
	glTranslatef(0.0f,0.0f, zDistance2);
	glRotatef(xRot2, 1.0f, 0.0f, 0.0f);
	glRotatef(yRot2, 0.0f, 1.0f, 0.0f);

    glLightfv(GL_LIGHT0,GL_POSITION,lightPos);
    glLightfv(GL_LIGHT0,GL_SPOT_DIRECTION,spotDir);

	glColor3ub(255,0,0);	
	glTranslatef(lightPos[0],lightPos[1],lightPos[2]);
    glutSolidCone(4.0f,6.0f,15,15);
    glPushAttrib(GL_LIGHTING_BIT);
	glDisable(GL_LIGHTING);
	glColor3ub(255,255,0);
	glutSolidSphere(3.0f, 15, 15);
    glPopAttrib();
	glPopMatrix();   

   
	glPushMatrix();	

	glColor3ub(0, 0, 0);
	glutSolidTorus(0.5f, 2.0f, 15, 15);

	//시계 판. 
	glFrontFace(GL_CW);

	glBindTexture(GL_TEXTURE_2D, textureID);
	glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
	glEnable(GL_TEXTURE_2D);
	

	glBegin(GL_TRIANGLE_FAN);
	glColor3ub(196,196,196);
	glTexCoord2f(0.5f, 0.5f);
	glVertex3f(0.0f, 0.0f,-4.5f);
	for(angle =0.0f; angle < (2.0f*GL_PI); angle += (2.0f*GL_PI/12.0f))
	{
		x = 30.0f*sin(angle);
		y = 30.0f*cos(angle);

		glTexCoord2f(0.5f - x / 60.0f, 0.5f - y / 60.0f);
		glVertex3f(x, y, -4.5f);
	}
	glTexCoord2f(0.5f, 0.1f);
	glVertex3f(0.0f, 30.0f,-4.5f);
	glEnd();	

	glDisable(GL_TEXTURE_2D);
	glFrontFace(GL_CCW);
  

	// 초바늘 
	glPushMatrix();
	glRotatef(fSecAngle, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 11.0f, 0.0f);
	glPushMatrix();
	glScalef(1.0f, 15.0f, 1.0f);
	glColor3ub(0,0,255);
	glutSolidCube(1.0f);
	glPopMatrix();	
	glTranslatef(0.0f, 8.4f, 0.0f);
	glColor3ub(0,0,0);
	glutSolidOctahedron();
	glPopMatrix();

	//분바늘
	glPushMatrix();
	glRotatef(fMinAngle, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 9.2f, 0.0f);
	glPushMatrix();
	glScalef(1.0f, 12.0f, 1.0f);
	glColor3ub(0,255,0);
	glutSolidCube(1.0f);
	glPopMatrix();	
	glTranslatef(0.0f, 7.0f, 0.0f);
	glColor3ub(0,0,0);
	glutSolidOctahedron();
	glPopMatrix();

	//시바늘
	glPushMatrix();
	glRotatef(fHourAngle, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 8.0f, 0.0f);
	glPushMatrix();
	glScalef(1.0f, 9.0f, 1.0f);
	glColor3ub(255,0,0);
	glutSolidCube(1.0f);
	glPopMatrix();	
	glTranslatef(0.0f, 5.5f, 0.0f);
	glColor3ub(0,0,0);
	glutSolidOctahedron();
	glPopMatrix();

	//시간 점.
	glFrontFace(GL_CCW);
	glPushMatrix();
	glTranslatef(0.0f, 25.0f, -4.5f);
	glScalef(0.5f, 1.0f, 1.0f);
	glColor3ub(255,0,0);
	glutSolidCube(2.0f);	
	glPopMatrix();

	glPushMatrix();
	glRotatef(30.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();

	glPushMatrix();
	glRotatef(60.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();

	glPushMatrix();
	glRotatef(90.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glScalef(0.5f, 1.0f, 1.0f);
	glColor3ub(255,0,0);
	glutSolidCube(2.0f);	
	glPopMatrix();

	glPushMatrix();
	glRotatef(120.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();

	glPushMatrix();
	glRotatef(150.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();

	glPushMatrix();
	glRotatef(180.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glScalef(0.5f, 1.0f, 1.0f);
	glColor3ub(255,0,0);
	glutSolidCube(2.0f);	
	glPopMatrix();

	glPushMatrix();
	glRotatef(210.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();

	glPushMatrix();
	glRotatef(240.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();

	glPushMatrix();
	glRotatef(270.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glScalef(0.5f, 1.0f, 1.0f);
	glColor3ub(255,0,0);
	glutSolidCube(2.0f);	
	glPopMatrix();

	glPushMatrix();
	glRotatef(300.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();

	glPushMatrix();
	glRotatef(330.0, 0.0f, 0.0f, 1.0f);
	glTranslatef(0.0f, 25.0f, -4.5f);
	glColor3ub(0,0,255);
	glutSolidCone(1.0f,1.4f,10,10);
	glPopMatrix();


	// 시계 추 
	glTranslatef(0.0f, 0.0f, -4.5f );
	glRotatef(pendulumAng, 0.0f, 0.0f, 1.0f);
	glPushMatrix();
	glTranslatef(0.0f, -33.0f, 0.0f );
	glScalef(1.0f, 5.0f, 1.0f);
	glColor3ub(255,255,255);
	glutSolidCube(1.0f);
	glPopMatrix();
	glTranslatef(0.0f, -42.0f, 0.0f );
	glColor3ub(255,255,0);
	glutSolidTorus(1.0f, 6.0f, 20, 15);
	glPopMatrix();

	glPopMatrix();

	glutSwapBuffers(); 	
}
void KeyControl(int key, int x, int y)
{
	if (iMode==MODE_OBJECT) // 물체의 회전 & 이동
	{
		if(key == GLUT_KEY_UP)
			xRot -=5.0f;

		if(key == GLUT_KEY_DOWN)
			xRot +=5.0f;

		if(key == GLUT_KEY_LEFT)
			yRot -=5.0f;

		if(key == GLUT_KEY_RIGHT)
			yRot +=5.0f;

		// change Z-distance
		if(key == GLUT_KEY_HOME)
			zDistance += 5.0f;
		if(key == GLUT_KEY_END)
			zDistance -= 5.0f;
	}
	else //광원의 회전 & 이동 
	{
		if(key == GLUT_KEY_UP)
			xRot2 -=5.0f;

		if(key == GLUT_KEY_DOWN)
			xRot2 +=5.0f;

		if(key == GLUT_KEY_LEFT)
			yRot2 -=5.0f;

		if(key == GLUT_KEY_RIGHT)
			yRot2 +=5.0f;

		// change Z-distance
		if(key == GLUT_KEY_HOME)
			zDistance2 -= 5.0f;
		if(key == GLUT_KEY_END)
			zDistance2 += 5.0f;

	}


	glutPostRedisplay();   // 변환된 좌표값으로 redrawing

}

void main()
{
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
	glutInitWindowSize(512,512);
	glutInitWindowPosition(0,0);
	glutCreateWindow("Analog Clock");

	glutCreateMenu(ProcessMenu);
    glutAddMenuEntry("시계 이동 및 회전",1);
    glutAddMenuEntry("광원 이동 및 회전",2);
    glutAttachMenu(GLUT_RIGHT_BUTTON);

	SetupRC();
	glutReshapeFunc(ChangeSize);
	glutTimerFunc(33,TimerFunc,1); //add 
	glutSpecialFunc(KeyControl);
	glutDisplayFunc(RenderScene);

	glutMainLoop();
}
