Team Fortress 2 Source Code as on 22/4/2020
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.

1742 lines
42 KiB

  1. //========= Copyright 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. #include "SDL_syswm.h"
  10. #if defined( OSX )
  11. #define DONT_DEFINE_BOOL
  12. #include <objc/message.h>
  13. #endif
  14. #endif
  15. #if defined( WIN32 ) && !defined( _X360 ) && !defined( DX_TO_GL_ABSTRACTION )
  16. #include "winlite.h"
  17. #include "xbox/xboxstubs.h"
  18. #endif
  19. #if defined( IS_WINDOWS_PC ) && !defined( USE_SDL )
  20. #include <winsock.h>
  21. #elif defined(_X360)
  22. // nothing to include for 360
  23. #elif defined(OSX)
  24. #elif defined(LINUX)
  25. #include "tier0/dynfunction.h"
  26. #elif defined(_WIN32)
  27. #include "tier0/dynfunction.h"
  28. #else
  29. #error
  30. #endif
  31. #include "appframework/ilaunchermgr.h"
  32. #include "igame.h"
  33. #include "cl_main.h"
  34. #include "host.h"
  35. #include "quakedef.h"
  36. #include "tier0/vcrmode.h"
  37. #include "tier0/icommandline.h"
  38. #include "ivideomode.h"
  39. #include "gl_matsysiface.h"
  40. #include "cdll_engine_int.h"
  41. #include "vgui_baseui_interface.h"
  42. #include "iengine.h"
  43. #include "keys.h"
  44. #include "VGuiMatSurface/IMatSystemSurface.h"
  45. #include "tier3/tier3.h"
  46. #include "sound.h"
  47. #include "vgui_controls/Controls.h"
  48. #include "vgui_controls/MessageDialog.h"
  49. #include "sys_dll.h"
  50. #include "inputsystem/iinputsystem.h"
  51. #include "inputsystem/ButtonCode.h"
  52. #ifdef WIN32
  53. #undef WIN32_LEAN_AND_MEAN
  54. #include "unicode/unicode.h"
  55. #endif
  56. #include "GameUI/IGameUI.h"
  57. #include "matchmaking.h"
  58. #include "sv_main.h"
  59. #include "video/ivideoservices.h"
  60. #include "sys.h"
  61. #include "materialsystem/imaterial.h"
  62. #if defined( _X360 )
  63. #include "xbox/xbox_win32stubs.h"
  64. #include "hl2orange.spa.h"
  65. #endif
  66. #if defined( LINUX )
  67. #include "snd_dev_sdl.h"
  68. #endif
  69. #ifdef DBGFLAG_ASSERT
  70. #define AssertExit( _exp ) Assert( _exp )
  71. #define AssertExitF( _exp ) Assert( _exp )
  72. #else
  73. #define AssertExit( _exp ) if ( !( _exp ) ) return;
  74. #define AssertExitF( _exp ) if ( !( _exp ) ) return false;
  75. #endif
  76. // memdbgon must be the last include file in a .cpp file!!!
  77. #include "tier0/memdbgon.h"
  78. void S_BlockSound (void);
  79. void S_UnblockSound (void);
  80. void ClearIOStates( void );
  81. //-----------------------------------------------------------------------------
  82. // Game input events
  83. //-----------------------------------------------------------------------------
  84. enum GameInputEventType_t
  85. {
  86. IE_Close = IE_FirstAppEvent,
  87. IE_WindowMove,
  88. IE_AppActivated,
  89. };
  90. #ifdef WIN32
  91. static IUnicodeWindows *unicode = NULL;
  92. #endif
  93. //-----------------------------------------------------------------------------
  94. // Purpose: Main game interface, including message pump and window creation
  95. //-----------------------------------------------------------------------------
  96. class CGame : public IGame
  97. {
  98. public:
  99. CGame( void );
  100. virtual ~CGame( void );
  101. bool Init( void *pvInstance );
  102. bool Shutdown( void );
  103. bool CreateGameWindow( void );
  104. void DestroyGameWindow();
  105. void SetGameWindow( void* hWnd );
  106. // This is used in edit mode to override the default wnd proc associated w/
  107. bool InputAttachToGameWindow();
  108. void InputDetachFromGameWindow();
  109. void PlayStartupVideos( void );
  110. // This is the SDL_Window* under SDL, HWND otherwise.
  111. void* GetMainWindow( void );
  112. // This will be the HWND under D3D + Windows (both with and without SDL), SDL_Window* everywhere else.
  113. void* GetMainDeviceWindow( void );
  114. // This will be the HWND under Windows, the WindowRef under Mac, and (for now) NULL on Linux
  115. void* GetMainWindowPlatformSpecificHandle( void );
  116. void** GetMainWindowAddress( void );
  117. void GetDesktopInfo( int &width, int &height, int &refreshrate );
  118. void SetWindowXY( int x, int y );
  119. void SetWindowSize( int w, int h );
  120. void GetWindowRect( int *x, int *y, int *w, int *h );
  121. bool IsActiveApp( void );
  122. void SetCanPostActivateEvents( bool bEnable );
  123. bool CanPostActivateEvents();
  124. public:
  125. #ifdef USE_SDL
  126. void SetMainWindow( SDL_Window* window );
  127. #else
  128. #ifdef WIN32
  129. int WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  130. #endif
  131. void SetMainWindow( HWND window );
  132. #endif
  133. void SetActiveApp( bool active );
  134. bool LoadUnicode();
  135. void UnloadUnicode();
  136. // Message handlers.
  137. public:
  138. void HandleMsg_WindowMove( const InputEvent_t &event );
  139. void HandleMsg_ActivateApp( const InputEvent_t &event );
  140. void HandleMsg_Close( const InputEvent_t &event );
  141. // Call the appropriate HandleMsg_ function.
  142. void DispatchInputEvent( const InputEvent_t &event );
  143. // Dispatch all the queued up messages.
  144. virtual void DispatchAllStoredGameMessages();
  145. private:
  146. void AppActivate( bool fActive );
  147. void PlayVideoAndWait( const char *filename, bool bNeedHealthWarning = false); // plays a video file and waits till it's done to return. Can be interrupted by user.
  148. private:
  149. void AttachToWindow();
  150. void DetachFromWindow();
  151. #ifndef _X360
  152. static const wchar_t CLASSNAME[];
  153. #else
  154. static const char CLASSNAME[];
  155. #endif
  156. bool m_bExternallySuppliedWindow;
  157. #if defined( WIN32 )
  158. HWND m_hWindow;
  159. #if !defined( USE_SDL )
  160. HINSTANCE m_hInstance;
  161. // Stores a wndproc to chain message calls to
  162. WNDPROC m_ChainedWindowProc;
  163. RECT m_rcLastRestoredClientRect;
  164. #endif
  165. #endif
  166. #if defined( USE_SDL )
  167. SDL_Window *m_pSDLWindow;
  168. #endif
  169. int m_x;
  170. int m_y;
  171. int m_width;
  172. int m_height;
  173. bool m_bActiveApp;
  174. CSysModule *m_hUnicodeModule;
  175. bool m_bCanPostActivateEvents;
  176. int m_iDesktopWidth, m_iDesktopHeight, m_iDesktopRefreshRate;
  177. void UpdateDesktopInformation();
  178. #ifdef WIN32
  179. void UpdateDesktopInformation( WPARAM wParam, LPARAM lParam );
  180. #endif
  181. };
  182. static CGame g_Game;
  183. IGame *game = ( IGame * )&g_Game;
  184. #if !defined( _X360 )
  185. const wchar_t CGame::CLASSNAME[] = L"Valve001";
  186. #else
  187. const char CGame::CLASSNAME[] = "Valve001";
  188. #endif
  189. // In VCR playback mode, it sleeps this amount each frame.
  190. int g_iVCRPlaybackSleepInterval = 0;
  191. // During VCR playback, if this is true, then it'll pause at the end of each frame.
  192. bool g_bVCRSingleStep = false;
  193. bool g_bWaitingForStepKeyUp = false; // Used to prevent it from running frames while you hold the S key down.
  194. bool g_bShowVCRPlaybackDisplay = true;
  195. // These are all the windows messages that can change game state.
  196. // See CGame::WindowProc for a description of how they work.
  197. struct GameMessageHandler_t
  198. {
  199. int m_nEventType;
  200. void (CGame::*pFn)( const InputEvent_t &event );
  201. };
  202. GameMessageHandler_t g_GameMessageHandlers[] =
  203. {
  204. { IE_AppActivated, &CGame::HandleMsg_ActivateApp },
  205. { IE_WindowMove, &CGame::HandleMsg_WindowMove },
  206. { IE_Close, &CGame::HandleMsg_Close },
  207. { IE_Quit, &CGame::HandleMsg_Close },
  208. };
  209. void CGame::AppActivate( bool fActive )
  210. {
  211. // If text mode, force it to be active.
  212. if ( g_bTextMode )
  213. {
  214. fActive = true;
  215. }
  216. // Don't bother if we're already in the correct state
  217. if ( IsActiveApp() == fActive )
  218. return;
  219. // Don't let video modes changes queue up another activate event
  220. SetCanPostActivateEvents( false );
  221. #ifndef SWDS
  222. if ( videomode )
  223. {
  224. if ( fActive )
  225. {
  226. videomode->RestoreVideo();
  227. }
  228. else
  229. {
  230. videomode->ReleaseVideo();
  231. }
  232. }
  233. if ( host_initialized )
  234. {
  235. if ( fActive )
  236. {
  237. // Clear keyboard states (should be cleared already but...)
  238. // VGui_ActivateMouse will reactivate the mouse soon.
  239. ClearIOStates();
  240. UpdateMaterialSystemConfig();
  241. }
  242. else
  243. {
  244. // Clear keyboard input and deactivate the mouse while we're away.
  245. ClearIOStates();
  246. if ( g_ClientDLL )
  247. {
  248. g_ClientDLL->IN_DeactivateMouse();
  249. }
  250. }
  251. }
  252. #endif // SWDS
  253. SetActiveApp( fActive );
  254. #ifdef _XBOX
  255. if ( host_initialized )
  256. {
  257. ClearIOStates();
  258. if ( fActive )
  259. {
  260. UpdateMaterialSystemConfig();
  261. }
  262. }
  263. SetActiveApp( fActive );
  264. #endif
  265. // Allow queueing of activation events
  266. SetCanPostActivateEvents( true );
  267. }
  268. void CGame::HandleMsg_WindowMove( const InputEvent_t &event )
  269. {
  270. game->SetWindowXY( event.m_nData, event.m_nData2 );
  271. #ifndef SWDS
  272. videomode->UpdateWindowPosition();
  273. #endif
  274. }
  275. void CGame::HandleMsg_ActivateApp( const InputEvent_t &event )
  276. {
  277. AppActivate( event.m_nData ? true : false );
  278. }
  279. void CGame::HandleMsg_Close( const InputEvent_t &event )
  280. {
  281. if ( eng->GetState() == IEngine::DLL_ACTIVE )
  282. {
  283. eng->SetQuitting( IEngine::QUIT_TODESKTOP );
  284. }
  285. }
  286. void CGame::DispatchInputEvent( const InputEvent_t &event )
  287. {
  288. switch( event.m_nType )
  289. {
  290. // Handle button events specially,
  291. // since we have all manner of crazy filtering going on when dealing with them
  292. case IE_ButtonPressed:
  293. case IE_ButtonDoubleClicked:
  294. case IE_ButtonReleased:
  295. Key_Event( event );
  296. break;
  297. default:
  298. // Let vgui have the first whack at events
  299. if ( g_pMatSystemSurface && g_pMatSystemSurface->HandleInputEvent( event ) )
  300. break;
  301. for ( int i=0; i < ARRAYSIZE( g_GameMessageHandlers ); i++ )
  302. {
  303. if ( g_GameMessageHandlers[i].m_nEventType == event.m_nType )
  304. {
  305. (this->*g_GameMessageHandlers[i].pFn)( event );
  306. break;
  307. }
  308. }
  309. break;
  310. }
  311. }
  312. void CGame::DispatchAllStoredGameMessages()
  313. {
  314. #if !defined( NO_VCR )
  315. if ( VCRGetMode() == VCR_Playback )
  316. {
  317. InputEvent_t event;
  318. while ( VCRHook_PlaybackGameMsg( &event ) )
  319. {
  320. event.m_nTick = g_pInputSystem->GetPollTick();
  321. DispatchInputEvent( event );
  322. }
  323. }
  324. else
  325. {
  326. int nEventCount = g_pInputSystem->GetEventCount();
  327. const InputEvent_t* pEvents = g_pInputSystem->GetEventData( );
  328. for ( int i = 0; i < nEventCount; ++i )
  329. {
  330. VCRHook_RecordGameMsg( pEvents[i] );
  331. DispatchInputEvent( pEvents[i] );
  332. }
  333. VCRHook_RecordEndGameMsg();
  334. }
  335. #else
  336. int nEventCount = g_pInputSystem->GetEventCount();
  337. const InputEvent_t* pEvents = g_pInputSystem->GetEventData( );
  338. for ( int i = 0; i < nEventCount; ++i )
  339. {
  340. DispatchInputEvent( pEvents[i] );
  341. }
  342. #endif
  343. }
  344. void VCR_EnterPausedState()
  345. {
  346. // Turn this off in case they're in single-step mode.
  347. g_bVCRSingleStep = false;
  348. #ifdef WIN32
  349. // This is cheesy, but GetAsyncKeyState is blocked (in protected_things.h)
  350. // from being accidentally used, so we get it through it by getting its pointer directly.
  351. static HINSTANCE hInst = LoadLibrary( "user32.dll" );
  352. if ( !hInst )
  353. return;
  354. typedef SHORT (WINAPI *GetAsyncKeyStateFn)( int vKey );
  355. static GetAsyncKeyStateFn pfn = (GetAsyncKeyStateFn)GetProcAddress( hInst, "GetAsyncKeyState" );
  356. if ( !pfn )
  357. return;
  358. // In this mode, we enter a wait state where we only pay attention to R and Q.
  359. while ( 1 )
  360. {
  361. if ( pfn( 'R' ) & 0x8000 )
  362. break;
  363. if ( pfn( 'Q' ) & 0x8000 )
  364. TerminateProcess( GetCurrentProcess(), 1 );
  365. if ( pfn( 'S' ) & 0x8000 )
  366. {
  367. if ( !g_bWaitingForStepKeyUp )
  368. {
  369. // Do a single step.
  370. g_bVCRSingleStep = true;
  371. g_bWaitingForStepKeyUp = true; // Don't do another single step until they release the S key.
  372. break;
  373. }
  374. }
  375. else
  376. {
  377. // Ok, they released the S key, so we'll process it next time the key goes down.
  378. g_bWaitingForStepKeyUp = false;
  379. }
  380. Sleep( 2 );
  381. }
  382. #else
  383. Assert( !"Impl me" );
  384. #endif
  385. }
  386. #ifdef WIN32
  387. void VCR_HandlePlaybackMessages(
  388. HWND hWnd,
  389. UINT uMsg,
  390. WPARAM wParam,
  391. LPARAM lParam
  392. )
  393. {
  394. if ( uMsg == WM_KEYDOWN )
  395. {
  396. if ( wParam == VK_SUBTRACT || wParam == 0xbd )
  397. {
  398. g_iVCRPlaybackSleepInterval += 5;
  399. }
  400. else if ( wParam == VK_ADD || wParam == 0xbb )
  401. {
  402. g_iVCRPlaybackSleepInterval -= 5;
  403. }
  404. else if ( toupper( wParam ) == 'Q' )
  405. {
  406. TerminateProcess( GetCurrentProcess(), 1 );
  407. }
  408. else if ( toupper( wParam ) == 'P' )
  409. {
  410. VCR_EnterPausedState();
  411. }
  412. else if ( toupper( wParam ) == 'S' && !g_bVCRSingleStep )
  413. {
  414. g_bWaitingForStepKeyUp = true;
  415. VCR_EnterPausedState();
  416. }
  417. else if ( toupper( wParam ) == 'D' )
  418. {
  419. g_bShowVCRPlaybackDisplay = !g_bShowVCRPlaybackDisplay;
  420. }
  421. g_iVCRPlaybackSleepInterval = clamp( g_iVCRPlaybackSleepInterval, 0, 500 );
  422. }
  423. }
  424. //-----------------------------------------------------------------------------
  425. // Calls the default window procedure
  426. // FIXME: It would be nice to remove the need for this, which we can do
  427. // if we can make unicode work when running inside hammer.
  428. //-----------------------------------------------------------------------------
  429. static LONG WINAPI CallDefaultWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  430. {
  431. if ( unicode )
  432. return unicode->DefWindowProcW( hWnd, uMsg, wParam, lParam );
  433. return DefWindowProc( hWnd, uMsg, wParam, lParam );
  434. }
  435. #endif
  436. //-----------------------------------------------------------------------------
  437. // Purpose: The user has accepted an invitation to a game, we need to detect if
  438. // it's TF2 and restart properly if it is
  439. //-----------------------------------------------------------------------------
  440. void XBX_HandleInvite( DWORD nUserId )
  441. {
  442. #ifdef _X360
  443. // Grab our invite info
  444. XINVITE_INFO inviteInfo;
  445. DWORD dwError = XInviteGetAcceptedInfo( nUserId, &inviteInfo );
  446. if ( dwError != ERROR_SUCCESS )
  447. return;
  448. // We only care if we're asked to join an Orange Box session
  449. if ( inviteInfo.dwTitleID != TITLEID_THE_ORANGE_BOX )
  450. {
  451. // Do the normal "we've been invited to a game" behavior
  452. return;
  453. }
  454. // Otherwise, launch depending on our current MOD
  455. if ( !Q_stricmp( GetCurrentMod(), "tf" ) )
  456. {
  457. // We're already running TF2, so just join the session
  458. if ( nUserId != XBX_GetPrimaryUserId() )
  459. {
  460. // Switch users, the other had the invite
  461. XBX_SetPrimaryUserId( nUserId );
  462. }
  463. // Kick off our join
  464. g_pMatchmaking->JoinInviteSession( &(inviteInfo.hostInfo) );
  465. }
  466. else
  467. {
  468. // Save off our session ID for later retrieval
  469. // NOTE: We may need to actually save off the inviter's XID and search for them later on if we took too long or the
  470. // session they were a part of went away
  471. XBX_SetInviteSessionId( inviteInfo.hostInfo.sessionID );
  472. XBX_SetInvitedUserId( nUserId );
  473. // Quit via the menu path "QuitNoConfirm"
  474. EngineVGui()->SystemNotification( SYSTEMNOTIFY_INVITE_SHUTDOWN );
  475. }
  476. #endif //_X360
  477. }
  478. #if defined( WIN32 ) && !defined( USE_SDL )
  479. //-----------------------------------------------------------------------------
  480. // Main windows procedure
  481. //-----------------------------------------------------------------------------
  482. int CGame::WindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  483. {
  484. LONG lRet = 0;
  485. HDC hdc;
  486. PAINTSTRUCT ps;
  487. //
  488. // NOTE: the way this function works is to handle all messages that just call through to
  489. // Windows or provide data to it.
  490. //
  491. // Any messages that change the engine's internal state (like key events) are stored in a list
  492. // and processed at the end of the frame. This is necessary for VCR mode to work correctly because
  493. // Windows likes to pump messages during some of its API calls like SetWindowPos, and unless we add
  494. // custom code around every Windows API call so VCR mode can trap the wndproc calls, VCR mode can't
  495. // reproduce the calls to the wndproc.
  496. //
  497. if ( eng->GetQuitting() != IEngine::QUIT_NOTQUITTING )
  498. return CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam );
  499. // If we're playing back, listen to a couple input things used to drive VCR mode
  500. if ( VCRGetMode() == VCR_Playback )
  501. {
  502. VCR_HandlePlaybackMessages( hWnd, uMsg, wParam, lParam );
  503. }
  504. //
  505. // Note: NO engine state should be changed in here while in VCR record or playback.
  506. // We can send whatever we want to Windows, but if we change its state in here instead of
  507. // in DispatchAllStoredGameMessages, the playback may not work because Windows messages
  508. // are not deterministic, so you might get different messages during playback than you did during record.
  509. //
  510. InputEvent_t event;
  511. memset( &event, 0, sizeof(event) );
  512. event.m_nTick = g_pInputSystem->GetPollTick();
  513. switch ( uMsg )
  514. {
  515. case WM_CREATE:
  516. ::SetForegroundWindow( hWnd );
  517. break;
  518. case WM_ACTIVATEAPP:
  519. {
  520. if ( CanPostActivateEvents() )
  521. {
  522. bool bActivated = ( wParam == 1 );
  523. event.m_nType = IE_AppActivated;
  524. event.m_nData = bActivated;
  525. g_pInputSystem->PostUserEvent( event );
  526. }
  527. }
  528. break;
  529. case WM_POWERBROADCAST:
  530. // Don't go into Sleep mode when running engine, we crash on resume for some reason (as
  531. // do half of the apps I have running usually anyway...)
  532. if ( wParam == PBT_APMQUERYSUSPEND )
  533. {
  534. Msg( "OS requested hibernation, ignoring request.\n" );
  535. return BROADCAST_QUERY_DENY;
  536. }
  537. lRet = CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam );
  538. break;
  539. case WM_SYSCOMMAND:
  540. if ( ( wParam == SC_MONITORPOWER ) || ( wParam == SC_KEYMENU ) || ( wParam == SC_SCREENSAVE ) )
  541. return lRet;
  542. if ( wParam == SC_CLOSE )
  543. {
  544. #if !defined( NO_VCR )
  545. // handle the close message, but make sure
  546. // it's not because we accidently hit ALT-F4
  547. if ( HIBYTE(VCRHook_GetKeyState(VK_LMENU)) || HIBYTE(VCRHook_GetKeyState(VK_RMENU) ) )
  548. return lRet;
  549. #endif
  550. Cbuf_Clear();
  551. Cbuf_AddText( "quit\n" );
  552. }
  553. #ifndef SWDS
  554. if ( VCRGetMode() == VCR_Disabled )
  555. {
  556. S_BlockSound();
  557. S_ClearBuffer();
  558. }
  559. #endif
  560. lRet = CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam );
  561. #ifndef SWDS
  562. if ( VCRGetMode() == VCR_Disabled )
  563. {
  564. S_UnblockSound();
  565. }
  566. #endif
  567. break;
  568. case WM_CLOSE:
  569. // Handle close messages
  570. event.m_nType = IE_Close;
  571. g_pInputSystem->PostUserEvent( event );
  572. return 0;
  573. case WM_MOVE:
  574. event.m_nType = IE_WindowMove;
  575. event.m_nData = (short)LOWORD(lParam);
  576. event.m_nData2 = (short)HIWORD(lParam);
  577. g_pInputSystem->PostUserEvent( event );
  578. break;
  579. case WM_SIZE:
  580. if ( wParam != SIZE_MINIMIZED )
  581. {
  582. // Update restored client rect
  583. ::GetClientRect( hWnd, &m_rcLastRestoredClientRect );
  584. }
  585. else
  586. {
  587. #ifndef _X360
  588. // Fix the window rect to have same client area as it used to have
  589. // before it got minimized
  590. RECT rcWindow;
  591. ::GetWindowRect( hWnd, &rcWindow );
  592. rcWindow.right = rcWindow.left + m_rcLastRestoredClientRect.right;
  593. rcWindow.bottom = rcWindow.top + m_rcLastRestoredClientRect.bottom;
  594. ::AdjustWindowRect( &rcWindow, ::GetWindowLong( hWnd, GWL_STYLE ), FALSE );
  595. ::MoveWindow( hWnd, rcWindow.left, rcWindow.top,
  596. rcWindow.right - rcWindow.left, rcWindow.bottom - rcWindow.top, FALSE );
  597. #endif
  598. }
  599. break;
  600. case WM_SYSCHAR:
  601. // keep Alt-Space from happening
  602. break;
  603. case WM_COPYDATA:
  604. // Hammer -> engine remote console command.
  605. // Return true to indicate that the message was handled.
  606. Cbuf_AddText( (const char *)(((COPYDATASTRUCT *)lParam)->lpData) );
  607. Cbuf_AddText( "\n" );
  608. lRet = 1;
  609. break;
  610. #if defined( _X360 )
  611. case WM_XREMOTECOMMAND:
  612. Cbuf_AddText( (const char*)lParam );
  613. Cbuf_AddText( "\n" );
  614. break;
  615. case WM_SYS_STORAGEDEVICESCHANGED:
  616. if ( !EngineVGui()->IsGameUIVisible() )
  617. {
  618. EngineVGui()->ActivateGameUI();
  619. }
  620. EngineVGui()->SystemNotification( SYSTEMNOTIFY_STORAGEDEVICES_CHANGED );
  621. break;
  622. case WM_XMP_PLAYBACKCONTROLLERCHANGED:
  623. S_EnableMusic( lParam != 0 );
  624. break;
  625. case WM_LIVE_INVITE_ACCEPTED:
  626. XBX_HandleInvite( LOWORD( lParam ) );
  627. break;
  628. case WM_SYS_SIGNINCHANGED:
  629. if ( XUserGetSigninState( XBX_GetPrimaryUserId() ) == eXUserSigninState_NotSignedIn )
  630. {
  631. // X360TBD: User signed out - pause the game?
  632. }
  633. EngineVGui()->SystemNotification( lParam ? SYSTEMNOTIFY_USER_SIGNEDIN : SYSTEMNOTIFY_USER_SIGNEDOUT );
  634. break;
  635. case WM_SYS_UI:
  636. if ( lParam )
  637. {
  638. // Don't activate it if it's already active (a sub window may be active)
  639. // Multiplayer doesn't want the UI to appear, since it can't pause anyway
  640. if ( !EngineVGui()->IsGameUIVisible() && g_ServerGlobalVariables.maxClients == 1 )
  641. {
  642. Cbuf_AddText( "gameui_activate" );
  643. }
  644. }
  645. EngineVGui()->SystemNotification( lParam ? SYSTEMNOTIFY_XUIOPENING : SYSTEMNOTIFY_XUICLOSED );
  646. break;
  647. case WM_SYS_MUTELISTCHANGED:
  648. g_pMatchmaking->UpdateMuteList();
  649. break;
  650. case WM_SYS_INPUTDEVICESCHANGED:
  651. {
  652. XINPUT_CAPABILITIES caps;
  653. if ( XInputGetCapabilities( XBX_GetPrimaryUserId(), XINPUT_FLAG_GAMEPAD, &caps ) == ERROR_DEVICE_NOT_CONNECTED )
  654. {
  655. if ( EngineVGui()->IsGameUIVisible() == false )
  656. {
  657. EngineVGui()->ActivateGameUI();
  658. }
  659. }
  660. }
  661. break;
  662. #endif
  663. case WM_PAINT:
  664. hdc = BeginPaint(hWnd, &ps);
  665. RECT rcClient;
  666. GetClientRect( hWnd, &rcClient );
  667. #ifndef SWDS
  668. // Only renders stuff if running -noshaderapi
  669. if ( videomode )
  670. {
  671. videomode->DrawNullBackground( hdc, rcClient.right, rcClient.bottom );
  672. }
  673. #endif
  674. EndPaint(hWnd, &ps);
  675. break;
  676. #ifndef _X360
  677. case WM_DISPLAYCHANGE:
  678. if ( !m_iDesktopHeight || !m_iDesktopWidth )
  679. {
  680. UpdateDesktopInformation( wParam, lParam );
  681. }
  682. break;
  683. #endif
  684. case WM_IME_NOTIFY:
  685. switch ( wParam )
  686. {
  687. default:
  688. break;
  689. #ifndef SWDS
  690. case 14:
  691. if ( !videomode->IsWindowedMode() )
  692. return 0;
  693. break;
  694. #endif
  695. }
  696. return CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam);
  697. default:
  698. lRet = CallWindowProc( m_ChainedWindowProc, hWnd, uMsg, wParam, lParam );
  699. break;
  700. }
  701. // return 0 if handled message, 1 if not
  702. return lRet;
  703. }
  704. #elif defined(OSX)
  705. #elif defined(LINUX)
  706. #elif defined(_WIN32)
  707. #else
  708. #error
  709. #endif
  710. #if defined( WIN32 ) && !defined( USE_SDL )
  711. //-----------------------------------------------------------------------------
  712. // Creates the game window
  713. //-----------------------------------------------------------------------------
  714. static LONG WINAPI HLEngineWindowProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  715. {
  716. return g_Game.WindowProc( hWnd, uMsg, wParam, lParam );
  717. }
  718. #define DEFAULT_EXE_ICON 101
  719. static void DoSomeSocketStuffInOrderToGetZoneAlarmToNoticeUs( void )
  720. {
  721. #ifdef IS_WINDOWS_PC
  722. WSAData wsaData;
  723. if ( ! WSAStartup( 0x0101, &wsaData ) )
  724. {
  725. SOCKET tmpSocket = socket( AF_INET, SOCK_DGRAM, 0 );
  726. if ( tmpSocket != INVALID_SOCKET )
  727. {
  728. char Options[]={ 1 };
  729. setsockopt( tmpSocket, SOL_SOCKET, SO_BROADCAST, Options, sizeof(Options));
  730. char pszHostName[256];
  731. gethostname( pszHostName, sizeof( pszHostName ) );
  732. hostent *hInfo = gethostbyname( pszHostName );
  733. if ( hInfo )
  734. {
  735. sockaddr_in myIpAddress;
  736. memset( &myIpAddress, 0, sizeof( myIpAddress ) );
  737. myIpAddress.sin_family = AF_INET;
  738. myIpAddress.sin_port = htons( 27015 ); // our normal server port
  739. myIpAddress.sin_addr.S_un.S_un_b.s_b1 = hInfo->h_addr_list[0][0];
  740. myIpAddress.sin_addr.S_un.S_un_b.s_b2 = hInfo->h_addr_list[0][1];
  741. myIpAddress.sin_addr.S_un.S_un_b.s_b3 = hInfo->h_addr_list[0][2];
  742. myIpAddress.sin_addr.S_un.S_un_b.s_b4 = hInfo->h_addr_list[0][3];
  743. if ( bind( tmpSocket, ( sockaddr * ) &myIpAddress, sizeof( myIpAddress ) ) != -1 )
  744. {
  745. if ( sendto( tmpSocket, pszHostName, 1, 0, ( sockaddr *) &myIpAddress, sizeof( myIpAddress ) ) == -1 )
  746. {
  747. // error?
  748. }
  749. }
  750. }
  751. closesocket( tmpSocket );
  752. }
  753. WSACleanup();
  754. }
  755. #endif
  756. }
  757. #endif
  758. bool CGame::CreateGameWindow( void )
  759. {
  760. // get the window name
  761. char windowName[256];
  762. windowName[0] = 0;
  763. KeyValues *modinfo = new KeyValues("ModInfo");
  764. if (modinfo->LoadFromFile(g_pFileSystem, "gameinfo.txt"))
  765. {
  766. Q_strncpy( windowName, modinfo->GetString("game"), sizeof(windowName) );
  767. }
  768. if (!windowName[0])
  769. {
  770. Q_strncpy( windowName, "HALF-LIFE 2", sizeof(windowName) );
  771. }
  772. if ( IsOpenGL() )
  773. {
  774. V_strcat( windowName, " - OpenGL", sizeof( windowName ) );
  775. }
  776. #if PIX_ENABLE || defined( PIX_INSTRUMENTATION )
  777. // 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.
  778. V_strcat( windowName, " - PIX_ENABLE", sizeof( windowName ) );
  779. #endif
  780. const char *p = CommandLine()->ParmValue( "-window_name_suffix", "" );
  781. if ( p && V_strlen( p ) )
  782. {
  783. V_strcat( windowName, " - ", sizeof( windowName ) );
  784. V_strcat( windowName, p, sizeof( windowName ) );
  785. }
  786. #if defined( WIN32 ) && !defined( USE_SDL )
  787. #ifndef SWDS
  788. if ( IsPC() )
  789. {
  790. if ( !LoadUnicode() )
  791. {
  792. return false;
  793. }
  794. }
  795. #if !defined( _X360 )
  796. WNDCLASSW wc;
  797. #else
  798. WNDCLASS wc;
  799. #endif
  800. memset( &wc, 0, sizeof( wc ) );
  801. wc.style = CS_OWNDC | CS_DBLCLKS;
  802. wc.lpfnWndProc = CallDefaultWindowProc;
  803. wc.hInstance = m_hInstance;
  804. wc.lpszClassName = CLASSNAME;
  805. // find the icon file in the filesystem
  806. if ( IsPC() )
  807. {
  808. char localPath[ MAX_PATH ];
  809. if ( g_pFileSystem->GetLocalPath( "resource/game.ico", localPath, sizeof(localPath) ) )
  810. {
  811. g_pFileSystem->GetLocalCopy( localPath );
  812. wc.hIcon = (HICON)::LoadImage(NULL, localPath, IMAGE_ICON, 0, 0, LR_LOADFROMFILE | LR_DEFAULTSIZE);
  813. }
  814. else
  815. {
  816. wc.hIcon = (HICON)LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE( DEFAULT_EXE_ICON ) );
  817. }
  818. }
  819. #ifndef SWDS
  820. char const *pszGameType = modinfo->GetString( "type" );
  821. if ( pszGameType && Q_stristr( pszGameType, "multiplayer" ) )
  822. DoSomeSocketStuffInOrderToGetZoneAlarmToNoticeUs();
  823. #endif
  824. wchar_t uc[512];
  825. if ( IsPC() )
  826. {
  827. ::MultiByteToWideChar(CP_UTF8, 0, windowName, -1, uc, sizeof( uc ) / sizeof(wchar_t));
  828. }
  829. modinfo->deleteThis();
  830. modinfo = NULL;
  831. // Oops, we didn't clean up the class registration from last cycle which
  832. // might mean that the wndproc pointer is bogus
  833. #ifndef _X360
  834. unicode->UnregisterClassW( CLASSNAME, m_hInstance );
  835. // Register it again
  836. unicode->RegisterClassW( &wc );
  837. #else
  838. RegisterClass( &wc );
  839. #endif
  840. // Note, it's hidden
  841. DWORD style = WS_POPUP | WS_CLIPSIBLINGS;
  842. // Give it a frame if we want a border
  843. if ( videomode->IsWindowedMode() )
  844. {
  845. if( !CommandLine()->FindParm( "-noborder" ) )
  846. {
  847. style |= WS_OVERLAPPEDWINDOW;
  848. style &= ~WS_THICKFRAME;
  849. }
  850. }
  851. // Never a max box
  852. style &= ~WS_MAXIMIZEBOX;
  853. int w, h;
  854. // Create a full screen size window by default, it'll get resized later anyway
  855. w = GetSystemMetrics( SM_CXSCREEN );
  856. h = GetSystemMetrics( SM_CYSCREEN );
  857. // Create the window
  858. DWORD exFlags = 0;
  859. if ( g_bTextMode )
  860. {
  861. style &= ~WS_VISIBLE;
  862. exFlags |= WS_EX_TOOLWINDOW; // So it doesn't show up in the taskbar.
  863. }
  864. #if !defined( _X360 )
  865. HWND hwnd = unicode->CreateWindowExW( exFlags, CLASSNAME, uc, style,
  866. 0, 0, w, h, NULL, NULL, m_hInstance, NULL );
  867. // NOTE: On some cards, CreateWindowExW slams the FPU control word
  868. SetupFPUControlWord();
  869. #else
  870. HWND hwnd = CreateWindowEx( exFlags, CLASSNAME, windowName, style,
  871. 0, 0, w, h, NULL, NULL, m_hInstance, NULL );
  872. #endif
  873. if ( !hwnd )
  874. {
  875. Error( "Fatal Error: Unable to create game window!" );
  876. return false;
  877. }
  878. SetMainWindow( hwnd );
  879. AttachToWindow( );
  880. return true;
  881. #else
  882. return true;
  883. #endif
  884. #elif defined( USE_SDL )
  885. bool windowed = videomode->IsWindowedMode();
  886. modinfo->deleteThis();
  887. modinfo = NULL;
  888. if ( !g_pLauncherMgr->CreateGameWindow( windowName, windowed, 0, 0 ) )
  889. {
  890. Error( "Fatal Error: Unable to create game window!" );
  891. return false;
  892. }
  893. char localPath[ MAX_PATH ];
  894. if ( g_pFileSystem->GetLocalPath( "resource/game-icon.bmp", localPath, sizeof(localPath) ) )
  895. {
  896. g_pFileSystem->GetLocalCopy( localPath );
  897. g_pLauncherMgr->SetApplicationIcon( localPath );
  898. }
  899. SetMainWindow( (SDL_Window*)g_pLauncherMgr->GetWindowRef() );
  900. AttachToWindow( );
  901. return true;
  902. #else
  903. #error
  904. #endif
  905. }
  906. //-----------------------------------------------------------------------------
  907. // Destroys the game window
  908. //-----------------------------------------------------------------------------
  909. void CGame::DestroyGameWindow()
  910. {
  911. #if defined( USE_SDL )
  912. g_pLauncherMgr->DestroyGameWindow();
  913. #else
  914. #ifndef DEDICATED
  915. // Destroy all things created when the window was created
  916. if ( !m_bExternallySuppliedWindow )
  917. {
  918. DetachFromWindow( );
  919. if ( m_hWindow )
  920. {
  921. DestroyWindow( m_hWindow );
  922. m_hWindow = (HWND)0;
  923. }
  924. #if !defined( _X360 )
  925. unicode->UnregisterClassW( CLASSNAME, m_hInstance );
  926. UnloadUnicode();
  927. #else
  928. UnregisterClass( CLASSNAME, m_hInstance );
  929. #endif
  930. }
  931. else
  932. {
  933. m_hWindow = (HWND)0;
  934. m_bExternallySuppliedWindow = false;
  935. }
  936. #endif // !defined( SWDS )
  937. #endif
  938. }
  939. //-----------------------------------------------------------------------------
  940. // This is used in edit mode to specify a particular game window (created by hammer)
  941. //-----------------------------------------------------------------------------
  942. void CGame::SetGameWindow( void *hWnd )
  943. {
  944. m_bExternallySuppliedWindow = true;
  945. #if defined( USE_SDL )
  946. SDL_RaiseWindow( (SDL_Window *)hWnd );
  947. #else
  948. SetMainWindow( (HWND)hWnd );
  949. #endif
  950. }
  951. //-----------------------------------------------------------------------------
  952. //
  953. //-----------------------------------------------------------------------------
  954. void CGame::AttachToWindow()
  955. {
  956. #if defined( WIN32 )
  957. if ( !m_hWindow )
  958. return;
  959. #if !defined( USE_SDL )
  960. m_ChainedWindowProc = (WNDPROC)GetWindowLongPtrW( m_hWindow, GWLP_WNDPROC );
  961. SetWindowLongPtrW( m_hWindow, GWLP_WNDPROC, (LONG_PTR)HLEngineWindowProc );
  962. #endif
  963. #endif // WIN32
  964. if ( g_pInputSystem )
  965. {
  966. // Attach the input system window proc
  967. #if defined( WIN32 )
  968. g_pInputSystem->AttachToWindow( (void *)m_hWindow );
  969. #else
  970. g_pInputSystem->AttachToWindow( (void *)m_pSDLWindow );
  971. #endif
  972. g_pInputSystem->EnableInput( true );
  973. g_pInputSystem->EnableMessagePump( false );
  974. }
  975. if ( g_pMatSystemSurface )
  976. {
  977. // Attach the vgui matsurface window proc
  978. #if defined( WIN32 )
  979. g_pMatSystemSurface->AttachToWindow( (void *)m_hWindow, true );
  980. #else
  981. g_pMatSystemSurface->AttachToWindow( (void *)m_pSDLWindow, true );
  982. #endif
  983. g_pMatSystemSurface->EnableWindowsMessages( true );
  984. }
  985. }
  986. void CGame::DetachFromWindow()
  987. {
  988. #if defined( WIN32 ) && !defined( USE_SDL )
  989. if ( !m_hWindow || !m_ChainedWindowProc )
  990. {
  991. m_ChainedWindowProc = NULL;
  992. return;
  993. }
  994. #endif
  995. if ( g_pMatSystemSurface )
  996. {
  997. // Detach the vgui matsurface window proc
  998. g_pMatSystemSurface->AttachToWindow( NULL );
  999. }
  1000. if ( g_pInputSystem )
  1001. {
  1002. // Detach the input system window proc
  1003. g_pInputSystem->EnableInput( false );
  1004. g_pInputSystem->DetachFromWindow( );
  1005. }
  1006. #if defined( WIN32 ) && !defined( USE_SDL )
  1007. Assert( (WNDPROC)GetWindowLongPtrW( m_hWindow, GWLP_WNDPROC ) == HLEngineWindowProc );
  1008. SetWindowLongPtrW( m_hWindow, GWLP_WNDPROC, (LONG_PTR)m_ChainedWindowProc );
  1009. #endif
  1010. }
  1011. //-----------------------------------------------------------------------------
  1012. // This is used in edit mode to override the default wnd proc associated w/
  1013. // the game window specified in SetGameWindow.
  1014. //-----------------------------------------------------------------------------
  1015. bool CGame::InputAttachToGameWindow()
  1016. {
  1017. // We can't use this feature unless we didn't control the creation of the window
  1018. if ( !m_bExternallySuppliedWindow )
  1019. return true;
  1020. AttachToWindow();
  1021. #ifndef DEDICATED
  1022. vgui::surface()->OnScreenSizeChanged( videomode->GetModeStereoWidth(), videomode->GetModeStereoHeight() );
  1023. #endif
  1024. // We don't get WM_ACTIVATEAPP messages in this case; simulate one.
  1025. AppActivate( true );
  1026. #if defined( WIN32 ) && !defined( USE_SDL )
  1027. // Capture + hide the mouse
  1028. SetCapture( m_hWindow );
  1029. #elif defined( USE_SDL )
  1030. Assert( !"Impl me" );
  1031. return false;
  1032. #else
  1033. #error
  1034. #endif
  1035. return true;
  1036. }
  1037. void CGame::InputDetachFromGameWindow()
  1038. {
  1039. // We can't use this feature unless we didn't control the creation of the window
  1040. if ( !m_bExternallySuppliedWindow )
  1041. return;
  1042. #if defined( WIN32 ) && !defined( USE_SDL )
  1043. if ( !m_ChainedWindowProc )
  1044. return;
  1045. // Release + show the mouse
  1046. ReleaseCapture();
  1047. #elif defined( USE_SDL )
  1048. Assert( !"Impl me" );
  1049. #else
  1050. #error "have no idea what OS we are building for"
  1051. #endif
  1052. // We don't get WM_ACTIVATEAPP messages in this case; simulate one.
  1053. AppActivate( false );
  1054. DetachFromWindow();
  1055. }
  1056. void CGame::PlayStartupVideos( void )
  1057. {
  1058. if ( IsX360() || Plat_IsInBenchmarkMode() )
  1059. return;
  1060. #ifndef SWDS
  1061. // Wait for the mode to change and stabilized
  1062. // FIXME: There's really no way to know when this is completed, so we have to guess a time that will mostly be correct
  1063. if ( videomode->IsWindowedMode() == false )
  1064. {
  1065. Sys_Sleep( 1000 );
  1066. }
  1067. bool bEndGame = CommandLine()->CheckParm( "-endgamevid" );
  1068. bool bRecap = CommandLine()->CheckParm( "-recapvid" ); // FIXME: This is a temp addition until the movie playback is centralized -- jdw
  1069. bool bNeedHealthWarning = false;
  1070. const char *HealthFile = "media/HealthWarning.txt";
  1071. FileHandle_t hFile;
  1072. COM_OpenFile( HealthFile, &hFile );
  1073. //There is no access to steam at this point so we are checking for the presence of an empty file that will only exist in the chinese depot
  1074. if ( hFile != FILESYSTEM_INVALID_HANDLE )
  1075. {
  1076. bNeedHealthWarning = true;
  1077. COM_CloseFile( hFile );
  1078. }
  1079. if (!bNeedHealthWarning && !bEndGame && !bRecap && (CommandLine()->CheckParm("-dev") || CommandLine()->CheckParm("-novid") || CommandLine()->CheckParm("-allowdebug")))
  1080. return;
  1081. const char *pszFile = "media/StartupVids.txt";
  1082. if ( bEndGame )
  1083. {
  1084. // Don't go back into the map that triggered this.
  1085. CommandLine()->RemoveParm( "+map" );
  1086. CommandLine()->RemoveParm( "+load" );
  1087. pszFile = "media/EndGameVids.txt";
  1088. }
  1089. else if ( bRecap )
  1090. {
  1091. pszFile = "media/RecapVids.txt";
  1092. }
  1093. int vidFileLength;
  1094. // have to use the malloc memory allocation option in COM_LoadFile since the memory system isn't set up at this point.
  1095. const char *buffer = (char *) COM_LoadFile( pszFile, 5, &vidFileLength );
  1096. if ((buffer == NULL) || (vidFileLength == 0))
  1097. {
  1098. return;
  1099. }
  1100. // hide cursor while playing videos
  1101. #if defined( USE_SDL )
  1102. g_pLauncherMgr->SetMouseVisible( false );
  1103. #elif defined( WIN32 )
  1104. ::ShowCursor( FALSE );
  1105. #endif
  1106. #if defined( LINUX )
  1107. extern void VAudioInit();
  1108. VAudioInit();
  1109. Audio_CreateSDLAudioDevice();
  1110. #endif
  1111. const char *start = buffer;
  1112. while( true )
  1113. {
  1114. start = COM_Parse(start);
  1115. if ( Q_strlen( com_token ) <= 0 )
  1116. {
  1117. break;
  1118. }
  1119. // get the path to the media file and play it.
  1120. char localPath[MAX_PATH];
  1121. g_pFileSystem->GetLocalPath( com_token, localPath, sizeof(localPath) );
  1122. PlayVideoAndWait( localPath, bNeedHealthWarning );
  1123. localPath[0] = 0; // just to make sure we don't play the same avi file twice in the case that one movie is there but another isn't.
  1124. }
  1125. // show cursor again
  1126. #if defined( USE_SDL )
  1127. g_pLauncherMgr->SetMouseVisible( true );
  1128. #elif defined( WIN32 )
  1129. ::ShowCursor( TRUE );
  1130. #endif
  1131. // call free on the buffer since the buffer was malloc'd in COM_LoadFile
  1132. free( (void *)buffer );
  1133. #endif // SWDS
  1134. }
  1135. //-----------------------------------------------------------------------------
  1136. // Purpose: Plays a video until the video completes or ESC is pressed
  1137. // Input : *filename - Name of the file (relative to the filesystem)
  1138. //-----------------------------------------------------------------------------
  1139. void CGame::PlayVideoAndWait( const char *filename, bool bNeedHealthWarning )
  1140. {
  1141. // do we have a filename and a video system, and not on a console?
  1142. if ( !filename || !filename[0] || g_pVideo == NULL )
  1143. return;
  1144. // is it the valve logo file?
  1145. bool bIsValveLogo = ( Q_strstr( filename, "valve.") != NULL );
  1146. //Chinese health messages appears for 11 seconds, so we force a minimum delay time for those
  1147. float forcedMinTime = ( bIsValveLogo && bNeedHealthWarning ) ? 11.0f : -1.0f;
  1148. #if defined( WIN32 ) && !defined ( _X360 ) && !defined( USE_SDL )
  1149. // Black out the back of the screen once at the beginning of each video (since we're not scaling to fit)
  1150. HDC dc = ::GetDC( m_hWindow );
  1151. RECT rect;
  1152. rect.top = 0;
  1153. rect.bottom = m_height;
  1154. rect.left = 0;
  1155. rect.right = m_width;
  1156. HBRUSH hBlackBrush = (HBRUSH) ::GetStockObject( BLACK_BRUSH );
  1157. ::SetViewportOrgEx( dc, 0, 0, NULL );
  1158. ::FillRect( dc, &rect, hBlackBrush );
  1159. ::ReleaseDC( (HWND) GetMainWindow(), dc );
  1160. #else
  1161. // need OS specific way to clear screen
  1162. #endif
  1163. VideoResult_t status = g_pVideo->PlayVideoFileFullScreen( filename, "GAME", GetMainWindowPlatformSpecificHandle (),
  1164. m_width, m_height, m_iDesktopWidth, m_iDesktopHeight, videomode->IsWindowedMode(),
  1165. forcedMinTime, VideoPlaybackFlags::DEFAULT_FULLSCREEN_OPTIONS | VideoPlaybackFlags::FILL_WINDOW );
  1166. // Everything ok?
  1167. if ( status == VideoResult::SUCCESS )
  1168. {
  1169. return;
  1170. }
  1171. // We don't worry if it could not find something to could play
  1172. if ( status == VideoResult::VIDEO_FILE_NOT_FOUND )
  1173. {
  1174. return;
  1175. }
  1176. // Debug Builds, we want an error looked at by a developer, Release builds just send a message to the spew
  1177. #ifdef _DEBUG
  1178. Error( "Error %d occurred attempting to play video file %s\n", (int) status, filename );
  1179. #else
  1180. Msg( "Error %d occurred attempting to play video file %s\n", (int) status, filename );
  1181. #endif
  1182. }
  1183. //-----------------------------------------------------------------------------
  1184. // Purpose: Constructor
  1185. //-----------------------------------------------------------------------------
  1186. CGame::CGame()
  1187. {
  1188. #if defined( USE_SDL )
  1189. m_pSDLWindow = 0;
  1190. #endif
  1191. #if defined( WIN32 )
  1192. #if !defined( USE_SDL )
  1193. unicode = NULL;
  1194. m_hUnicodeModule = NULL;
  1195. m_hInstance = 0;
  1196. m_ChainedWindowProc = NULL;
  1197. #endif
  1198. m_hWindow = 0;
  1199. #endif
  1200. m_x = m_y = 0;
  1201. m_width = m_height = 0;
  1202. m_bActiveApp = false;
  1203. m_bCanPostActivateEvents = true;
  1204. m_iDesktopWidth = 0;
  1205. m_iDesktopHeight = 0;
  1206. m_iDesktopRefreshRate = 0;
  1207. }
  1208. //-----------------------------------------------------------------------------
  1209. // Purpose: Destructor
  1210. //-----------------------------------------------------------------------------
  1211. CGame::~CGame()
  1212. {
  1213. }
  1214. //-----------------------------------------------------------------------------
  1215. // Purpose:
  1216. //-----------------------------------------------------------------------------
  1217. bool CGame::Init( void *pvInstance )
  1218. {
  1219. m_bExternallySuppliedWindow = false;
  1220. #if defined( WIN32 ) && !defined( USE_SDL )
  1221. OSVERSIONINFO vinfo;
  1222. vinfo.dwOSVersionInfoSize = sizeof(vinfo);
  1223. if ( !GetVersionEx( &vinfo ) )
  1224. {
  1225. return false;
  1226. }
  1227. if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32s )
  1228. {
  1229. return false;
  1230. }
  1231. m_hInstance = (HINSTANCE)pvInstance;
  1232. #endif
  1233. return true;
  1234. }
  1235. bool CGame::Shutdown( void )
  1236. {
  1237. #if defined( WIN32 ) && !defined( USE_SDL )
  1238. m_hInstance = 0;
  1239. #endif
  1240. return true;
  1241. }
  1242. bool CGame::LoadUnicode( void )
  1243. {
  1244. #ifdef WIN32
  1245. m_hUnicodeModule = Sys_LoadModule( "unicode" );
  1246. if ( !m_hUnicodeModule )
  1247. {
  1248. Error( "Unable to load unicode.dll" );
  1249. return false;
  1250. }
  1251. CreateInterfaceFn factory = Sys_GetFactory( m_hUnicodeModule );
  1252. if ( !factory )
  1253. {
  1254. Error( "Unable to get factory from unicode.dll" );
  1255. return false;
  1256. }
  1257. unicode = ( IUnicodeWindows * )factory( VENGINE_UNICODEINTERFACE_VERSION, NULL );
  1258. if ( !unicode )
  1259. {
  1260. Error( "Unable to load interface '%s' from unicode.dll", VENGINE_UNICODEINTERFACE_VERSION );
  1261. return false;
  1262. }
  1263. #endif
  1264. return true;
  1265. }
  1266. void CGame::UnloadUnicode()
  1267. {
  1268. #ifdef WIN32
  1269. unicode = NULL;
  1270. if ( m_hUnicodeModule )
  1271. {
  1272. Sys_UnloadModule( m_hUnicodeModule );
  1273. m_hUnicodeModule = NULL;
  1274. }
  1275. #endif
  1276. }
  1277. void *CGame::GetMainWindow( void )
  1278. {
  1279. #ifdef USE_SDL
  1280. return (void*)m_pSDLWindow;
  1281. #else
  1282. return GetMainWindowPlatformSpecificHandle();
  1283. #endif
  1284. }
  1285. void *CGame::GetMainDeviceWindow( void )
  1286. {
  1287. #if defined( DX_TO_GL_ABSTRACTION ) && defined( USE_SDL )
  1288. return (void*)m_pSDLWindow;
  1289. #else
  1290. return (void*)m_hWindow;
  1291. #endif
  1292. }
  1293. void *CGame::GetMainWindowPlatformSpecificHandle( void )
  1294. {
  1295. #ifdef WIN32
  1296. return (void*)m_hWindow;
  1297. #else
  1298. SDL_SysWMinfo pInfo;
  1299. SDL_VERSION( &pInfo.version );
  1300. if ( !SDL_GetWindowWMInfo( (SDL_Window*)m_pSDLWindow, &pInfo ) )
  1301. {
  1302. Error( "Fatal Error: Unable to get window info from SDL." );
  1303. return NULL;
  1304. }
  1305. #ifdef OSX
  1306. id nsWindow = (id)pInfo.info.cocoa.window;
  1307. SEL selector = sel_registerName("windowRef");
  1308. id windowRef = objc_msgSend( nsWindow, selector );
  1309. return windowRef;
  1310. #else
  1311. // Not used on Linux.
  1312. return NULL;
  1313. #endif
  1314. #endif // !WIN32
  1315. }
  1316. void** CGame::GetMainWindowAddress( void )
  1317. {
  1318. #ifdef WIN32
  1319. return (void**)&m_hWindow;
  1320. #else
  1321. return NULL;
  1322. #endif
  1323. }
  1324. void CGame::GetDesktopInfo( int &width, int &height, int &refreshrate )
  1325. {
  1326. #if defined( USE_SDL )
  1327. width = 640;
  1328. height = 480;
  1329. refreshrate = 0;
  1330. // Go through all the displays and return the size of the largest.
  1331. for( int i = 0; i < SDL_GetNumVideoDisplays(); i++ )
  1332. {
  1333. SDL_Rect rect;
  1334. if ( !SDL_GetDisplayBounds( i, &rect ) )
  1335. {
  1336. if ( ( rect.w > width ) || ( ( rect.w == width ) && ( rect.h > height ) ) )
  1337. {
  1338. width = rect.w;
  1339. height = rect.h;
  1340. }
  1341. }
  1342. }
  1343. #else
  1344. // order of initialization means that this might get called early. In that case go ahead and grab the current
  1345. // screen window and setup based on that.
  1346. // we need to do this when initializing the base list of video modes, for example
  1347. if ( m_iDesktopWidth == 0 )
  1348. {
  1349. HDC dc = ::GetDC( NULL );
  1350. width = ::GetDeviceCaps(dc, HORZRES);
  1351. height = ::GetDeviceCaps(dc, VERTRES);
  1352. refreshrate = ::GetDeviceCaps(dc, VREFRESH);
  1353. ::ReleaseDC( NULL, dc );
  1354. return;
  1355. }
  1356. width = m_iDesktopWidth;
  1357. height = m_iDesktopHeight;
  1358. refreshrate = m_iDesktopRefreshRate;
  1359. #endif
  1360. }
  1361. void CGame::UpdateDesktopInformation( )
  1362. {
  1363. #if defined( USE_SDL )
  1364. // Get the size of the display we will be displayed fullscreen on.
  1365. static ConVarRef sdl_displayindex( "sdl_displayindex" );
  1366. int displayIndex = sdl_displayindex.IsValid() ? sdl_displayindex.GetInt() : 0;
  1367. SDL_DisplayMode mode;
  1368. SDL_GetDesktopDisplayMode( displayIndex, &mode );
  1369. m_iDesktopWidth = mode.w;
  1370. m_iDesktopHeight = mode.h;
  1371. m_iDesktopRefreshRate = mode.refresh_rate;
  1372. #else
  1373. HDC dc = ::GetDC( m_hWindow );
  1374. m_iDesktopWidth = ::GetDeviceCaps(dc, HORZRES);
  1375. m_iDesktopHeight = ::GetDeviceCaps(dc, VERTRES);
  1376. m_iDesktopRefreshRate = ::GetDeviceCaps(dc, VREFRESH);
  1377. ::ReleaseDC( m_hWindow, dc );
  1378. #endif
  1379. }
  1380. #ifdef WIN32
  1381. void CGame::UpdateDesktopInformation( WPARAM wParam, LPARAM lParam )
  1382. {
  1383. m_iDesktopWidth = LOWORD( lParam );
  1384. m_iDesktopHeight = HIWORD( lParam );
  1385. }
  1386. #endif
  1387. #ifndef USE_SDL
  1388. void CGame::SetMainWindow( HWND window )
  1389. {
  1390. m_hWindow = window;
  1391. // update our desktop info (since the results will change if we are going to fullscreen mode)
  1392. if ( !m_iDesktopWidth || !m_iDesktopHeight )
  1393. {
  1394. UpdateDesktopInformation();
  1395. }
  1396. }
  1397. #else
  1398. void CGame::SetMainWindow( SDL_Window* window )
  1399. {
  1400. #if defined( WIN32 )
  1401. // For D3D, we need to access the underlying HWND of the SDL_Window.
  1402. // We also can't do this in GetMainDeviceWindow and just use that, because for some reason
  1403. // people use GetMainWindowAddress and store that pointer to our member.
  1404. SDL_SysWMinfo pInfo;
  1405. SDL_VERSION( &pInfo.version );
  1406. if ( !SDL_GetWindowWMInfo( (SDL_Window*)g_pLauncherMgr->GetWindowRef(), &pInfo ) )
  1407. {
  1408. Error( "Fatal Error: Unable to get window info from SDL." );
  1409. return;
  1410. }
  1411. m_hWindow = pInfo.info.win.window;
  1412. #endif
  1413. m_pSDLWindow = window;
  1414. // update our desktop info (since the results will change if we are going to fullscreen mode)
  1415. if ( !m_iDesktopWidth || !m_iDesktopHeight )
  1416. {
  1417. UpdateDesktopInformation();
  1418. }
  1419. }
  1420. #endif
  1421. void CGame::SetWindowXY( int x, int y )
  1422. {
  1423. m_x = x;
  1424. m_y = y;
  1425. }
  1426. void CGame::SetWindowSize( int w, int h )
  1427. {
  1428. m_width = w;
  1429. m_height = h;
  1430. }
  1431. void CGame::GetWindowRect( int *x, int *y, int *w, int *h )
  1432. {
  1433. if ( x )
  1434. {
  1435. *x = m_x;
  1436. }
  1437. if ( y )
  1438. {
  1439. *y = m_y;
  1440. }
  1441. if ( w )
  1442. {
  1443. *w = m_width;
  1444. }
  1445. if ( h )
  1446. {
  1447. *h = m_height;
  1448. }
  1449. }
  1450. bool CGame::IsActiveApp( void )
  1451. {
  1452. return m_bActiveApp;
  1453. }
  1454. void CGame::SetCanPostActivateEvents( bool bEnabled )
  1455. {
  1456. m_bCanPostActivateEvents = bEnabled;
  1457. }
  1458. bool CGame::CanPostActivateEvents()
  1459. {
  1460. return m_bCanPostActivateEvents;
  1461. }
  1462. void CGame::SetActiveApp( bool active )
  1463. {
  1464. m_bActiveApp = active;
  1465. }