#include "RuneDev.h"
#include "../resource.h"

#define REMOVE_ROLE_TIME		2.0f

const TCHAR						g_WCNameStr[]			= _T("GameDev Frame");
const TCHAR						g_frameTitleStr[]		= _T("GameDev Frame");
const INT32						g_resourceArenaSize		= 8388608 * 8;
CRuneDev*						g_pRuneDev				= NULL;
bool							g_out					= false;
float							g_handleTime[20];

struct TestQuality{
	float time;
	const char* name;
};

TestQuality						g_qualityRecord[16]		= {
	0.0f, "Terrain Update",		//0
	0.0f, "Sky Update",			//1
	0.0f, "Sprite Update",		//2
	0.0f, "UI Update",			//3
	0.0f, "Update",				//4
	0.0f, "BeginScene",			//5
	0.0f, "Terrain Render",		//6
	0.0f, "Sky Render",			//7
	0.0f, "Sprite Render",		//8
	0.0f, "3D Scene End",		//9
	0.0f, "Blur Render",		//10
	0.0f, "UI Render",			//11
	0.0f, "Other 2D Render(Text, Cursor..)",			//12
	0.0f, "End Scene",			//13
	0.0f, "Present",			//14
	0.0f, "Render",				//15
};

LRESULT CALLBACK	FrameWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
void				FontTextureRally();

// ------------------------------------------------------------------------------------------------
void UiOuputError(const char* errorStr)
{
	g_pError->AddMessage(0, 0, errorStr);
}

// ------------------------------------------------------------------------------------------------
CRuneDev::CRuneDev()
{
	g_pRuneDev					= this;

	m_hInstance					= NULL;
	m_hFrameWnd					= NULL;
	m_isWindowed				= false;
	m_isExit					= false;
	m_isActived					= false;	
	m_windowStyle				= 0;
	m_xScreen					= 0;
	m_yScreen					= 0;
	m_frameTime					= 0.0f;
	m_elapsedTime				= 0.0f;
	m_fps						= 0.0f;	
	m_isHardwaveCursor			= true;
	m_isCursorVisible			= true;
	m_isCursorLock				= false;
	m_isRuneRelease				= false;
		
	m_pRuAudioLibrary			= NULL;
	m_pRuSwapChain				= NULL;
	m_pRuTimer					= NULL;	
	m_pRuTerrain				= NULL;	
	m_pRuMinimap				= NULL;
	m_pCamera					= NULL;
	m_pBlurTexture1				= NULL;
	m_pBlurTexture2				= NULL;
	m_pRuWorldEnvironment		= NULL;
	m_pRuGaiaObject				= NULL;
	m_pRuCameraController		= NULL;
	m_pInputCOM					= NULL;
	m_pKeyboard					= NULL;
	m_pMouse					= NULL;
	m_pCursorIcon				= NULL;
	m_pDragCursorIcon			= NULL;
	m_pSysFontType				= NULL;
	m_pRuHighlighter			= NULL;

	m_pRuWidgetGrid				= NULL;
	m_gridPos					= CRuVector3(0.0f, 0.0f, 0.0f);
	m_isGridLock				= false;
	m_gridHalfSize				= 100;
	m_gridSpacing				= 5;
	
	m_interface					= NULL;
	
	m_roleIndex.clear();
	m_roleGarbage.clear();
	m_playerPos.Set( 0.0f, 0.0f, 0.0f );

	m_isCameraFollowRole		= TRUE;
	m_cameraNearPlane			= 1.0f;
	m_cameraFarPlane			= 1800.0f;
//	m_cameraFOV					= 1.0472f;
	m_cameraFOV					= 0.9599f;
	m_cameraBackdropNearPlane	= 960.0f;
	m_cameraBackdropFarPlane	= 4800.0f;
	
	m_isSprite_Update			= true;
	m_isSprite_Render			= true;
	m_isShowFps					= false;
	m_isGlow					= false;
	m_isEnvironmentUpdate		= true;
	m_isEnvironmentRender		= true;
	m_isStableFrame				= false;

	m_fogMin					= 500;
	m_fogMax					= 1000;
	
	memset( &m_clientRect, 0, sizeof(m_clientRect) );
	memset( &m_windowRect, 0, sizeof(m_windowRect) );
	memset( m_resourceRootDirectoryStr, 0, sizeof(m_resourceRootDirectoryStr) );
}

// ------------------------------------------------------------------------------------------------
CRuneDev::~CRuneDev()
{
	RuneDevRelease();
}

// ------------------------------------------------------------------------------------------------
bool CRuneDev::CreateWnd( HINSTANCE hInstance, int screenWidth, int screenHeight )
{
	WNDCLASSEX WndClass;

	m_hInstance = hInstance;

	// Register frame window
	WndClass.cbSize = sizeof(WNDCLASSEX);
	WndClass.style = 0;
	WndClass.lpfnWndProc = FrameWndProc;
	WndClass.cbClsExtra = 0;
	WndClass.cbWndExtra = 0;
	WndClass.hInstance = hInstance;
	WndClass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1)) ;
	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	WndClass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
	WndClass.lpszMenuName = NULL;
	WndClass.lpszClassName = g_WCNameStr;
	WndClass.hIconSm = NULL;
	RegisterClassEx(&WndClass);

	m_windowStyle = WS_OVERLAPPEDWINDOW | WS_VISIBLE;
	//m_windowStyle = WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_POPUP|WS_SYSMENU|WS_VISIBLE|WS_MAXIMIZEBOX|WS_MINIMIZEBOX;

	// Set the window's initial width
	RECT rect;
	SetRect( &rect, 0, 0, screenWidth, screenHeight );
	AdjustWindowRect( &rect, m_windowStyle, FALSE );

	m_hFrameWnd = CreateWindowEx( 0, g_WCNameStr, g_frameTitleStr, m_windowStyle, CW_USEDEFAULT, CW_USEDEFAULT,
								  rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hInstance, NULL );
	if ( m_hFrameWnd )
	{
		ShowWindow( m_hFrameWnd, SW_SHOW );
		UpdateWindow( m_hFrameWnd );
		GetWindowRect( m_hFrameWnd, &m_windowRect );
		GetClientRect( m_hFrameWnd, &m_clientRect );
		return TRUE;
	}

	return FALSE;
}

