////////////////////////////////////////////////////////////
//                                                        //
//  PC MAGAZIN - PC Underground                           //
//  PC Underground OpenGL Startup - F8 drücken !          //
//                                                        //
////////////////////////////////////////////////////////////
#define     WIN32_LEAN_AND_MEAN
#define     WIN32_EXTRA_LEAN
#define     VC_EXTRALEAN

#include	<windows.h>			
#include	<gl\gl.h>			
#include	<gl\glu.h>			
#include	"resource.h"

#pragma comment(lib, "Winmm.lib")	//Search for the windows multimedia library at compile time
#pragma comment(lib, "OpenGL32.lib")//Search for the OpenGL32 library at compile time
#pragma comment(lib, "Glu32.lib")	//Search for the Glu32 library at compile time
#pragma comment(lib, "Glaux.lib")	//Search for the Glu32 library at compile time

const char pcuWindowTitle[] = "www.dachsbacher.de/pcu - PC Underground P-Buffer Example - (w)(c)2002 C. Dachsbacher";

#define ALPHABUFFERDEPTH	4
#define ZBUFFERDEPTH		16


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

bool		keys[ 256 ];
int			active = 1;
int			fullscreen = 0;

int			windowX, windowY;

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

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

	windowX = width;
	windowY = height;

	glMatrixMode( GL_PROJECTION );
	glPushMatrix();
	glLoadIdentity();
	glViewport( 0, 0, width, height );
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

int InitGL()
{
	glShadeModel( GL_SMOOTH );
	glClearColor( 0.2f, 0.2f, 0.3f, 0.0f );
	glClearDepth( 1.0f );
	
	glEnable( GL_DEPTH_TEST );

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

	extern void init3DEngine();
	init3DEngine();

	return true;
}

int DrawGLScene()
{
	extern void draw3DEngine();
	draw3DEngine();

	return true;
}

void KillGLWindow()
{
	extern void quit3DEngine();
	quit3DEngine();

	if ( fullscreen )
	{
		ChangeDisplaySettings( NULL, 0 );
		ShowCursor( true );
	}

	if ( hRC )
	{
		if ( !wglMakeCurrent( NULL, NULL ) )
		{
			MessageBox( NULL, "DC/RC konnte nicht freigegeben werden", "PC Underground: OGL Error",
						MB_OK | MB_ICONERROR );
		}

		if ( !wglDeleteContext( hRC ) )
		{
			MessageBox( NULL, "Rendering Context konnte nicht freigegeben werden",
						"PC Underground: OGL Error", MB_OK | MB_ICONERROR );
		}
		hRC = NULL;
	}

	if ( hDC && !ReleaseDC( hWnd, hDC ) )
	{
		MessageBox( NULL, "Device Context konnte nicht freigegeben werden",
					"PC Underground: OGL Error", MB_OK | MB_ICONERROR );
		hDC = NULL;
	}

	if ( hWnd && !DestroyWindow( hWnd ) )
	{
		MessageBox( NULL, "HWND konnte nicht freigegeben werden", "PC Underground: OGL Error",
					MB_OK | MB_ICONERROR );
		hWnd = NULL;
	}

	if ( !UnregisterClass( "PCUWindowClass", hInstance ) )
	{
		MessageBox( NULL, "Regsitrierung der Fensterklasse konnte nicht rückgängig gemacht werden",
					"PC Underground: OGL Error", MB_OK | MB_ICONERROR );
		hInstance = NULL;
	}
}

