#include <windows.h>		
#include <gl\gl.h>			
#include <gl\glu.h>			
#include <gl\glaux.h>		

HDC			hDC=NULL;		
HGLRC		hRC=NULL;		
HWND		hWnd=NULL;		
HINSTANCE	hInstance;		

bool	keys[256];			
bool	active=TRUE;		
bool	fullscreen=TRUE;	
bool	light=true;
bool	textures=true;
bool	wire= true;
bool	wire1= true;
GLuint tex[3];

GLuint base;
GLfloat rot = 0.0f;
GLYPHMETRICSFLOAT gmf[96];	

AUX_RGBImageRec *texture[5];

GLUquadricObj *obj;

GLfloat o1_rot = 0.0f;	   // 지구의 자전각 
GLfloat o2_rot1 = 0.0f;    // 달의 공전각
GLfloat o2_rot2 = 0.0f;	   // 달의 자전각
GLfloat o3_rot1 = 120.0f;
GLfloat o3_rot2 = 0.0f;
GLfloat o4_rot1 = 240.0f;
GLfloat o4_rot2 = 0.0f;
GLfloat distance = 7.0f;  // 달과 지구의 각 중심간의 거리	

GLfloat ratio;

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);	

GLvoid BuildFont(GLvoid)								
{
	HFONT	font;										

	base = glGenLists(96);								

	font = CreateFont(	-12,							
						0,								
						0,								
						0,								
						FW_BOLD,						
						FALSE,							
						FALSE,							
						FALSE,							
						HANGUL_CHARSET,					
						OUT_TT_PRECIS,					
						CLIP_DEFAULT_PRECIS,			
						ANTIALIASED_QUALITY,			
						FF_DONTCARE|DEFAULT_PITCH,		
						"Comic Sans MS");				

	SelectObject(hDC, font);							

	wglUseFontOutlines(	hDC,							
						32,								
						96,								
						base,							
						0.1f,							
						0.5f,							
						WGL_FONT_POLYGONS,				
						gmf);
}

void TexturesInit()
{
	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);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);

	
	glNewList(1, GL_COMPILE);
	   texture[0] = auxDIBImageLoad("KOREA.bmp");
	   glTexImage2D(GL_TEXTURE_2D, 0, 3, texture[0]->sizeX, texture[0]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture[0]->data);
    glEndList();

	glNewList(2, GL_COMPILE);
	   texture[1] = auxDIBImageLoad("TOGO.bmp");
	   glTexImage2D(GL_TEXTURE_2D, 0, 3, texture[1]->sizeX, texture[1]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture[1]->data);
    glEndList();

	glNewList(3, GL_COMPILE);
	   texture[2] = auxDIBImageLoad("BACK.bmp");
	   glTexImage2D(GL_TEXTURE_2D, 0, 3, texture[2]->sizeX, texture[2]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture[2]->data);
    glEndList();

	glNewList(4, GL_COMPILE);
	   texture[3] = auxDIBImageLoad("FRANCE.bmp");
	   glTexImage2D(GL_TEXTURE_2D, 0, 3, texture[3]->sizeX, texture[3]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture[3]->data);
    glEndList();

	glNewList(5, GL_COMPILE);
	   texture[4] = auxDIBImageLoad("SWIS.bmp");
	   glTexImage2D(GL_TEXTURE_2D, 0, 3, texture[4]->sizeX, texture[4]->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture[4]->data);
    glEndList();

}


GLvoid KillFont(GLvoid)									
{
	glDeleteLists(base, 96);							
}

GLvoid glPrint(const char *text)
{
	glPushAttrib(GL_LIST_BIT);							
	glListBase(base - 32);								
	glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);	
	glPopAttrib();										
}




GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		
{
	if (height==0)										
	{
		height=1;										
	}

	glViewport(0,0,width,height);						

	glMatrixMode(GL_PROJECTION);						
	glLoadIdentity();									

	
	ratio = (GLfloat)width/(GLfloat)height;
	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);							
	glLoadIdentity();									
}

