/** 
 * \file Game.cpp
 * \brief CGame class function implementation.
 * 
 * This file is games' mode switcher.
 * Game is divided into several modes:
 * 1. Menu mode - when you start the game you see the main menu (See CMenu class for details).
 * 2. Movie mode - when you start new game, intro movie is played (See CMovie for details).
 * 3. Level mode - when game starts you are in level mode (See CLevel class for details).
 * 4. Bonus mode - Additional modes can be added easily like bonus levels, etc. 
 * \author Petar Bajic, MPE (C) All Rights Reserved, Homepage: www.mystic-peanut.com
 * \date January, 16 2007.
 */

#include "Game.h"
#include "Language.h"
#include <ctime>

/**
 * Standard constructor. 
 * Game varibles are initialized to 0.
 * To see real initialization, see CGame::Init() function.
 */
CGame::CGame()
{
	m_GamePaused = false;
	m_PausedByAltTab = false;
	m_wasMaximized = false;
	m_GameMode = GAMEMODE_MENU;
	m_pd3dDevice = NULL;
	m_pd3dPP = NULL;
	m_pD3D = NULL;
	m_pDS = NULL;
	m_screenWidth = 0;
	m_screenHeight = 0;
	m_oldScreenWidth = 0;
	m_oldScreenHeight = 0;
	m_Menu = new CMenu();
	m_Level = new CLevel();
	m_Movie = new CMovie();
	m_Bonus = new CBonus();
	m_EyePt = D3DXVECTOR3( -15.0f , 15.0f, 0.0f );
	m_LookatPt = D3DXVECTOR3( 0.0f, 0.0f, +4.0f );
	m_UpVec = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
	m_ElapsedTime = 0;
	m_CurrentTime = 0;
	m_BaseTime = 0;
	m_bUsingQPF = false;
	m_aspectRatio = 0.0f;
	m_loadingTexture1 = NULL;
	m_loadingTexture2 = NULL;
	m_loadingTexture3 = NULL;
	m_sprite = NULL;
	m_pFont = NULL;
	m_pTerrain = NULL;
	m_pTurtle = NULL;
	m_pSheep = NULL;
	m_ConfigFullScreen = false;
	m_ConfigDetails = true;
	m_ConfigDificulty = 2.0;
	m_ConfigLanguage = 0;
	m_ConfigStartCount = 0;
	m_Language = NULL;
	m_total_counter = 0;
	m_total_number = 0;
}

/**
 * Standard Destructor
 * All that is created (alocated) in Init should be released here.
 */
CGame::~CGame()
{
	m_Menu->~CMenu(); //calling destructor of menu will release all that menu has allocated
	m_Level->~CLevel(); //calling destructor of level will release all that level has allocated
	m_Movie->~CMovie(); //calling destructor of movie will release all that movie has allocated
	m_Bonus->~CBonus();
	if (m_pd3dDevice != NULL)
		m_pd3dDevice->Release();
	if (m_pD3D != NULL)
		m_pD3D->Release();
	SAFE_RELEASE( m_pDS );
	SAFE_RELEASE(m_sprite);
	SAFE_RELEASE(m_pFont);
	SAFE_RELEASE(m_loadingTexture1);
	SAFE_RELEASE(m_loadingTexture2);
	SAFE_RELEASE(m_loadingTexture3);
	SAFE_DELETE(m_pTerrain);
	SAFE_DELETE(m_pTurtle);
}

/**
 * Render Loading Picture. When user starts the game, loading screen is displayed
 * because it takes time to load all models. Sheep is being 'filled' while loading.
 */