// --------------------------------------------------------------------------------------
bool CRuneDev::RuneDevInitialize( HINSTANCE hInstance, int screenWidth, int screenHeight, bool isWindowed )
{
	if ( m_hFrameWnd ) return FALSE;
	if ( !CreateWnd( hInstance, screenWidth, screenHeight ) ) return FALSE;

	// 
	CErrorList::Initialize(hInstance, m_hFrameWnd);

	// 開啟引擎並保存回傳 SwapChain
	if ( (m_pRuSwapChain = RuInitialize( m_hFrameWnd, m_hFrameWnd, g_resourceArenaSize )) == NULL )
		return FALSE;

	// 開啟音效系統
	if ( RuSymphony_Initialize() == FALSE )
		return FALSE;

	// 開啟音效庫
	m_pRuAudioLibrary = ruNEW CRuFusion_AudioLibrary();

	// 建立主鏡頭
	m_isRuneRelease = true;
	m_pCamera = ruNEW CRuCamera;
	m_pCamera->SetCameraPosition( CRuVector3(0.0f, 10.0f, -30.0f) );	// 鏡頭所在位置
	m_pCamera->SetTargetPosition( CRuVector3(0.0f, 10.0f, 0.0f) );		// 鏡頭目的位置
	m_pCamera->SetCameraUpVector( CRuVector3(0.0f, 1.0f, 0.0f) );		// 鏡頭上方所朝方向	

	m_pBlurTexture1	= g_ruEngine->CreateRenderTarget(512, 512, 1, ruSURFACEFMT_A8R8G8B8);
	m_pBlurTexture2	= g_ruEngine->CreateRenderTarget(512, 512, 1, ruSURFACEFMT_A8R8G8B8);

	m_pRuCameraController = ruNEW CRuController_Camera();
	m_pRuCameraController->SetTarget(m_pCamera);

	// 貼圖初始化
	CTextureImage::Initialize();

	// 字型初始化
	CRuFontChar::Initialize( FontTextureRally );

	// 產生系統使用文字物件
	m_pSysFontType = CRuFontType::GetFontType( "Arial", 18, ruFONTWEIGHT_BOLD, ruFONTOUTLINE_NORMAL );	

	IBaseSprite::Initialize();
	IBaseSprite::SetFontType( m_pSysFontType );	

	// 界面初始化
	m_interface = ruNEW CInterface(m_resourceRootDirectoryStr);

	// 設定畫面解析度
	AdjustWindowSize( screenWidth, screenHeight );				// 將視窗調整為設定尺寸大小
	SetScreenSize( screenWidth, screenHeight, isWindowed );	

	// 設定天空
	InitialEnvironment();
	
	// 將音效庫設入事件管理器
	g_pRuGlobalEventManager->SetAudioLibrary(m_pRuAudioLibrary);

	m_pRuTimer = ruNEW CRuPerformanceTimer();
	m_pRuTimer->Initialize(0);
	m_pRuTimer->ElapsedTime();	

	m_pRuHighlighter = ruNEW CRuController_Highlighter();
	m_pRuHighlighter->SetPulsePeriod(4.0f);
	m_pRuHighlighter->SetHighlightColor0(CRuColor4(1.0f, 0.1f, 0.1f, 0.1f));
	m_pRuHighlighter->SetHighlightColor1(CRuColor4(1.0f, 0.2f, 0.2f, 0.2f));	

	/*
	m_pScene->LoadTerrain( "Rune Resources\\Terrain\\export map 6b.ros" );
	m_pRoleSpriteManage = new CRoleSpriteManage;	
	CRoleSprite *pRole = m_pRoleSpriteManage->CreateRoleSprite( 1 );
	pRole->LoadCharacter( "Models\\human_female_complete.ros" );
	pRole->SetPos( CRuVector3(50.0f, 50.0f, 50.0f ) );
	pRole->SetWalkSpeed( 33.0f );
	*/

	// 產生輸入裝置
	m_pInputCOM = ruNEW CInputCOM;
	m_pInputCOM->Init( m_hFrameWnd, hInstance );
	m_pKeyboard = ruNEW CInputDevice;
	m_pKeyboard->Create( m_pInputCOM, eID_Keyboard );
	m_pMouse = ruNEW CInputDevice;
	m_pMouse->Create( m_pInputCOM, eID_Mouse );	

	// SetTimer( m_hFrameWnd, NULL, 100, NULL );

	// ********************************************************************************************
	//
	// 若有其他系統需要初始化可在這裏初始
	//
	// ********************************************************************************************	
	Init();	

#ifdef RUINCLUDE_MEMORYMANAGER
	// Bookmark initial memory status
	m_memoryBookmark = CRuMemoryHeapFactory::GetMemoryBookmark();
#endif

	return TRUE;
}

// ------------------------------------------------------------------------------------------------
void CRuneDev::RuneDevRelease()
{
	Release();
	
	ClearCursorIcon();
	ClearDragCursorIcon();

	CRuFontChar::Shutdown();
	CTextureImage::Shutdown();

	SAFE_DELETE(m_interface);	
	SAFE_DELETE( m_pKeyboard );
	SAFE_DELETE( m_pMouse );
	SAFE_DELETE( m_pInputCOM );	
	SAFE_DELETE( m_pRuTimer );	
	ruSAFE_RELEASE( m_pRuHighlighter );
	ruSAFE_RELEASE( m_pBlurTexture1 );
	ruSAFE_RELEASE( m_pBlurTexture2 );
	ruSAFE_RELEASE( m_pRuSwapChain );
	ruSAFE_RELEASE( m_pRuCameraController );
	ReleaseWidgetGrid();

	ClearRoleSprite();
	IBaseSprite::Shutdown();

	ReleaseTerrain();
	ReleaseEnvironment();
	
	SAFE_DELETE( m_pCamera );	

	// 關閉引擎
	if (m_isRuneRelease)
	{
		m_isRuneRelease = false;
		RuShutdown();
	}

	// 關閉音效系統
	RuSymphony_Shutdown();

	// 關閉音效庫
	ruSAFE_RELEASE(m_pRuAudioLibrary);

	//
	CErrorList::Shutdown();

#ifdef RUINCLUDE_MEMORYMANAGER
	// Report any memory leaks
	CRuMemoryHeapFactory::ReportMemoryLeaks(m_memoryBookmark);
#endif
}

