CSC3222_Gaming_Technologies_And_Simulations / nclgl / Window.cpp
Window.cpp
Raw
#include "Window.h"
#include "Mouse.h"
#include "Keyboard.h"

Window* Window::window;

Keyboard*Window::keyboard	= NULL;
Mouse*Window::mouse			= NULL;
//GameTimer*Window::timer		= NULL;

Window::Window(std::string title, int sizeX, int sizeY, bool fullScreen)	{
	renderer		= NULL;
	window			= this;
	forceQuit		= false;
	init			= false;
	mouseLeftWindow	= false;
	lockMouse		= false;
	showMouse		= true;

	this->fullScreen = fullScreen;

	size.x = (float)sizeX; size.y = (float)sizeY;

	fullScreen ? position.x = 0.0f : position.x = 100.0f;
	fullScreen ? position.y = 0.0f : position.y = 100.0f;

	HINSTANCE hInstance = GetModuleHandle( NULL );

	WNDCLASSEX windowClass;
	ZeroMemory(&windowClass, sizeof(WNDCLASSEX));

	if(!GetClassInfoEx(hInstance,WINDOWCLASS,&windowClass))	{
		windowClass.cbSize		= sizeof(WNDCLASSEX);
	    windowClass.style		= CS_HREDRAW | CS_VREDRAW;
		windowClass.lpfnWndProc	= (WNDPROC)WindowProc;
		windowClass.hInstance	= hInstance;
		windowClass.hCursor		= LoadCursor(NULL, IDC_ARROW);
		windowClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
		windowClass.lpszClassName = WINDOWCLASS;

		if(!RegisterClassEx(&windowClass)) {
			std::cout << "Window::Window(): Failed to register class!" << std::endl;
			return;
		}
	}

	if(fullScreen) {
		DEVMODE dmScreenSettings;								// Device Mode
		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory's Cleared

		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure
		dmScreenSettings.dmPelsWidth	= sizeX;				// Selected Screen Width
		dmScreenSettings.dmPelsHeight	= sizeY;				// Selected Screen Height
		dmScreenSettings.dmBitsPerPel	= 32;					// Selected Bits Per Pixel
		dmScreenSettings.dmDisplayFrequency = 60;
		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT|DM_DISPLAYFREQUENCY;

		if(ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)	{
			std::cout << "Window::Window(): Failed to switch to fullscreen!" << std::endl;
			return;
		}
	}

	windowHandle = CreateWindowEx(fullScreen ? WS_EX_TOPMOST : NULL,
	WINDOWCLASS,    // name of the window class
	title.c_str(),   // title of the window
	fullScreen ? WS_POPUP|WS_VISIBLE : WS_OVERLAPPEDWINDOW|WS_POPUP|WS_VISIBLE|WS_SYSMENU|WS_MAXIMIZEBOX|WS_MINIMIZEBOX,    // window style
						(int)position.x,	// x-position of the window
                        (int)position.y,	// y-position of the window
                        (int)size.x,		// width of the window
                        (int)size.y,		// height of the window
                        NULL,				// No parent window!
                        NULL,				// No Menus!
                        hInstance,			// application handle
                        NULL);				// No multiple windows!

 	if(!windowHandle) {
		std::cout << "Window::Window(): Failed to create window!" << std::endl;
		return;
	}

	if(!keyboard) {
		keyboard	= new Keyboard(windowHandle);
	}
	if(!mouse) {
		mouse		= new Mouse(windowHandle);
	}
	//if(!timer) {
		timer		= new GameTimer();
	//}
	elapsedMS	= timer->GetMS();

	Window::GetMouse()->SetAbsolutePositionBounds((unsigned int)size.x,(unsigned int)size.y);

	POINT pt;
	GetCursorPos(&pt);
	ScreenToClient(window->windowHandle, &pt);
	Window::GetMouse()->SetAbsolutePosition(pt.x,pt.y);

	LockMouseToWindow(lockMouse);
	ShowOSPointer(showMouse);

	init = true;
}


Window::~Window(void)
{
	delete keyboard;keyboard = NULL;
	delete mouse;	mouse = NULL;
}

HWND Window::GetHandle() {
	return windowHandle;
}

bool Window::HasInitialised() {
	return init;
}

void	Window::SetRenderer(OGLRenderer* r)	{
	renderer = r;
	if(r) {
		renderer->Resize((int)size.x,(int)size.y);				
	}
}

bool	Window::UpdateWindow() {
	MSG		msg;

	float diff = timer->GetMS()-elapsedMS;

	Window::GetMouse()->UpdateDoubleClick(diff);

	Window::GetKeyboard()->UpdateHolds();
	Window::GetMouse()->UpdateHolds();

	while(PeekMessage(&msg,windowHandle,0,0,PM_REMOVE)) {
		CheckMessages(msg); 
	}

	elapsedMS = timer->GetMS();

	return !forceQuit;
}