void CGame::RenderLoading(D3DXVECTOR2 loadingTrans2, WCHAR* strText)
{
	D3DXMATRIX mat;
	D3DXVECTOR2 spriteCentre=D3DXVECTOR2(0.0f,0.0f);
	D3DXVECTOR2 scaling=D3DXVECTOR2(0.5f,0.5f);
	D3DXVECTOR2 loadingTrans((float)m_screenWidth/2-235,(float)m_screenHeight/2-360);
	float rotation=0;
	RECT rect;
	rect.top = 420;
	rect.bottom = 550;
	rect.left = 30;
	rect.right = 462;

	// Clear the backbuffer to a black color
	m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
	// Begin the scene
	if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
	{
		m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, TRUE );
		m_sprite->Begin(D3DXSPRITE_ALPHABLEND);
		//Draw full image sheep
		my_DrawSprite(&mat, &scaling, &spriteCentre, rotation, &loadingTrans, m_loadingTexture1, m_sprite, true, &rect, strText, m_pFont, 0xFFAA0000);
		//Draw shifting white background - creates illusion of sheep being filled
		scaling.x = 0.6f;
		my_DrawSprite(&mat, &scaling, &spriteCentre, rotation, &loadingTrans2, m_loadingTexture2, m_sprite, true, NULL, NULL, NULL, NULL);
		//Draw transparent sheep with red text
		scaling.x = 0.5f;
		my_DrawSprite(&mat, &scaling, &spriteCentre, rotation, &loadingTrans, m_loadingTexture3, m_sprite, true, &rect, strText, m_pFont, 0xFFAA0000);
		m_sprite->End();
		m_pd3dDevice->SetRenderState( D3DRS_ALPHABLENDENABLE, FALSE );
		m_pd3dDevice->EndScene(); // End the scene
	}
	// Present the backbuffer contents to the display
	m_pd3dDevice->Present( NULL, NULL, NULL, NULL );

}

/**
 * Write settings to ini file.
 * On game exit, active settings are being written to config.ini file.
 * These include Fullscreen mode, dificulty, details, etc.
 */
void CGame::WriteSettingsToFile()
{
	FILE * pFile;
	char str[256];
	pFile = _wfopen (L"config.ini", L"w");
	if (pFile!=NULL)
	{
		fputs ("Config file",pFile);
		fputs ("\n\n",pFile);
		//Save fullscreen config to config.ini
		if(m_ConfigFullScreen)
			fputs ("FULLSCREEN - yes",pFile);
		else
			fputs ("FULLSCREEN - no",pFile);
		fputs ("\n",pFile);

		if(m_ConfigDificulty == 2.0)
			fputs ("DIFICULTY  - hard",pFile);
		else
			fputs ("DIFICULTY  - easy",pFile);
		fputs ("\n",pFile);

		if(m_ConfigDetails)
			fputs ("DETAILS    - yes",pFile);
		else
			fputs ("DETAILS    - no",pFile);
		fputs ("\n",pFile);

		if(m_ConfigLanguage == 0)
			fputs ("LANGUAGE   - english",pFile);
		else
			fputs ("LANGUAGE   - srpski",pFile);
		fputs ("\n",pFile);

		sprintf(&str[0],"STARTCNT   - %d",m_ConfigStartCount);
		fputs(str,pFile);

		fputs ("\n",pFile);
		fputs ("\n",pFile);
		fputs ("Config end",pFile);
		fputs ("\n",pFile);
		fputs ("\n",pFile);
		fputs ("MPE (c) 2007 www.mystic-peanut.com",pFile);
		fclose(pFile);
	}
}

/**
 * Load data from config.ini file.
 * When game is started, settings like fullscreen, dificulty and details are loaded. 
 */
