Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2730 lines
72 KiB

  1. //===== Copyright 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. //===========================================================================//
  6. #if defined( USE_SDL )
  7. #undef PROTECTED_THINGS_ENABLE
  8. #include "SDL.h"
  9. #endif
  10. #if defined( WIN32 ) && !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  11. #include "winlite.h"
  12. #include "xbox/xboxstubs.h"
  13. #endif
  14. #if defined( IS_WINDOWS_PC ) && !defined( USE_SDL )
  15. #include <winsock.h>
  16. #elif defined(_X360)
  17. // nothing to include for 360
  18. #elif defined(OSX)
  19. #include <Carbon/Carbon.h>
  20. #elif defined(LINUX)
  21. #include "tier0/dynfunction.h"
  22. #elif defined(_WIN32)
  23. #include "tier0/dynfunction.h"
  24. #elif defined( _PS3 )
  25. #include "basetypes.h"
  26. #include "ps3/ps3_core.h"
  27. #include "ps3/ps3_win32stubs.h"
  28. #include <cell/audio.h>
  29. #include <sysutil/sysutil_sysparam.h>
  30. #else
  31. #error
  32. #endif
  33. #include "appframework/ilaunchermgr.h"
  34. #include "igame.h"
  35. #include "cl_main.h"
  36. #include "host.h"
  37. #include "quakedef.h"
  38. #include "tier0/icommandline.h"
  39. #include "ivideomode.h"
  40. #include "gl_matsysiface.h"
  41. #include "cdll_engine_int.h"
  42. #include "vgui_baseui_interface.h"
  43. #include "iengine.h"
  44. #include "avi/iavi.h"
  45. #include "keys.h"
  46. #include "VGuiMatSurface/IMatSystemSurface.h"
  47. #include "tier3/tier3.h"
  48. #include "sound.h"
  49. #include "vgui_controls/Controls.h"
  50. #include "vgui_controls/MessageDialog.h"
  51. #include "sys_dll.h"
  52. #include "inputsystem/iinputsystem.h"
  53. #include "inputsystem/ButtonCode.h"
  54. #include "GameUI/IGameUI.h"
  55. #include "sv_main.h"
  56. #if defined( BINK_VIDEO )
  57. #include "bink/bink.h"
  58. #endif
  59. #include "vgui/IVGui.h"
  60. #include "IHammer.h"
  61. #include "inputsystem/iinputstacksystem.h"
  62. #include "avi/ibik.h"
  63. #include "materialsystem/imaterial.h"
  64. #include "characterset.h"
  65. #include "server.h"
  66. #if defined( INCLUDE_SCALEFORM )
  67. #include "scaleformui/scaleformui.h"
  68. #endif
  69. #include <vgui/ILocalize.h>
  70. #include <vgui/ISystem.h>
  71. #if defined( _X360 )
  72. #include "xbox/xbox_win32stubs.h"
  73. #include "snd_dev_xaudio.h"
  74. #include "xmp.h"
  75. #include "xbox/xbox_launch.h"
  76. #include "ixboxsystem.h"
  77. extern IXboxSystem *g_pXboxSystem;
  78. #endif
  79. #if defined( LINUX )
  80. #include "snd_dev_sdl.h"
  81. #endif
  82. #include "matchmaking/imatchframework.h"
  83. #include "tier2/tier2.h"
  84. #include "tier1/fmtstr.h"
  85. #if !defined( PLATFORM_X360 )
  86. #include "cl_steamauth.h"
  87. #endif
  88. #if defined( PLATFORM_WINDOWS )
  89. #include "vaudio/ivaudio.h"
  90. extern void VAudioInit();
  91. extern IVAudio * vaudio;
  92. #endif
  93. // memdbgon must be the last include file in a .cpp file!!!
  94. #include "tier0/memdbgon.h"
  95. extern ConVar cv_vguipanel_active;
  96. void S_BlockSound (void);
  97. void S_UnblockSound (void);
  98. void ClearIOStates( void );
  99. //-----------------------------------------------------------------------------
  100. // Game input events
  101. //-----------------------------------------------------------------------------
  102. enum GameInputEventType_t
  103. {
  104. IE_WindowMove = IE_FirstAppEvent,
  105. IE_AppActivated,
  106. };
  107. //-----------------------------------------------------------------------------
  108. // Purpose: Main game interface, including message pump and window creation
  109. //-----------------------------------------------------------------------------
  110. class CGame : public IGame
  111. {
  112. public:
  113. CGame( void );
  114. virtual ~CGame( void );
  115. bool Init( void *pvInstance );
  116. bool Shutdown( void );
  117. bool CreateGameWindow( void );
  118. void DestroyGameWindow();
  119. void SetGameWindow( void* hWnd );
  120. // This is used in edit mode to override the default wnd proc associated w/
  121. bool InputAttachToGameWindow();
  122. void InputDetachFromGameWindow();
  123. void PlayStartupVideos( void );
  124. void* GetMainWindow( void );
  125. void** GetMainWindowAddress( void );
  126. void GetDesktopInfo( int &width, int &height, int &refreshrate );
  127. void SetWindowXY( int x, int y );
  128. void SetWindowSize( int w, int h );
  129. void GetWindowRect( int *x, int *y, int *w, int *h );
  130. bool IsActiveApp( void );
  131. void SetCanPostActivateEvents( bool bEnable );
  132. bool CanPostActivateEvents();
  133. virtual void OnScreenSizeChanged( int nOldWidth, int nOldHeight );
  134. public:
  135. void SetMainWindow( HWND window );
  136. void SetActiveApp( bool active );
  137. #if defined( WIN32 ) || defined( _GAMECONSOLE )
  138. int WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  139. #endif
  140. // plays a video file and waits until completed. Can be interrupted by user input.
  141. virtual void PlayVideoListAndWait( const char *szVideoFileList, bool bNeedHealthWarning = false );
  142. virtual void PlayVideoAndWait(const char *filename, bool bNeedHealthWarning = false);
  143. // Message handlers.
  144. public:
  145. void HandleMsg_WindowMove( const InputEvent_t &event );
  146. void HandleMsg_ActivateApp( const InputEvent_t &event );
  147. void HandleMsg_Close( const InputEvent_t &event );
  148. // Call the appropriate HandleMsg_ function.
  149. void DispatchInputEvent( const InputEvent_t &event );
  150. // Dispatch all the queued up messages.
  151. virtual void DispatchAllStoredGameMessages();
  152. InputContextHandle_t GetInputContext() { return m_hInputContext; }
  153. private:
  154. void AppActivate( bool fActive );
  155. private:
  156. void AttachToWindow();
  157. void DetachFromWindow();
  158. #ifndef _X360
  159. static const wchar_t CLASSNAME[];
  160. #else
  161. static const char CLASSNAME[];
  162. #endif
  163. bool m_bExternallySuppliedWindow;
  164. #if USE_SDL
  165. SDL_Window *m_hWindow;
  166. #elif defined( WIN32 )
  167. HWND m_hWindow;
  168. HINSTANCE m_hInstance;
  169. // Stores a wndproc to chain message calls to
  170. WNDPROC m_ChainedWindowProc;
  171. RECT m_rcLastRestoredClientRect;
  172. #elif OSX
  173. WindowRef m_hWindow;
  174. #else
  175. #error
  176. #endif
  177. int m_x;
  178. int m_y;
  179. int m_width;
  180. int m_height;
  181. bool m_bActiveApp;
  182. bool m_bCanPostActivateEvents;
  183. int m_iDesktopWidth, m_iDesktopHeight, m_iDesktopRefreshRate;
  184. void UpdateDesktopInformation( HWND hWnd );
  185. #ifdef WIN32
  186. void UpdateDesktopInformation( WPARAM wParam, LPARAM lParam );
  187. #endif
  188. InputContextHandle_t m_hInputContext;
  189. };
  190. static CGame g_Game;
  191. IGame *game = ( IGame * )&g_Game;
  192. #if defined( _PS3 )
  193. extern void AbortLoadingUpdatesDueToShutdown();
  194. extern bool SaveUtilV2_CanShutdown();
  195. void PS3_sysutil_callback_forwarder( uint64 uiStatus, uint64 uiParam )
  196. {
  197. if ( Steam3Client().SteamUtils() )
  198. Steam3Client().SteamUtils()->PostPS3SysutilCallback( uiStatus, uiParam, NULL );
  199. if ( uiStatus == CELL_SYSUTIL_REQUEST_EXITGAME )
  200. {
  201. SaveUtilV2_CanShutdown();
  202. AbortLoadingUpdatesDueToShutdown();
  203. }
  204. }
  205. int PS3_WindowProc_Proxy( xevent_t const &ev )
  206. {
  207. // HWND = NULL
  208. // message = WM_*** (arg1)
  209. // LPARAM = parameter (arg2)
  210. // WPARAM = 0 (arg3)
  211. // Note the order of parameters to WindowProc:
  212. // WindowProc( HWND, MSG, WPARAM=arg3=0, LPARAM )
  213. if ( ev.arg3 )
  214. {
  215. // Event has sysutil payload
  216. PS3_sysutil_callback_forwarder( ev.sysutil_status, ev.sysutil_param );
  217. if ( 0 && g_pMatchFramework )
  218. {
  219. KeyValues *kv = new KeyValues( "Ps3SysutilCallback" );
  220. kv->SetUint64( "status", ev.sysutil_status );
  221. kv->SetUint64( "param", ev.sysutil_param );
  222. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kv );
  223. }
  224. }
  225. return g_Game.WindowProc( NULL, ev.arg1, ev.arg3, ev.arg2 );
  226. }
  227. #endif
  228. #if !defined( _X360 )
  229. const wchar_t CGame::CLASSNAME[] = L"Valve001";
  230. #else
  231. const char CGame::CLASSNAME[] = "Valve001";
  232. #endif
  233. // In VCR playback mode, it sleeps this amount each frame.
  234. int g_iVCRPlaybackSleepInterval = 0;
  235. // During VCR playback, if this is true, then it'll pause at the end of each frame.
  236. bool g_bVCRSingleStep = false;
  237. bool g_bWaitingForStepKeyUp = false; // Used to prevent it from running frames while you hold the S key down.
  238. bool g_bShowVCRPlaybackDisplay = true;
  239. InputContextHandle_t GetGameInputContext()
  240. {
  241. return g_Game.GetInputContext();
  242. }
  243. // These are all the windows messages that can change game state.
  244. // See CGame::WindowProc for a description of how they work.
  245. struct GameMessageHandler_t
  246. {
  247. int m_nEventType;
  248. void (CGame::*pFn)( const InputEvent_t &event );
  249. };
  250. GameMessageHandler_t g_GameMessageHandlers[] =
  251. {
  252. { IE_AppActivated, &CGame::HandleMsg_ActivateApp },
  253. { IE_WindowMove, &CGame::HandleMsg_WindowMove },
  254. { IE_Close, &CGame::HandleMsg_Close },
  255. { IE_Quit, &CGame::HandleMsg_Close },
  256. };
  257. void CGame::AppActivate( bool fActive )
  258. {
  259. // If text mode, force it to be active.
  260. if ( g_bTextMode )
  261. {
  262. fActive = true;
  263. }
  264. // Don't bother if we're already in the correct state
  265. if ( IsActiveApp() == fActive )
  266. return;
  267. // Don't let video modes changes queue up another activate event
  268. SetCanPostActivateEvents( false );
  269. #ifndef DEDICATED
  270. if ( videomode )
  271. {
  272. if ( fActive )
  273. {
  274. videomode->RestoreVideo();
  275. }
  276. else
  277. {
  278. videomode->ReleaseVideo();
  279. }
  280. }
  281. #ifdef OSX
  282. // make sure the mouse cursor is in a sane location, force it to screen middle
  283. if ( fActive )
  284. {
  285. g_pLauncherMgr->SetCursorPosition( m_width/2, m_height/2 );
  286. }
  287. #endif
  288. if ( host_initialized )
  289. {
  290. if ( fActive )
  291. {
  292. // Clear keyboard states (should be cleared already but...)
  293. // VGui_ActivateMouse will reactivate the mouse soon.
  294. ClearIOStates();
  295. UpdateMaterialSystemConfig();
  296. }
  297. else
  298. {
  299. // Clear keyboard input and deactivate the mouse while we're away.
  300. ClearIOStates();
  301. if ( g_ClientDLL )
  302. {
  303. g_ClientDLL->IN_DeactivateMouse();
  304. }
  305. }
  306. }
  307. #endif // DEDICATED
  308. SetActiveApp( fActive );
  309. // Allow queueing of activation events
  310. SetCanPostActivateEvents( true );
  311. }
  312. void CGame::HandleMsg_WindowMove( const InputEvent_t &event )
  313. {
  314. game->SetWindowXY( event.m_nData, event.m_nData2 );
  315. #ifndef DEDICATED
  316. videomode->UpdateWindowPosition();
  317. #endif
  318. }
  319. void CGame::HandleMsg_ActivateApp( const InputEvent_t &event )
  320. {
  321. AppActivate( event.m_nData ? true : false );
  322. }
  323. void CGame::HandleMsg_Close( const InputEvent_t &event )
  324. {
  325. if ( eng->GetState() == IEngine::DLL_ACTIVE )
  326. {
  327. eng->SetQuitting( IEngine::QUIT_TODESKTOP );
  328. }
  329. }
  330. void CGame::DispatchInputEvent( const InputEvent_t &event )
  331. {
  332. switch( event.m_nType )
  333. {
  334. // Handle button events specially,
  335. // since we have all manner of crazy filtering going on when dealing with them
  336. case IE_ButtonPressed:
  337. case IE_ButtonDoubleClicked:
  338. case IE_ButtonReleased:
  339. case IE_KeyTyped:
  340. case IE_KeyCodeTyped:
  341. Key_Event( event );
  342. break;
  343. // Broadcast analog values both to VGui & to GameUI
  344. case IE_AnalogValueChanged:
  345. {
  346. // mouse events should go to vgui first, but joystick events should go to scaleform first
  347. if ( event.m_nData >= JOYSTICK_FIRST_AXIS )
  348. {
  349. if ( g_pScaleformUI && g_pScaleformUI->HandleInputEvent( event ) )
  350. break;
  351. if ( g_pMatSystemSurface && g_pMatSystemSurface->HandleInputEvent( event ) )
  352. break;
  353. }
  354. else
  355. {
  356. if ( g_pMatSystemSurface && g_pMatSystemSurface->HandleInputEvent( event ) )
  357. break;
  358. #if defined( INCLUDE_SCALEFORM )
  359. bool vguiActive = IsPC() && cv_vguipanel_active.GetBool();
  360. // we filter input while the console is visible, to prevent scaleform from
  361. // handling anything underneath the console
  362. if ( !vguiActive && g_pScaleformUI && g_pScaleformUI->HandleInputEvent( event ) )
  363. break;
  364. #endif // INCLUDE_SCALEFORM
  365. }
  366. // Let GameUI have the next whack at events
  367. if ( g_ClientDLL && g_ClientDLL->HandleGameUIEvent( event ) )
  368. break;
  369. }
  370. break;
  371. case IE_OverlayEvent:
  372. if ( event.m_nData == 1 )
  373. {
  374. // Overlay has activated
  375. if ( !EngineVGui()->IsGameUIVisible() && sv.IsActive() && sv.IsSinglePlayerGame() )
  376. {
  377. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "gameui_activate" );
  378. }
  379. }
  380. break;
  381. #ifdef _PS3
  382. case IE_ControllerUnplugged:
  383. WindowProc( 0, WM_SYS_INPUTDEVICESCHANGED, 0, ( 1 << event.m_nData ) );
  384. break;
  385. case IE_PS_CameraUnplugged:
  386. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnPSEyeChangedStatus", "CamStatus", event.m_nData ) );
  387. break;
  388. case IE_PS_Move_OutOfView:
  389. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnPSMoveOutOfViewChanged", "OutOfViewBool", event.m_nData ) );
  390. break;
  391. #endif
  392. default:
  393. // Let vgui have the first whack at events
  394. if ( g_pMatSystemSurface && g_pMatSystemSurface->HandleInputEvent( event ) )
  395. break;
  396. #if defined( INCLUDE_SCALEFORM )
  397. bool vguiActive = IsPC() && cv_vguipanel_active.GetBool();
  398. // we filter all input while the console is visible, to prevent scaleform from
  399. // handling anything underneath the console
  400. if ( !vguiActive && g_pScaleformUI && g_pScaleformUI->HandleInputEvent( event ) )
  401. break;
  402. #endif // INCLUDE_SCALEFORM
  403. for ( int i=0; i < ARRAYSIZE( g_GameMessageHandlers ); i++ )
  404. {
  405. if ( g_GameMessageHandlers[i].m_nEventType == event.m_nType )
  406. {
  407. (this->*g_GameMessageHandlers[i].pFn)( event );
  408. break;
  409. }
  410. }
  411. break;
  412. }
  413. }
  414. void CGame::DispatchAllStoredGameMessages()
  415. {
  416. int nEventCount = g_pInputSystem->GetEventCount();
  417. const InputEvent_t* pEvents = g_pInputSystem->GetEventData( );
  418. for ( int i = 0; i < nEventCount; ++i )
  419. {
  420. DispatchInputEvent( pEvents[i] );
  421. }
  422. }
  423. void VCR_EnterPausedState()
  424. {
  425. // Turn this off in case they're in single-step mode.
  426. g_bVCRSingleStep = false;
  427. #ifdef WIN32
  428. // This is cheesy, but GetAsyncKeyState is blocked (in protected_things.h)
  429. // from being accidentally used, so we get it through it by getting its pointer directly.
  430. static HINSTANCE hInst = LoadLibrary( "user32.dll" );
  431. if ( !hInst )
  432. return;
  433. typedef SHORT (WINAPI *GetAsyncKeyStateFn)( int vKey );
  434. static GetAsyncKeyStateFn pfn = (GetAsyncKeyStateFn)GetProcAddress( hInst, "GetAsyncKeyState" );
  435. if ( !pfn )
  436. return;
  437. // In this mode, we enter a wait state where we only pay attention to R and Q.
  438. while ( 1 )
  439. {
  440. if ( pfn( 'R' ) & 0x8000 )
  441. break;
  442. if ( pfn( 'Q' ) & 0x8000 )
  443. TerminateProcess( GetCurrentProcess(), 1 );
  444. if ( pfn( 'S' ) & 0x8000 )
  445. {
  446. if ( !g_bWaitingForStepKeyUp )
  447. {
  448. // Do a single step.
  449. g_bVCRSingleStep = true;
  450. g_bWaitingForStepKeyUp = true; // Don't do another single step until they release the S key.
  451. break;
  452. }
  453. }
  454. else
  455. {
  456. // Ok, they released the S key, so we'll process it next time the key goes down.
  457. g_bWaitingForStepKeyUp = false;
  458. }
  459. Sleep( 2 );
  460. }
  461. #else
  462. Assert( !"Impl me" );
  463. #endif
  464. }
  465. #ifdef WIN32
  466. void VCR_HandlePlaybackMessages(
  467. HWND hWnd,
  468. UINT uMsg,
  469. WPARAM wParam,
  470. LPARAM lParam
  471. )
  472. {
  473. if ( uMsg == WM_KEYDOWN )
  474. {
  475. if ( wParam == VK_SUBTRACT || wParam == 0xbd )
  476. {
  477. g_iVCRPlaybackSleepInterval += 5;
  478. }
  479. else if ( wParam == VK_ADD || wParam == 0xbb )
  480. {
  481. g_iVCRPlaybackSleepInterval -= 5;
  482. }
  483. else if ( toupper( wParam ) == 'Q' )
  484. {
  485. TerminateProcess( GetCurrentProcess(), 1 );
  486. }
  487. else if ( toupper( wParam ) == 'P' )
  488. {
  489. VCR_EnterPausedState();
  490. }
  491. else if ( toupper( wParam ) == 'S' && !g_bVCRSingleStep )
  492. {
  493. g_bWaitingForStepKeyUp = true;
  494. VCR_EnterPausedState();
  495. }
  496. else if ( toupper( wParam ) == 'D' )
  497. {
  498. g_bShowVCRPlaybackDisplay = !g_bShowVCRPlaybackDisplay;
  499. }
  500. g_iVCRPlaybackSleepInterval = clamp( g_iVCRPlaybackSleepInterval, 0, 500 );
  501. }
  502. }
  503. //-----------------------------------------------------------------------------
  504. // Calls the default window procedure
  505. // FIXME: It would be nice to remove the need for this, which we can do
  506. // if we can make unicode work when running inside hammer.
  507. //-----------------------------------------------------------------------------
  508. static LONG WINAPI CallDefaultWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  509. {
  510. #if defined( _GAMECONSOLE )
  511. return 0;
  512. #else
  513. return DefWindowProcW( hWnd, uMsg, wParam, lParam );
  514. #endif
  515. }
  516. #endif
  517. //-----------------------------------------------------------------------------
  518. // Purpose: The user has accepted an invitation to a game, we need to detect if
  519. // it's our game and restart properly if it is
  520. //-----------------------------------------------------------------------------
  521. void XBX_HandleInvite( DWORD nUserId )
  522. {
  523. #ifdef _X360
  524. g_pMatchFramework->AcceptInvite( nUserId );
  525. #endif //_X360
  526. }
  527. #if defined( WIN32 ) && !defined( USE_SDL )
  528. //-----------------------------------------------------------------------------
  529. // Main windows procedure
  530. //-----------------------------------------------------------------------------
  531. int CGame::WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  532. {
  533. LONG lRet = 0;
  534. BOOL bCallDefault = 0;
  535. #if defined( WIN32 )
  536. HDC hdc;
  537. PAINTSTRUCT ps;
  538. //
  539. // NOTE: the way this function works is to handle all messages that just call through to
  540. // Windows or provide data to it.
  541. //
  542. // Any messages that change the engine's internal state (like key events) are stored in a list
  543. // and processed at the end of the frame. This is necessary for VCR mode to work correctly because
  544. // Windows likes to pump messages during some of its API calls like SetWindowPos, and unless we add
  545. // custom code around every Windows API call so VCR mode can trap the wndproc calls, VCR mode can't
  546. // reproduce the calls to the wndproc.
  547. //
  548. if ( eng->GetQuitting() != IEngine::QUIT_NOTQUITTING )
  549. return CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam );
  550. #endif // WIN32
  551. //
  552. // Note: NO engine state should be changed in here while in VCR record or playback.
  553. // We can send whatever we want to Windows, but if we change its state in here instead of
  554. // in DispatchAllStoredGameMessages, the playback may not work because Windows messages
  555. // are not deterministic, so you might get different messages during playback than you did during record.
  556. //
  557. InputEvent_t event;
  558. memset( &event, 0, sizeof(event) );
  559. event.m_nTick = g_pInputSystem->GetPollTick();
  560. switch ( uMsg )
  561. {
  562. case WM_CREATE:
  563. ::SetForegroundWindow( hWnd );
  564. break;
  565. case WM_ACTIVATEAPP:
  566. {
  567. if ( CanPostActivateEvents() )
  568. {
  569. bool bActivated = ( wParam == 1 );
  570. event.m_nType = IE_AppActivated;
  571. event.m_nData = bActivated;
  572. g_pInputSystem->PostUserEvent( event );
  573. }
  574. // handle focus changes including fullscreen
  575. if ( wParam == 0 )
  576. {
  577. S_UpdateWindowFocus( false );
  578. }
  579. else
  580. {
  581. S_UpdateWindowFocus( true );
  582. }
  583. }
  584. break;
  585. case WM_POWERBROADCAST:
  586. // Don't go into Sleep mode when running engine, we crash on resume for some reason (as
  587. // do half of the apps I have running usually anyway...)
  588. if ( wParam == PBT_APMQUERYSUSPEND )
  589. {
  590. Msg( "OS requested hibernation, ignoring request.\n" );
  591. return BROADCAST_QUERY_DENY;
  592. }
  593. bCallDefault = true;
  594. break;
  595. #if defined( WIN32 )
  596. case WM_SYSCOMMAND:
  597. if ( ( wParam == SC_MONITORPOWER ) || ( wParam == SC_KEYMENU ) || ( wParam == SC_SCREENSAVE ) )
  598. return lRet;
  599. if ( wParam == SC_CLOSE )
  600. {
  601. // handle the close message, but make sure
  602. // it's not because we accidently hit ALT-F4
  603. if ( HIBYTE(GetKeyState(VK_LMENU)) || HIBYTE(GetKeyState(VK_RMENU) ) )
  604. return lRet;
  605. Cbuf_Clear( Cbuf_GetCurrentPlayer() );
  606. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit\n" );
  607. }
  608. #ifndef DEDICATED
  609. S_BlockSound();
  610. S_ClearBuffer();
  611. #endif
  612. lRet = CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam );
  613. #ifndef DEDICATED
  614. S_UnblockSound();
  615. #endif
  616. break;
  617. #endif
  618. case WM_SYS_SHUTDOWNREQUEST:
  619. Assert( IsGameConsole() );
  620. Cbuf_Clear( Cbuf_GetCurrentPlayer() );
  621. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "quit_gameconsole\n" );
  622. break;
  623. case WM_MOVE:
  624. event.m_nType = IE_WindowMove;
  625. event.m_nData = (short)LOWORD(lParam);
  626. event.m_nData2 = (short)HIWORD(lParam);
  627. g_pInputSystem->PostUserEvent( event );
  628. break;
  629. #if defined( WIN32 )
  630. case WM_SIZE:
  631. if ( wParam != SIZE_MINIMIZED )
  632. {
  633. // Update restored client rect
  634. ::GetClientRect( hWnd, &m_rcLastRestoredClientRect );
  635. }
  636. else
  637. {
  638. #ifndef _GAMECONSOLE
  639. // Fix the window rect to have same client area as it used to have
  640. // before it got minimized
  641. RECT rcWindow;
  642. ::GetWindowRect( hWnd, &rcWindow );
  643. rcWindow.right = rcWindow.left + m_rcLastRestoredClientRect.right;
  644. rcWindow.bottom = rcWindow.top + m_rcLastRestoredClientRect.bottom;
  645. ::AdjustWindowRect( &rcWindow, ::GetWindowLong( hWnd, GWL_STYLE ), FALSE );
  646. ::MoveWindow( hWnd, rcWindow.left, rcWindow.top,
  647. rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, FALSE );
  648. #endif
  649. }
  650. break;
  651. #endif
  652. case WM_SETFOCUS:
  653. if ( g_pHammer )
  654. g_pHammer->NoteEngineGotFocus();
  655. break;
  656. case WM_SYSCHAR:
  657. // keep Alt-Space from happening
  658. break;
  659. case WM_COPYDATA:
  660. //
  661. // Researching all codebase legacy yields the following use cases.
  662. // COPYDATASTRUCT.dwParam = 0 in most cases:
  663. // + another engine instance passing over commandline when executed with -hijack param
  664. // + worldcraft editor sending a command
  665. // + mdlviewer sending a reload model command
  666. // + Hammer -> engine remote console command.
  667. // COPYDATASTRUCT.cbData = 0 in another case:
  668. // + materialsystem enumerating and sending message to other materialsystem windows
  669. // Our WNDPROC should return true to indicate that the message was handled.
  670. //
  671. {
  672. COPYDATASTRUCT &cpData = *( ( COPYDATASTRUCT * ) lParam );
  673. if ( cpData.cbData )
  674. { // There is payload supplied to the message
  675. if ( cpData.dwData == 0 )
  676. { // Legacy protocol to put console command into command buffer
  677. const char *pcBuffer = ( const char * ) ( cpData.lpData );
  678. Cbuf_AddText( Cbuf_GetCurrentPlayer(), pcBuffer );
  679. lRet = 1;
  680. }
  681. else if ( cpData.dwData == 0x43525950 ) // CRYP
  682. { // Encryption key supplied for connection
  683. // Format:
  684. // dot.ted.ip.adr:port>4bytes16bytesupto256bytes
  685. const char *pcBuffer = ( const char * ) ( cpData.lpData );
  686. const char *pcTerm = V_strnchr( pcBuffer, '>', 24 );
  687. if ( pcTerm && pcTerm > pcBuffer )
  688. {
  689. DWORD numBytesForAddress = pcTerm - pcBuffer + 1;
  690. if ( ( numBytesForAddress < cpData.cbData ) &&
  691. ( cpData.cbData - numBytesForAddress > sizeof( int32 ) + NET_CRYPT_KEY_LENGTH ) &&
  692. ( cpData.cbData - numBytesForAddress - sizeof( int32 ) - NET_CRYPT_KEY_LENGTH <= 256 ) &&
  693. !!( *reinterpret_cast< const int32 * >( pcTerm + 1 ) & 0xFFFF0000 ) ) // client key must use high bits and be not zero
  694. {
  695. CFmtStr fmtAddr( "%.*s", pcTerm - pcBuffer, pcBuffer );
  696. extern void RegisterServerCertificate( char const *szServerAddress, int numBytesPayload, void const *pvPayload );
  697. RegisterServerCertificate( fmtAddr.Access(), cpData.cbData - numBytesForAddress, pcTerm + 1 );
  698. lRet = 1;
  699. }
  700. }
  701. }
  702. }
  703. }
  704. break;
  705. #if defined( _GAMECONSOLE )
  706. case WM_XREMOTECOMMAND:
  707. Cbuf_AddText( Cbuf_GetCurrentPlayer(), (const char*)lParam );
  708. break;
  709. case WM_SYS_STORAGEDEVICESCHANGED:
  710. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnSysStorageDevicesChanged" ) );
  711. break;
  712. case WM_LIVE_CONTENT_INSTALLED:
  713. {
  714. #if defined ( _X360 )
  715. bool isArcadeTitleUnlocked = g_pXboxSystem->IsArcadeTitleUnlocked();
  716. g_pXboxSystem->UpdateArcadeTitleUnlockStatus();
  717. if ( !isArcadeTitleUnlocked && g_pXboxSystem->IsArcadeTitleUnlocked() )
  718. {
  719. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnUnlockArcadeTitle" ) );
  720. }
  721. #endif
  722. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnDowloadableContentInstalled" ) );
  723. break;
  724. }
  725. case WM_LIVE_MEMBERSHIP_PURCHASED:
  726. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnLiveMembershipPurchased" ) );
  727. break;
  728. case WM_LIVE_VOICECHAT_AWAY:
  729. #if defined( _X360 )
  730. // If we're triggered with lParam = true, we are now using LIVE Party Chat or Private Chat, not the Game Chat Channel.
  731. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnLiveVoicechatAway", "NotTitleChat", ( lParam == 1 ) ? "1" : "0" ) );
  732. #endif
  733. break;
  734. case WM_XMP_PLAYBACKCONTROLLERCHANGED:
  735. S_EnableMusic( lParam != 0 );
  736. break;
  737. case WM_LIVE_INVITE_ACCEPTED:
  738. XBX_HandleInvite( LOWORD( lParam ) );
  739. break;
  740. case WM_SYS_SIGNINCHANGED:
  741. {
  742. xevent_SYS_SIGNINCHANGED_t *pSysEvent = reinterpret_cast< xevent_SYS_SIGNINCHANGED_t * >( lParam );
  743. Assert( pSysEvent );
  744. if ( !pSysEvent )
  745. break;
  746. #if defined( _X360 ) && !defined( _CERT_NODEFINE )
  747. DevMsg( "WM_SYS_SIGNINCHANGED( ptr=0x%p, 0x%08X )\n", pSysEvent, pSysEvent->dwParam );
  748. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  749. {
  750. XUSER_SIGNIN_STATE eState = XUserGetSigninState( k );
  751. XUID xid;
  752. if ( ERROR_SUCCESS != XUserGetXUID( k, &xid ) )
  753. xid = 0ull;
  754. DevMsg( " User%d [ %llx %d ] XUID=%llx state = %d\n", k, pSysEvent->xuid[k], pSysEvent->state[k], xid, eState );
  755. }
  756. #endif
  757. if ( pSysEvent->dwParam )
  758. {
  759. //
  760. // This is a special handler for crazy Xbox LIVE notifications
  761. // when console lost connection to Secure Gateway and tries to
  762. // re-establish its security tickets and other secure crap.
  763. // See: https://bugbait.valvesoftware.com/show_bug.cgi?id=27583
  764. // TCR 001 BAS Game Stability
  765. // Repro Steps:
  766. // 1) Launch [Game] with two controllers and an extra profile that is Gold, and has no Ethernet connected.
  767. // 2) From the main menu select "Start Game"
  768. // 3) During gameplay have the inactive controller sign into the gold profile.
  769. // It will generate the following sign-in notification:
  770. // [DBG]: [XNET:2] AuthWarn: SG connection failed! Retrying with fresh ticket (update 0).
  771. // [DBG]: [XNET:2] AuthWarn: XNetDnsLookup timed out for XEAS.PART.XBOXLIVE.COM
  772. // [DBG]: [XNET:2] Warning: Unexpected TGT error 0x80151904!
  773. // WM_SYS_SIGNINCHANGED( 0x00000000, 0x00000001 )
  774. // User0 XUID=0 state = 0 <--- all the users state is reported as signed out with NULL XUID
  775. // WM_LIVE_CONNECTIONCHANGED( 0x00000000, 0x80151904 )
  776. // User0 XUID=0 state = 0
  777. // Followed by:
  778. // WM_SYS_SIGNINCHANGED( 0x00000000, 0x00000002 )
  779. // User0 XUID=e0000a2e5a849e42 state = 1
  780. // User1 XUID=e0000b49fab8416e state = 1
  781. // To handle this we will ignore notifications when controller mask doesn't specify signed-in controllers.
  782. //
  783. bool bSomeUsersStillSignedIn = false;
  784. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  785. {
  786. if ( (pSysEvent->dwParam & ( 1 << k )) == 0 )
  787. continue;
  788. if ( pSysEvent->state[k] != eXUserSigninState_NotSignedIn )
  789. {
  790. bSomeUsersStillSignedIn = true;
  791. break;
  792. }
  793. }
  794. if ( !bSomeUsersStillSignedIn )
  795. {
  796. // This is the crazy notification mentioned above, discard
  797. DevMsg( "WM_SYS_SIGNINCHANGED is discarded due to invalid parameters!\n" );
  798. break;
  799. }
  800. }
  801. {
  802. //
  803. // This is a handler for TCR exploit of X360 blade
  804. // TCR 015 BAS Sign-In Changes
  805. // Using inactive controller to initiate sign-in, but actually
  806. // pressing last "A" button on an active controller will not
  807. // generate a sign-out message, but will generate a new sign-in
  808. // message.
  809. // We need to keep XUIDs around and if a new sign-in message is
  810. // coming from a new XUID we fake a sign-out message first and
  811. // then the new sign-in message.
  812. //
  813. MEM_ALLOC_CREDIT();
  814. static XUID s_arrSignedInXUIDs[ XUSER_MAX_COUNT ] = { 0 };
  815. KeyValues *pEvent = NULL;
  816. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  817. {
  818. XUID xidOld = s_arrSignedInXUIDs[k];
  819. XUID xidNew = pSysEvent->xuid[k];
  820. if ( xidOld )
  821. {
  822. // We had a ctrl signed in this slot
  823. bool bSignedOut = false;
  824. if ( pSysEvent->state[k] == eXUserSigninState_NotSignedIn )
  825. {
  826. bSignedOut = true;
  827. }
  828. else if ( !IsEqualXUID( xidNew, xidOld ) )
  829. {
  830. bSignedOut = true;
  831. }
  832. // If user signed out, add to notification
  833. if ( bSignedOut )
  834. {
  835. if ( !pEvent )
  836. {
  837. pEvent = new KeyValues( "OnSysSigninChange" );
  838. pEvent->SetString( "action", "signout" );
  839. }
  840. int idx = pEvent->GetInt( "numUsers", 0 );
  841. pEvent->SetInt( "numUsers", idx + 1 );
  842. int nMask = pEvent->GetInt( "mask", 0 );
  843. pEvent->SetInt( "mask", nMask | ( 1 << k ) );
  844. char bufUserIdx[32];
  845. sprintf( bufUserIdx, "user%d", idx );
  846. pEvent->SetInt( bufUserIdx, k );
  847. }
  848. }
  849. s_arrSignedInXUIDs[k] = xidNew;
  850. }
  851. if ( pEvent )
  852. {
  853. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( pEvent );
  854. }
  855. }
  856. if ( pSysEvent->dwParam )
  857. {
  858. MEM_ALLOC_CREDIT();
  859. KeyValues *pEvent = new KeyValues( "OnSysSigninChange" );
  860. pEvent->SetString( "action", "signin" );
  861. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  862. {
  863. if ( (pSysEvent->dwParam & ( 1 << k )) == 0 )
  864. continue;
  865. int idx = pEvent->GetInt( "numUsers", 0 );
  866. pEvent->SetInt( "numUsers", idx + 1 );
  867. int nMask = pEvent->GetInt( "mask", 0 );
  868. pEvent->SetInt( "mask", nMask | ( 1 << k ) );
  869. char bufUserIdx[32];
  870. sprintf( bufUserIdx, "user%d", idx );
  871. pEvent->SetInt( bufUserIdx, k );
  872. }
  873. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( pEvent );
  874. }
  875. }
  876. break;
  877. case WM_LIVE_CONNECTIONCHANGED:
  878. #if defined( _X360 ) && !defined( _CERT )
  879. DevMsg( "WM_LIVE_CONNECTIONCHANGED( 0x%08X, 0x%08X )\n", wParam, lParam );
  880. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  881. {
  882. XUSER_SIGNIN_STATE eState = XUserGetSigninState( k );
  883. XUID xid;
  884. if ( ERROR_SUCCESS != XUserGetXUID( k, &xid ) )
  885. xid = 0ull;
  886. DevMsg( " User%d XUID=%llx state = %d\n", k, xid, eState );
  887. }
  888. #endif
  889. // Vitaliy [8/5/2008]
  890. // Triggering any callbacks from inside WM_LIVE_CONNECTIONCHANGED is
  891. // unreliable because access to accounts sign-in information is blocked.
  892. // Repro case: user1 is signed into Live, user2 signs in with local account
  893. // then WM_LIVE_CONNECTIONCHANGED will be triggered and XUserGetSigninState
  894. // will be returning 0 for all user ids.
  895. break; // end case WM_LIVE_CONNECTIONCHANGED
  896. case WM_SYS_UI:
  897. if ( lParam )
  898. {
  899. // When the blade opens, release all buttons
  900. g_pInputSystem->ResetInputState();
  901. // Don't activate it if it's already active (a sub window may be active)
  902. // Multiplayer doesn't want the UI to appear, since it can't pause anyway
  903. if ( !EngineVGui()->IsGameUIVisible() && sv.IsActive() && sv.IsSinglePlayerGame() )
  904. {
  905. Cbuf_AddText( Cbuf_GetCurrentPlayer(), "gameui_activate" );
  906. }
  907. }
  908. {
  909. MEM_ALLOC_CREDIT();
  910. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  911. "OnSysXUIEvent", "action", lParam ? "opening" : "closed" ) );
  912. }
  913. break;
  914. case WM_FRIENDS_FRIEND_ADDED: // Need to update mutelist for friends changes in case of Friends-Only privileges
  915. case WM_FRIENDS_FRIEND_REMOVED:
  916. case WM_SYS_MUTELISTCHANGED:
  917. {
  918. MEM_ALLOC_CREDIT();
  919. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues( "OnSysMuteListChanged" ) );
  920. }
  921. break;
  922. case WM_SYS_PROFILESETTINGCHANGED:
  923. {
  924. MEM_ALLOC_CREDIT();
  925. if ( KeyValues *kvNotify = new KeyValues( "OnSysProfileSettingsChanged" ) )
  926. {
  927. kvNotify->SetInt( "mask", lParam );
  928. for ( int k = 0; k < XUSER_MAX_COUNT; ++ k )
  929. {
  930. if ( lParam & ( 1 << k ) )
  931. {
  932. kvNotify->SetInt( CFmtStr( "user%d", k ), 1 );
  933. }
  934. }
  935. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( kvNotify );
  936. }
  937. }
  938. break;
  939. case WM_SYS_INPUTDEVICESCHANGED:
  940. {
  941. MEM_ALLOC_CREDIT();
  942. int nDisconnectedDeviceMask = 0;
  943. for ( DWORD k = 0; k < XBX_GetNumGameUsers(); ++ k )
  944. {
  945. #ifdef _X360
  946. XINPUT_CAPABILITIES caps;
  947. if ( XInputGetCapabilities( XBX_GetUserId(k), XINPUT_FLAG_GAMEPAD, &caps ) == ERROR_DEVICE_NOT_CONNECTED )
  948. #elif defined( _PS3 )
  949. if ( lParam & ( 1 << XBX_GetUserId(k) ) ) // PS3 passes disconnected controllers mask in lParam
  950. #else
  951. Assert(0);
  952. if ( 0 )
  953. #endif
  954. {
  955. nDisconnectedDeviceMask |= ( 1 << k );
  956. }
  957. }
  958. if ( nDisconnectedDeviceMask )
  959. {
  960. // This message is only sent when one of our active users has lost their controller connection
  961. // FIXME: Only do this when the guest is at fault? A "toast" is already presented to the user by the API otherwise.
  962. g_pMatchFramework->GetEventsSubscription()->BroadcastEvent( new KeyValues(
  963. "OnSysInputDevicesChanged", "mask", nDisconnectedDeviceMask ) );
  964. }
  965. }
  966. break;
  967. #if defined( _DEMO )
  968. case WM_XCONTROLLER_KEY:
  969. if ( lParam )
  970. {
  971. // any keydown activity resets the timeout or changes into interactivbe demo mode
  972. Host_RestartDemoTimeout( true );
  973. }
  974. bCallDefault = true;
  975. break;
  976. #endif
  977. #endif
  978. #if defined( WIN32 )
  979. case WM_PAINT:
  980. hdc = BeginPaint(hWnd, &ps);
  981. RECT rcClient;
  982. GetClientRect( hWnd, &rcClient );
  983. EndPaint(hWnd, &ps);
  984. break;
  985. #endif
  986. #if defined( WIN32 ) && !defined( _X360 )
  987. case WM_DISPLAYCHANGE:
  988. if ( !m_iDesktopHeight || !m_iDesktopWidth )
  989. {
  990. UpdateDesktopInformation( wParam, lParam );
  991. }
  992. break;
  993. #endif
  994. case WM_IME_NOTIFY:
  995. switch ( wParam )
  996. {
  997. default:
  998. break;
  999. #ifndef DEDICATED
  1000. case 14:
  1001. if ( !videomode->IsWindowedMode() )
  1002. return 0;
  1003. break;
  1004. #endif
  1005. }
  1006. bCallDefault = true;
  1007. break;
  1008. default:
  1009. bCallDefault = true;
  1010. break;
  1011. }
  1012. if ( bCallDefault )
  1013. {
  1014. #ifdef _PS3
  1015. lRet = 0;
  1016. #else
  1017. lRet = CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam );
  1018. #endif
  1019. }
  1020. // return 0 if handled message, 1 if not
  1021. return lRet;
  1022. }
  1023. #elif defined(OSX)
  1024. #elif defined( LINUX )
  1025. #elif defined(_WIN32)
  1026. #else
  1027. #error
  1028. #endif
  1029. #if defined( WIN32 ) && !defined( USE_SDL )
  1030. //-----------------------------------------------------------------------------
  1031. // Creates the game window
  1032. //-----------------------------------------------------------------------------
  1033. static LRESULT WINAPI HLEngineWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  1034. {
  1035. return g_Game.WindowProc( hWnd, uMsg, wParam, lParam );
  1036. }
  1037. #define DEFAULT_EXE_ICON 101
  1038. static void DoSomeSocketStuffInOrderToGetZoneAlarmToNoticeUs( void )
  1039. {
  1040. #ifdef IS_WINDOWS_PC
  1041. WSAData wsaData;
  1042. if ( ! WSAStartup( 0x0101, &wsaData ) )
  1043. {
  1044. SOCKET tmpSocket = socket( AF_INET, SOCK_DGRAM, 0 );
  1045. if ( tmpSocket != INVALID_SOCKET )
  1046. {
  1047. char Options[]={ 1 };
  1048. setsockopt( tmpSocket, SOL_SOCKET, SO_BROADCAST, Options, sizeof(Options));
  1049. char pszHostName[256];
  1050. gethostname( pszHostName, sizeof( pszHostName ) );
  1051. hostent *hInfo = gethostbyname( pszHostName );
  1052. if ( hInfo )
  1053. {
  1054. sockaddr_in myIpAddress;
  1055. memset( &myIpAddress, 0, sizeof( myIpAddress ) );
  1056. myIpAddress.sin_family = AF_INET;
  1057. myIpAddress.sin_port = htons( 27015 ); // our normal server port
  1058. myIpAddress.sin_addr.S_un.S_un_b.s_b1 = hInfo->h_addr_list[0][0];
  1059. myIpAddress.sin_addr.S_un.S_un_b.s_b2 = hInfo->h_addr_list[0][1];
  1060. myIpAddress.sin_addr.S_un.S_un_b.s_b3 = hInfo->h_addr_list[0][2];
  1061. myIpAddress.sin_addr.S_un.S_un_b.s_b4 = hInfo->h_addr_list[0][3];
  1062. if ( bind( tmpSocket, ( sockaddr * ) &myIpAddress, sizeof( myIpAddress ) ) != -1 )
  1063. {
  1064. if ( sendto( tmpSocket, pszHostName, 1, 0, ( sockaddr *) &myIpAddress, sizeof( myIpAddress ) ) == -1 )
  1065. {
  1066. // error?
  1067. }
  1068. }
  1069. }
  1070. closesocket( tmpSocket );
  1071. }
  1072. WSACleanup();
  1073. }
  1074. #endif
  1075. }
  1076. #endif
  1077. bool CGame::CreateGameWindow( void )
  1078. {
  1079. // get the window name
  1080. char windowName[256];
  1081. windowName[0] = 0;
  1082. KeyValues *modinfo = new KeyValues("ModInfo");
  1083. if (modinfo->LoadFromFile(g_pFileSystem, "gameinfo.txt"))
  1084. {
  1085. Q_strncpy( windowName, modinfo->GetString("game"), sizeof(windowName) );
  1086. }
  1087. if (!windowName[0])
  1088. {
  1089. Q_strncpy( windowName, "HALF-LIFE 2", sizeof(windowName) );
  1090. }
  1091. if ( IsOpenGL() )
  1092. {
  1093. V_strcat( windowName, " - OpenGL", sizeof( windowName ) );
  1094. }
  1095. #if PIX_ENABLE || defined( PIX_INSTRUMENTATION )
  1096. // PIX_ENABLE/PIX_INSTRUMENTATION is a big slowdown (that should never be checked in, but sometimes is by accident), so add this to the Window title too.
  1097. V_strcat( windowName, " - PIX_ENABLE", sizeof( windowName ) );
  1098. #endif
  1099. const char *p = CommandLine()->ParmValue( "-window_name_suffix", "" );
  1100. if ( p && V_strlen( p ) )
  1101. {
  1102. V_strcat( windowName, " - ", sizeof( windowName ) );
  1103. V_strcat( windowName, p, sizeof( windowName ) );
  1104. }
  1105. #if defined( USE_SDL )
  1106. modinfo->deleteThis();
  1107. modinfo = NULL;
  1108. if ( !g_pLauncherMgr->CreateGameWindow( windowName, true, 0, 0, true ) )
  1109. {
  1110. Error( "Fatal Error: Unable to create game window!" );
  1111. return false;
  1112. }
  1113. char localPath[ MAX_PATH ];
  1114. if ( g_pFileSystem->GetLocalPath( "resource/game-icon.bmp", localPath, sizeof(localPath) ) )
  1115. {
  1116. g_pFileSystem->GetLocalCopy( localPath );
  1117. g_pLauncherMgr->SetApplicationIcon( localPath );
  1118. }
  1119. SetMainWindow( ( HWND )g_pLauncherMgr->GetWindowRef() );
  1120. AttachToWindow( );
  1121. return true;
  1122. #elif defined( WIN32 ) && !defined( USE_SDL )
  1123. #ifndef DEDICATED
  1124. #if !defined( _X360 )
  1125. WNDCLASSW wc;
  1126. #else
  1127. WNDCLASS wc;
  1128. #endif
  1129. memset( &wc, 0, sizeof( wc ) );
  1130. wc.style = CS_OWNDC | CS_DBLCLKS;
  1131. #if !defined( _GAMECONSOLE )
  1132. wc.lpfnWndProc = DefWindowProcW;
  1133. #else
  1134. wc.lpfnWndProc = CallDefaultWindowProc;
  1135. #endif
  1136. wc.hInstance = m_hInstance;
  1137. wc.lpszClassName = CLASSNAME;
  1138. // find the icon file in the filesystem
  1139. if ( IsPC() )
  1140. {
  1141. char localPath[ MAX_PATH ];
  1142. if ( g_pFileSystem->GetLocalPath( "resource/game.ico", localPath, sizeof(localPath) ) )
  1143. {
  1144. g_pFileSystem->GetLocalCopy( localPath );
  1145. wc.hIcon = (HICON)::LoadImage(NULL, localPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
  1146. }
  1147. else
  1148. {
  1149. wc.hIcon = (HICON)LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE( DEFAULT_EXE_ICON ) );
  1150. }
  1151. }
  1152. #ifndef DEDICATED
  1153. char const *pszGameType = modinfo->GetString( "type" );
  1154. if ( pszGameType && Q_stristr( pszGameType, "multiplayer" ) )
  1155. DoSomeSocketStuffInOrderToGetZoneAlarmToNoticeUs();
  1156. #endif
  1157. wchar_t uc[512];
  1158. if ( IsPC() )
  1159. {
  1160. ::MultiByteToWideChar(CP_UTF8, 0, windowName, -1, uc, sizeof( uc ) / sizeof(wchar_t));
  1161. }
  1162. modinfo->deleteThis();
  1163. modinfo = NULL;
  1164. // Oops, we didn't clean up the class registration from last cycle which
  1165. // might mean that the wndproc pointer is bogus
  1166. #ifndef _X360
  1167. UnregisterClassW( CLASSNAME, m_hInstance );
  1168. // Register it again
  1169. RegisterClassW( &wc );
  1170. #else
  1171. RegisterClass( &wc );
  1172. #endif
  1173. // Note, it's hidden
  1174. DWORD style = WS_POPUP | WS_CLIPSIBLINGS;
  1175. // Give it a frame if we want a border
  1176. if ( videomode->IsWindowedMode() )
  1177. {
  1178. if( !CommandLine()->FindParm( "-noborder" )&& !videomode->NoWindowBorder() )
  1179. {
  1180. style |= WS_OVERLAPPEDWINDOW;
  1181. style &= ~WS_THICKFRAME;
  1182. }
  1183. }
  1184. // Never a max box
  1185. style &= ~WS_MAXIMIZEBOX;
  1186. int w, h;
  1187. // Create a full screen size window by default, it'll get resized later anyway
  1188. w = GetSystemMetrics( SM_CXSCREEN );
  1189. h = GetSystemMetrics( SM_CYSCREEN );
  1190. // Create the window
  1191. DWORD exFlags = 0;
  1192. if ( g_bTextMode )
  1193. {
  1194. style &= ~WS_VISIBLE;
  1195. exFlags |= WS_EX_TOOLWINDOW; // So it doesn't show up in the taskbar.
  1196. }
  1197. #if !defined( _X360 )
  1198. HWND hwnd = CreateWindowExW( exFlags, CLASSNAME, uc, style,
  1199. 0, 0, w, h, NULL, NULL, m_hInstance, NULL );
  1200. // NOTE: On some cards, CreateWindowExW slams the FPU control word
  1201. SetupFPUControlWord();
  1202. #else
  1203. HWND hwnd = CreateWindowEx( exFlags, CLASSNAME, windowName, style,
  1204. 0, 0, w, h, NULL, NULL, m_hInstance, NULL );
  1205. #endif
  1206. if ( !hwnd )
  1207. {
  1208. Error( "Fatal Error: Unable to create game window!" );
  1209. return false;
  1210. }
  1211. SetMainWindow( hwnd );
  1212. AttachToWindow( );
  1213. return true;
  1214. #else
  1215. return true;
  1216. #endif
  1217. #elif defined(OSX)
  1218. modinfo->deleteThis();
  1219. modinfo = NULL;
  1220. if ( !g_pLauncherMgr->CreateGameWindow( windowName, true, 640, 480 ) )
  1221. {
  1222. Error( "Fatal Error: Unable to create game window!" );
  1223. return false;
  1224. }
  1225. char localPath[ MAX_PATH ];
  1226. if ( g_pFileSystem->GetLocalPath( "resource/game.icns", localPath, sizeof(localPath) ) )
  1227. {
  1228. g_pFileSystem->GetLocalCopy( localPath );
  1229. g_pLauncherMgr->SetApplicationIcon( localPath );
  1230. }
  1231. SetMainWindow( g_pLauncherMgr->GetWindowRef() );
  1232. AttachToWindow( );
  1233. return true;
  1234. #else
  1235. #error
  1236. #endif
  1237. }
  1238. //-----------------------------------------------------------------------------
  1239. // Destroys the game window
  1240. //-----------------------------------------------------------------------------
  1241. void CGame::DestroyGameWindow()
  1242. {
  1243. #if defined( USE_SDL )
  1244. g_pLauncherMgr->DestroyGameWindow();
  1245. #elif defined( WIN32 )
  1246. #ifndef DEDICATED
  1247. // Destroy all things created when the window was created
  1248. if ( !m_bExternallySuppliedWindow )
  1249. {
  1250. DetachFromWindow( );
  1251. if ( m_hWindow )
  1252. {
  1253. DestroyWindow( m_hWindow );
  1254. m_hWindow = (HWND)0;
  1255. }
  1256. #if !defined( _X360 )
  1257. UnregisterClassW( CLASSNAME, m_hInstance );
  1258. #else
  1259. UnregisterClass( CLASSNAME, m_hInstance );
  1260. #endif
  1261. }
  1262. else
  1263. {
  1264. m_hWindow = (HWND)0;
  1265. m_bExternallySuppliedWindow = false;
  1266. }
  1267. #endif // !DEDICATED
  1268. #elif defined( OSX )
  1269. g_pLauncherMgr->DestroyGameWindow();
  1270. #elif defined (_PS3)
  1271. #else
  1272. #error
  1273. #endif
  1274. }
  1275. //-----------------------------------------------------------------------------
  1276. // This is used in edit mode to specify a particular game window (created by hammer)
  1277. //-----------------------------------------------------------------------------
  1278. void CGame::SetGameWindow( void *hWnd )
  1279. {
  1280. m_bExternallySuppliedWindow = true;
  1281. #if defined( USE_SDL )
  1282. SDL_RaiseWindow( (SDL_Window *)hWnd );
  1283. #elif defined( WIN32 )
  1284. SetMainWindow( (HWND)hWnd );
  1285. #elif defined( OSX ) && defined( PLATFORM_64BITS )
  1286. Assert( !"unimpl OSX-64" );
  1287. #elif defined( OSX )
  1288. SetUserFocusWindow( (WindowRef)hWnd );
  1289. #else
  1290. #error
  1291. #endif
  1292. }
  1293. //-----------------------------------------------------------------------------
  1294. //
  1295. //-----------------------------------------------------------------------------
  1296. void CGame::AttachToWindow()
  1297. {
  1298. if ( !m_hWindow )
  1299. return;
  1300. #if defined( WIN32 ) && !defined( USE_SDL )
  1301. m_ChainedWindowProc = (WNDPROC)GetWindowLongPtrW( m_hWindow, GWLP_WNDPROC );
  1302. SetWindowLongPtrW( m_hWindow, GWLP_WNDPROC, (LONG_PTR)HLEngineWindowProc );
  1303. #endif
  1304. if ( g_pInputSystem )
  1305. {
  1306. // Attach the input system window proc
  1307. g_pInputSystem->AttachToWindow( (void *)m_hWindow );
  1308. g_pInputSystem->EnableInput( true );
  1309. g_pInputSystem->EnableMessagePump( false );
  1310. }
  1311. if ( g_pMatSystemSurface )
  1312. {
  1313. // Attach the vgui matsurface window proc
  1314. g_pMatSystemSurface->SetAppDrivesInput( true );
  1315. g_pMatSystemSurface->EnableWindowsMessages( true );
  1316. }
  1317. }
  1318. void CGame::DetachFromWindow()
  1319. {
  1320. #if defined( WIN32 ) && !defined( USE_SDL )
  1321. if ( !m_hWindow || !m_ChainedWindowProc )
  1322. {
  1323. m_ChainedWindowProc = NULL;
  1324. return;
  1325. }
  1326. #endif
  1327. if ( g_pMatSystemSurface )
  1328. {
  1329. // Detach the vgui matsurface
  1330. g_pMatSystemSurface->EnableWindowsMessages( false );
  1331. }
  1332. if ( g_pInputSystem )
  1333. {
  1334. // Detach the input system window proc
  1335. g_pInputSystem->EnableInput( false );
  1336. g_pInputSystem->DetachFromWindow( );
  1337. }
  1338. #if defined( WIN32 ) && !defined( USE_SDL )
  1339. Assert( (WNDPROC)GetWindowLongPtrW( m_hWindow, GWLP_WNDPROC ) == HLEngineWindowProc );
  1340. SetWindowLongPtrW( m_hWindow, GWLP_WNDPROC, (LONG_PTR)m_ChainedWindowProc );
  1341. #endif
  1342. }
  1343. //-----------------------------------------------------------------------------
  1344. // This is used in edit mode to override the default wnd proc associated w/
  1345. // the game window specified in SetGameWindow.
  1346. //-----------------------------------------------------------------------------
  1347. bool CGame::InputAttachToGameWindow()
  1348. {
  1349. // We can't use this feature unless we didn't control the creation of the window
  1350. if ( !m_bExternallySuppliedWindow )
  1351. return true;
  1352. AttachToWindow();
  1353. #ifndef DEDICATED
  1354. vgui::surface()->OnScreenSizeChanged( videomode->GetModeWidth(), videomode->GetModeHeight() );
  1355. #endif
  1356. // We don't get WM_ACTIVATEAPP messages in this case; simulate one.
  1357. AppActivate( true );
  1358. #if defined( WIN32 ) && !defined( USE_SDL )
  1359. // Capture + hide the mouse
  1360. g_pInputStackSystem->SetMouseCapture( m_hInputContext, true );
  1361. #elif defined(OSX)
  1362. Assert( !"Impl me" );
  1363. return false;
  1364. #elif defined( LINUX )
  1365. Assert( !"Impl me" );
  1366. return false;
  1367. #elif defined(_WIN32)
  1368. Assert( !"Impl me" );
  1369. return false;
  1370. #elif defined(_PS3)
  1371. #else
  1372. #error
  1373. #endif
  1374. return true;
  1375. }
  1376. void CGame::InputDetachFromGameWindow()
  1377. {
  1378. // We can't use this feature unless we didn't control the creation of the window
  1379. if ( !m_bExternallySuppliedWindow )
  1380. return;
  1381. #if defined( WIN32 ) && !defined( USE_SDL )
  1382. if ( !m_ChainedWindowProc )
  1383. return;
  1384. // Release + show the mouse
  1385. ReleaseCapture();
  1386. #elif defined(OSX)
  1387. Assert( !"Impl me" );
  1388. #elif defined( LINUX )
  1389. Assert( !"Impl me" );
  1390. #elif defined(_WIN32)
  1391. Assert( !"Impl me" );
  1392. #elif defined(_PS3)
  1393. #else
  1394. #error
  1395. #endif
  1396. // We don't get WM_ACTIVATEAPP messages in this case; simulate one.
  1397. AppActivate( false );
  1398. DetachFromWindow();
  1399. }
  1400. void CGame::PlayStartupVideos( void )
  1401. {
  1402. if ( Plat_IsInBenchmarkMode() )
  1403. return;
  1404. #ifndef DEDICATED
  1405. // Wait for the mode to change and stabilized
  1406. // FIXME: There's really no way to know when this is completed, so we have to guess a time that will mostly be correct
  1407. if ( IsPC() && videomode->IsWindowedMode() == false )
  1408. {
  1409. ThreadSleep( 1000 );
  1410. }
  1411. bool bEndGame = CommandLine()->CheckParm("-endgamevid") ? true : false;
  1412. bool bRecap = CommandLine()->CheckParm("-recapvid") ? true : false; // FIXME: This is a temp addition until the movie playback is centralized -- jdw
  1413. bool bNeedHealthWarning = IsPC() && g_pFullFileSystem->FileExists( "media/HealthWarning.txt" );
  1414. if ( !bNeedHealthWarning &&
  1415. !bEndGame &&
  1416. !bRecap &&
  1417. ( CommandLine()->CheckParm( "-dev" ) ||
  1418. CommandLine()->CheckParm( "-novid" ) ||
  1419. CommandLine()->CheckParm( "-allowdebug" ) ||
  1420. CommandLine()->CheckParm( "-console" ) ||
  1421. CommandLine()->CheckParm( "-toconsole" ) ) )
  1422. return;
  1423. char *pszFile = "media/startupvids" PLATFORM_EXT ".txt";
  1424. if ( bEndGame )
  1425. {
  1426. // Don't go back into the map that triggered this.
  1427. CommandLine()->RemoveParm( "+map" );
  1428. CommandLine()->RemoveParm( "+load" );
  1429. pszFile = "media/EndGameVids.txt";
  1430. }
  1431. else if ( bRecap )
  1432. {
  1433. pszFile = "media/RecapVids.txt";
  1434. }
  1435. #if defined( PLATFORM_WINDOWS ) && defined( BINK_VIDEO )
  1436. VAudioInit();
  1437. void *pMilesEngine = NULL;
  1438. if ( g_pBIK)
  1439. {
  1440. ConVarRef windows_speaker_config("windows_speaker_config");
  1441. if ( windows_speaker_config.IsValid() && windows_speaker_config.GetInt() >= 5 )
  1442. {
  1443. pMilesEngine = vaudio ? vaudio->CreateMilesAudioEngine() : NULL;
  1444. #if !defined( _GAMECONSOLE )
  1445. g_pBIK->SetMilesSoundDevice( pMilesEngine );
  1446. #endif //!defined( _GAMECONSOLE )
  1447. }
  1448. else
  1449. {
  1450. #if !defined( _GAMECONSOLE )
  1451. g_pBIK->SetMilesSoundDevice( NULL );
  1452. #endif //!defined( _GAMECONSOLE )
  1453. }
  1454. }
  1455. #endif // defined( PLATFORM_WINDOWS ) && defined( BINK_VIDEO )
  1456. PlayVideoListAndWait( pszFile );
  1457. #if defined( PLATFORM_WINDOWS ) && defined( BINK_VIDEO )
  1458. if ( pMilesEngine )
  1459. {
  1460. #if !defined( _GAMECONSOLE )
  1461. g_pBIK->SetMilesSoundDevice( NULL );
  1462. #endif //!defined( _GAMECONSOLE )
  1463. vaudio->DestroyMilesAudioEngine( pMilesEngine );
  1464. }
  1465. #endif
  1466. #endif // DEDICATED
  1467. }
  1468. #define MAX_CAPTION_LENGTH 256
  1469. class CCaptionSequencer
  1470. {
  1471. public:
  1472. CCaptionSequencer( void ) : m_bCaptions( false )
  1473. {
  1474. Reset();
  1475. }
  1476. void Reset( void )
  1477. {
  1478. // captioning start when rendering stable, not simply at movie start
  1479. m_CaptionStartTime = 0;
  1480. // initial priming state to fetch a caption
  1481. m_bShowingCaption = false;
  1482. m_bCaptionStale = true;
  1483. m_CurCaptionString[0] = '\0';
  1484. m_CurCaptionStartTime = 0.0f;
  1485. m_CurCaptionEndTime = 0.0f;
  1486. m_CurCaptionColor = 0xFFFFFFFF;
  1487. if ( m_CaptionBuf.TellPut() )
  1488. {
  1489. // reset to start
  1490. m_CaptionBuf.SeekGet( CUtlBuffer::SEEK_HEAD, 0 );
  1491. }
  1492. }
  1493. void Init( const char *pFilename )
  1494. {
  1495. m_bCaptions = false;
  1496. if ( g_pFullFileSystem->ReadFile( pFilename, "GAME", m_CaptionBuf ) )
  1497. {
  1498. // FIXME: This needs the MOD dir to construct the filename properly!
  1499. // See me when this is being merged into Main -- jweier
  1500. g_pVGuiLocalize->AddFile( "resource/l4d360ui_%language%.txt", "GAME", true );
  1501. m_bCaptions = true;
  1502. }
  1503. }
  1504. void SetStartTime( float flStarTtime )
  1505. {
  1506. // Start our captions now
  1507. m_CaptionStartTime = Plat_FloatTime();
  1508. }
  1509. bool GetCaptionToken( char *token, int tokenLen )
  1510. {
  1511. if ( !token || !tokenLen )
  1512. return false;
  1513. if ( !m_CaptionBuf.IsValid() )
  1514. {
  1515. // end of data
  1516. return false;
  1517. }
  1518. m_CaptionBuf.GetLine( token, tokenLen );
  1519. #ifdef _WIN32
  1520. char *pCRLF = V_stristr( token, "\r" );
  1521. if ( pCRLF )
  1522. {
  1523. *pCRLF = '\0';
  1524. }
  1525. m_CaptionBuf.SeekGet( CUtlBuffer::SEEK_CURRENT, 1 );
  1526. #else
  1527. char *pCRLF = V_stristr( token, "\n" );
  1528. if ( pCRLF )
  1529. {
  1530. *pCRLF = '\0';
  1531. }
  1532. #endif
  1533. return true;
  1534. }
  1535. bool GetNextCaption( void )
  1536. {
  1537. char buff[MAX_CAPTION_LENGTH];
  1538. if ( !GetCaptionToken( m_CurCaptionString, sizeof( m_CurCaptionString ) ) )
  1539. {
  1540. // end of captions
  1541. m_CurCaptionString[0] = '\0';
  1542. return false;
  1543. }
  1544. // hex color
  1545. GetCaptionToken( buff, sizeof( buff ) );
  1546. sscanf( buff, "%x", &m_CurCaptionColor );
  1547. // float start time
  1548. GetCaptionToken( buff, sizeof( buff ) );
  1549. m_CurCaptionStartTime = atof( buff );
  1550. // float end time
  1551. GetCaptionToken( buff, sizeof( buff ) );
  1552. m_CurCaptionEndTime = atof( buff );
  1553. // have valid caption
  1554. m_bCaptionStale = false;
  1555. return true;
  1556. }
  1557. const char *GetCurrentCaption( int *pColorOut )
  1558. {
  1559. if ( m_bCaptions == false )
  1560. return NULL;
  1561. if ( m_CaptionStartTime )
  1562. {
  1563. // get a timeline
  1564. float elapsed = Plat_FloatTime() - m_CaptionStartTime;
  1565. // Get a new caption because we've just finished one
  1566. if ( !m_bShowingCaption && m_bCaptionStale )
  1567. {
  1568. GetNextCaption();
  1569. }
  1570. if ( m_bShowingCaption )
  1571. {
  1572. if ( elapsed > m_CurCaptionEndTime ) // Caption just turned off
  1573. {
  1574. m_bShowingCaption = false; // Don't draw caption
  1575. m_bCaptionStale = true; // Trigger getting a new one on the next frame
  1576. }
  1577. }
  1578. else
  1579. {
  1580. if ( elapsed > m_CurCaptionStartTime ) // Turn Caption on
  1581. {
  1582. m_bShowingCaption = true;
  1583. }
  1584. }
  1585. if ( m_bShowingCaption && m_CurCaptionString[0] )
  1586. {
  1587. if ( pColorOut )
  1588. {
  1589. *pColorOut = m_CurCaptionColor;
  1590. }
  1591. return m_CurCaptionString;
  1592. }
  1593. }
  1594. return NULL;
  1595. }
  1596. private:
  1597. // Captions / Subtitles
  1598. bool m_bCaptions;
  1599. bool m_bShowingCaption;
  1600. bool m_bCaptionStale;
  1601. vgui::HScheme m_hCaptionFont;
  1602. float m_CaptionStartTime;
  1603. CUtlBuffer m_CaptionBuf;
  1604. char m_CurCaptionString[MAX_CAPTION_LENGTH];
  1605. float m_CurCaptionStartTime;
  1606. float m_CurCaptionEndTime;
  1607. unsigned int m_CurCaptionColor;
  1608. };
  1609. // Panel for drawing subtitles on a movie panel
  1610. // Panel for drawing subtitles on a movie panel
  1611. class CSubtitlePanel : public vgui::Panel
  1612. {
  1613. public:
  1614. CSubtitlePanel( vgui::Panel *parent, const char *pMovieName, int nPlaybackHeight ) : vgui::Panel( parent, "SubtitlePanel" )
  1615. {
  1616. // FIXME: Need a better method for this
  1617. vgui::HScheme hScheme = vgui::scheme()->LoadSchemeFromFile("Resource/SourceScheme.res", "Tracker" );
  1618. vgui::IScheme *pNewScheme = vgui::scheme()->GetIScheme( hScheme );
  1619. if ( pNewScheme )
  1620. {
  1621. m_hFont = pNewScheme->GetFont( "CloseCaption_IntroMovie", true );
  1622. }
  1623. m_pSubtitleLabel = new vgui::Label( this, "SubtitleLabel", L"" );
  1624. m_pSubtitleLabel->SetFont( m_hFont );
  1625. int fontTall = vgui::surface()->GetFontTall( m_hFont );
  1626. int width, height;
  1627. vgui::surface()->GetScreenSize( width, height );
  1628. // clamp width to title safe area
  1629. int xPos = width * 0.05f;
  1630. width *= 0.9f;
  1631. // assume video is centered
  1632. // must be scaled according to playback height, due to letterboxing
  1633. // don't want to cut into or overlap border, need to be within video, and title safe
  1634. // so pushes up according to font height
  1635. int yOffset = ( nPlaybackHeight - height )/2;
  1636. int yPos = ( 0.85f * nPlaybackHeight - fontTall ) - yOffset;
  1637. // captions are anchored to a baseline and grow upward
  1638. // any resolution changes then are title safe
  1639. m_pSubtitleLabel->SetPos( xPos, yPos );
  1640. m_pSubtitleLabel->SetTall( fontTall*2 );
  1641. m_pSubtitleLabel->SetWide( width );
  1642. m_pSubtitleLabel->SetContentAlignment( vgui::Label::a_center );
  1643. m_pSubtitleLabel->SetCenterWrap( true );
  1644. // Strip our extension
  1645. char captionFilename[MAX_QPATH];
  1646. Q_StripExtension( pMovieName, captionFilename, MAX_QPATH );
  1647. // Now add on the '_captions.txt' ending
  1648. Q_strncat( captionFilename, "_captions.txt", MAX_QPATH );
  1649. // Setup our captions
  1650. m_Captions.Init( captionFilename );
  1651. }
  1652. void StartCaptions( void )
  1653. {
  1654. m_Captions.SetStartTime( Plat_FloatTime() );
  1655. }
  1656. virtual void Paint( void )
  1657. {
  1658. int nColor = 0xFFFFFFFF;
  1659. const char *pCaptionText = m_Captions.GetCurrentCaption( &nColor );
  1660. m_pSubtitleLabel->SetText( pCaptionText );
  1661. // Pull the color out of this hex value
  1662. int r = ( nColor >> 24 ) & 0xFF;
  1663. int g = ( nColor >> 16 ) & 0xFF;
  1664. int b = ( nColor >> 8 ) & 0xFF;
  1665. int a = ( nColor >> 0 ) & 0xFF;
  1666. m_pSubtitleLabel->SetFgColor( Color(r,g,b,a) );
  1667. vgui::Panel::Paint();
  1668. }
  1669. private:
  1670. CCaptionSequencer m_Captions;
  1671. vgui::HFont m_hFont;
  1672. vgui::Label *m_pSubtitleLabel;
  1673. };
  1674. const char *lpszDubbedLanguages[] =
  1675. {
  1676. "english",
  1677. "french",
  1678. "german",
  1679. "spanish",
  1680. "russian"
  1681. };
  1682. //-----------------------------------------------------------------------------
  1683. // Purpose: Determines if we should be playing with captions
  1684. //-----------------------------------------------------------------------------
  1685. inline bool ShouldUseCaptioning( void )
  1686. {
  1687. char language[64];
  1688. // Fallback to English
  1689. V_strncpy( language, "english", sizeof( language ) );
  1690. #if !defined( NO_STEAM ) && !defined( DEDICATED )
  1691. // When Steam isn't running we can't get the language info...
  1692. if ( Steam3Client().SteamApps() )
  1693. {
  1694. V_strncpy( language, Steam3Client().SteamApps()->GetCurrentGameLanguage(), sizeof(language) );
  1695. }
  1696. #endif
  1697. // Iterate through the language we have dubbed and don't subtitle in that case
  1698. for ( int i = 0; i < ARRAYSIZE( lpszDubbedLanguages ); i++ )
  1699. {
  1700. if ( Q_stricmp( language, lpszDubbedLanguages[i] ) == 0 )
  1701. return false;
  1702. }
  1703. return true;
  1704. }
  1705. //-----------------------------------------------------------------------------
  1706. // Purpose: Tests for players attempting to skip a movie via keypress
  1707. //-----------------------------------------------------------------------------
  1708. bool UserRequestingMovieSkip( void )
  1709. {
  1710. if ( IsGameConsole() )
  1711. {
  1712. // Any joystick can cause the skip, so we must check all four
  1713. for ( int i = 0; i < XUSER_MAX_COUNT; i++ )
  1714. {
  1715. // If any of these buttons are down, we skip
  1716. if ( g_pInputSystem->IsButtonDown( ButtonCodeToJoystickButtonCode( KEY_XBUTTON_A, i ) ) ||
  1717. g_pInputSystem->IsButtonDown( ButtonCodeToJoystickButtonCode( KEY_XBUTTON_B, i ) ) ||
  1718. g_pInputSystem->IsButtonDown( ButtonCodeToJoystickButtonCode( KEY_XBUTTON_X, i ) ) ||
  1719. g_pInputSystem->IsButtonDown( ButtonCodeToJoystickButtonCode( KEY_XBUTTON_Y, i ) ) ||
  1720. g_pInputSystem->IsButtonDown( ButtonCodeToJoystickButtonCode( KEY_XBUTTON_START, i ) ) ||
  1721. g_pInputSystem->IsButtonDown( ButtonCodeToJoystickButtonCode( KEY_XBUTTON_BACK, i ) ) )
  1722. {
  1723. return true;
  1724. }
  1725. }
  1726. // Nothing pressed
  1727. return false;
  1728. }
  1729. return ( g_pInputSystem->IsButtonDown( KEY_ESCAPE ) ||
  1730. g_pInputSystem->IsButtonDown( KEY_SPACE ) ||
  1731. g_pInputSystem->IsButtonDown( KEY_ENTER ) );
  1732. }
  1733. #if defined( _X360 )
  1734. static char const * GetConsoleLocaleRatingsBoard()
  1735. {
  1736. switch ( XGetLocale() )
  1737. {
  1738. case XC_LOCALE_AUSTRALIA: return "OFLC";
  1739. case XC_LOCALE_AUSTRIA: return "PEGI";
  1740. case XC_LOCALE_BELGIUM: return "PEGI";
  1741. case XC_LOCALE_BRAZIL: return "";
  1742. case XC_LOCALE_CANADA: return "ESRB";
  1743. case XC_LOCALE_CHILE: return "";
  1744. case XC_LOCALE_CHINA: return "";
  1745. case XC_LOCALE_COLOMBIA: return "";
  1746. case XC_LOCALE_CZECH_REPUBLIC: return "PEGI";
  1747. case XC_LOCALE_DENMARK: return "PEGI";
  1748. case XC_LOCALE_FINLAND: return "PEGI";
  1749. case XC_LOCALE_FRANCE: return "PEGI";
  1750. case XC_LOCALE_GERMANY: return "USK";
  1751. case XC_LOCALE_GREECE: return "PEGI";
  1752. case XC_LOCALE_HONG_KONG: return "";
  1753. case XC_LOCALE_HUNGARY: return "";
  1754. case XC_LOCALE_INDIA: return "";
  1755. case XC_LOCALE_IRELAND: return "BBFCPEGI";
  1756. case XC_LOCALE_ITALY: return "PEGI";
  1757. case XC_LOCALE_JAPAN: return "CERO";
  1758. case XC_LOCALE_KOREA: return "GRB";
  1759. case XC_LOCALE_MEXICO: return "";
  1760. case XC_LOCALE_NETHERLANDS: return "PEGI";
  1761. case XC_LOCALE_NEW_ZEALAND: return "OFLC";
  1762. case XC_LOCALE_NORWAY: return "PEGI";
  1763. case XC_LOCALE_POLAND: return "PEGI";
  1764. case XC_LOCALE_PORTUGAL: return "PEGI";
  1765. case XC_LOCALE_SINGAPORE: return "";
  1766. case XC_LOCALE_SLOVAK_REPUBLIC: return "PEGI";
  1767. case XC_LOCALE_SOUTH_AFRICA: return "";
  1768. case XC_LOCALE_SPAIN: return "PEGI";
  1769. case XC_LOCALE_SWEDEN: return "PEGI";
  1770. case XC_LOCALE_SWITZERLAND: return "PEGI";
  1771. case XC_LOCALE_TAIWAN: return "";
  1772. case XC_LOCALE_GREAT_BRITAIN: return "BBFCPEGI";
  1773. case XC_LOCALE_UNITED_STATES: return "ESRB";
  1774. default: return NULL;
  1775. }
  1776. }
  1777. #endif
  1778. void CGame::PlayVideoListAndWait( const char *szVideoFileList, bool bNeedHealthWarning /* = false */ )
  1779. {
  1780. #ifndef DEDICATED
  1781. CUtlBuffer vidBuffer( 0, 0, CUtlBuffer::TEXT_BUFFER );
  1782. if ( !g_pFullFileSystem->ReadFile( szVideoFileList, "GAME", vidBuffer ) )
  1783. {
  1784. return;
  1785. }
  1786. #if defined( USE_SDL )
  1787. int CursorStateBak = SDL_ShowCursor( -1 );
  1788. SDL_ShowCursor( 0 );
  1789. #elif defined( WIN32 )
  1790. // hide cursor while playing videos
  1791. ::ShowCursor(FALSE);
  1792. #endif
  1793. #if defined( OSX ) && !defined( USE_SDL )
  1794. CGDisplayHideCursor( kCGDirectMainDisplay );
  1795. #endif
  1796. #ifdef _X360
  1797. // TCR024
  1798. XMPOverrideBackgroundMusic();
  1799. #endif
  1800. #ifdef _GAMECONSOLE
  1801. // Install movie player match framework
  1802. extern IMatchFramework *g_pMoviePlayer_MatchFramework;
  1803. bool bInstalledMoviePlayerMatchFramework = false;
  1804. if ( !g_pMatchFramework && IsGameConsole() )
  1805. {
  1806. #ifdef _X360
  1807. XOnlineStartup();
  1808. #endif
  1809. g_pMatchFramework = g_pMoviePlayer_MatchFramework;
  1810. bInstalledMoviePlayerMatchFramework = true;
  1811. }
  1812. #ifdef _PS3
  1813. int iLibAudioInitCode = cellAudioInit();
  1814. CellAudioOutState caosDevice = {0};
  1815. if ( iLibAudioInitCode >= 0 )
  1816. {
  1817. int numDevices = cellAudioOutGetNumberOfDevice( CELL_AUDIO_OUT_PRIMARY );
  1818. if ( numDevices > 0 )
  1819. {
  1820. int iAudioState = cellAudioOutGetState( CELL_AUDIO_OUT_PRIMARY, 0, &caosDevice );
  1821. if ( g_pBIK && ( iAudioState >= 0 ) )
  1822. {
  1823. g_pBIK->SetPS3SoundDevice( caosDevice.soundMode.channel );
  1824. }
  1825. }
  1826. }
  1827. #endif
  1828. #endif
  1829. characterset_t breakSet;
  1830. CharacterSetBuild( &breakSet, "" );
  1831. char moviePath[MAX_PATH];
  1832. while ( !IsPS3QuitRequested() )
  1833. {
  1834. int nTokenSize = vidBuffer.ParseToken( &breakSet, moviePath, sizeof( moviePath ) );
  1835. if ( nTokenSize <= 0 )
  1836. {
  1837. break;
  1838. }
  1839. // get the path to the file and play it.
  1840. PlayVideoAndWait( moviePath, bNeedHealthWarning );
  1841. }
  1842. #ifdef _GAMECONSOLE
  1843. #ifdef _PS3
  1844. if ( iLibAudioInitCode >= 0 )
  1845. {
  1846. cellAudioQuit();
  1847. }
  1848. #endif
  1849. if ( ( g_pMatchFramework == g_pMoviePlayer_MatchFramework ) && bInstalledMoviePlayerMatchFramework )
  1850. {
  1851. #ifdef _X360
  1852. XOnlineCleanup();
  1853. #endif
  1854. g_pMatchFramework = NULL;
  1855. }
  1856. #endif
  1857. #ifdef _X360
  1858. // TCR024
  1859. XMPRestoreBackgroundMusic();
  1860. #endif
  1861. #if defined( USE_SDL )
  1862. SDL_ShowCursor( CursorStateBak );
  1863. #elif defined( WIN32 )
  1864. // show cursor again
  1865. ::ShowCursor(TRUE);
  1866. #endif
  1867. #ifdef OSX
  1868. CGDisplayShowCursor( kCGDirectMainDisplay );
  1869. #endif
  1870. #endif // DEDICATED
  1871. }
  1872. //-----------------------------------------------------------------------------
  1873. // Plays a Bink video until the video completes or user input cancels
  1874. //-----------------------------------------------------------------------------
  1875. void CGame::PlayVideoAndWait( const char *filename, bool bNeedHealthWarning )
  1876. {
  1877. #if defined( BINK_VIDEO )
  1878. #if defined( IS_WINDOWS_PC ) || defined( OSX ) || defined( _GAMECONSOLE )
  1879. if ( !filename || !filename[0] )
  1880. return;
  1881. if ( !g_pBIK )
  1882. return;
  1883. #if defined( _X360 ) && defined( _DEMO )
  1884. // Xbox 360 is required to show ratings from the locale specific ratings board
  1885. if ( char const *pszRating = Q_stristr( filename, "RATINGBOARD" ) )
  1886. {
  1887. // Determine the rating of the current locale
  1888. char const *szRatingBoard = GetConsoleLocaleRatingsBoard();
  1889. if ( !szRatingBoard || !*szRatingBoard )
  1890. return;
  1891. // Format it into the buffer
  1892. int nRatingPrefixLen = ( pszRating - filename );
  1893. int numBufferBytes = nRatingPrefixLen + Q_strlen( szRatingBoard ) + 32;
  1894. char *pchRatingBuffer = ( char * ) stackalloc( numBufferBytes );
  1895. Q_snprintf( pchRatingBuffer, numBufferBytes, "%.*s%s.bik", nRatingPrefixLen, filename, szRatingBoard );
  1896. filename = pchRatingBuffer; // stackalloc ensures that the buffer is valid until the function returns
  1897. }
  1898. #else
  1899. if ( Q_stristr( filename, "RATINGBOARD" ) )
  1900. return;
  1901. #endif
  1902. // Supplying a NULL context will cause Bink to allocate its own
  1903. // FIXME: At this point we're playing at the full volume of the computer, NOT the user's set volume in the game!
  1904. #if defined( _X360 )
  1905. if ( Audio_CreateXAudioDevice( false ) )
  1906. {
  1907. #if defined ( BINK_VIDEO )
  1908. if ( !g_pBIK->HookXAudio() )
  1909. return;
  1910. #endif
  1911. }
  1912. #elif defined( LINUX )
  1913. Audio_CreateSDLAudioDevice();
  1914. #elif defined( _PS3 )
  1915. // S_Init(); // fully initialize sound system here
  1916. #elif defined( PLATFORM_WINDOWS )
  1917. //BinkSoundUseDirectSound( NULL ); // Bink sound is initialized by the caller now
  1918. #endif
  1919. CMatRenderContextPtr pRenderContext( g_pMaterialSystem );
  1920. #if defined ( QUICKTIME_VIDEO )
  1921. IQuickTime *pVideoPlayer = g_pQuickTime;
  1922. QUICKTIMEMaterial_t VideoHandle;
  1923. QUICKTIMEMaterial_t InvalidVideoHandle = QUICKTIMEMATERIAL_INVALID;
  1924. #elif defined( BINK_VIDEO )
  1925. IBik *pVideoPlayer = g_pBIK;
  1926. BIKHandle_t VideoHandle;
  1927. BIKHandle_t InvalidVideoHandle = BIKHANDLE_INVALID;
  1928. #else
  1929. #error "Need to have support for video playback enabled via source_video_base.vpc"
  1930. #endif
  1931. if ( !pVideoPlayer )
  1932. return;
  1933. // get the path to the media file and play it.
  1934. char localPath[MAX_PATH];
  1935. // Are we wanting to use a quicktime ".mov" version of the media instead of what's specified?
  1936. #if defined( FORCE_QUICKTIME ) && defined( QUICKTIME_VIDEO )
  1937. // is it not a .mov file extension?
  1938. if ( V_stristr( com_token, ".mov") == NULL )
  1939. {
  1940. // Compose Quicktime version
  1941. char QTPath[MAX_PATH];
  1942. V_strncpy( QTPath, filename, MAX_PATH );
  1943. V_SetExtension( QTPath, ".mov", MAX_PATH );
  1944. g_pFileSystem->GetLocalPath( QTPath, localPath, sizeof(localPath) );
  1945. }
  1946. else
  1947. #endif
  1948. {
  1949. V_strncpy( localPath, filename, sizeof(localPath) );
  1950. }
  1951. // Load and create our BINK or QuickTime video
  1952. VideoHandle = pVideoPlayer->CreateMaterial( "VideoMaterial", localPath, "GAME" );
  1953. if ( VideoHandle == InvalidVideoHandle )
  1954. {
  1955. return;
  1956. }
  1957. float flU0 = 0.0f;
  1958. float flV0 = 0.0f;
  1959. float flU1, flV1;
  1960. pVideoPlayer->GetTexCoordRange( VideoHandle, &flU1, &flV1 );
  1961. IMaterial *pMaterial = pVideoPlayer->GetMaterial( VideoHandle );
  1962. int nTexHeight = pMaterial->GetMappingHeight();
  1963. int nTexWidth = pMaterial->GetMappingWidth();
  1964. int nWidth, nHeight;
  1965. pVideoPlayer->GetFrameSize( VideoHandle, &nWidth, &nHeight );
  1966. const AspectRatioInfo_t &aspectRatioInfo = materials->GetAspectRatioInfo();
  1967. // Determine how the video's aspect ratio relates to the screen's
  1968. float flPhysicalFrameRatio = aspectRatioInfo.m_flFrameBuffertoPhysicalScalar * ( ( float )m_width / ( float )m_height );
  1969. float flVideoRatio = ( ( float ) nWidth / ( float ) nHeight );
  1970. int nPlaybackWidth;
  1971. int nPlaybackHeight;
  1972. if ( flVideoRatio > flPhysicalFrameRatio )
  1973. {
  1974. // Height must be adjusted
  1975. nPlaybackWidth = m_width;
  1976. // Have to account for the difference between physical and pixel aspect ratios.
  1977. nPlaybackHeight = ( ( float )m_width / aspectRatioInfo.m_flPhysicalToFrameBufferScalar ) / flVideoRatio;
  1978. }
  1979. else if ( flVideoRatio < flPhysicalFrameRatio )
  1980. {
  1981. // Width must be adjusted
  1982. // Have to account for the difference between physical and pixel aspect ratios.
  1983. nPlaybackWidth = ( float )m_height * flVideoRatio * aspectRatioInfo.m_flPhysicalToFrameBufferScalar;
  1984. nPlaybackHeight = m_height;
  1985. }
  1986. else
  1987. {
  1988. // Ratio matches
  1989. nPlaybackWidth = m_width;
  1990. nPlaybackHeight = m_height;
  1991. }
  1992. // Turn off our vertex alpha for these draw calls as they don't write alpha per-vertex
  1993. pMaterial->SetMaterialVarFlag( MATERIAL_VAR_VERTEXALPHA, false );
  1994. // Prep the screen
  1995. pRenderContext->Viewport( 0, 0, m_width, m_height );
  1996. pRenderContext->DepthRange( 0, 1 );
  1997. pRenderContext->ClearColor3ub( 0, 0, 0 );
  1998. pRenderContext->SetToneMappingScaleLinear( Vector(1,1,1) );
  1999. // Find our letterboxing offset
  2000. int xpos = ( (float) ( m_width - nPlaybackWidth ) / 2 );
  2001. int ypos = ( (float) ( m_height - nPlaybackHeight ) / 2 );
  2002. // Enable the input system's message pump
  2003. g_pInputSystem->EnableMessagePump( true );
  2004. // Panel which allows for subtitling of startup movies
  2005. CSubtitlePanel *pSubtitlePanel = NULL;
  2006. bool bUseCaptioning = ShouldUseCaptioning();
  2007. if ( bUseCaptioning )
  2008. {
  2009. // Create a panel whose purpose is to
  2010. pSubtitlePanel = new CSubtitlePanel( NULL, filename, nPlaybackHeight );
  2011. pSubtitlePanel->SetParent( g_pMatSystemSurface->GetEmbeddedPanel() );
  2012. pSubtitlePanel->SetPaintBackgroundEnabled( false );
  2013. pSubtitlePanel->SetPaintEnabled( true );
  2014. pSubtitlePanel->SetBounds( 0, 0, m_width, m_height );
  2015. // VGUI needs a chance to move this panel into its global space
  2016. vgui::ivgui()->RunFrame();
  2017. // Start the caption sequence
  2018. pSubtitlePanel->StartCaptions();
  2019. }
  2020. // We need to make sure that these keys have been released since last pressed, otherwise you can skip
  2021. // movies inadvertently
  2022. bool bKeyDebounced = ( UserRequestingMovieSkip() == false );
  2023. bool bExitingProcess = false;
  2024. #if defined( _DEMO ) && defined( _X360 )
  2025. bExitingProcess = Host_IsDemoExiting();
  2026. #endif
  2027. while ( 1 )
  2028. {
  2029. #ifdef _GAMECONSOLE
  2030. if ( !bExitingProcess )
  2031. {
  2032. XBX_ProcessEvents(); // Force events to be processed that will deliver us ingame invites
  2033. XBX_DispatchEventsQueue(); // Dispatch the events too
  2034. }
  2035. #endif
  2036. // Pump messages to avoid lockups on focus change
  2037. g_pInputSystem->PollInputState( GetBaseLocalClient().IsActive() );
  2038. game->DispatchAllStoredGameMessages();
  2039. // xbox cannot skip legals
  2040. if ( bKeyDebounced && ( IsPC() || ( IsGameConsole() && !Q_stristr( filename, "valve" ) ) ) )
  2041. {
  2042. if ( !bExitingProcess && UserRequestingMovieSkip() )
  2043. break;
  2044. }
  2045. else
  2046. {
  2047. bKeyDebounced = ( UserRequestingMovieSkip() == false );
  2048. }
  2049. // Update our frame
  2050. if ( pVideoPlayer->Update( VideoHandle ) == false )
  2051. break;
  2052. if( IsPS3QuitRequested() )
  2053. break;
  2054. pRenderContext->AntiAliasingHint( AA_HINT_MOVIE );
  2055. // Clear the draw buffer and blt the material to it
  2056. pRenderContext->ClearBuffers( true, true, true );
  2057. pRenderContext->DrawScreenSpaceRectangle( pMaterial, xpos, ypos, nPlaybackWidth, nPlaybackHeight, flU0*nTexWidth, flV0*nTexHeight, flU1*nTexWidth-1, flV1*nTexHeight-1, nTexWidth, nTexHeight );
  2058. // Draw our VGUI panel
  2059. if ( bUseCaptioning )
  2060. {
  2061. vgui::surface()->PaintTraverse( pSubtitlePanel->GetVPanel() );
  2062. }
  2063. // Busy wait until we are ready to swap.
  2064. #ifdef QUICKTIME_VIDEO
  2065. while ( !pVideoPlayer->ReadyForSwap( BIKHandle ) )
  2066. #else
  2067. // TODO - is this valid with threaded bink changes?: while ( !pVideoPlayer->ReadyForSwap( BIKHandle ) )
  2068. #endif
  2069. {
  2070. NULL;
  2071. }
  2072. g_pMaterialSystem->SwapBuffers();
  2073. if ( ENABLE_BIK_PERF_SPEW )
  2074. {
  2075. // timing debug code for bink playback
  2076. static double flPreviousTime = -1.0;
  2077. double flTime = Plat_FloatTime();
  2078. double flDeltaTime = flTime - flPreviousTime;
  2079. if ( flDeltaTime > 0.0 )
  2080. {
  2081. Warning( "%0.2lf sec*60 %0.2lf fps\n", flDeltaTime * 60.0, 1.0 / flDeltaTime );
  2082. }
  2083. flPreviousTime = flTime;
  2084. }
  2085. }
  2086. // Disable the input system's message pump
  2087. g_pInputSystem->EnableMessagePump( false );
  2088. // Clean up the Bink video
  2089. if ( VideoHandle != InvalidVideoHandle )
  2090. {
  2091. pVideoPlayer->DestroyMaterial( VideoHandle );
  2092. }
  2093. // Clean up VGUI work
  2094. delete pSubtitlePanel;
  2095. #endif
  2096. #endif // BINK_VIDEO
  2097. }
  2098. //-----------------------------------------------------------------------------
  2099. // Purpose: Constructor
  2100. //-----------------------------------------------------------------------------
  2101. CGame::CGame()
  2102. {
  2103. #ifndef LINUX
  2104. m_hWindow = 0;
  2105. #endif
  2106. m_x = m_y = 0;
  2107. m_width = m_height = 0;
  2108. m_bActiveApp = false;
  2109. m_bCanPostActivateEvents = true;
  2110. m_iDesktopWidth = 0;
  2111. m_iDesktopHeight = 0;
  2112. m_iDesktopRefreshRate = 0;
  2113. m_hInputContext = INPUT_CONTEXT_HANDLE_INVALID;
  2114. #if defined( WIN32 ) && !defined( USE_SDL )
  2115. m_hInstance = 0;
  2116. m_ChainedWindowProc = NULL;
  2117. #endif
  2118. }
  2119. //-----------------------------------------------------------------------------
  2120. // Purpose: Destructor
  2121. //-----------------------------------------------------------------------------
  2122. CGame::~CGame()
  2123. {
  2124. }
  2125. //-----------------------------------------------------------------------------
  2126. // Purpose:
  2127. //-----------------------------------------------------------------------------
  2128. bool CGame::Init( void *pvInstance )
  2129. {
  2130. m_bExternallySuppliedWindow = false;
  2131. #if defined( WIN32 ) && !defined( USE_SDL )
  2132. OSVERSIONINFO vinfo;
  2133. vinfo.dwOSVersionInfoSize = sizeof(vinfo);
  2134. if ( !GetVersionEx( &vinfo ) )
  2135. {
  2136. return false;
  2137. }
  2138. if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32s )
  2139. {
  2140. return false;
  2141. }
  2142. m_hInstance = (HINSTANCE)pvInstance;
  2143. #endif
  2144. m_hInputContext = g_pInputStackSystem->PushInputContext();
  2145. // Capture + hide the mouse
  2146. g_pInputStackSystem->SetMouseCapture( m_hInputContext, true );
  2147. return true;
  2148. }
  2149. bool CGame::Shutdown( void )
  2150. {
  2151. if ( m_hInputContext != INPUT_CONTEXT_HANDLE_INVALID )
  2152. {
  2153. g_pInputStackSystem->PopInputContext();
  2154. m_hInputContext = INPUT_CONTEXT_HANDLE_INVALID;
  2155. }
  2156. #if defined( WIN32 ) && !defined( USE_SDL )
  2157. m_hInstance = 0;
  2158. #endif
  2159. #ifdef _PS3
  2160. AbortLoadingUpdatesDueToShutdown();
  2161. #endif
  2162. return true;
  2163. }
  2164. void *CGame::GetMainWindow( void )
  2165. {
  2166. #if defined( LINUX )
  2167. return 0;
  2168. #else
  2169. return (void*)m_hWindow;
  2170. #endif
  2171. }
  2172. #if defined(USE_SDL)
  2173. void** CGame::GetMainWindowAddress( void )
  2174. {
  2175. m_hWindow = (SDL_Window *)g_pLauncherMgr->GetWindowRef();
  2176. return (void**)&m_hWindow;
  2177. }
  2178. #elif defined( WIN32 )
  2179. void** CGame::GetMainWindowAddress( void )
  2180. {
  2181. return (void**)&m_hWindow;
  2182. }
  2183. #elif defined(OSX)
  2184. void** CGame::GetMainWindowAddress( void )
  2185. {
  2186. m_hWindow = (WindowRef)g_pLauncherMgr->GetWindowRef();
  2187. return (void**)&m_hWindow;
  2188. }
  2189. #else
  2190. #error
  2191. #endif
  2192. void CGame::GetDesktopInfo( int &width, int &height, int &refreshrate )
  2193. {
  2194. #if defined(USE_SDL)
  2195. width = 640;
  2196. height = 480;
  2197. refreshrate = 0;
  2198. // Go through all the displays and return the size of the largest.
  2199. for( int i = 0; i < SDL_GetNumVideoDisplays(); i++ )
  2200. {
  2201. SDL_Rect rect;
  2202. if ( !SDL_GetDisplayBounds( i, &rect ) )
  2203. {
  2204. if ( ( rect.w > width ) || ( ( rect.w == width ) && ( rect.h > height ) ) )
  2205. {
  2206. width = rect.w;
  2207. height = rect.h;
  2208. }
  2209. }
  2210. }
  2211. #elif defined( WIN32 )
  2212. // order of initialization means that this might get called early. In that case go ahead and grab the current
  2213. // screen window and setup based on that.
  2214. // we need to do this when initializing the base list of video modes, for example
  2215. if ( m_iDesktopWidth == 0 )
  2216. {
  2217. HDC dc = ::GetDC( NULL );
  2218. width = ::GetDeviceCaps(dc, HORZRES);
  2219. height = ::GetDeviceCaps(dc, VERTRES);
  2220. refreshrate = ::GetDeviceCaps(dc, VREFRESH);
  2221. ::ReleaseDC( NULL, dc );
  2222. return;
  2223. }
  2224. width = m_iDesktopWidth;
  2225. height = m_iDesktopHeight;
  2226. refreshrate = m_iDesktopRefreshRate;
  2227. #elif defined(OSX)
  2228. if ( m_iDesktopWidth == 0 )
  2229. {
  2230. CGDirectDisplayID mainDisplay = CGMainDisplayID();
  2231. CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(mainDisplay);
  2232. width = (int)CGDisplayModeGetWidth(displayMode);
  2233. height = (int)CGDisplayModeGetHeight(displayMode);
  2234. refreshrate = (int)CGDisplayModeGetRefreshRate(displayMode);
  2235. }
  2236. width = m_iDesktopWidth;
  2237. height = m_iDesktopHeight;
  2238. refreshrate = m_iDesktopRefreshRate;
  2239. #else
  2240. #error
  2241. #endif
  2242. }
  2243. void CGame::UpdateDesktopInformation( HWND hWnd )
  2244. {
  2245. #if defined(USE_SDL)
  2246. // Get the size of the display we will be displayed fullscreen on.
  2247. static ConVarRef sdl_displayindex( "sdl_displayindex" );
  2248. int displayIndex = sdl_displayindex.IsValid() ? sdl_displayindex.GetInt() : 0;
  2249. SDL_DisplayMode mode;
  2250. SDL_GetDesktopDisplayMode( displayIndex, &mode );
  2251. m_iDesktopWidth = mode.w;
  2252. m_iDesktopHeight = mode.h;
  2253. m_iDesktopRefreshRate = mode.refresh_rate;
  2254. #elif defined( WIN32 )
  2255. HDC dc = ::GetDC( hWnd );
  2256. m_iDesktopWidth = ::GetDeviceCaps(dc, HORZRES);
  2257. m_iDesktopHeight = ::GetDeviceCaps(dc, VERTRES);
  2258. m_iDesktopRefreshRate = ::GetDeviceCaps(dc, VREFRESH);
  2259. ::ReleaseDC( hWnd, dc );
  2260. #elif defined(OSX)
  2261. CGDirectDisplayID mainDisplay = CGMainDisplayID();
  2262. CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(mainDisplay);
  2263. m_iDesktopWidth = (int)CGDisplayModeGetWidth(displayMode);
  2264. m_iDesktopHeight = (int)CGDisplayModeGetHeight(displayMode);;
  2265. m_iDesktopRefreshRate = (int)CGDisplayModeGetRefreshRate(displayMode);
  2266. #else
  2267. #error
  2268. #endif
  2269. }
  2270. #ifdef WIN32
  2271. void CGame::UpdateDesktopInformation( WPARAM wParam, LPARAM lParam )
  2272. {
  2273. m_iDesktopWidth = LOWORD( lParam );
  2274. m_iDesktopHeight = HIWORD( lParam );
  2275. }
  2276. #endif
  2277. void CGame::SetMainWindow( HWND window )
  2278. {
  2279. #if defined( USE_SDL )
  2280. m_hWindow = (SDL_Window*)window;
  2281. #elif defined( WIN32 ) && !defined( USE_SDL )
  2282. m_hWindow = window;
  2283. #elif OSX
  2284. m_hWindow = (WindowRef)window;
  2285. #else
  2286. #error
  2287. #endif
  2288. if ( IsPC() && !IsPosix() )
  2289. {
  2290. avi->SetMainWindow( (void*)window );
  2291. }
  2292. // update our desktop info (since the results will change if we are going to fullscreen mode)
  2293. if ( !m_iDesktopWidth || !m_iDesktopHeight )
  2294. {
  2295. UpdateDesktopInformation( window );
  2296. }
  2297. }
  2298. void CGame::SetWindowXY( int x, int y )
  2299. {
  2300. m_x = x;
  2301. m_y = y;
  2302. }
  2303. void CGame::SetWindowSize( int w, int h )
  2304. {
  2305. m_width = w;
  2306. m_height = h;
  2307. }
  2308. void CGame::GetWindowRect( int *x, int *y, int *w, int *h )
  2309. {
  2310. if ( x )
  2311. {
  2312. *x = m_x;
  2313. }
  2314. if ( y )
  2315. {
  2316. *y = m_y;
  2317. }
  2318. if ( w )
  2319. {
  2320. *w = m_width;
  2321. }
  2322. if ( h )
  2323. {
  2324. *h = m_height;
  2325. }
  2326. }
  2327. bool CGame::IsActiveApp( void )
  2328. {
  2329. return m_bActiveApp;
  2330. }
  2331. void CGame::SetCanPostActivateEvents( bool bEnabled )
  2332. {
  2333. m_bCanPostActivateEvents = bEnabled;
  2334. }
  2335. bool CGame::CanPostActivateEvents()
  2336. {
  2337. return m_bCanPostActivateEvents;
  2338. }
  2339. void CGame::SetActiveApp( bool active )
  2340. {
  2341. m_bActiveApp = active;
  2342. }
  2343. void CGame::OnScreenSizeChanged( int nOldWidth, int nOldHeight )
  2344. {
  2345. if ( g_ClientDLL )
  2346. {
  2347. g_ClientDLL->OnScreenSizeChanged( nOldWidth, nOldHeight );
  2348. }
  2349. }