void Window::CheckMessages(MSG &msg)	{
	switch (msg.message)	{				// Is There A Message Waiting?
		case (WM_QUIT):
		case (WM_CLOSE): {					// Have We Received A Quit Message?
			window->ShowOSPointer(true);
			window->LockMouseToWindow(false);
			forceQuit = true;
		}break;
		case (WM_INPUT): {
			UINT dwSize;
			GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, NULL, &dwSize,sizeof(RAWINPUTHEADER));

			BYTE* lpb = new BYTE[dwSize];
	
			GetRawInputData((HRAWINPUT)msg.lParam, RID_INPUT, lpb, &dwSize,sizeof(RAWINPUTHEADER));
			RAWINPUT* raw = (RAWINPUT*)lpb;

			if (keyboard && raw->header.dwType == RIM_TYPEKEYBOARD) {
				Window::GetKeyboard()->Update(raw);
			}

			if (mouse && raw->header.dwType == RIM_TYPEMOUSE) {
				Window::GetMouse()->Update(raw);
			}
			delete lpb;
		}break;

		default: {								// If Not, Deal With Window Messages
			TranslateMessage(&msg);				// Translate The Message
			DispatchMessage(&msg);				// Dispatch The Message
		}
	}
}

LRESULT CALLBACK Window::WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)	{
    switch(message)	 {
        case(WM_DESTROY):	{
			window->ShowOSPointer(true);
			window->LockMouseToWindow(false);

			PostQuitMessage(0);
			window->forceQuit = true;
		} break;
		case (WM_ACTIVATE): {
			//int fMinimized	= (BOOL) HIWORD(wParam);
			if(LOWORD(wParam) == WA_INACTIVE)	{
				ReleaseCapture();
				ClipCursor(NULL);
				mouse->Sleep();
				keyboard->Sleep();			
			}
			else{
				if(window->init) {
					mouse->Wake();	
					keyboard->Wake();

					POINT pt;
					GetCursorPos(&pt);
					ScreenToClient(window->windowHandle, &pt);
					mouse->SetAbsolutePosition(pt.x,pt.y);

					if(window->lockMouse) {
						window->LockMouseToWindow(true);
					}
				}
			}
			return 0;
		}break;
		case (WM_LBUTTONDOWN): {
			if(window->lockMouse) {
				window->LockMouseToWindow(true);
			}

		}break;

		case (WM_MOUSEMOVE): {
			TRACKMOUSEEVENT tme;
			tme.cbSize = sizeof(TRACKMOUSEEVENT);
			tme.dwFlags = TME_LEAVE;
			tme.hwndTrack = window->windowHandle;
			TrackMouseEvent(&tme);

			if(window->mouseLeftWindow) {
				window->mouseLeftWindow = false;
				mouse->Wake();
				keyboard->Wake();

				POINT pt;
				GetCursorPos(&pt);
				ScreenToClient(window->windowHandle, &pt);
				mouse->SetAbsolutePosition(pt.x,pt.y);
			}

		}break;
		case(WM_MOUSELEAVE):{
			window->mouseLeftWindow = true;
			mouse->Sleep();
			keyboard->Sleep();
		}break;
		case(WM_SIZE): {
			window->size.x = (float)LOWORD(lParam);
			window->size.y = (float)HIWORD(lParam);
			if(window->renderer) {
				window->renderer->Resize(LOWORD(lParam),HIWORD(lParam));				
			}

			if(window->init) {
				mouse->SetAbsolutePositionBounds(LOWORD(lParam),HIWORD(lParam));

				POINT pt;
				GetCursorPos(&pt);
				ScreenToClient(window->windowHandle, &pt);
				mouse->SetAbsolutePosition(pt.x,pt.y);

				window->LockMouseToWindow(window->lockMouse);
			}
		}break;
    }
    return DefWindowProc (hWnd, message, wParam, lParam);
}

void	Window::LockMouseToWindow(bool lock)	{
	lockMouse = lock;
	if(lock) {
		RECT		windowRect;
		GetWindowRect (window->windowHandle, &windowRect);

		SetCapture(window->windowHandle);
		ClipCursor(&windowRect);

		POINT pt;
		GetCursorPos(&pt);
		ScreenToClient(window->windowHandle, &pt);
		Window::GetMouse()->SetAbsolutePosition(pt.x,pt.y);
	}
	else{
		ReleaseCapture();
		ClipCursor(NULL);
	}
}

void	Window::ShowOSPointer(bool show)	{
	if(show == showMouse) {
		return;	//ShowCursor does weird things, due to being a counter internally...
	}

	showMouse = show;
	if(show) {
		ShowCursor(1);
	}
	else{
		ShowCursor(0);
	}
}