int InitGL(GLvoid)										
{
	glShadeModel(GL_SMOOTH);							
	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				
	glClearDepth(1.0f);									
	glEnable(GL_DEPTH_TEST);						
	glEnable(GL_COLOR_MATERIAL);
	glEnable(GL_LIGHT0);

	glDepthFunc(GL_LEQUAL);								
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	


	obj = gluNewQuadric();
    gluQuadricNormals(obj, GLU_SMOOTH);
    gluQuadricOrientation(obj, GLU_OUTSIDE);
    gluQuadricTexture(obj, GL_FALSE);

	BuildFont();

	glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);
	

	TexturesInit();
	
	glEnable(GL_TEXTURE_2D);

	return TRUE;										
}

int DrawGLScene(GLvoid)									
{
if(wire1)	glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
	
if(!wire1)	glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);


    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

	glInitNames();

	glTranslatef(0.0f, 0.0f, -22.0f);

if(!light)	glDisable(GL_LIGHTING);
if(light)	glEnable(GL_LIGHTING);

if(!textures)	glDisable(GL_TEXTURE_2D);
if(textures)	glEnable(GL_TEXTURE_2D);
	glPushName(100);
	glPushMatrix();
		glTranslatef(0.0, 6.0f, 0.0f);					
		glRotatef(rot, 1.0f, 1.0f, 0.0f);	
		glTranslatef(-2.0f, 0.0f, 0.0f);					
		glColor3f(0.0f, 1.0f, 0.0f);		// 문자색상
		glScalef(1.0f, 1.0f, 1.0f);
		glPrint(" GROUP_G ");
	glPopMatrix();
	glPopName();

	glRotatef(45, 1.0f, 1.0f, 0.0f);

	glPushName(101);	// 한국
	glPushMatrix();
		glTranslatef(0.0f, 0.0f, 0.0f);
        glRotatef(o1_rot, 1.0f, 1.0f, 0.0f);
if(wire)		gluQuadricDrawStyle(obj, GLU_FILL);
	    glColor3f(0.9f, 0.0f, 0.0f);
		glCallList(1);
		gluQuadricTexture(obj, GL_TRUE);
		gluSphere(obj, 1.5f, 24, 24);
if(!wire)		gluQuadricDrawStyle(obj, GLU_LINE);
	    glColor3f(0.9f, 0.9f, 0.9f);
		gluSphere(obj, 1.5f, 24, 24);
	glPopMatrix();
	glPopName();

	glPushName(102);	// 토고
	glPushMatrix();
		glRotatef(o2_rot1, 0.0f, 1.0f, 0.0f);
		glTranslatef(distance, 0.0f, 0.0f);
	    glRotatef(o2_rot2, 0.0f, 1.0f, 0.0f);
if(wire)		gluQuadricDrawStyle(obj, GLU_FILL);
		
		glColor3f(0.5f, 0.5f, 0.0f);
		glCallList(2);
		gluQuadricTexture(obj, GL_TRUE);
		gluSphere(obj, 1.5f, 12, 12);
if(!wire)		gluQuadricDrawStyle(obj, GLU_LINE);
		glColor3f(0.9f, 0.9f, 0.0f);
        gluSphere(obj, 1.5f, 12, 12);
	glPopMatrix();
	glPopName();
	


	glPushName(104);	// 프랑스
	glPushMatrix();
		glRotatef(o3_rot1, 0.0f, 1.0f, 0.0f);
		glTranslatef(distance, 0.0f, 0.0f);
	    glRotatef(o3_rot2, 0.0f, 1.0f, 0.0f);
if(wire)		gluQuadricDrawStyle(obj, GLU_FILL);
		
		glColor3f(0.0f, 0.0f, 0.9f);
		glCallList(4);
		gluQuadricTexture(obj, GL_TRUE);
		gluSphere(obj, 1.5f, 12, 12);