bool CGame::LoadSettingsFromFile(HWND hWnd)
{
	//Open fileName
	FILE * pFile;
	char str[200];
	
	pFile = _wfopen (L"config.ini",L"r");
	if (pFile!=NULL)
	{
		fgets(str,200,pFile);
		char* strLastSlash = strrchr( str, '\n' );
		if( strLastSlash )
			strLastSlash[0] = '\0';
		//Check if file content is as expected
		if (!strcmp(str,"Config file"))
		{
			fgets(str,200,pFile);

			//FULLSCREEN
			fgets(str,200,pFile);
			strLastSlash = strrchr( str, '\n' );
			if( strLastSlash )
				strLastSlash[0] = '\0';
			strLastSlash = strrchr( str, '-' );
			if (!strcmp(&(strLastSlash[2]),"yes"))
				m_ConfigFullScreen = true;
			else
				m_ConfigFullScreen = false;

			//DIFICULTY
			fgets(str,200,pFile);
			strLastSlash = strrchr( str, '\n' );
			if( strLastSlash )
				strLastSlash[0] = '\0';
			strLastSlash = strrchr( str, '-' );
			if (!strcmp(&(strLastSlash[2]),"easy"))
				m_ConfigDificulty = 3.0;
			else
				m_ConfigDificulty = 2.0;

			//DETAILS
			fgets(str,200,pFile);
			strLastSlash = strrchr( str, '\n' );
			if( strLastSlash )
				strLastSlash[0] = '\0';
			strLastSlash = strrchr( str, '-' );
			if (!strcmp(&(strLastSlash[2]),"yes"))
				m_ConfigDetails = true;
			else
				m_ConfigDetails = false;

			//LANGUAGE
			fgets(str,200,pFile);
			strLastSlash = strrchr( str, '\n' );
			if( strLastSlash )
				strLastSlash[0] = '\0';
			strLastSlash = strrchr( str, '-' );
			if (!strcmp(&(strLastSlash[2]),MPE_TEXT_ENGLISH))
				m_ConfigLanguage = 0;
			else
				m_ConfigLanguage = 1;

			//START NUMBER
			fgets(str,200,pFile);
			strLastSlash = strrchr( str, '\n' );
			if( strLastSlash )
				strLastSlash[0] = '\0';
			strLastSlash = strrchr( str, '-' );
			m_ConfigStartCount = atoi(&(strLastSlash[2]));
			m_ConfigStartCount++;

			//Last content check
			fgets(str,200,pFile);
			fgets(str,200,pFile);
			strLastSlash = strrchr( str, '\n' );
			if( strLastSlash )
				strLastSlash[0] = '\0';
			if (strcmp(str,"Config end"))
			{
				MessageBox(hWnd,L"Corrupted config.ini file!",L"Error",MB_OK);
				m_ConfigDificulty = 3.0;
				m_ConfigFullScreen = false;
				m_ConfigDetails = true;
				m_ConfigLanguage = 0;
				m_ConfigStartCount = 1;
				//return false;
			}
			
		}
		else
		{
			MessageBox(hWnd,L"Corrupted config.ini file!",L"Error",MB_OK);
			m_ConfigDificulty = 3.0;
			m_ConfigFullScreen = false;
			m_ConfigDetails = true;
			m_ConfigLanguage = 0;
			m_ConfigStartCount = 1;
			//return false;
		}
	}
	else
	{
		//MessageBox(hWnd,L"Could not find config.ini file",L"Error",MB_OK);
		m_ConfigDificulty = 3.0;
		m_ConfigFullScreen = false;
		m_ConfigDetails = true;
		m_ConfigLanguage = 0;
		m_ConfigStartCount = 1;
		//return false;
	}
	return true;
}

/**
 * Init function loads all game elements (models, music, textures...) and sets default parameters.
 * It calls init functions of all game modes like CMenu::Init() and CLevel::Init(), 
 * sending them various environment parameters and 'global' game variables.
 */
