// tmp_opengl.cpp : Defines the entry point for the application.
//
// ---------------------------------------------------------------
// Draw 3d text using wglUuseFontoutlines
// ---------------------------------------------------------------
//
// -------------------N.B.------------
// You must tell your linker to link to the openGl libraries:
// ++++++++++++++++ 
// Visual C++
// ++++++++++++++++
// In Visual C++ go to Project, Settings, and then click on the LINK tab. 
// Under "Object/Library Modules" at the beginning of the line (before kernel32.lib) add OpenGL32.lib GLu32.lib and GLaux.lib. 
// Once you've done this click  OK. 
//
// pre-complied header for Visual C++, comment this out for other compilers
#include "stdafx.h"
//
// ++++++++++++++++
// Dev-C++
// ++++++++++++++++
// In DevC++ select Project_Menu -> Project_options -> Parameters_Tab, type:
// -lopengl32 -lglu32 -lglaux
// in the "linker Box"
//
// Other Compilers will have diferent methods for specifing the link files



//////////////////////////////////////////////////////////////////////////////
//INCLUDES
//////////////////////////////////////////////////////////////////////////////
#define WIN32_LEAN_AND_MEAN 

#include    
#include  //Standard OpenGL Header
#include  //OpenGL utilities

//////////////////////////////////////////////////////////////////////////////
//DEFINES
//////////////////////////////////////////////////////////////////////////////
//name for our window class
#define WINDOWCLASS "win32OpenGL"
//title of the application
#define WINDOWTITLE "Simple OpenGl Program"

//////////////////////////////////////////////////////////////////////////////
//PROTOTYPES
//////////////////////////////////////////////////////////////////////////////
bool Prog_Init();//game data initalizer
void Prog_Loop();//main game loop
void Prog_Done();//game clean up

//////////////////////////////////////////////////////////////////////////////
//GLOBALS
//////////////////////////////////////////////////////////////////////////////
HINSTANCE hInstMain=NULL;//main application handle
HWND hWndMain=NULL;//handle to our main window
HDC g_hdc; 	// global handle to device context
HGLRC g_hrc; 	// global handle to rendering context

void SetupPixelFormat(HDC hdc){
	int nPixelFormat;

	  // set the pixel format we want
	static PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),	// size of structure
		1,                              // default version
		PFD_DRAW_TO_WINDOW |            // window drawing support
		PFD_SUPPORT_OPENGL |            // OpenGL support
		PFD_DOUBLEBUFFER,               // double buffering support
		PFD_TYPE_RGBA,                  // RGBA color mode
		32,                           // 32 bit color mode
		0, 0, 0, 0, 0, 0,               // ignore color bits, non-palettized mode
		0,                              // no alpha buffer
		0,                              // ignore shift bit
		0,                              // no accumulation buffer
		0, 0, 0, 0,                     // ignore accumulation bits
		16,                             // 16 bit z-buffer size
		0,                              // no stencil buffer
		0,                              // no auxiliary buffer
		PFD_MAIN_PLANE,                 // main drawing plane
		0,                              // reserved
		0, 0, 0 };                      // layer masks ignored

	// choose best matching pixelformat
	nPixelFormat=ChoosePixelFormat(hdc, &pfd);

	if (nPixelFormat == 0) {
		MessageBox(NULL, "ChoosePixelFormat() failed:  "
		   "Cannot find a suitable pixel format.", "Error", MB_OK); 
		return ;
    } 
 
	//set pixel format to device context
    if (SetPixelFormat(hdc,nPixelFormat,&pfd)== FALSE) {
		MessageBox(NULL, "SetPixelFormat() failed:  "
		   "Cannot set format specified.", "Error", MB_OK);
		return ;
    } 

	
}

void GLResize(int width,int height){

			if(height==0){height=1;} // prevent divide by zero

			glViewport(0,0,width,height);  // set new viewport size

			glMatrixMode(GL_PROJECTION); // reset projection matrix
			glLoadIdentity();

			//calculate new prespective and aspect ratio
			gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);

			glMatrixMode(GL_MODELVIEW); // reset modelview matrix
			glLoadIdentity();
}