if(!wire)		gluQuadricDrawStyle(obj, GLU_LINE);
		glColor3f(0.9f, 0.9f, 0.9f);
        gluSphere(obj, 1.5f, 12, 12);
	glPopMatrix();
	glPopName();

	glPushName(105);	// 스위스
	glPushMatrix();
		glRotatef(o4_rot1, 0.0f, 1.0f, 0.0f);
		glTranslatef(distance, 0.0f, 0.0f);
	    glRotatef(o4_rot2, 0.0f, 1.0f, 0.0f);
if(wire)		gluQuadricDrawStyle(obj, GLU_FILL);
		
		glColor3f(0.0f, 0.0f, 0.9f);
		glCallList(5);
		gluQuadricTexture(obj, GL_TRUE);
		gluSphere(obj, 1.5f, 12, 12);
if(!wire)		gluQuadricDrawStyle(obj, GLU_LINE);
		glColor3f(0.9f, 0.9f, 0.9f);
        gluSphere(obj, 1.5f, 12, 12);
	glPopMatrix();
	glPopName();

	
	rot += 5.0f;
	o1_rot+=5.0f; if(o1_rot>359.5f) o1_rot=0.0f;
	o2_rot1+=2.0f; if(o2_rot1>359.95f) o2_rot1=0.0;	//토고 공전
	o2_rot2+=3.0f; if(o2_rot2>358.0f) o2_rot2=0.0;	//토고 자전
	o3_rot1+=2.0f; if(o3_rot1>359.95f) o3_rot1=0.0;	//프랑스 공전
	o3_rot2+=3.0f; if(o3_rot2>358.0f) o3_rot2=0.0;	//프랑스 자전
	o4_rot1+=2.0f; if(o4_rot1>359.95f) o4_rot1=0.0;	//스위스 공전
	o4_rot2+=3.0f; if(o4_rot2>358.0f) o4_rot2=0.0;	//스위스 자전

	glPushName(103);
	glPushMatrix();
	glRotatef(-45, 1.0f, 1.0f, 0.0f);
	glColor3f(1.0f, 1.0f, 1.0f);
	glCallList(3);
	glBegin(GL_QUADS);
		glTexCoord2f(0.0f, 0.0f); glVertex3f(-18.0f, -14.0f, -10.0f);
		glTexCoord2f(1.0f, 0.0f); glVertex3f(18.0f, -14.0f, -10.0f);
		glTexCoord2f(1.0f, 1.0f); glVertex3f(18.0f, 14.0f, -10.0f);
		glTexCoord2f(0.0f, 1.0f); glVertex3f(-18.0f, 14.0f,-10.0f);
	glEnd(); 
	glPopMatrix();
	glPopName();
	
    return TRUE;
}

void ProcessSelect(GLuint index[64])  
{
	switch(index[3]) {
		case 100: MessageBox(hWnd, "Team Project", "Selection", MB_OK); break;
		case 101: MessageBox(hWnd, "대한민국\nFIFA 랭킹 : 29위\n1승(3점)", "Selection", MB_OK); break;
		case 102: MessageBox(hWnd, "토고\nFIFA 랭킹 : 61위\n1패(0점)", "Selection", MB_OK); break;
		case 103: MessageBox(hWnd, "순위\n1.대한민국\n2.프랑스\n2.스위스\n4.토고", "Selection", MB_OK); break;
		case 104: MessageBox(hWnd, "프랑스\nFIFA 랭킹 : 8위\n1무(1점)", "Selection", MB_OK); break;
		case 105: MessageBox(hWnd, "스위스\nFIFA 랭킹 : 35위\n1무(1점)", "Selection", MB_OK); break;

		default: MessageBox(hWnd, "What?", "Selection", MB_OK); break;
	}
}