bool CGame::Init(HWND hWnd, int screenWidth, int screenHeight)
{
	WCHAR wstr[256];
	m_screenWidth = screenWidth;
	m_screenHeight = screenHeight;
	m_GameMode = GAMEMODE_MENU;
	m_aspectRatio = (float)screenWidth/(float)screenHeight;

	//Seed random generator
	srand(time(0));

	//Load settings from ini file:
	if(!LoadSettingsFromFile(hWnd))
		return false;

	if(m_ConfigFullScreen)
	{
		CaptureWindowParameters(hWnd);
	}

	m_Language = new CLanguage();
	if(!m_Language->SetLanguage(m_ConfigLanguage))
		return false;

	//Init DirectX 3D
	if (!InitD3D(hWnd, &m_pd3dDevice, &m_pD3D, &m_pd3dPP, m_ConfigFullScreen))
	{
		//Display Error Message "D3D could not be initialized, check directX version"
		return false;
	}

	if(m_ConfigFullScreen)
	{
		//Set fullscreen parameters
		m_screenWidth = m_pd3dPP->BackBufferWidth;
		m_screenHeight = m_pd3dPP->BackBufferHeight;
		m_oldScreenWidth = screenWidth;
		m_oldScreenHeight = screenHeight;
		m_aspectRatio = (float)m_screenWidth/(float)m_screenHeight;
	}

	//Draw Loading... picture. (This takes so much space it could be moved to separate function)
	D3DXVECTOR2 loadingTrans2((float)m_screenWidth/2-60,(float)m_screenHeight/2-135);

	if (FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,L"Media/Pics/loading3.png", &m_loadingTexture3 )))
	{
		MessageBox(hWnd,L"Could not load Media/Pics/loading3.png file",L"Error",MB_OK);
		return false;
	}
	if (FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,L"Media/Pics/loading2.png", &m_loadingTexture2 )))
	{
		MessageBox(hWnd,L"Could not load Media/Pics/loading2.png file",L"Error",MB_OK);
		return false;
	}
	if (FAILED(D3DXCreateTextureFromFile(m_pd3dDevice,L"Media/Pics/loading1.png", &m_loadingTexture1 )))
	{
		MessageBox(hWnd,L"Could not load Media/Pics/loading1.png file",L"Error",MB_OK);
		return false;
	}
	if (FAILED(D3DXCreateSprite(m_pd3dDevice,&m_sprite)))
	{
		MessageBox(hWnd,L"Could not create sprite component",L"Error",MB_OK);
		return false;
	}
	if (FAILED(D3DXCreateFont(m_pd3dDevice,22, 0, 0, 0, false, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, L"Arial",&m_pFont)))
	{
		MessageBox(hWnd,L"Could not create font component",L"Error",MB_OK);
		return false;
	}

	SetupMatrices(&m_pd3dDevice, &m_EyePt, &m_LookatPt, &m_UpVec, m_aspectRatio);

	//Draw loading screen
	wsprintf(&wstr[0],L"%s... 10%%",m_Language->GetText(MPE_TEXT_GAME_LOADING));
	RenderLoading(loadingTrans2, wstr);

	//Init Sound
	if (!InitSound(hWnd, &m_pDS))
	{
		return false;
	}
	//Init Lights
	if (!(InitLight(m_pd3dDevice, &m_Light1, &m_Light2, &m_Light3)))
	{
		return false;
	}

	//Render Loading Picture
	loadingTrans2.y -=10;
	wsprintf(&wstr[0],L"%s... 20%%",m_Language->GetText(MPE_TEXT_GAME_LOADING));
	RenderLoading(loadingTrans2, wstr);

	//Init Terrain
	m_pTerrain = new CTerrain();
	if (!m_pTerrain->Init(hWnd, m_pd3dDevice, m_screenWidth, m_screenHeight))
	{
		MessageBox(hWnd,L"Could not load Terrain",L"Error",MB_OK);
		return false;
	}

	//Render Loading Picture
	loadingTrans2.y -=20;
	wsprintf(&wstr[0],L"%s... 50%%",m_Language->GetText(MPE_TEXT_GAME_LOADING));
	RenderLoading(loadingTrans2, wstr);

	//Load Turtle and Sheep (and later send their instances to Menu, Movie and Level)
	m_pTurtle = new CTurtle();
	if (!m_pTurtle->Init(hWnd,m_pd3dDevice))
		return false; //Turtle.cpp writes error message
	m_pSheep = new CSheep();
	if (!m_pSheep->Init(hWnd,m_pd3dDevice,m_pDS))
		return false;//Sheep.cpp writes error message

	//Init Level, load all models
	if(!(m_Level->Init(hWnd, m_pd3dDevice, m_screenWidth, m_screenHeight, m_pDS, m_pTerrain, m_pTurtle, m_pSheep, m_Language)))
	{
		//Display Error Message "Level could not be initialized"
		return false;
	}

	//Render Loading Picture
	loadingTrans2.y -=20;
	wsprintf(&wstr[0],L"%s... 70%%",m_Language->GetText(MPE_TEXT_GAME_LOADING));
	RenderLoading(loadingTrans2, wstr);

	//Init Main Menu GUI
	if(!(m_Menu->Init(hWnd, m_pd3dDevice, m_screenWidth, m_screenHeight, m_pDS, m_ConfigDificulty, m_ConfigDetails, m_ConfigFullScreen, m_pTurtle, m_Language)))
	{
		//Display Error Message "Menu could not be initialized"
		return false;
	}

	//Render Loading Picture
	loadingTrans2.y -=20;
	wsprintf(&wstr[0],L"%s... 90%%",m_Language->GetText(MPE_TEXT_GAME_LOADING));
	RenderLoading(loadingTrans2, wstr);

	//Init Movies
	if(!m_Movie->Init(hWnd, m_pd3dDevice, m_screenWidth, m_screenHeight, m_pTerrain, m_pTurtle, m_pSheep, m_Language))
	{
		return false;
	}

	//Init Bonus Levels
	m_Bonus->Init(m_pd3dDevice);

	//Render Loading Picture
	loadingTrans2.y -=20;
	wsprintf(&wstr[0],L"%s... 100%%",m_Language->GetText(MPE_TEXT_GAME_LOADING));
	RenderLoading(loadingTrans2, wstr);

	//Init time after all inits
    // Use QueryPerformanceFrequency() to get frequency of timer.  
	LARGE_INTEGER qwTicksPerSec;
	m_bUsingQPF = (bool) (QueryPerformanceFrequency( &qwTicksPerSec ) != 0);
	if (!m_bUsingQPF)
		return false;
	m_QPFTicksPerSec = qwTicksPerSec.QuadPart;
	LARGE_INTEGER qwTime;
	QueryPerformanceCounter( &qwTime );
	m_BaseTime = qwTime.QuadPart;

	return true;
}