//////////////////////////////////////////////////////////////////////////////
//WINDOWPROC
//////////////////////////////////////////////////////////////////////////////
LRESULT CALLBACK TheWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
	//which message did we get?
	switch(uMsg)
	{
		case WM_CREATE: //window is being created
		{
			return 0;
		}break;

		case WM_DESTROY://the window is being destroyed
		{
			//deselect RC and delete
			wglMakeCurrent(g_hdc,NULL);
			wglDeleteContext(g_hrc);
			
			//tell the application we are quitting
			PostQuitMessage(0);
			//handled message, so return 0
			return(0);
		}break;
		
		case WM_PAINT://the window needs repainting
		{
			//a variable needed for painting information
			PAINTSTRUCT ps;
			
			//start painting
			HDC hdc=BeginPaint(hwnd,&ps);

			/////////////////////////////
			//painting code would go here
			/////////////////////////////

			//end painting
			EndPaint(hwnd,&ps);
						
			//handled message, so return 0
			return(0);
		}break;
	
		case WM_SIZE:
		{	
			GLResize(LOWORD(lParam), HIWORD(lParam));
			return(0);
		}break;
	
	}

	//pass along any other message to default message handler
	return(DefWindowProc(hwnd,uMsg,wParam,lParam));
}


//////////////////////////////////////////////////////////////////////////////
//WINMAIN
//////////////////////////////////////////////////////////////////////////////
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
	//assign instance to global variable
	hInstMain=hInstance;

	//create window class
	WNDCLASSEX wcx;

	//set the size of the structure
	wcx.cbSize=sizeof(WNDCLASSEX);

	//class style
	wcx.style=CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

	//window procedure
	wcx.lpfnWndProc=TheWindowProc;

	//class extra
	wcx.cbClsExtra=0;

	//window extra
	wcx.cbWndExtra=0;

	//application handle
	wcx.hInstance=hInstMain;

	//icon
	wcx.hIcon=LoadIcon(NULL,IDI_APPLICATION);

	//cursor
	wcx.hCursor=LoadCursor(NULL,IDC_ARROW);

	//background color
	wcx.hbrBackground=NULL;

	//menu
	wcx.lpszMenuName=NULL;

	//class name
	wcx.lpszClassName=WINDOWCLASS;

	//small icon
	wcx.hIconSm=NULL;

	//register the window class, return 0 if not successful
	if(!RegisterClassEx(&wcx)) return(0);

	DWORD dwExStyle;
	DWORD dwStyle;

	int width=320,height=240;
	
	dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
	dwStyle = WS_OVERLAPPEDWINDOW;
	

	// set up the window we're rendering to so that the top left corner is at (0,0)
	// and the bottom right corner is (height,width)
	RECT  windowRect;
	windowRect.left = 0;
	windowRect.right = (LONG) width;
	windowRect.top = 0;
	windowRect.bottom = (LONG) height;

	// change the size of the rect to account for borders, etc. set by the style
	AdjustWindowRectEx(&windowRect, dwStyle, FALSE, dwExStyle);

	//create main window
	hWndMain=CreateWindowEx(dwExStyle,
				WINDOWCLASS,WINDOWTITLE, 
				WS_BORDER | WS_SYSMENU | WS_VISIBLE |WS_CLIPCHILDREN |
					WS_CLIPSIBLINGS |dwStyle,
				0,0,
				windowRect.right - windowRect.left, // width
                windowRect.bottom - windowRect.top, // height
				NULL,NULL,hInstMain,NULL
				);

	//error check
	if(!hWndMain) return(0);

	g_hdc=GetDC(hWndMain); // get window DC

	SetupPixelFormat(g_hdc); //

	g_hrc=wglCreateContext(g_hdc); // create a rendering context
	wglMakeCurrent(g_hdc,g_hrc);// make it current

	ShowWindow(hWndMain,SW_SHOW);
	
	UpdateWindow(hWndMain);

	GLResize(width,height);

	//if program initialization failed, then return with 0
	if(!Prog_Init()) return(0);

	//message structure
	MSG msg;

	//message pump
	for(;;)	
	{
		//look for a message
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			//there is a message

			//check that we arent quitting

			if(msg.message==WM_QUIT) break;
			
			//translate message
			TranslateMessage(&msg);

			//dispatch message
			DispatchMessage(&msg);
		}

		//run main game loop
		Prog_Loop();
	}
	
	//clean up program data
	Prog_Done();

	//return the wparam from the WM_QUIT message
	return(msg.wParam);
}