BOOL CreateGLWindow( char *title, int width, int height, int bits, int fullscreenflag )
{
	int			PixelFormat;
	WNDCLASS	wc;
	DWORD		dwExStyle;
	DWORD		dwStyle;
	RECT		WindowRect;

	WindowRect.left		= 0;
	WindowRect.right	= width;
	WindowRect.top		= 0;
	WindowRect.bottom	= height;

	windowX = width;
	windowY = height;

	fullscreen = fullscreenflag;

	// hier erzeugen wir unsere fensterklasse
	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( hInstance, MAKEINTRESOURCE( IDI_DEMO_ICON ) );
	wc.hCursor			= LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground	= NULL;
	wc.lpszMenuName		= NULL;
	wc.lpszClassName	= "PCUWindowClass";

	if ( !RegisterClass( &wc ) )
	{
		MessageBox( NULL, "Fensterklasse konnte nicht registriert werden",
					"PC Underground: Win Error", MB_OK | MB_ICONERROR );
		return false;
	}
	
	if ( fullscreen )
	{
		DEVMODE screenRes;
		memset( &screenRes, 0, sizeof( screenRes ) );

		screenRes.dmSize		= sizeof(screenRes);
		screenRes.dmPelsWidth	= width;
		screenRes.dmPelsHeight	= height;
		screenRes.dmBitsPerPel	= bits;
		screenRes.dmFields		= DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;

		if ( ChangeDisplaySettings( &screenRes, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
		{
			// gewünschter vollbild modus geht nicht: beenden oder fenster ?
			if ( MessageBox( NULL, "Vollbild Modus wird nicht unterstützt. Weiter im Fenster ?", 
							 "PC Underground: OpenGL", MB_YESNO | MB_ICONEXCLAMATION ) == IDYES )
				fullscreen = false;	else
				return false;
		}

		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 );

	// fenster erzeugen
	if ( !( hWnd = CreateWindowEx(	dwExStyle,
									"PCUWindowClass",
									title,
									dwStyle | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
									0, 0, WindowRect.right-WindowRect.left,	WindowRect.bottom-WindowRect.top,
									NULL, NULL,	hInstance, NULL ) ) )
	{
		KillGLWindow();
		return false;
	}

	static	PIXELFORMATDESCRIPTOR pfd =
	{
		sizeof(PIXELFORMATDESCRIPTOR),				// Größe des Pixel Format Descriptor
		1,											// Version 
		PFD_GENERIC_ACCELERATED|
		PFD_DRAW_TO_WINDOW |						// Format muß Fenster unterstützen
		PFD_SUPPORT_OPENGL |						// ... und OpenGL
		PFD_DOUBLEBUFFER,							// Double Buffering
		PFD_TYPE_RGBA,								// RGBA Format
		bits,										// Farbtiefe
		0, 0, 0, 0, 0, 0,							// 
		ALPHABUFFERDEPTH,							// kein Alpha Buffer
		0,											// 
		0,											// kein Accumulation Buffer
		0, 0, 0, 0,									// 
		ZBUFFERDEPTH,											// 16Bit Z-Buffer
		4,											// kein Stencil Buffer
		0,											// kein Auxiliary Buffer
		PFD_MAIN_PLANE,								// 
		0,											// 
		0, 0, 0										// 
	};
	
	if ( !( hDC = GetDC( hWnd ) ) )
	{
		KillGLWindow();
		MessageBox( NULL, "OpenGL Device Context konnte nicht erzeugt werden",
					"PC Underground: Error", MB_OK | MB_ICONERROR );
		return false;
	}

	if ( !( PixelFormat = ChoosePixelFormat( hDC, &pfd ) ) )
	{
		KillGLWindow();
		MessageBox( NULL, "Es wurde kein passendes Pixelformat gefunden",
					"PC Underground: Error", MB_OK | MB_ICONERROR );
		return false;
	}

	if( !SetPixelFormat( hDC, PixelFormat, &pfd ) )
	{
		KillGLWindow();
		MessageBox( NULL, "Pixelformat konnnte nicht gesetzt werden",
					"PC Underground: Error", MB_OK | MB_ICONERROR );
		return false;
	}

	if (!( hRC = wglCreateContext( hDC ) ) )
	{
		KillGLWindow();
		MessageBox( NULL, "Es konnte kein OpenGL Rendering Context erzeugt werden",
					"PC Underground: Error", MB_OK | MB_ICONERROR );
		return false;
	}

	if( !wglMakeCurrent( hDC, hRC ) )
	{
		KillGLWindow();
		MessageBox( NULL, "OpenGl Rendering Context konnte nicht aktiviert werden",
					"PC Underground: Error", MB_OK | MB_ICONERROR );
		return false;
	}

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

	if ( !InitGL() )
	{
		KillGLWindow();
		MessageBox( NULL, "Initialisierung fehlgeschlagen",
					"PC Underground: Error", MB_OK | MB_ICONERROR );
		return false;
	}

	return true;
}

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

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

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

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

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

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


INT WINAPI WinMain(HINSTANCE hInst,HINSTANCE hPrevInst, LPSTR lpCmdLine,INT nCmdShow ) 
{
	MSG		msg;
	BOOL	done = false;

	fullscreen = 0;

	if (!CreateGLWindow( (char*)pcuWindowTitle, 640, 480, 32, 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 )
			{
				if ( keys[ VK_ESCAPE ] )
					done = true; else
				{
					DrawGLScene();
					SwapBuffers(hDC);
				}
			}

			if ( keys[ VK_F8 ] )
			{
				keys[ VK_F8 ] = false;
				KillGLWindow();
				fullscreen = 1 - fullscreen;
				if ( !CreateGLWindow( (char*)pcuWindowTitle, 640, 480, 32, fullscreen ) )
					return 0;
			}
		}
	}

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