/**
 * On Event function catch events like mouse click and keyboard input.
 * It takes care of resizing game window.
 * It passes events to appropriate game mode.
 */
bool CGame::OnEvent(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	float iMouseX = (float)LOWORD(lParam);
	float iMouseY = (float)HIWORD(lParam);
    bool bAltDown = ( (lParam & (1 << 29)) != 0 ); //boolean wich tells us if ALT key is pressed
	int code = -1;

	//First we catch some gamemode-independent events
	switch (msg)
	{
		case WM_DESTROY:
			WriteSettingsToFile();
			this->~CGame();
            PostQuitMessage( 0 );
            return true;
		case WM_SYSKEYDOWN:
		//Catch ALT+ENTER event to switch to fullscreen and back
		if (bAltDown && (wParam == VK_RETURN))
		{
			//To switch to fullscreen and back, we need to reset the device. To do so we need to do follow these steps:
			//1. Call OnLostDevice() for any D3DX objects that support it and Release() any resources in D3DPOOL_DEFAULT
			//2. Call IDirect3DDevice9::Reset(), passing in new presentaion parameters.
			//3. Call OnResetDevice() for any D3DX objects that support it and re-crate any resources in D3DPOOL_DEFAULT
			/*4. Call SetWindowLongPtr() to set the new window style, then SetWindowPos with the SWP_FRAMECHANGED flag to update the window
				This isn't so important for going from windowed to fullscreen, more so the other way. Something like:
				DWORD dwstyle = bFullscreen ? WS_POPUP : WS_OVERLAPPEDWINDOW;
				SetWindowLong(m_hWnd, GWL_style, dwstyle);
				SetWindowPos(m_hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED);
				Obviously where bFullscreen is a boolean indicating if you're going to fullscreen mode or not.*/

			m_GamePaused = true;
			//ShowWindow(hWnd, SW_HIDE);
			OnLostDevice();
			ToggleFullScreen(hWnd, m_pd3dDevice, &m_pd3dPP, m_pD3D,&m_oldScreenWidth, &m_oldScreenHeight, &m_screenWidth, &m_screenHeight);
			OnResetDevice(hWnd);
			//ShowWindow(hWnd, SW_SHOW);
			m_ConfigFullScreen = !m_ConfigFullScreen;
			m_GamePaused = false;
			return true;
		}
		break;
		case WM_SETFOCUS:
			{
				m_GamePaused = false;
				if(m_PausedByAltTab)
				{
					m_PausedByAltTab = false;
				}
				return true;
			}
		break;
		case WM_KILLFOCUS:
			{
				m_GamePaused = true;
				return true;
			}
		break;
		//Force minimum size window, to prevent resizing window to very small sizes where interface cant fit it.
		case WM_GETMINMAXINFO:
		{
			MINMAXINFO* lpMMI = (MINMAXINFO*) lParam;
			lpMMI->ptMinTrackSize.x = 700;
			lpMMI->ptMinTrackSize.y = 550;
			return true;
		}
		break;
		//User started resizing the window
		case WM_ENTERSIZEMOVE:
		{
			m_GamePaused = true;
			return true;
		}
		break;
		//User finished resizing the window
		case WM_EXITSIZEMOVE:
		{
			//We check if window dimensions are changed
			RECT rcCurrentClient;
			RECT rectNewWindow;
			GetWindowRect(hWnd,&rectNewWindow);
			GetClientRect(hWnd, &rcCurrentClient);
			if ((rcCurrentClient.right != m_screenWidth) || (rcCurrentClient.bottom != m_screenHeight))
			{
				//if ((rcCurrentClient.right>699)&&(rcCurrentClient.bottom>550))
				//{
					//save old and set new screen size
					m_oldScreenWidth = m_screenWidth;
					m_oldScreenHeight = m_screenHeight;
					m_screenWidth = rcCurrentClient.right;
					m_screenHeight = rcCurrentClient.bottom;
					//reset device
					OnLostDevice();
					m_pd3dPP->BackBufferWidth = m_screenWidth;
					m_pd3dPP->BackBufferHeight = m_screenHeight; //we keep the same Presentation Parameters, just the buffer size is changed
					Reset3D(m_pd3dDevice, m_pd3dPP); 
					OnResetDevice(hWnd);
					//this needed for level 
					m_Level->m_MousePosX = m_screenWidth/2 + rectNewWindow.left;
					m_Level->m_MousePosY = m_screenHeight/2 + rectNewWindow.top;
				//}
				//else
				//{
					//SetClientRectangle();
					//or
					//PostMessage(hWnd, WM_SIZEMOVE, 500, 500);
				//}
			}
			else //Move only
			{
				m_Level->WindowMove(hWnd, m_screenWidth, m_screenHeight);
			}
			m_GamePaused = false;
			return true;
		}
		break;

		case WM_SIZE:
		{
			if (wParam == SIZE_MINIMIZED)
			{
				//We stop rendering when game is minimized
				m_GamePaused = true;
				return true;
			}
			if (wParam == SIZE_MAXIMIZED)
			{
				m_GamePaused = false;
				RECT rcCurrentClient;
				GetClientRect(hWnd, &rcCurrentClient);
				//save old and set new screen size
				m_oldScreenWidth = m_screenWidth;
				m_oldScreenHeight = m_screenHeight;
				m_screenWidth = rcCurrentClient.right;
				m_screenHeight = rcCurrentClient.bottom;
				//reset device
				OnLostDevice();
				m_pd3dPP->BackBufferWidth = m_screenWidth;
				m_pd3dPP->BackBufferHeight = m_screenHeight; //we keep the same Presentation Parameters, just the buffer size is changed
				Reset3D(m_pd3dDevice, m_pd3dPP); 
				OnResetDevice(hWnd);
				m_wasMaximized = true;
				return true;
			}
			if (wParam == SIZE_RESTORED)
			{
				m_GamePaused = false;
				//Window can be restored from minimized, in that case we don't need to reset device cause window size
				//is same as before, but if window was maximized and then restored, we need to reset device to new size.
				if (m_wasMaximized)
				{
					m_wasMaximized = false;
					RECT rcCurrentClient;
					GetClientRect(hWnd, &rcCurrentClient);
					//save old and set new screen size
					m_oldScreenWidth = m_screenWidth;
					m_oldScreenHeight = m_screenHeight;
					m_screenWidth = rcCurrentClient.right;
					m_screenHeight = rcCurrentClient.bottom;
					//reset device
					OnLostDevice();
					m_pd3dPP->BackBufferWidth = m_screenWidth;
					m_pd3dPP->BackBufferHeight = m_screenHeight; //we keep the same Presentation Parameters, just the buffer size is changed
					Reset3D(m_pd3dDevice, m_pd3dPP); 
					OnResetDevice(hWnd);
				}
				return true;
			}
		}
		break;
	}

	//Here are events that have mode specific functionality.
	//Same key press can be interpreted differently in different game modes.
	switch (m_GameMode)
	{
	case GAMEMODE_MENU:
		{
			//send message to main menu
			if(m_Menu->OnEvent(m_pd3dDevice, hWnd, msg, wParam, lParam, &code))
			{
				switch (code)
				{
					case MENU_OPTION_RETURN_NEWGAME:
					{
						m_GameMode = GAMEMODE_MOVIE;
						m_Movie->playMovie();
					}
					break;
					case MENU_OPTION_RETURN_OPTIONS:
					{
					}
					break;
					case MENU_OPTION_RETURN_EXIT:
					{
						WriteSettingsToFile();
						this->~CGame();
						PostQuitMessage( 0 );
					}
					break;
					case MENU_OPTION_RETURN_DIFFICULTY_HARD:
					{
						m_ConfigDificulty = 2.0f;
					}
					break;
					case MENU_OPTION_RETURN_DIFFICULTY_EASY:
					{
						m_ConfigDificulty = 3.0f;
					}
					break;
					case MENU_OPTION_RETURN_DETAILS_ON:
					{
						m_ConfigDetails = true;
					}
					break;
					case MENU_OPTION_RETURN_DETAILS_OFF:
					{
						m_ConfigDetails = false;
					}
				}
				return true;
			}
		}
		break;
	case GAMEMODE_LEVEL:
		{
			//send message to regular level (magic item use for example)
			//moving and shooting commands are exceptions done in MoveLevel (cause they need faster response time)
			if(m_Level->OnEvent(m_pd3dDevice, m_pDS, hWnd, msg, wParam, lParam, &code))
			{
				if (code == LEVEL_RETURN_BONUS)
					m_GameMode = GAMEMODE_BONUS;
				if (code == LEVEL_RETURN_MENU)
				{
					m_Menu->Restart();
					m_GameMode = GAMEMODE_MENU;
					m_GamePaused = false; //just in case game was paused
				}
				return true;
			}
		}
		break;
	case GAMEMODE_MOVIE:
		{
			//no need to send message to game movie, to every user keypress, movie ends
			if ((msg == WM_KEYDOWN)||(msg == WM_LBUTTONDOWN)||(msg == WM_RBUTTONDOWN))
			{
				if (m_total_number != 0)
				{
					int average_framerate = m_total_counter/m_total_number;
					//if average framerate is lower then 20 then automaticly turn off details.
					if (average_framerate < 20)
						m_ConfigDetails = false;
					m_total_counter = 0;
					m_total_number = 0;
				}
				m_Movie->stopMovie();
				m_Level->LevelStart(m_ConfigDificulty, m_ConfigDetails, m_pSheep);
				m_GameMode = GAMEMODE_LEVEL;
				return true;
			}
		}
		break;
	case GAMEMODE_BONUS:
		{
			//send message to bonus level
			m_Bonus->OnEvent(m_pd3dDevice, hWnd, msg, wParam, lParam, &code);
		}
		break;
	default:
		{
			m_GameMode = GAMEMODE_MENU;
		}
	}
	return false; //false means windows will handle event by default
}