// ------------------------------------------------------------------------------------------------
bool CRuneDev::SetScreenSize( DWORD width, DWORD height, bool isWindowed )
{
	if ( m_xScreen != width || m_yScreen != height || m_isWindowed != isWindowed )
	{
		/*
		if ( m_isWindowed != isWindowed )
			AdjustWindowForChange();
		*/		

		// 更新畫面解析度
		if ( !RuSetResolution( m_pRuSwapChain, (UINT32)width, (UINT32)height, !isWindowed ) )
			return FALSE;

		float scale = (float)width / height;

		// 設定鏡頭視角
		if ( m_pCamera )
		{
			m_pCamera->SetPerspectiveProjectionFOV( m_cameraNearPlane, m_cameraFarPlane, m_cameraFOV, (float)width / height );
			m_pCamera->SetBackdropDistance( m_cameraBackdropNearPlane, m_cameraBackdropFarPlane );
		}

		m_isWindowed = isWindowed;
		m_xScreen = width;
		m_yScreen = height;

		m_UIHeight = 768.0f; 
		m_UIWidth = 768.0f*scale;
		
		// 設定界面視窗大小
		g_ruSceneRenderer->Ru2D_SetViewportScale(m_UIWidth, m_UIHeight);
		if (m_interface)
			m_interface->SetScreenSize(m_UIWidth, m_UIHeight);

		return TRUE;
	}

	return FALSE;
}