//////////////////////////////////////////////////////////////////////////////
//INITIALIZATION
//////////////////////////////////////////////////////////////////////////////
int font_list_base_3d=1000;
int font_list_base_2d=2000;

bool Prog_Init()
{
	////////////////////////////////////
	//your initialization code goes here
	////////////////////////////////////

	glEnable(GL_DEPTH_TEST); // check for depth
	
	glCullFace(GL_BACK); 
	glEnable(GL_CULL_FACE);
	
	glEnable(GL_LIGHTING); // switch on lighting
	glEnable(GL_LIGHT0); // switch on light0

	
	GLfloat light_color[]={1.0, 1.0, 1.0, 1.0};
	GLfloat light_position[]={10.0, 10.0, 10.0,0.0};


	glLightfv(GL_LIGHT0, GL_DIFFUSE, light_color); // set color of diffuse component
	glLightfv(GL_LIGHT0, GL_SPECULAR, light_color); // set color of specular component


	glLightfv(GL_LIGHT0, GL_POSITION, light_position);   // set position


	glEnable(GL_NORMALIZE);



	
	// create and select the font we want to use
	HFONT font = CreateFont(40, 0, 0, 0,
                           FW_NORMAL, FALSE, FALSE, FALSE,
                           ANSI_CHARSET, 0,
							0,0,0,"Times New Roman"); // can only use true type fonts

	SelectObject(g_hdc, font);


	wglUseFontOutlines(g_hdc,0,127,font_list_base_3d, 0.0f, 0.1f,WGL_FONT_POLYGONS,NULL); 
		// generate a display list for every character (up to ascii 127)
		// generate as accurately as possible (0.0f deviation)
		// extrude by 0.1 units
		// generate polygons (not lines) to render the fonts

	/*DeleteObject(font);

	font = CreateFont(0, 0, 0, 0,
                           FW_NORMAL, FALSE, FALSE, FALSE,
                           ANSI_CHARSET, 0,
							0, 0,0,"Courier New"); // can only use true type fonts


*/
	wglUseFontBitmaps(g_hdc,0,127,font_list_base_2d); 
	

	return(true);//return success
}

//////////////////////////////////////////////////////////////////////////////
//CLEANUP
//////////////////////////////////////////////////////////////////////////////
void Prog_Done()
{
	//////////////////////////
	//clean up code goes here
	//////////////////////////
}


//////////////////////////////////////////////////////////////////////////////
//MAIN GAME LOOP
//////////////////////////////////////////////////////////////////////////////

void Prog_Loop()
{
	///////////////////////////
	//main game logic goes here
	///////////////////////////
	
	static float angle =0.0f; // angle of rotation (in degrees)

	
	// Prepare to draw
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);//clear buffers
	glMatrixMode(GL_MODELVIEW); // reset modelview matrix
	glLoadIdentity();
	
	

	angle+=0.2f; // increase angle of rotation
	if(angle>=360.0f){angle-=360.0f;} // reset angle

	
	glTranslatef(0.0f,0.0f,-5.0f); 		// move modeling coords  back 5 units.



	glRotatef(angle, 0.0f, 1.0f, 0.0f); // rotate everything around y-axis, 
	glTranslatef(-2.0f,0.0f,0.0f); 

	glPushMatrix(); // save transforms
	
	glListBase(font_list_base_3d); //start of our font lists 
	glCallLists(12, GL_UNSIGNED_BYTE, "Hello World."); 
	
	glPopMatrix(); // restore transforms

	SwapBuffers(g_hdc); // bring back buffer foreground
}