/**
 * Standard DirectX functionality. 
 * It must be called when something big changes with the display, 
 * like switching to fullscreen mode. 
 * First is called OnLostDevice, then OnResetDevice.
 */
void CGame::OnLostDevice()
{
	m_Menu->OnLostDevice();
	m_Movie->OnLostDevice();
	m_Level->OnLostDevice();
	m_sprite->OnLostDevice();
	m_pFont->OnLostDevice();

}

/**
 * Standard DirectX functionality. 
 * It must be called when something big changes with the display, 
 * like switching to fullscreen mode. 
 * First is called OnLostDevice, then OnResetDevice.
 */
void CGame::OnResetDevice(HWND hWnd)
{
	InitLight(m_pd3dDevice, &m_Light1, &m_Light2, &m_Light3);
	m_aspectRatio = (float)m_screenWidth / (float)m_screenHeight;
	m_Menu->OnResetDevice(m_screenWidth, m_screenHeight);
	m_Movie->OnResetDevice(m_pd3dDevice, m_screenWidth, m_screenHeight);
	m_Level->OnResetDevice(hWnd, m_pd3dDevice, m_screenWidth, m_screenHeight);
	m_sprite->OnResetDevice();
	m_pFont->OnResetDevice();
}

/**
 * OnFrameMove Function is called before render function
 * to calculate position of all objects in that moment.
 * It moves all animated object by little bit depending
 * on m_CurrentTime and m_elapsedTime game variables.
 *
 * This function checks game mode, and calculates move only for the active mode.
 */