// --------------------------------------------------------------------------------------
bool CRuneDev::AdjustWindowSize( DWORD width, DWORD height )
{
	RECT rc;
	SetRect( &rc, 0, 0, width, height );
	AdjustWindowRect( &rc, m_windowStyle, FALSE );

	SetWindowPos( m_hFrameWnd, NULL, 0, 0, rc.right - rc.left, rc.bottom - rc.top, SWP_NOZORDER | SWP_SHOWWINDOW | SWP_NOMOVE );
	GetWindowRect( m_hFrameWnd, &m_windowRect );
	GetClientRect( m_hFrameWnd, &m_clientRect );

	return true;
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetResourcePath( const char* pathStr )
{
	memset( m_resourceRootDirectoryStr, 0, sizeof(m_resourceRootDirectoryStr) );	
	if ( pathStr && strlen(pathStr) > 0 )
	{
		_tcscpy( m_resourceRootDirectoryStr, pathStr );
		int len = strlen( m_resourceRootDirectoryStr );
		if ( m_resourceRootDirectoryStr[len-1] == '\\' )
			m_resourceRootDirectoryStr[len-1] = 0;
	}
	
	m_interface->SetResourcePath(m_resourceRootDirectoryStr);
	g_ruResourceManager->SetRootDirectory(m_resourceRootDirectoryStr);
	g_ruSymphony->SetResourcePath(m_resourceRootDirectoryStr);
}

// --------------------------------------------------------------------------------------
const char*	CRuneDev::GetFullFilePath( const char* fileStr )
{
	static int count = 0;
	static char tmpStr[5][MAX_PATH];

	count++;
	if ( count >= 5 )
		count = 0;
	
	if ( m_resourceRootDirectoryStr[0] == 0 )
		strcpy( tmpStr[count], fileStr );
	else
		sprintf( tmpStr[count], "%s\\%s", m_resourceRootDirectoryStr, fileStr );

	return tmpStr[count];
}

// --------------------------------------------------------------------------------------
bool CRuneDev::AdjustWindowForChange()
{
	if ( m_isWindowed ) {
		SetWindowLong( m_hFrameWnd, GWL_STYLE, m_windowStyle);
	} else {		
		SetWindowLong( m_hFrameWnd, GWL_STYLE, WS_POPUP|WS_SYSMENU|WS_VISIBLE );
	}
	return TRUE;
}

// ------------------------------------------------------------------------------------------------
int CRuneDev::Run()
{
	MSG Msg;

	PeekMessage( &Msg, NULL, 0U, 0U, PM_NOREMOVE );
	while( Msg.message != WM_QUIT )
	{
		BOOL boMessage = PeekMessage( &Msg, NULL, 0U, 0U, PM_REMOVE | PM_NOYIELD );
		if( boMessage )	
		{
			TranslateMessage(&Msg);
			DispatchMessage(&Msg);
		} 
		else
		{
			if ( m_isExit )
				SendMessage( m_hFrameWnd, WM_CLOSE, 0, 0 );
			else if ( true )
				FrameLoop();
			else
			{
				WaitMessage();
			}			
		}
	}

	return (int)Msg.wParam;	
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetFogDistance( float fmin, float fmax )
{
	m_fogMin = fmin;
	m_fogMax = fmax;
}

// --------------------------------------------------------------------------------------
void CRuneDev::DefaultCamera()
{
	m_pCamera->SetCameraPosition( CRuVector3(0.0f, 0.0f, 100.0f) );		// 鏡頭所在位置
	m_pCamera->SetTargetPosition( CRuVector3(0.0f, 0.0f, 0.0f) );		// 鏡頭目的位置
	m_pCamera->SetCameraUpVector( CRuVector3(0.0f, 1.0f, 0.0f) );		// 鏡頭上方所朝方向
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetCameraFarPlane( float farPlane )
{
	if ( m_pCamera )
	{
		m_cameraFarPlane = farPlane;
		m_pCamera->SetPerspectiveProjectionFOV( m_cameraNearPlane, m_cameraFarPlane, m_cameraFOV, (float)m_xScreen / m_yScreen );
		m_pCamera->SetBackdropDistance( m_cameraBackdropNearPlane, m_cameraBackdropFarPlane );
	}
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetCameraPos( CRuVector3& pos )
{
	if ( m_pCamera )
		m_pCamera->SetCameraPosition( pos );
}

// --------------------------------------------------------------------------------------
void CRuneDev::MoveCameraPos( CRuVector3& pos )
{
	if ( m_pCamera )
		m_pCamera->SetCameraPosition( pos + m_pCamera->GetCameraPosition() );
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetCursorIcon( const char* fileName )
{
	if ( m_pCursorIcon == NULL )
		m_pCursorIcon = ruNEW CTextureImage;
	m_pCursorIcon->SetFileName( fileName );
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetDragCursorIcon( const char* fileName )
{
	if ( m_pDragCursorIcon == NULL )
		m_pDragCursorIcon = ruNEW CTextureImage;
	m_pDragCursorIcon->SetFileName( fileName );
}

// --------------------------------------------------------------------------------------
void CRuneDev::ClearCursorIcon()
{
	SAFE_DELETE( m_pCursorIcon );
}

// --------------------------------------------------------------------------------------
void CRuneDev::ClearDragCursorIcon()
{
	SAFE_DELETE( m_pDragCursorIcon );
}

// --------------------------------------------------------------------------------------
void CRuneDev::RenderCursor()
{
	CRuRectangle dest, tex;
	tex.Set( 0.0f, 0.0f, 1.0f, 1.0f );
	dest.m_left		= (float)m_xCursor * m_UIWidth / m_xScreen;
	dest.m_top		= (float)m_yCursor * m_UIHeight / m_yScreen;
	dest.m_right	= dest.m_left + 32.0f;
	dest.m_bottom	= dest.m_top + 32.0f;

	if ( m_pDragCursorIcon )
		m_pDragCursorIcon->Draw( dest, tex, ALPHA_MODE_BLEND, 0xFFFFFFFF );

	if ( m_pCursorIcon )
		m_pCursorIcon->Draw( dest, tex, ALPHA_MODE_BLEND, 0xFFFFFFFF );
}

// --------------------------------------------------------------------------------------
void CRuneDev::ReleaseTerrain()
{
	ruSAFE_RELEASE( m_pRuTerrain );
	ruSAFE_RELEASE( m_pRuMinimap );
	ruSAFE_RELEASE( m_pRuGaiaObject );
}

// --------------------------------------------------------------------------------------
bool CRuneDev::LoadTerrain( const char* resourceName )
{	
	CRuOptimalTerrain_DataSource_DS *terrainDS = ruNEW CRuOptimalTerrain_DataSource_DS();

	ReleaseEnvironment();
	ReleaseTerrain();

	// 讀取地表資料來源
	CRuDataStore_Disk *mapFileDataStore = ruNEW CRuDataStore_Disk();
	if(mapFileDataStore->Open(GetFullFilePath(resourceName), TRUE))
	{
		if( terrainDS->Open(mapFileDataStore) )
		{
			// 建立地表管理物件
			m_pRuTerrain = ruNEW CRuOptimalTerrain();
			m_pRuTerrain->Initialize();
			m_pRuTerrain->AttachDataSource(terrainDS);

			// 碰撞資訊
			m_pRuGaiaObject = m_pRuTerrain->GetGaiaObject();
			m_pRuGaiaObject->AddRef();

			// 設定鏡頭控制器所使用的碰撞資料
			m_pRuCameraController->SetCollisionObject(m_pRuTerrain);

			// Create new minimap manager
			m_pRuMinimap = ruNEW CRuFusion_Minimap();
			m_pRuMinimap->SetWorldProperties(resourceName, m_pRuTerrain->GetTerrainBounds());

/*			
			IRuTexture *maskTexture = g_ruResourceManager->LoadTexture("texture\\MinimapMask");
			if(maskTexture)
			{
				m_pRuMinimap->SetMinimapMask(maskTexture);
				ruSAFE_RELEASE(maskTexture);
			}
*/			

/*
			// 碰撞資訊
			CRuDataStore_Disk *diskStore = ruNEW CRuDataStore_Disk();
			char tmp[MAX_PATH];
			strcpy( tmp, resourceName );
			strcpy( tmp + strlen(tmp) - 4, ".col" );


			if ( diskStore->Open( GetFullFilePath(tmp), TRUE) )
			{
				m_pRuGaiaObject = ruNEW CRuGaia_DataStore();
				m_pRuGaiaObject->Open(diskStore);

				// 設定鏡頭控制器所使用的碰撞資料
				m_pRuCameraController->SetCollisionObject(m_pRuGaiaObject);
			}
			ruSAFE_RELEASE(diskStore);
*/
		}
		terrainDS->Release();
	}	
	mapFileDataStore->Release();

/*
	// 讀取地表資料來源
	CRuDataStore_Disk *mapFileDataStore = ruNEW CRuDataStore_Disk();
	if(mapFileDataStore->Open(GetFullFilePath(resourceName), TRUE))
	{
		if( terrainDS->Open(mapFileDataStore) )
		{
			// 建立地表管理物件
			m_pRuTerrain = ruNEW CRuOptimalTerrain();
			m_pRuTerrain->Initialize();
			m_pRuTerrain->AttachDataSource(terrainDS);

			// 碰撞資訊
			CRuDataStore_Disk *diskStore = ruNEW CRuDataStore_Disk();
			char tmp[MAX_PATH];
			strcpy( tmp, resourceName );
			strcpy( tmp + strlen(tmp) - 4, ".col" );


			if ( diskStore->Open( GetFullFilePath(tmp), TRUE) )
			{
				m_pRuGaiaObject = ruNEW CRuGaia_DataStore();
				m_pRuGaiaObject->Open(diskStore);

				// 設定鏡頭控制器所使用的碰撞資料
				m_pRuCameraController->SetCollisionObject(m_pRuGaiaObject);
			}

			ruSAFE_RELEASE(diskStore);
		}
		terrainDS->Release();
	}	
	mapFileDataStore->Release();
*/
	// 設定天空
	InitialEnvironment();

	// 設定地表資訊
	IBaseSprite::SetRuTerrain( m_pRuTerrain, m_pRuGaiaObject );

	return (m_pRuTerrain) ? true : false;
}

// --------------------------------------------------------------------------------------
void CRuneDev::UpdateTerrain()
{
	if( m_pRuTerrain )
	{
		assert( m_pCamera );

		// 設定地表的鏡頭
		m_pRuTerrain->SetCamera( m_pCamera );

		// 更新地表
		m_pRuTerrain->Update( m_elapsedTime );

		// 撥放動態物件
		RuACT_PlayMotionEx(m_pRuTerrain, 0xFFFFFFFF, "idle");
	}
}

// --------------------------------------------------------------------------------------
void CRuneDev::RenderTerrain()
{
	if( m_pRuTerrain )
	{
		// 繪製地表
		g_ruSceneRenderer->Scene_Submit( m_pRuTerrain );
	}
}

// --------------------------------------------------------------------------------------
bool CRuneDev::ChangeScreenPoint(int x, int y, CRuVector3& pos)
{
	if (m_pCamera)
	{
		// Calculate view origin in world space
		CRuVector3 homPt, viewPt, worldPt, pt1, pt2;

		m_pCamera->Coord_ScreenToHomogeneous(x, y, m_xScreen, m_yScreen, homPt);
		m_pCamera->Coord_HomogeneousToView(homPt, viewPt);
		m_pCamera->Coord_ViewToWorld(viewPt, worldPt);

		pt1 = m_pCamera->GetCameraPosition();
		pt2 = pt1 + (worldPt - pt1) * 1000.0f;

		if ( IBaseSprite::TerrainTest( pt1, pt2, &pos ) )
			return true;
	}
	return false;
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetTerrainDetailLevel(int level)
{
	if ( m_pRuTerrain )
	{
		m_pRuTerrain->SetTerrainDetailLevel(level);
	}
}

// --------------------------------------------------------------------------------------
void CRuneDev::ReleaseEnvironment()
{
	ruSAFE_RELEASE( m_pRuWorldEnvironment );
}

// --------------------------------------------------------------------------------------
void CRuneDev::InitialEnvironment()
{
	if ( m_pRuWorldEnvironment == NULL )
	{
		m_pRuWorldEnvironment = ruNEW CRuEntity_Environment();
		m_pRuWorldEnvironment->Initialize(32, 10, 1.570796f, m_cameraFarPlane, 1.0f, 2.0f);
	}	
}

// --------------------------------------------------------------------------------------
void CRuneDev::UpdateEnvironment( CRuVector3& pos )
{
	if( m_pRuWorldEnvironment )
	{
		// Select proper zone descriptor to use
		if(m_pRuGaiaObject)
		{
			m_pRuWorldEnvironment->SelectZoneDescriptor(m_pRuGaiaObject, m_pRuTerrain, pos, 0, 0);
//			m_pRuWorldEnvironment->SelectZoneDescriptor(m_pRuGaiaObject, pos, 0, 0);
		}

		// Update world environment and render sky dome
		m_pRuWorldEnvironment->SetCamera(m_pCamera);
		m_pRuWorldEnvironment->Update(m_elapsedTime);
	}
}

// --------------------------------------------------------------------------------------
void CRuneDev::RenderEnvironment()
{
	// 繪製天空
	g_ruSceneRenderer->Scene_Submit(m_pRuWorldEnvironment);
}

// --------------------------------------------------------------------------------------
void CRuneDev::UpdateInterface()
{
	// 重新取得輸入裝置資訊
	InputState inputState;
	memset( &inputState, 0, sizeof(inputState) );

	// 取得鍵盤資訊
	if ( m_pKeyboard->Update() )
	{
		for ( int i = 0; i < 256; i++ )
			inputState.key[i] = m_pKeyboard->GetKeyState(i);
	}

	// 取得滑鼠資訊
	if ( m_pMouse->Update() )
	{
		for ( int i = 0; i < 4; i++ )
			inputState.button[i] = m_pMouse->GetButtonState(i);

		inputState.xDelta = (int)(m_pMouse->GetXDelta() * m_UIWidth / m_xScreen);
		inputState.yDelta = (int)(m_pMouse->GetYDelta() * m_UIHeight / m_yScreen);
		inputState.zDelta = m_pMouse->GetZDelta();
	}

	// 更新游標座標值
	if ( m_isCursorLock )
	{
		if ( m_isWindowed )
		{
			POINT pt;
			pt.x = m_xCursor;
			pt.y = m_yCursor;
			ClientToScreen( m_hFrameWnd, &pt );
			SetCursorPos( pt.x, pt.y );
		}
	}
	else
	{
		// 使用視窗座標值
		POINT pt;
		GetCursorPos( &pt );
		ScreenToClient( m_hFrameWnd, &pt );

		m_xCursor = pt.x;
		m_yCursor = pt.y;

		/*
		// 視窗模式,強制使用視窗游標座標值
		if ( m_isWindowed )
		{
			POINT pt;
			GetCursorPos( &pt );
			ScreenToClient( m_hFrameWnd, &pt );

			m_xCursor = pt.x;
			m_yCursor = pt.y;
		}
		else
		{
			m_xCursor += inputState.xDelta;
			m_yCursor += inputState.yDelta;

			if ( m_xCursor < 0 )
				m_xCursor = 0;
			else if ( m_xCursor > (int)m_xScreen )
				m_xCursor = m_xScreen;

			if ( m_yCursor < 0 )
				m_yCursor = 0;
			else if ( m_yCursor > (int)m_yScreen )
				m_yCursor = m_yScreen;
		}
		*/
	}

	// 更新界面
	inputState.xPos = (int)(m_xCursor * m_UIWidth / m_xScreen);
	inputState.yPos = (int)(m_yCursor * m_UIHeight / m_yScreen);
    
	m_interface->Update(m_elapsedTime, inputState);
}

// --------------------------------------------------------------------------------------
CRoleSprite* CRuneDev::CreateRoleSprite( int ID, int lastID )
{
	CRoleSprite *pNew = NULL, *pLast = NULL;
	RoleIndex::iterator iter;

	if ( lastID != -1 )					// 物件已經建立
	{
		// 搜尋舊物件
		if ( (iter = m_roleIndex.find( lastID )) != m_roleIndex.end() )
		{
			pLast = iter->second;
			if ( pLast->RefCount() <= 0 )
			{
				m_roleIndex.erase( iter );
				for ( RoleGarbage::iterator gar_iter = m_roleGarbage.begin(); gar_iter != m_roleGarbage.end(); gar_iter++ )
				{
					if ( (*gar_iter).first == iter )
					{
						m_roleGarbage.erase( gar_iter );
						break;
					}
				}
			}
			else
			{
				pLast->DelRefCount();
				iter->second = ruNEW CRoleSprite;
				iter->second->AddRefCount();
				iter->second->SetIdentify( lastID );
			}
		}
	}

	if ( (iter = m_roleIndex.find( ID )) != m_roleIndex.end() )
	{
		pNew = iter->second;
		pNew->AddRefCount();
	}
	else
	{
		if ( pLast == NULL )
		{
			pNew = ruNEW CRoleSprite;
			pNew->SetIdentify( ID );
			pNew->AddRefCount();
			m_roleIndex.insert( make_pair( ID, pNew ) );

			SendCreateRoleSprite( pNew );
		}
		else
		{
			pNew = pLast;
			pNew->SetIdentify( ID );
			pNew->AddRefCount();
			m_roleIndex.insert( make_pair( ID, pNew ) );
		}		
	}

	return pNew;
}

// --------------------------------------------------------------------------------------
CRoleSprite* CRuneDev::FindRoleSprite( int ID )
{
	RoleIndex::iterator iter = m_roleIndex.find( ID );
	if ( iter != m_roleIndex.end() )
		return iter->second;
	
	return NULL;
}

// --------------------------------------------------------------------------------------
void CRuneDev::DeleteRoleSprite( int ID )
{
	RoleIndex::iterator iter = m_roleIndex.find( ID );
	if ( iter != m_roleIndex.end() )
	{
		CRoleSprite* pSprite = iter->second;
		pSprite->DelRefCount();
		
		if ( pSprite->RefCount() <= 0 )
		{
			// 檢查是否有相同物件將被刪除
			RoleGarbage::iterator now_iter = m_roleGarbage.begin();
			for ( ; now_iter != m_roleGarbage.end(); now_iter++ )
			{
				if ( (*now_iter).first == iter )
				{
					m_roleGarbage.erase( now_iter );
					break;
				}
			}

			m_roleGarbage.push_back( make_pair(iter, m_frameTime + REMOVE_ROLE_TIME) );
		}
	}
	else
		g_pError->AddMessage( 0, 0, "Error !! 刪除不存在物件 %d", ID );
}

// --------------------------------------------------------------------------------------
void CRuneDev::ClearRoleSprite()
{
	/*
	for ( list< pair<CRoleSprite*, float> >::iterator iter = m_roleGarbage.begin(); iter != m_roleGarbage.end(); iter++ )
		delete (*iter).first;
	*/
	m_roleGarbage.clear();

	for ( RoleIndex::iterator iter = m_roleIndex.begin(); iter != m_roleIndex.end(); iter++ )
		delete iter->second;
	m_roleIndex.clear();
}

// --------------------------------------------------------------------------------------
CRoleSprite* CRuneDev::GetTopRoleSprite( int x, int y, int exclude )
{
	multimap<float, CRoleSprite*> role_depth;
	for ( RoleIndex::iterator iter = m_roleIndex.begin(); iter != m_roleIndex.end(); iter++ )
	{
		CRoleSprite* pSprite = iter->second;
		if ( pSprite->GetRuEntity() && pSprite->GetIdentify() != exclude )
		{
			CRuVector3 vec = pSprite->GetPos();
			m_pCamera->GetCameraTransform().TransformPoint( vec );
			if ( vec.m_z > -10 )
				role_depth.insert( make_pair( vec.m_z, pSprite ) );
		}
	}

	for ( multimap<float, CRoleSprite*>::iterator iter = role_depth.begin(); iter != role_depth.end(); iter++ )
	{
		if ( RuEntity_PickTest( (iter->second)->GetRuEntity(), m_pCamera, m_pRuSwapChain, x, y ) )
			return iter->second;
	}

	return NULL;
}

// --------------------------------------------------------------------------------------
void CRuneDev::SetHighlightSprite( CRoleSprite* sprite )
{
	if ( m_pRuHighlighter )
	{
		CRuEntity* ruEntity = NULL;
		if (sprite)
			ruEntity = sprite->GetRuEntity();

		m_pRuHighlighter->SetTarget(ruEntity);
	}
}

// --------------------------------------------------------------------------------------
void CRuneDev::ResetRoleSpriteWidget()
{
	RoleIndex::iterator iter = m_roleIndex.begin();
	for ( ; iter != m_roleIndex.end(); iter++ )
		(iter->second)->SetWidgetTexture();
}

/*
// --------------------------------------------------------------------------------------
CRoleSprite* CRuneDev::RecycleRoleSprite( int ID )
{
	for ( RoleGarbage::iterator iter = m_roleGarbage.begin(); iter != m_roleGarbage.end(); iter++ )
	{
		CRoleSprite* pSprite = (*iter).first;
		if ( pSprite->GetIdentify() == ID )
		{
			m_roleGarbage.erase( iter );
			return pSprite;
		}
	}
	return NULL;
}
*/

// --------------------------------------------------------------------------------------
void CRuneDev::UpdateRoleSprite()
{
	// 是否有待移除物件
	RoleGarbage::iterator now_iter = m_roleGarbage.begin();
	while ( now_iter != m_roleGarbage.end() )
	{
		RoleGarbage::iterator next_iter = now_iter;
		next_iter++;

		RoleIndex::iterator role_iter = (*now_iter).first;
		if ( (role_iter->second)->RefCount() > 0 )
			m_roleGarbage.erase( now_iter );
		else if ( (*now_iter).second < m_frameTime )		
		{
			SendDeleteRoleSprite( role_iter->second );
			delete role_iter->second;
			m_roleIndex.erase( role_iter );
			m_roleGarbage.erase( now_iter );
		}
		now_iter = next_iter;
	}

	IBaseSprite::UpdateAll( m_elapsedTime );

	/*
	for ( RoleIndex::iterator iter = m_roleIndex.begin(); iter != m_roleIndex.end(); iter++ )
		(iter->second)->Update( m_elapsedTime );
	*/
}

// --------------------------------------------------------------------------------------
void CRuneDev::RenderSprite()
{
	IBaseSprite::RenderAll();

	/*
	for ( RoleIndex::iterator iter = m_roleIndex.begin(); iter != m_roleIndex.end(); iter++ )
		(iter->second)->Render();
	*/
}

// --------------------------------------------------------------------------------------
void CRuneDev::CreateWidgetGrid(CRuVector3 pos, bool isLock, float halfSize, float spacing)
{
	ReleaseWidgetGrid();

	m_gridPos			= pos;
	m_isGridLock		= isLock;
	m_gridHalfSize		= halfSize;
	m_gridSpacing		= spacing;

	// 產生格線
	m_pRuWidgetGrid = new CRuEntity_Widget_Grid;
	if ( m_pRuWidgetGrid )
	{
		m_pRuWidgetGrid->SetGridProperties( CRuVector3(1.0f, 0.0f, 0.0f), CRuVector3(0.0f, 1.0f, 0.0f), CRuVector3(0.0f, 0.0f, 0.0f), m_gridHalfSize, m_gridSpacing );
	}
}

// --------------------------------------------------------------------------------------
void CRuneDev::ReleaseWidgetGrid()
{
	ruSAFE_RELEASE( m_pRuWidgetGrid );
}

// --------------------------------------------------------------------------------------
void CRuneDev::Update()
{
	float time = (float)m_pRuTimer->GetTime() / 1000.0f;
	float last = time;

	UpdateTerrain();

	last = time;
	time = (float)m_pRuTimer->GetTime() / 1000.0f;
	g_handleTime[0] += time - last;

	if ( m_isSprite_Update )
		UpdateRoleSprite();

	last = time;
	time = (float)m_pRuTimer->GetTime() / 1000.0f;
	g_handleTime[1] += time - last;

	UpdateInterface();

	last = time;
	time = (float)m_pRuTimer->GetTime() / 1000.0f;
	g_handleTime[2] += time - last;

	if ( m_isEnvironmentUpdate )
		UpdateEnvironment( m_playerPos );

	last = time;
	time = (float)m_pRuTimer->GetTime() / 1000.0f;
	g_handleTime[3] += time - last;

	m_pRuHighlighter->Update(m_elapsedTime);

	if ( m_pRuWidgetGrid )
	{
		CRuVector3 pos;
		if ( m_isGridLock )
		{
			pos = m_playerPos;
			pos.m_y += 16.0f;
		}
		else
			pos = m_gridPos;

		pos.m_y += 5.0f;
		m_pRuWidgetGrid->SnapGrid(CRuVector3(0.0f, 0.0f, 0.0f), pos);
		m_pRuWidgetGrid->Update( m_elapsedTime );
	}
}

// ------------------------------------------------------------------------------------------------
bool CRuneDev::FrameLoop()
{
	static float s_time = 0.0f;	
	static float s_stableTime = 0.0f;
	//CRoleSprite *pRole = m_pRoleSpriteManage->FindRoleSprite( m_playerID );

	float time = (float)m_pRuTimer->GetTime() / 1000.0f;
	float elapsedTime = time - m_frameTime;
	float last;

	/*
	// 控制穩速
	if ( m_isStableFrame )
	{
		while ( elapsedTime < s_stableTime )
		{
			time = (float)m_pRuTimer->GetTime() / 1000.0f;
			elapsedTime = time - m_frameTime;
		}		
		//if ( elapsedTime < s_stableTime )
		//	return true;

		if ( elapsedTime > 0.2f )
			s_stableTime = 0.0f;
		else
			s_stableTime = elapsedTime * 0.95f;
	}
	*/

	m_frameTime		= time;
	m_elapsedTime	= elapsedTime;	

	// 更新鏡頭及控制器
	m_pRuCameraController->Update(m_elapsedTime);
	m_pCamera->Update(m_elapsedTime);

	Update();

	last = time;
	time = (float)m_pRuTimer->GetTime() / 1000.0f;
	g_handleTime[4] += time - last;

	// 開始繪製
	if( g_ruEngine->BeginScene() )
	{		
		// 開始3D繪圖
		g_ruSceneRenderer->Scene_Begin();

		// 選取主要swap chain為繪製平面
		// m_pRuSwapChain->SelectRenderTarget();

		// 選用主鏡頭
		g_ruSceneRenderer->SetCamera( m_pCamera );

		// 設定主要swap chain為輸出目標
		g_ruSceneRenderer->Scene_SetRenderTarget( m_pRuSwapChain, 1000, RUCLEAR_TARGET | RUCLEAR_ZBUFFER | RUCLEAR_STENCIL, 0x00000000, 1.0f, 0);
		g_ruEngine->Clear( RUCLEAR_TARGET, 0x00000000, 0.0f, 0 );

		// 設定霧
//		g_ruSceneRenderer->GetShaderParameterBlock()->SetParameter(ruPARAMTYPE_FOG_START, RuCastFloatToDWORD(m_fogMin));
//		g_ruSceneRenderer->GetShaderParameterBlock()->SetParameter(ruPARAMTYPE_FOG_END, RuCastFloatToDWORD(m_fogMax));

		last = time;
		time = (float)m_pRuTimer->GetTime() / 1000.0f;
		g_handleTime[5] += time - last;

		if ( m_isEnvironmentRender )
			RenderEnvironment();

		last = time;
		time = (float)m_pRuTimer->GetTime() / 1000.0f;
		g_handleTime[6] += time - last;

		// 繪製地表跟天空
		RenderTerrain();

		last = time;
		time = (float)m_pRuTimer->GetTime() / 1000.0f;
		g_handleTime[7] += time - last;

		if ( m_pRuWidgetGrid )
			g_ruSceneRenderer->Scene_Submit( m_pRuWidgetGrid );

		// 繪出角色
		if ( m_isSprite_Render )
			RenderSprite();

		last = time;
		time = (float)m_pRuTimer->GetTime() / 1000.0f;
		g_handleTime[8] += time - last;

		// 繪出界面
		if (m_interface)
			m_interface->Render3D();

		// 結束3D繪圖
		g_ruSceneRenderer->Scene_End();

		last = time;
		time = (float)m_pRuTimer->GetTime() / 1000.0f;
		g_handleTime[9] += time - last;

		// Blur
		if ( m_isGlow )
			RuPostFX_Blur( m_pRuSwapChain, m_pBlurTexture1, m_pBlurTexture2 );

		last = time;
		time = (float)m_pRuTimer->GetTime() / 1000.0f;
		g_handleTime[10] += time - last;

		if ( g_ruSceneRenderer->Ru2D_Begin() )
		{
			// 繪出界面
			if (m_interface)
				m_interface->Render2D();
			
			/*
			if (m_pRuMinimap)
			{
				m_pRuMinimap->SetMinimapViewport(CRuRectangle(60.0f, 200.0f, 60.0f + 192.0f, 200.0f + 192.0f));
				m_pRuMinimap->SetMinimapOrigin(CRuVector2(192.0f / 2.0f, 192.0f / 2.0f));
				m_pRuMinimap->SetZoom(0.75f);
				m_pRuMinimap->SetPlayerPosition(m_playerPos);
				m_pRuMinimap->Display();
			}
			*/

			last = time;
			time = (float)m_pRuTimer->GetTime() / 1000.0f;
			g_handleTime[11] += time - last;

			if ( m_isShowFps )
			{
				WCHAR* tmp = NULL;
				char text[MAX_PATH];

				sprintf( text, "fps : %.2f %.4f", m_fps, s_stableTime );
				tmp = TransToWChar(text);
				CRuFontChar::DrawText(m_pSysFontType, 800, 10, 0xFFFFFF00, tmp );
				SAFE_DELETE(tmp);
				sprintf( text, "sprite : %d", IBaseSprite::GetContainer().size() );				
				tmp = TransToWChar(text);
				CRuFontChar::DrawText(m_pSysFontType, 800, 28, 0xFFFFFF00, tmp );
				SAFE_DELETE(tmp);

				sprintf( text, "Texture:%d/%d", CTextureImage::LoadedCapacity(), MAX_TEXTUREIMAGE );
				tmp = TransToWChar(text);
				CRuFontChar::DrawText( m_pSysFontType, 800, 46, 0xFFFFFF00, tmp );
				SAFE_DELETE(tmp);
				
				/*
				sprintf( text, "Small font:%d/%d Large font:%d/%d",
					CRuFontTexture::GetSmallFontSize() - CRuFontTexture::FreeSmallFontCapacity(), CRuFontTexture::GetSmallFontSize(),
					CRuFontTexture::GetLargeFontSize() - CRuFontTexture::FreeLargeFontCapacity(), CRuFontTexture::GetLargeFontSize() );
				tmp = TransToWChar(text);
				CRuFontChar::DrawText( m_pSysFontType, 800, 64, 0xFFFFFF00, tmp );
				SAFE_DELETE(tmp);
				*/

				int line = 0;
				for ( int i = 0; i < 16; i++ )
				{
					float time = abs(g_qualityRecord[i].time);
					sprintf( text, "%.4f(%.2f%%) %s", time, time/(s_time/m_fps), g_qualityRecord[i].name );
					tmp = TransToWChar(text);
					CRuFontChar::DrawText( m_pSysFontType, (float)800, (float)(82 + i*16), 0xBFDEDEDE, tmp );
					SAFE_DELETE(tmp);
				}
			}
			
			/*
			char tmp[MAX_PATH];
			sprintf(tmp, "Screen Size (%d x %d) UISize (%.1f x %.1f)", m_xScreen, m_yScreen, m_UIWidth, m_UIHeight);
			CRuFontChar::DrawText( m_pSysFontType, 400.0f, 100.0f, 0xBFDEDE00, tmp );
			*/
			
			// 繪出游標
			bool isDrawCursor = m_isCursorVisible;
			if ( m_isWindowed )
			{
				POINT pt;
				GetCursorPos( &pt );
				ScreenToClient( m_hFrameWnd, &pt );
				if ( (DWORD)pt.x > m_xScreen || (DWORD)pt.y > m_yScreen )
					isDrawCursor = false;
			}
			if ( isDrawCursor )
				RenderCursor();

			last = time;
			time = (float)m_pRuTimer->GetTime() / 1000.0f;
			g_handleTime[12] += time - last;

			g_ruSceneRenderer->Ru2D_End();						// 結束2D繪圖
			//g_ruSceneRenderer->Ru2D_SetScissorRect(NULL);
		}

		// 結束繪製
		if( !g_ruEngine->EndScene() )
		{
		}

		last = time;
		time = (float)m_pRuTimer->GetTime() / 1000.0f;
		g_handleTime[13] += time - last;
	}	

	// Present主要swap chain
	m_pRuSwapChain->Present();

	last = time;
	time = (float)m_pRuTimer->GetTime() / 1000.0f;
	g_handleTime[14] += time - last;

	// 輸出視窗資訊
	{
		static float oldTime;
		static float frame;
		
		/*
		if ( m_elapsedTime > maxTime )
			maxTime = m_elapsedTime;
		*/

		// 計算每秒張數
		if ( m_frameTime - oldTime >= 1.0f )
		{
			m_fps = frame / (m_frameTime - oldTime);
			s_time = m_frameTime - oldTime;

			for ( int i = 0 ; i < 16; i++ )
			{
				if ( i == 15 )
				{
					g_qualityRecord[i].time = 0.0f;
					for ( int j = 5; j < 14; j++ )
						g_qualityRecord[i].time += g_qualityRecord[j].time;
				}
				else
				{
					g_qualityRecord[i].time = g_handleTime[i] / frame;
				}				
				g_handleTime[i] = 0.0f;
			}
			oldTime = m_frameTime;			
			frame = 0.0f;
		}
		frame++;
	}

	if ( g_out )
	{
		g_pError->AddMessage( 0 ,0, "time %.4f", m_elapsedTime );
	}

	if ( !m_isActived )
		SleepEx( 50 , true );

	return true;
}

// ------------------------------------------------------------------------------------------------
LRESULT CRuneDev::WndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
	if (m_interface)
		m_interface->WndProc(iMsg, wParam, lParam);

	switch ( iMsg )
	{
		/*
	case WM_SETCURSOR:
		if ( m_isHardwaveCursor )
		{
			SetCursor( NULL );
			g_ruEngineD3D->GetD3DDevice()->ShowCursor( TRUE );
			return TRUE;
		}
		*/
		break;

	case WM_ACTIVATE:
		if ( LOWORD(wParam) == WA_INACTIVE )
			m_isActived = false;
		else
			m_isActived = true;
		return 0;

	case WM_KEYDOWN:
		switch ( wParam)
		{
		case 'T':
			//g_out = !g_out;
			break;
		}
		break;

	case WM_ACTIVATEAPP:
		m_isActived = ( wParam ) ? true : false;
		break;

		/*
		case WM_TIMER:
		if ( !m_isActived )
		Update();
		break;
		*/

	case WM_SIZE:
		switch ( wParam )
		{
		case SIZE_RESTORED:
		case SIZE_MAXIMIZED:
			{
				RECT clientOld;
				clientOld = m_clientRect;

				// Update window properties
				GetWindowRect( hWnd, &m_windowRect );
				GetClientRect( hWnd, &m_clientRect );
				if ( m_clientRect.right - m_clientRect.left != clientOld.right - clientOld.left ||
					m_clientRect.bottom - m_clientRect.top != clientOld.bottom - clientOld.top )
				{
					SetScreenSize( m_clientRect.right - m_clientRect.left, m_clientRect.bottom - m_clientRect.top, m_isWindowed );
				}					
			}
			break;
		}
		break;

	case WM_CLOSE:
		{			
			DestroyWindow( hWnd );
			PostQuitMessage(0);
			return 0;
		}
	}
	return DefWindowProc(hWnd, iMsg, wParam, lParam);
}

// ------------------------------------------------------------------------------------------------
LRESULT CALLBACK FrameWndProc(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{	
	return g_pRuneDev->WndProc(hWnd, iMsg, wParam, lParam);
}

// ------------------------------------------------------------------------------------------------
void FontTextureRally()
{
	g_pRuneDev->ResetRoleSpriteWidget();
}
// ------------------------------------------------------------------------------------------------
bool CRuneDev::SetMiniMapMask( const char* cszFile )
{

	IRuTexture *maskTexture = g_ruResourceManager->LoadTexture( cszFile );
	if(maskTexture)
	{
		g_pRuneDev->m_pRuMinimap->SetMinimapMask(maskTexture);
		ruSAFE_RELEASE(maskTexture);
		return true;
	}
	
	return false;
}