void SelectObjects(GLint x, GLint y) 
{
	GLuint selectBuff[64];
	GLint hits, viewport[4];

	glSelectBuffer(64, selectBuff);
	glGetIntegerv(GL_VIEWPORT, viewport);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
		glRenderMode(GL_SELECT);
		glLoadIdentity();
		gluPickMatrix(x, viewport[3]-y, 2, 2, viewport);
		gluPerspective(45.0f,ratio,0.1f,100.0f);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		DrawGLScene();
		hits = glRenderMode(GL_RENDER);
		if(hits>0) ProcessSelect(selectBuff);
		glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glMatrixMode(GL_MODELVIEW);
}


GLvoid KillGLWindow(GLvoid)								
{
	if (fullscreen)										
	{
		ChangeDisplaySettings(NULL,0);					
		ShowCursor(TRUE);								
	}

	if (hRC)											
	{
		if (!wglMakeCurrent(NULL,NULL))					
		{
			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))						
		{
			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}
		hRC=NULL;										
	}

	if (hDC && !ReleaseDC(hWnd,hDC))					
	{
		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hDC=NULL;										
	}

	if (hWnd && !DestroyWindow(hWnd))					
	{
		MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hWnd=NULL;										
	}

	if (!UnregisterClass("OpenGL",hInstance))			
	{
		MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hInstance=NULL;									
	}


	gluDeleteQuadric(obj);      
}

 
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint		PixelFormat;			
	WNDCLASS	wc;						
	DWORD		dwExStyle;				
	DWORD		dwStyle;				
	RECT		WindowRect;				
	WindowRect.left=(long)0;			
	WindowRect.right=(long)width;		
	WindowRect.top=(long)0;				
	WindowRect.bottom=(long)height;		

	fullscreen=fullscreenflag;			

	hInstance			= GetModuleHandle(NULL);				
	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	
	wc.lpfnWndProc		= (WNDPROC) WndProc;					
	wc.cbClsExtra		= 0;									
	wc.cbWndExtra		= 0;									
	wc.hInstance		= hInstance;							
	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			
	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			
	wc.hbrBackground	= NULL;									
	wc.lpszMenuName		= NULL;									
	wc.lpszClassName	= "OpenGL";								

	if (!RegisterClass(&wc))									
	{
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;											
	}
	
	if (fullscreen)												
	{
		DEVMODE dmScreenSettings;								
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	
		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		
		dmScreenSettings.dmPelsWidth	= width;				
		dmScreenSettings.dmPelsHeight	= height;				
		dmScreenSettings.dmBitsPerPel	= bits;					
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		
		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			
			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","2nd Term OpenGL Project",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
			{
				fullscreen=FALSE;		
			}
			else
			{
				
				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
				return FALSE;									
			}
		}
	}

	if (fullscreen)												
	{
		dwExStyle=WS_EX_APPWINDOW;								
		dwStyle=WS_POPUP;										
		ShowCursor(FALSE);										
	}
	else
	{
		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			
		dwStyle=WS_OVERLAPPEDWINDOW;							
	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		

	
	if (!(hWnd=CreateWindowEx(	dwExStyle,							
								"OpenGL",							
								title,							
								dwStyle |							
								WS_CLIPSIBLINGS |					
								WS_CLIPCHILDREN,					
								0, 0,								
								WindowRect.right-WindowRect.left,	
								WindowRect.bottom-WindowRect.top,	
								NULL,								
								NULL,								
								hInstance,							
								NULL)))								
	{
		KillGLWindow();								
		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								
	}

	static	PIXELFORMATDESCRIPTOR pfd=				
	{
		sizeof(PIXELFORMATDESCRIPTOR),				
		1,											
		PFD_DRAW_TO_WINDOW |						
		PFD_SUPPORT_OPENGL |						
		PFD_DOUBLEBUFFER,							
		PFD_TYPE_RGBA,								
		bits,										
		0, 0, 0, 0, 0, 0,							
		0,											
		0,											
		0,											
		0, 0, 0, 0,									
		16,											  
		0,											
		0,											
		PFD_MAIN_PLANE,								
		0,											
		0, 0, 0										
	};
	
	if (!(hDC=GetDC(hWnd)))							
	{
		KillGLWindow();								
		MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								
	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	
	{
		KillGLWindow();								
		MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								
	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		
	{
		KillGLWindow();								
		MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								
	}

	if (!(hRC=wglCreateContext(hDC)))				
	{
		KillGLWindow();								
		MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								
	}

	if(!wglMakeCurrent(hDC,hRC))					
	{
		KillGLWindow();								
		MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								
	}

	ShowWindow(hWnd,SW_SHOW);						
	SetForegroundWindow(hWnd);						
	SetFocus(hWnd);									
	ReSizeGLScene(width, height);					

	if (!InitGL())									
	{
		KillGLWindow();								
		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;							
	}

	return TRUE;								
}




LRESULT CALLBACK WndProc(	HWND	hWnd,			
							UINT	uMsg,			
							WPARAM	wParam,			
							LPARAM	lParam)			
{
	switch (uMsg)									
	{
		case WM_ACTIVATE:							
		{
			if (!HIWORD(wParam))					
			{
				active=TRUE;						
			}
			else
			{
				active=FALSE;						
			}

			return 0;								
		}

		case WM_SYSCOMMAND:							
		{
			switch (wParam)							
			{
				case SC_SCREENSAVE:					
				case SC_MONITORPOWER:				
				return 0;							
			}
			break;									
		}

		case WM_CLOSE:								
		{
			KillFont();
			PostQuitMessage(0);						
			return 0;								
		}

		case WM_KEYDOWN:							
		{
			keys[wParam] = TRUE;					
			return 0;								
		}




		case WM_KEYUP:								
		{
			keys[wParam] = FALSE;					
			return 0;								
		}


		case WM_LBUTTONDOWN: 
		{
			SelectObjects(LOWORD(lParam), HIWORD(lParam));
			return 0;
		}



		case WM_RBUTTONDOWN: 
		{
			
			 o2_rot1 += 3.0f; 
			 o3_rot1 += 3.0f; 
			 o4_rot1 += 3.0f; 
			return 0;
		}

		case WM_SIZE:								
		{
			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  
			return 0;								
		}
	}

	
	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}


int main(	HINSTANCE	hInstance,	HINSTANCE	hPrevInstance,		
					LPSTR		lpCmdLine,	int			nCmdShow)			
{
	MSG		msg;									
	BOOL	done=FALSE;								
	fullscreen=FALSE;							


	
	if (!CreateGLWindow("OpenGL Team Project",640,480,16,fullscreen))
	{
		return 0;									
	}

	while(!done)									
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	
		{
			if (msg.message==WM_QUIT)				
			{
				done=TRUE;							
			}
			else									
			{
				TranslateMessage(&msg);				
				DispatchMessage(&msg);				
			}
		}
		else										
		{
			
			if ((active && !DrawGLScene()) || keys[VK_ESCAPE])	
			{
				done=TRUE;							
			}
			else									
			{
				SwapBuffers(hDC);					
			}

			if (keys[VK_F1])						
			{
				keys[VK_F1]=FALSE;					
				KillGLWindow();						
				fullscreen=!fullscreen;				
				
				if (!CreateGLWindow("OpenGL Team Project",640,480,16,fullscreen))
				{
					return 0;						
				}
				
			}
			
			if (keys[VK_F2])						
			{
				keys[VK_F2]=FALSE;
				light=!light;				
				
			}
			if (keys[VK_F3])	
			{
				keys[VK_F3]=FALSE;
				textures=!textures;
				
			}
			if (keys[VK_F4])
			{
				keys[VK_F4]=FALSE;
				wire=!wire;	
				
			}
			if (keys[VK_F5])
			{
				keys[VK_F5]=FALSE;
				wire1=!wire1;
				
			}
			
		}
	}


	KillGLWindow();								
	return (msg.wParam);							
}