void CGame::OnFrameMove()
{

	LARGE_INTEGER qwTime;
	double tempTime;
	static double tempTime2 = 0.0;
	static int counter = 0;
	QueryPerformanceCounter( &qwTime );
	tempTime = (double) (qwTime.QuadPart - m_BaseTime)/ (double) m_QPFTicksPerSec;
	m_ElapsedTime = (float) (tempTime - m_CurrentTime);
	m_CurrentTime = tempTime;
	tempTime2 += m_ElapsedTime;
	counter++;
	if (tempTime2 > 1)
	{
		m_counter = counter;
		counter = 0;
		tempTime2 = 0.0;
		if (m_GameMode == GAMEMODE_MOVIE)
		{
			m_total_counter += m_counter;
			m_total_number ++;
		}
	}

	//ALT+TAB combination pressed - pause game
	if (GetAsyncKeyState(VK_TAB)&&GetAsyncKeyState(VK_MENU))
	{
		m_PausedByAltTab = true;
		m_GamePaused = true;
		if (!(m_Level->m_LevelPaused))
		{
			m_Level->Pause();
		}
		//m_plevelTheme->Pause();
		//m_LevelPaused = true;
		//ShowCursor(true);
	}
	
	SetupMatrices(&m_pd3dDevice, &m_EyePt, &m_LookatPt, &m_UpVec, m_aspectRatio);

	//we skip rendering when program minimised, out of the focus, etc... to save comp resources
	if (!m_GamePaused)
	{
		//In different game modes, we call different move functions
		switch (m_GameMode)
		{
		case GAMEMODE_MENU:
			{
				//move main menu
				m_Menu->OnFrameMove(m_pd3dDevice, m_CurrentTime, m_ElapsedTime);
			}
			break;
		case GAMEMODE_LEVEL:
			{
				//move level
				m_Level->OnFrameMove(m_pd3dDevice, m_CurrentTime, m_ElapsedTime);
			}
			break;
		case GAMEMODE_MOVIE:
			{
				//move movie :)
				m_Movie->OnFrameMove(m_pd3dDevice, m_CurrentTime, m_ElapsedTime);
			}
			break;
		case GAMEMODE_BONUS:
			{
				//move bonus level
				m_Bonus->OnFrameMove(m_pd3dDevice, m_CurrentTime, m_ElapsedTime);
			}
			break;
		default:
			{
				//render main menu
				m_GameMode = GAMEMODE_MENU;
			}
		}
	}
}

/**
 * Render function checks wich game mode is active. If Menu is on, it calls CMenu::Render(), etc.
 */
void CGame::OnRender()
{
	//we skip rendering when program minimised, out of the focus, etc... to save comp resources
	if (!m_GamePaused)
	{
		// Clear the backbuffer to a greenish color
		m_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,255,255), 1.0f, 0 );
		// Begin the scene
	    if( SUCCEEDED( m_pd3dDevice->BeginScene() ) )
	    {
			switch (m_GameMode)
			{
			case GAMEMODE_MENU:
				{
					//render main menu
					m_Menu->OnRender(m_pd3dDevice);
				}
				break;
			case GAMEMODE_LEVEL:
				{
					//render game regular level
					m_Level->OnRender(m_pd3dDevice, m_ElapsedTime, m_counter);
				}
				break;
			case GAMEMODE_MOVIE:
				{
					//render game movies
					m_Movie->OnRender(m_pd3dDevice);
				}
				break;
			case GAMEMODE_BONUS:
				{
					//render bonus levels
					m_Bonus->OnRender(m_pd3dDevice);
				}
				break;
			default:
				{
					//render main menu
					m_GameMode = GAMEMODE_MENU;
				}
			}
			// End the scene
			m_pd3dDevice->EndScene();
		}
		
		// Present the backbuffer contents to the display
		m_pd3dDevice->Present( NULL, NULL, NULL, NULL );
	}
}
