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.

2078 lines
54 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: An application framework
  4. //
  5. //=============================================================================//
  6. #include "SDL.h"
  7. #include "SDL_opengl.h"
  8. #include "appframework/ilaunchermgr.h"
  9. #include "inputsystem/ButtonCode.h"
  10. #include "togl/rendermechanism.h"
  11. #include "tier0/vprof_telemetry.h"
  12. #include "tier0/icommandline.h"
  13. #include "tier1/utllinkedlist.h"
  14. #include "tier1/convar.h"
  15. // NOTE: This has to be the last file included! (turned off below, since this is included like a header)
  16. #include "tier0/memdbgon.h"
  17. #ifdef GLMPRINTF
  18. #undef GLMPRINTF
  19. #endif
  20. #if GLMDEBUG
  21. #define GLMPRINTF(args) printf args
  22. #else
  23. #define GLMPRINTF(args)
  24. #endif
  25. #ifdef OSX
  26. ConVar osx_rawinput_set_one_time( "osx_rawinput_set_one_time", "0", FCVAR_ARCHIVE|FCVAR_HIDDEN, "");
  27. #endif
  28. ConVar gl_blit_halfx( "gl_blit_halfx", "0" );
  29. ConVar gl_blit_halfy( "gl_blit_halfy", "0" );
  30. ConVar gl_swapdebug( "gl_swapdebug", "0");
  31. ConVar gl_swaplimit( "gl_swaplimit", "0");
  32. ConVar gl_swapinterval( "gl_swapinterval", "0");
  33. ConVar gl_swaplimit_mt( "gl_swaplimit_mt", "3");
  34. ConVar gl_disable_forced_vsync( "gl_disable_forced_vsync", "0" );
  35. ConVar gl_swaptear( "gl_swaptear", "1" );
  36. ConVar gl_finish( "gl_finish", "0" );
  37. ConVar sdl_double_click_size( "sdl_double_click_size", "2" );
  38. ConVar sdl_double_click_time( "sdl_double_click_time", "400" );
  39. #if defined( DX_TO_GL_ABSTRACTION )
  40. COpenGLEntryPoints *gGL = NULL;
  41. #endif
  42. const int kBogusSwapInterval = INT_MAX;
  43. /*
  44. From Ryan Gordon:
  45. SDL's FULLSCREEN_DESKTOP mode on the mac now
  46. puts the game in its own fullscreen Space on OS X 10.7 and later, as of
  47. SDL 2.0.3, I think.
  48. There were several benefits to this, but it's possible (likely even)
  49. that Apple unhelpfully clamps you to vsync in this scenario, which would
  50. explain the 60fps max.
  51. There are a few options:
  52. - SDL_WINDOW_FULLSCREEN mode will not use this new magic (only
  53. SDL_WINDOW_FULLSCREEN_DESKTOP), but that brings other problems and I
  54. wouldn't recommend a drastic change like that.
  55. - You can force the old behavior with this hint:
  56. SDL_SetHint(SDL_HINT_VIDEO_MAC_FULLSCREEN_SPACES, "1");
  57. ...which must be called before SDL_Init(SDL_INIT_VIDEO) at the moment
  58. (that can be changed if you'd like to add a menu option that wants to
  59. toggle this setting at runtime, though). One can also force this with an
  60. environment variable, for what that's worth to most Mac users:
  61. export SDL_VIDEO_MAC_FULLSCREEN_SPACES=0
  62. - I haven't tried it, but maybe one can force vsync off with
  63. SDL_GL_SetSwapInterval(), and it's just that the default is different
  64. for Fullscreen Spaces? Simplest solution if it works, but I don't know.
  65. You can certainly just force it off to put the game back to the way it
  66. worked before, but the user experience is much nicer when you can just
  67. slide between the game and your desktop, etc. Discounting the clamp to
  68. Vsync, we found that a Fullscreen Space got a slightly faster framerate,
  69. too (plus it's how Apple "wants" you to do fullscreen at this point, etc).
  70. And of course, this is Mac-specific: this is in the Cocoa backend, and
  71. thus doesn't affect Windows or Linux, etc.
  72. */
  73. static void DebugPrintf( const char *pMsg, ... )
  74. {
  75. va_list args;
  76. va_start( args, pMsg );
  77. char buf[2048];
  78. V_vsnprintf( buf, sizeof( buf ), pMsg, args );
  79. va_end( args );
  80. Plat_DebugString( buf );
  81. }
  82. // #define SDLAPP_DEBUG
  83. #ifdef SDLAPP_DEBUG
  84. class LinuxAppFuncLogger
  85. {
  86. public:
  87. LinuxAppFuncLogger( const char *funcName ) : m_funcName( funcName )
  88. {
  89. printf( ">%s\n", m_funcName );
  90. };
  91. LinuxAppFuncLogger( const char *funcName, char *fmt, ... )
  92. {
  93. m_funcName = funcName;
  94. va_list vargs;
  95. va_start(vargs, fmt);
  96. vprintf( fmt, vargs );
  97. va_end( vargs );
  98. }
  99. ~LinuxAppFuncLogger( )
  100. {
  101. printf( "<%s\n", m_funcName );
  102. };
  103. const char *m_funcName;
  104. };
  105. #define SDLAPP_FUNC LinuxAppFuncLogger _logger_( __FUNCTION__ )
  106. #else
  107. #define SDLAPP_FUNC
  108. #endif
  109. #if defined( DX_TO_GL_ABSTRACTION )
  110. void CheckGLError( int line )
  111. {
  112. SDLAPP_FUNC;
  113. // Don't check this in enabled! glGetError() is extremely slow with threaded drivers.
  114. return;
  115. //char errbuf[1024];
  116. //borrowed from GLMCheckError.. slightly different
  117. GLenum errorcode = (GLenum)gGL->glGetError();
  118. //GLenum errorcode2 = 0;
  119. if ( errorcode != GL_NO_ERROR )
  120. {
  121. const char *decodedStr = GLMDecode( eGL_ERROR, errorcode );
  122. printf( "\n(%d) GL Error %08x = '%s'", line, errorcode, decodedStr );
  123. }
  124. }
  125. #endif
  126. //-----------------------------------------------------------------------------
  127. #if !defined( DEDICATED )
  128. void *VoidFnPtrLookup_GlMgr(const char *fn, bool &okay, const bool bRequired, void *fallback)
  129. {
  130. void *retval = NULL;
  131. if ((!okay) && (!bRequired)) // always look up if required (so we get a complete list of crucial missing symbols).
  132. return NULL;
  133. // The SDL path would work on all these platforms, if we were using SDL there, too...
  134. #if defined( USE_SDL )
  135. // SDL does the right thing, so we never need to use tier0 in this case.
  136. retval = SDL_GL_GetProcAddress(fn);
  137. //printf("CDynamicFunctionOpenGL: SDL_GL_GetProcAddress(\"%s\") returned %p\n", fn, retval);
  138. if ((retval == NULL) && (fallback != NULL))
  139. {
  140. //printf("CDynamicFunctionOpenGL: Using fallback %p for \"%s\"\n", fallback, fn);
  141. retval = fallback;
  142. }
  143. #else
  144. #error Unimplemented
  145. #endif
  146. // Note that a non-NULL response doesn't mean it's safe to call the function!
  147. // You always have to check that the extension is supported;
  148. // an implementation MAY return NULL in this case, but it doesn't have to (and doesn't, with the DRI drivers).
  149. okay = (okay && (retval != NULL));
  150. if (bRequired && !okay)
  151. {
  152. // We can't continue execution, because one or more GL function pointers will be NULL.
  153. Error( "Could not find required OpenGL entry point '%s'! Either your video card is unsupported, or your OpenGL driver needs to be updated.\n", fn);
  154. }
  155. return retval;
  156. }
  157. class CSDLMgr : public ILauncherMgr
  158. {
  159. public:
  160. CSDLMgr();
  161. // ILauncherMgr impls.
  162. public:
  163. virtual bool Connect( CreateInterfaceFn factory );
  164. virtual void Disconnect();
  165. virtual void *QueryInterface( const char *pInterfaceName );
  166. // Init, shutdown
  167. virtual InitReturnVal_t Init();
  168. virtual void Shutdown();
  169. virtual bool CreateGameWindow( const char *pTitle, bool bWindowed, int width, int height );
  170. virtual void IncWindowRefCount();
  171. virtual void DecWindowRefCount();
  172. // Get the next N events. The function returns the number of events that were filled into your array.
  173. virtual int GetEvents( CCocoaEvent *pEvents, int nMaxEventsToReturn, bool debugEvents = false );
  174. #ifdef LINUX
  175. virtual int PeekAndRemoveKeyboardEvents( bool *pbEsc, bool *pbReturn, bool *pbSpace, bool debugEvent = false );
  176. #endif
  177. // Set the mouse cursor position.
  178. virtual void SetCursorPosition( int x, int y );
  179. virtual void *GetWindowRef() { return (void *)m_Window; }
  180. virtual void SetWindowFullScreen( bool bFullScreen, int nWidth, int nHeight );
  181. virtual bool IsWindowFullScreen() { return m_bFullScreen; }
  182. virtual void MoveWindow( int x, int y );
  183. virtual void SizeWindow( int width, int tall );
  184. virtual void PumpWindowsMessageLoop();
  185. virtual void DestroyGameWindow();
  186. virtual void SetApplicationIcon( const char *pchAppIconFile );
  187. virtual void GetMouseDelta( int &x, int &y, bool bIgnoreNextMouseDelta = false );
  188. virtual void GetNativeDisplayInfo( int nDisplay, uint &nWidth, uint &nHeight, uint &nRefreshHz ); // Retrieve the size of the monitor (desktop)
  189. virtual void RenderedSize( uint &width, uint &height, bool set ); // either set or retrieve rendered size value (from dxabstract)
  190. virtual void DisplayedSize( uint &width, uint &height ); // query backbuffer size (window size whether FS or windowed)
  191. #if defined( DX_TO_GL_ABSTRACTION )
  192. virtual void GetDesiredPixelFormatAttribsAndRendererInfo( uint **ptrOut, uint *countOut, GLMRendererInfoFields *rendInfoOut );
  193. virtual PseudoGLContextPtr GetMainContext();
  194. // Get the NSGLContext for a window's main view - note this is the carbon windowref as an argument
  195. virtual PseudoGLContextPtr GetGLContextForWindow( void* windowref ) { return (PseudoGLContextPtr)m_GLContext; }
  196. virtual PseudoGLContextPtr CreateExtraContext();
  197. virtual void DeleteContext( PseudoGLContextPtr hContext );
  198. virtual bool MakeContextCurrent( PseudoGLContextPtr hContext );
  199. virtual GLMDisplayDB *GetDisplayDB( void );
  200. virtual void ShowPixels( CShowPixelsParams *params );
  201. #endif
  202. virtual void GetStackCrawl( CStackCrawlParams *params );
  203. virtual void WaitUntilUserInput( int msSleepTime );
  204. // Post an event to the input event queue.
  205. // if debugEvent is true, post it to the debug event queue.
  206. void PostEvent( const CCocoaEvent &theEvent, bool debugEvent=false );
  207. // ask if an event is debug flavor or not.
  208. bool IsDebugEvent( CCocoaEvent& event );
  209. virtual void SetMouseVisible( bool bState );
  210. virtual void SetMouseCursor( SDL_Cursor *hCursor );
  211. virtual void SetForbidMouseGrab( bool bForbidMouseGrab ) { m_bForbidMouseGrab = bForbidMouseGrab; }
  212. virtual void OnFrameRendered();
  213. virtual void SetGammaRamp( const uint16 *pRed, const uint16 *pGreen, const uint16 *pBlue );
  214. virtual double GetPrevGLSwapWindowTime() { return m_flPrevGLSwapWindowTime; }
  215. // Called to create a game window that will be hidden, designed for
  216. // getting an OpenGL context going so we can begin initializing things.
  217. bool CreateHiddenGameWindow( const char *pTitle, int width, int height );
  218. private:
  219. void handleKeyInput( const SDL_Event &event );
  220. #if defined( DX_TO_GL_ABSTRACTION )
  221. SDL_GLContext m_GLContext;
  222. GLuint m_readFBO;
  223. GLMDisplayDB *m_displayDB;
  224. #endif
  225. #if defined( OSX )
  226. // bool m_leopard; // true if <10.6.3 and we have to do extra work for fullscreen handling
  227. bool m_force_vsync; // true if 10.6.4 + bad NV driver
  228. #endif
  229. uint m_nWindowRefCount;
  230. SDL_Window *m_Window;
  231. bool m_bCursorVisible;
  232. bool m_bSetMouseVisibleCalled;
  233. SDL_Cursor *m_hCursor;
  234. bool m_bSetMouseCursorCalled;
  235. bool m_bHasFocus;
  236. bool m_bFullScreen;
  237. bool m_SizeWindowFullScreenState; // fullscreen state when SizeWindow() was called.
  238. bool m_bForbidMouseGrab;
  239. bool m_WindowShownAndRaised;
  240. int m_nMouseXDelta;
  241. int m_nMouseYDelta;
  242. int m_ScreenWidth;
  243. int m_ScreenHeight;
  244. int m_renderedWidth;
  245. int m_rendererHeight;
  246. int m_WindowWidth;
  247. int m_WindowHeight;
  248. bool m_bExpectSyntheticMouseMotion;
  249. int m_nMouseTargetX;
  250. int m_nMouseTargetY;
  251. int m_nWarpDelta;
  252. bool m_bRawInput;
  253. int m_lastKnownSwapInterval; // -1 if unknown, 0/1 otherwise
  254. int m_lastKnownSwapLimit; // -1 if unknown, 0/1 otherwise
  255. int m_pixelFormatAttribs[32];
  256. int m_pixelFormatAttribCount;
  257. float m_flMouseXScale;
  258. float m_flMouseYScale;
  259. // !!! FIXME: can we rename these from "Cocoa"?
  260. CThreadMutex m_CocoaEventsMutex; // use for either queue below
  261. CUtlLinkedList<CCocoaEvent,int> m_CocoaEvents;
  262. CUtlLinkedList<CCocoaEvent,int> m_DebugEvents; // intercepted keys which wil be passed over to GLM
  263. uint m_keyModifierMask;
  264. uint32_t m_keyModifiers;
  265. uint32_t m_mouseButtons;
  266. bool m_bGotMouseButtonDown;
  267. Uint32 m_MouseButtonDownTimeStamp;
  268. int m_MouseButtonDownX;
  269. int m_MouseButtonDownY;
  270. double m_flPrevGLSwapWindowTime;
  271. };
  272. ILauncherMgr *g_pLauncherMgr = NULL;
  273. void* CreateSDLMgr()
  274. {
  275. if ( g_pLauncherMgr == NULL )
  276. {
  277. g_pLauncherMgr = new CSDLMgr();
  278. }
  279. return (void *)g_pLauncherMgr;
  280. }
  281. // Display index where we are currently fullscreen on (or -1).
  282. ConVar sdl_displayindex_fullscreen( "sdl_displayindex_fullscreen", "-1", FCVAR_HIDDEN );
  283. // Display index to show window on.
  284. static bool g_bSDLDisplayindexSet = false;
  285. static void sdl_displayindex_changed( IConVar *pConVar, const char *pOldString, float flOldValue );
  286. ConVar sdl_displayindex( "sdl_displayindex", "0", FCVAR_HIDDEN, "SDL fullscreen display index.", sdl_displayindex_changed );
  287. static void sdl_displayindex_changed( IConVar *pConVar, const char *pOldString, float flOldValue )
  288. {
  289. int NumVideoDisplays = SDL_GetNumVideoDisplays();
  290. if ( ( sdl_displayindex.GetInt() < 0 ) || ( sdl_displayindex.GetInt() >= NumVideoDisplays ) )
  291. {
  292. sdl_displayindex.SetValue( 0 );
  293. }
  294. g_bSDLDisplayindexSet = true;
  295. }
  296. // Return display index of largest SDL display ( plus width & height ).
  297. static int GetLargestDisplaySize( int& Width, int& Height )
  298. {
  299. int nDisplay = 0;
  300. Width = 640;
  301. Height = 480;
  302. for ( int i = 0; i < SDL_GetNumVideoDisplays(); i++ )
  303. {
  304. SDL_Rect rect = { 0, 0, 0, 0 };
  305. SDL_GetDisplayBounds( i, &rect );
  306. if ( ( rect.w > Width ) || ( ( rect.w == Width ) && ( rect.h > Height ) ) )
  307. {
  308. Width = rect.w;
  309. Height = rect.h;
  310. nDisplay = i;
  311. }
  312. }
  313. return nDisplay;
  314. }
  315. CON_COMMAND( grab_window, "grab/ungrab window." )
  316. {
  317. if ( g_pLauncherMgr && g_pLauncherMgr->GetWindowRef() )
  318. {
  319. SDL_bool bGrab;
  320. SDL_Window *pWindow = ( SDL_Window * )g_pLauncherMgr->GetWindowRef();
  321. if ( args.ArgC() >= 2 )
  322. {
  323. bGrab = ( args[ 1 ][ 0 ] == '1' ) ? SDL_TRUE : SDL_FALSE;
  324. }
  325. else
  326. {
  327. bGrab = SDL_GetWindowGrab( pWindow ) ? SDL_FALSE : SDL_TRUE;
  328. }
  329. g_pLauncherMgr->SetForbidMouseGrab( !bGrab );
  330. if ( bGrab != SDL_GetWindowGrab( pWindow ) )
  331. {
  332. Msg( "SetWindowGrab( %s )\n", bGrab ? "true" : "false" );
  333. SDL_SetWindowGrab( pWindow, bGrab );
  334. // force non-fullscreen windows to the foreground if grabbed, so you can't
  335. // get your mouse locked to something in the background.
  336. if ( bGrab && !g_pLauncherMgr->IsWindowFullScreen() )
  337. {
  338. SDL_RaiseWindow( pWindow );
  339. }
  340. }
  341. }
  342. }
  343. CSDLMgr::CSDLMgr()
  344. {
  345. m_Window = NULL;
  346. Init();
  347. }
  348. InitReturnVal_t CSDLMgr::Init()
  349. {
  350. SDLAPP_FUNC;
  351. if (m_Window != NULL)
  352. return INIT_OK; // already initialized.
  353. if (!SDL_WasInit(SDL_INIT_VIDEO))
  354. {
  355. if (SDL_Init(SDL_INIT_VIDEO) == -1)
  356. Error( "SDL_Init(SDL_INIT_VIDEO) failed: %s", SDL_GetError() );
  357. #if defined( DX_TO_GL_ABSTRACTION )
  358. if ( CommandLine()->FindParm( "-gl_debug" ) )
  359. {
  360. SDL_GL_SetAttribute( SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG );
  361. }
  362. if (SDL_GL_LoadLibrary(NULL) == -1)
  363. Error( "SDL_GL_LoadLibrary(NULL) failed: %s", SDL_GetError() );
  364. #endif
  365. }
  366. fprintf(stderr, "SDL video target is '%s'\n", SDL_GetCurrentVideoDriver());
  367. Msg("SDL video target is '%s'\n", SDL_GetCurrentVideoDriver());
  368. m_bForbidMouseGrab = true;
  369. if ( !CommandLine()->FindParm("-nomousegrab") && CommandLine()->FindParm("-mousegrab") )
  370. {
  371. m_bForbidMouseGrab = false;
  372. }
  373. m_WindowShownAndRaised = false;
  374. m_bCursorVisible = true;
  375. m_bSetMouseVisibleCalled = false;
  376. m_hCursor = NULL;
  377. m_bSetMouseCursorCalled = false;
  378. m_bHasFocus = true;
  379. m_keyModifiers = 0;
  380. m_keyModifierMask = 0;
  381. m_mouseButtons = 0;
  382. #if defined( DX_TO_GL_ABSTRACTION )
  383. m_GLContext = NULL;
  384. m_readFBO = 0;
  385. m_displayDB = NULL;
  386. #endif
  387. m_nWindowRefCount = 0;
  388. m_Window = NULL;
  389. m_bFullScreen = false;
  390. m_SizeWindowFullScreenState = false;
  391. m_nMouseXDelta = 0;
  392. m_nMouseYDelta = 0;
  393. m_ScreenWidth = 0;
  394. m_ScreenHeight = 0;
  395. m_renderedWidth = 0;
  396. m_rendererHeight = 0;
  397. m_WindowWidth = 0;
  398. m_WindowHeight = 0;
  399. m_pixelFormatAttribCount = 0;
  400. m_lastKnownSwapInterval = kBogusSwapInterval;
  401. m_lastKnownSwapLimit = -1;
  402. m_flMouseXScale = 1.0f;
  403. m_flMouseYScale = 1.0f;
  404. m_bGotMouseButtonDown = false;
  405. m_MouseButtonDownTimeStamp = 0;
  406. m_MouseButtonDownX = 0;
  407. m_MouseButtonDownY = 0;
  408. m_bExpectSyntheticMouseMotion = false;
  409. m_nMouseTargetX = 0;
  410. m_nMouseTargetY = 0;
  411. m_nWarpDelta = 0;
  412. m_bRawInput = false;
  413. m_flPrevGLSwapWindowTime = 0.0f;
  414. memset(m_pixelFormatAttribs, '\0', sizeof (m_pixelFormatAttribs));
  415. int *attCursor = m_pixelFormatAttribs;
  416. #define SET_GL_ATTR(key,value) \
  417. *(attCursor++) = (int) (key); \
  418. *(attCursor++) = (int) (value);
  419. SET_GL_ATTR(SDL_GL_RED_SIZE, 8);
  420. SET_GL_ATTR(SDL_GL_GREEN_SIZE, 8);
  421. SET_GL_ATTR(SDL_GL_BLUE_SIZE, 8);
  422. SET_GL_ATTR(SDL_GL_ALPHA_SIZE, 8);
  423. SET_GL_ATTR(SDL_GL_DOUBLEBUFFER, 1);
  424. #ifdef OSX
  425. SET_GL_ATTR(SDL_GL_DEPTH_SIZE, 0);
  426. #else
  427. SET_GL_ATTR(SDL_GL_DEPTH_SIZE, 24);
  428. SET_GL_ATTR(SDL_GL_STENCIL_SIZE, 8);
  429. #endif
  430. SET_GL_ATTR(SDL_GL_ACCELERATED_VISUAL, 1);
  431. #undef SET_GL_ATTR
  432. m_pixelFormatAttribCount = (attCursor - &m_pixelFormatAttribs[0]) / 2;
  433. // we need a GL context before we dig down further, since we're calling
  434. // GL entry points, but the game hasn't made a window yet. So it's time
  435. // to make a window! We make a 640x480 one here, and later, when asked
  436. // to really actually make a window, we just resize the one we built here.
  437. if ( !CreateHiddenGameWindow( "", 640, 480 ) )
  438. Error( "CreateGameWindow failed" );
  439. SDL_HideWindow( m_Window );
  440. return INIT_OK;
  441. }
  442. bool CSDLMgr::Connect( CreateInterfaceFn factory )
  443. {
  444. SDLAPP_FUNC;
  445. return true;
  446. }
  447. void CSDLMgr::Disconnect()
  448. {
  449. SDLAPP_FUNC;
  450. }
  451. void *CSDLMgr::QueryInterface( const char *pInterfaceName )
  452. {
  453. SDLAPP_FUNC;
  454. if ( !Q_stricmp( pInterfaceName, SDLMGR_INTERFACE_VERSION ) )
  455. return this;
  456. return NULL;
  457. }
  458. void CSDLMgr::Shutdown()
  459. {
  460. SDLAPP_FUNC;
  461. if (gGL && m_readFBO)
  462. gGL->glDeleteFramebuffersEXT(1, &m_readFBO);
  463. m_readFBO = 0;
  464. if ( m_Window )
  465. {
  466. // Slam down the window refcount to 1 to guarantee the main GL context and window are killed.
  467. m_nWindowRefCount = 1;
  468. DestroyGameWindow();
  469. }
  470. SDL_GL_UnloadLibrary();
  471. SDL_QuitSubSystem(SDL_INIT_VIDEO);
  472. }
  473. bool CSDLMgr::CreateGameWindow( const char *pTitle, bool bWindowed, int width, int height )
  474. {
  475. SDLAPP_FUNC;
  476. // CreateGameWindow is being called. The the game initially calls this with width and height == 0.
  477. // But we don't want to show the window until it gets resized to what it should be, so we keep track as to whether
  478. // ShowWindow / RaiseWindow has been called yet in here, and if not we do the SDL_ShowWindow in
  479. // the MoveWindow() function down below.
  480. bool bShowWindow = true;
  481. m_WindowShownAndRaised = false;
  482. if ( ( width <= 0 ) || ( height <= 0 ) )
  483. {
  484. bShowWindow = false;
  485. // Don't mess with current width, height - use current (or sane defaults).
  486. uint defaultWidth = 0;
  487. uint defaultHeight = 0;
  488. uint defaultRefreshHz = 0; // Not used
  489. this->GetNativeDisplayInfo( -1, defaultWidth, defaultHeight, defaultRefreshHz );
  490. if ( 0 == defaultWidth ) defaultWidth = 1024;
  491. if ( 0 == defaultHeight ) defaultHeight = 768;
  492. width = m_WindowWidth ? m_WindowWidth : defaultWidth;
  493. height = m_WindowHeight ? m_WindowHeight : defaultHeight;
  494. }
  495. if ( m_Window )
  496. {
  497. if ( pTitle )
  498. {
  499. SDL_SetWindowTitle( m_Window, pTitle );
  500. }
  501. if ( ( m_bFullScreen != !bWindowed ) ||
  502. ( !bWindowed && ( sdl_displayindex.GetInt() != sdl_displayindex_fullscreen.GetInt() ) ) )
  503. {
  504. SetWindowFullScreen( !bWindowed, width, height );
  505. }
  506. else if ( bShowWindow )
  507. {
  508. SizeWindow( width, height );
  509. }
  510. if ( bShowWindow )
  511. {
  512. SDL_ShowWindow( m_Window );
  513. SDL_RaiseWindow( m_Window );
  514. m_WindowShownAndRaised = true;
  515. }
  516. return true;
  517. }
  518. if ( CreateHiddenGameWindow( pTitle, width, height ) )
  519. {
  520. SDL_ShowWindow( m_Window );
  521. return true;
  522. }
  523. else
  524. {
  525. return false;
  526. }
  527. }
  528. bool CSDLMgr::CreateHiddenGameWindow( const char *pTitle, int width, int height )
  529. {
  530. Assert( !m_Window );
  531. Assert( !m_bFullScreen );
  532. m_bFullScreen = false;
  533. sdl_displayindex_fullscreen.SetValue( -1 );
  534. #if defined( DX_TO_GL_ABSTRACTION )
  535. // Set up GL context...
  536. const int *attrib = m_pixelFormatAttribs;
  537. for (int i = 0; i < m_pixelFormatAttribCount; i++, attrib += 2)
  538. SDL_GL_SetAttribute((SDL_GLattr) attrib[0], attrib[1]);
  539. #endif
  540. // no window yet? Create one now!
  541. m_nWindowRefCount = 1;
  542. int x = SDL_WINDOWPOS_CENTERED;
  543. int y = SDL_WINDOWPOS_CENTERED;
  544. int flags = SDL_WINDOW_HIDDEN;
  545. #if defined( DX_TO_GL_ABSTRACTION )
  546. flags |= SDL_WINDOW_OPENGL;
  547. #endif
  548. m_Window = SDL_CreateWindow( pTitle, x, y, width, height, flags );
  549. if (m_Window == NULL)
  550. Error( "Failed to create SDL window: %s", SDL_GetError() );
  551. SetAssertDialogParent( m_Window );
  552. #ifdef OSX
  553. GLMRendererInfoFields rendererInfo;
  554. GetDisplayDB()->GetRendererInfo( 0, &rendererInfo );
  555. //-----------------------------------------------------------------------------------------
  556. //- enforce minimum system requirements for multiplayer branch (CSS / DOD / TF2) : no GMA950, X3100, or NV G7x.
  557. if (!CommandLine()->FindParm("-glmnosystemcheck")) // escape hatch
  558. {
  559. if ( rendererInfo.m_osComboVersion < 0x0A0607 )
  560. {
  561. Error( "This game requires OS X version 10.6.7 or higher" );
  562. exit(1);
  563. }
  564. // forbidden chipsets
  565. if ( rendererInfo.m_atiR5xx || rendererInfo.m_intel95x || rendererInfo.m_intel3100 || rendererInfo.m_nvG7x )
  566. {
  567. Error( "This game does not support this type of graphics processor" );
  568. exit(1);
  569. }
  570. }
  571. #endif
  572. #if defined( DX_TO_GL_ABSTRACTION )
  573. m_GLContext = SDL_GL_CreateContext(m_Window);
  574. if (m_GLContext == NULL)
  575. Error( "Failed to create GL context: %s", SDL_GetError() );
  576. SDL_GL_MakeCurrent(m_Window, m_GLContext);
  577. // !!! FIXME: note for later...we never delete this context anywhere, I think.
  578. // !!! FIXME: when we do get around to that, don't forget to delete/NULL gGL!
  579. static CDynamicFunctionOpenGL< true, const GLubyte *( APIENTRY *)(GLenum name), const GLubyte * > glGetString("glGetString");
  580. static CDynamicFunctionOpenGL< true, GLvoid ( APIENTRY *)(GLenum pname, GLint *params), GLvoid > glGetIntegerv("glGetIntegerv");
  581. #ifdef DBGFLAG_ASSERT
  582. const char *pszString = ( const char * )glGetString(GL_VENDOR);
  583. pszString = ( const char * )glGetString(GL_RENDERER);
  584. pszString = ( const char * )glGetString(GL_VERSION);
  585. pszString = ( const char * )glGetString(GL_EXTENSIONS);
  586. // If we specified -gl_debug, make sure the extension string is present now.
  587. if ( CommandLine()->FindParm( "-gl_debug" ) )
  588. {
  589. Assert( V_strstr(pszString, "GL_ARB_debug_output") );
  590. }
  591. #endif // DBGFLAG_ASSERT
  592. gGL = GetOpenGLEntryPoints(VoidFnPtrLookup_GlMgr);
  593. // It is now safe to call any base GL entry point that's supplied by gGL.
  594. // You still need to explicitly test for extension entry points, though!
  595. if ( CommandLine()->FindParm( "-gl_dump_strings" ) )
  596. {
  597. DebugPrintf("GL_RENDERER: %s\n", (const char *) gGL->glGetString(GL_RENDERER));
  598. DebugPrintf("GL_VENDOR: %s\n", (const char *) gGL->glGetString(GL_VENDOR));
  599. DebugPrintf("GL_VERSION: %s\n", (const char *) gGL->glGetString(GL_VERSION));
  600. const char *exts = (const char *) gGL->glGetString(GL_EXTENSIONS);
  601. DebugPrintf("GL_EXTENSIONS:%s\n", exts ? "" : NULL);
  602. if (exts)
  603. {
  604. for (const char *ptr = exts; *ptr; ptr++)
  605. DebugPrintf("%c", *ptr == ' ' ? '\n' : *ptr);
  606. DebugPrintf("\n");
  607. }
  608. DebugPrintf("\n");
  609. }
  610. gGL->glGenFramebuffersEXT(1, &m_readFBO);
  611. gGL->glViewport(0, 0, width, height); /* Reset The Current Viewport And Perspective Transformation */
  612. gGL->glScissor(0, 0, width, height); /* Reset The Current Viewport And Perspective Transformation */
  613. // Blank out the initial window, so we're not looking at uninitialized
  614. // video RAM trash until we start proper drawing.
  615. gGL->glClearColor(0,0,0,0);
  616. gGL->glClear(GL_COLOR_BUFFER_BIT);
  617. SDL_GL_SwapWindow(m_Window);
  618. gGL->glClear(GL_COLOR_BUFFER_BIT);
  619. SDL_GL_SwapWindow(m_Window);
  620. gGL->glClear(GL_COLOR_BUFFER_BIT);
  621. SDL_GL_SwapWindow(m_Window);
  622. #endif // DX_TO_GL_ABSTRACTION
  623. m_WindowWidth = width;
  624. m_WindowHeight = height;
  625. // Update mouse warp targets (dependent on window size).
  626. m_nMouseTargetX = m_WindowWidth / 2;
  627. m_nMouseTargetY = m_WindowHeight / 2;
  628. m_nWarpDelta = Max( m_WindowHeight / 3, 200 );
  629. return true;
  630. }
  631. #if defined( DX_TO_GL_ABSTRACTION )
  632. PseudoGLContextPtr CSDLMgr::GetMainContext()
  633. {
  634. SDLAPP_FUNC;
  635. return (PseudoGLContextPtr)m_GLContext;
  636. }
  637. PseudoGLContextPtr CSDLMgr::CreateExtraContext()
  638. {
  639. SDLAPP_FUNC;
  640. const int *attrib = m_pixelFormatAttribs;
  641. for (int i = 0; i < m_pixelFormatAttribCount; i++, attrib += 2)
  642. SDL_GL_SetAttribute((SDL_GLattr) attrib[0], attrib[1]);
  643. return (PseudoGLContextPtr) SDL_GL_CreateContext(m_Window);
  644. }
  645. void CSDLMgr::DeleteContext( PseudoGLContextPtr hContext )
  646. {
  647. SDLAPP_FUNC;
  648. Assert( (SDL_GLContext)hContext != m_GLContext );
  649. // Don't delete the main one.
  650. if ( (SDL_GLContext)hContext != m_GLContext )
  651. {
  652. if ( m_Window )
  653. {
  654. SDL_GL_MakeCurrent(m_Window, hContext);
  655. }
  656. SDL_GL_DeleteContext((SDL_GLContext) hContext);
  657. }
  658. }
  659. bool CSDLMgr::MakeContextCurrent( PseudoGLContextPtr hContext )
  660. {
  661. SDLAPP_FUNC;
  662. // We only ever have one GL context on Linux at the moment, so don't spam these calls.
  663. return SDL_GL_MakeCurrent(m_Window, (SDL_GLContext)hContext ) == 0;
  664. }
  665. #endif // DX_TO_GL_ABSTRACTION
  666. int CSDLMgr::GetEvents( CCocoaEvent *pEvents, int nMaxEventsToReturn, bool debugEvent )
  667. {
  668. SDLAPP_FUNC;
  669. m_CocoaEventsMutex.Lock();
  670. CUtlLinkedList<CCocoaEvent,int> &queue = debugEvent ? m_CocoaEvents : m_DebugEvents;
  671. int nAvailable = queue.Count();
  672. int nToWrite = MIN( nAvailable, nMaxEventsToReturn );
  673. CCocoaEvent *pCurEvent = pEvents;
  674. for ( int i=0; i < nToWrite; i++ )
  675. {
  676. int iHead = queue.Head();
  677. memcpy( pCurEvent, &queue[iHead], sizeof( CCocoaEvent ) );
  678. queue.Remove( iHead );
  679. ++pCurEvent;
  680. }
  681. m_CocoaEventsMutex.Unlock();
  682. return nToWrite;
  683. }
  684. #ifdef LINUX
  685. int CSDLMgr::PeekAndRemoveKeyboardEvents( bool *pbEsc, bool *pbReturn, bool *pbSpace, bool debugEvent )
  686. {
  687. SDLAPP_FUNC;
  688. m_CocoaEventsMutex.Lock();
  689. int nRead = 0;
  690. CUtlLinkedList<CCocoaEvent,int> &queue = debugEvent ? m_CocoaEvents : m_DebugEvents;
  691. int nEvents = queue.Count();
  692. for ( int iEvent=0; iEvent < nEvents; iEvent++ )
  693. {
  694. CCocoaEvent *pEvent = &queue[ iEvent ];
  695. switch( pEvent->m_EventType )
  696. {
  697. case CocoaEvent_KeyDown:
  698. {
  699. switch ( pEvent->m_VirtualKeyCode )
  700. {
  701. case SDL_SCANCODE_ESCAPE:
  702. nRead++;
  703. *pbEsc = true;
  704. pEvent->m_EventType = CocoaEvent_Deleted;
  705. break;
  706. case SDL_SCANCODE_RETURN:
  707. case SDL_SCANCODE_KP_ENTER:
  708. nRead++;
  709. *pbReturn = true;
  710. pEvent->m_EventType = CocoaEvent_Deleted;
  711. break;
  712. case SDL_SCANCODE_SPACE:
  713. nRead++;
  714. *pbSpace = true;
  715. pEvent->m_EventType = CocoaEvent_Deleted;
  716. break;
  717. }
  718. }
  719. }
  720. }
  721. m_CocoaEventsMutex.Unlock();
  722. return nRead;
  723. }
  724. #endif // LINUX
  725. bool CSDLMgr::IsDebugEvent( CCocoaEvent& event )
  726. {
  727. SDLAPP_FUNC;
  728. bool result = false;
  729. #if GLMDEBUG == 2
  730. // simple rule for now, if the option key is involved, it's a debug key
  731. // but only if GLM debugging is level 2 (specifically enabled) so we're
  732. // not stealing control for normal debug builds
  733. result |= ( (event.m_EventType == CocoaEvent_KeyDown) && ((event.m_ModifierKeyMask & (1<<eControlKey))!=0) );
  734. #endif
  735. return result;
  736. }
  737. // Set the mouse cursor position.
  738. void CSDLMgr::SetCursorPosition( int x, int y )
  739. {
  740. SDLAPP_FUNC;
  741. SDL_WarpMouseInWindow(m_Window, x, y);
  742. }
  743. void CSDLMgr::PostEvent( const CCocoaEvent &theEvent, bool debugEvent )
  744. {
  745. SDLAPP_FUNC;
  746. m_CocoaEventsMutex.Lock();
  747. CUtlLinkedList<CCocoaEvent,int> &queue = debugEvent ? m_CocoaEvents : m_DebugEvents;
  748. queue.AddToTail( theEvent );
  749. m_CocoaEventsMutex.Unlock();
  750. }
  751. void CSDLMgr::SetMouseVisible( bool bState )
  752. {
  753. SDLAPP_FUNC;
  754. // If this is the first time we've been called in this frame or we're setting it to visible, then store it.
  755. // This is to handle the case where the game toggles the mouse state between visible and !visible 1 billion times
  756. // in a frame.
  757. if ( !m_bSetMouseVisibleCalled || bState )
  758. {
  759. m_bCursorVisible = bState;
  760. m_bSetMouseVisibleCalled = true;
  761. }
  762. }
  763. void CSDLMgr::SetMouseCursor( SDL_Cursor *hCursor )
  764. {
  765. SDLAPP_FUNC;
  766. if ( m_hCursor != hCursor )
  767. {
  768. if ( !hCursor )
  769. {
  770. // SDL_SetCursor( NULL ) just forces a cursor redraw, so don't ever bother doing that.
  771. SetMouseVisible( false );
  772. }
  773. else
  774. {
  775. m_hCursor = hCursor;
  776. }
  777. m_bSetMouseCursorCalled = true;
  778. }
  779. }
  780. void CSDLMgr::OnFrameRendered()
  781. {
  782. SDLAPP_FUNC;
  783. if ( m_bCursorVisible && m_bSetMouseCursorCalled )
  784. {
  785. SDL_SetCursor( m_hCursor );
  786. m_bSetMouseCursorCalled = false;
  787. }
  788. if ( m_bSetMouseVisibleCalled )
  789. {
  790. ConVarRef rawinput( "m_rawinput" );
  791. #ifdef OSX
  792. // We default raw input to on on Mac and set it one time for all users since
  793. // it didn't used to be the default.
  794. if ( !osx_rawinput_set_one_time.GetBool() )
  795. {
  796. osx_rawinput_set_one_time.SetValue( 1 );
  797. rawinput.SetValue( 1 );
  798. }
  799. #endif
  800. m_bRawInput = !m_bCursorVisible && rawinput.IsValid() && rawinput.GetBool();
  801. SDL_bool bWindowGrab = !m_bCursorVisible ? SDL_TRUE : SDL_FALSE;
  802. SDL_bool bRelativeMouseMode = bWindowGrab;
  803. if ( !m_bRawInput )
  804. {
  805. if ( m_bForbidMouseGrab )
  806. bWindowGrab = SDL_FALSE;
  807. bRelativeMouseMode = SDL_FALSE;
  808. }
  809. SDL_SetWindowGrab( m_Window, bWindowGrab );
  810. SDL_SetRelativeMouseMode( bRelativeMouseMode );
  811. SDL_ShowCursor( m_bCursorVisible ? 1 : 0 );
  812. // force non-fullscreen windows to the foreground if grabbed, so you can't get your mouse locked to something in the background.
  813. if ( bWindowGrab && !m_bFullScreen )
  814. {
  815. SDL_RaiseWindow( m_Window );
  816. }
  817. m_bSetMouseVisibleCalled = false;
  818. }
  819. }
  820. #if defined( DX_TO_GL_ABSTRACTION )
  821. void CSDLMgr::ShowPixels( CShowPixelsParams *params )
  822. {
  823. SDLAPP_FUNC;
  824. tmZone( TELEMETRY_LEVEL0, TMZF_NONE, __FUNCTION__ );
  825. if (params->m_onlySyncView)
  826. return;
  827. int swapInterval = 0;
  828. int swapLimit = 0;
  829. if (gl_swapdebug.GetInt())
  830. {
  831. // just jam through these debug convars every frame
  832. // but they will be shock absorbed below
  833. swapInterval = gl_swapinterval.GetInt();
  834. swapLimit = gl_swaplimit.GetInt();
  835. }
  836. else
  837. {
  838. // jam through (sync&limit) = 1 or 0..
  839. swapInterval = params->m_vsyncEnable ? 1 : 0;
  840. swapLimit = 1; // params->m_vsyncEnable ? 1 : 0; // no good reason to turn off swap limit in normal user mode
  841. #ifdef OSX
  842. // only do the funky forced vsync for NV on 10.6.4 and only if the bypass is not turned on
  843. if (m_force_vsync && (gl_disable_forced_vsync.GetInt()==0))
  844. {
  845. swapInterval = 1;
  846. swapLimit = 1;
  847. }
  848. #else
  849. if (gl_swaptear.GetInt() && gGL->HasSwapTearExtension())
  850. {
  851. // For 0, do nothing. For 1, make it -1.
  852. swapInterval = -swapInterval;
  853. }
  854. #endif
  855. }
  856. // only touch them on changes, or right after a change in windowed/FS state
  857. if ( (swapInterval!=m_lastKnownSwapInterval) || (swapLimit!=m_lastKnownSwapLimit) )
  858. {
  859. if (swapInterval!=m_lastKnownSwapInterval)
  860. {
  861. // This code hits when we turn on vsync, if we're going to swap tear.
  862. // We want to do one frame of real vsync to get the engine to sync at the top
  863. // of the frame refresh.
  864. if (swapInterval < 0 && (m_lastKnownSwapInterval == 0 || m_lastKnownSwapInterval == kBogusSwapInterval)) {
  865. swapInterval = -swapInterval;
  866. }
  867. SDL_GL_SetSwapInterval(swapInterval);
  868. }
  869. m_lastKnownSwapInterval = swapInterval;
  870. m_lastKnownSwapLimit = swapLimit;
  871. printf("\n ##### swap interval = %d swap limit = %d #####\n", m_lastKnownSwapInterval, m_lastKnownSwapLimit );
  872. fflush(stdout);
  873. }
  874. #ifdef OSX
  875. if (!params->m_noBlit)
  876. {
  877. if ( params->m_useBlit ) // FBO blit path - which is what we *should* be using. But if the params say no, then don't do it because the ext is not there.
  878. {
  879. // bind a quickie FBO to enclose the source texture
  880. GLint myreadfb = 1000;
  881. glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, myreadfb);
  882. CheckGLError( __LINE__ );
  883. glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, 0); // to the default FB/backbuffer
  884. CheckGLError( __LINE__ );
  885. // attach source tex to source FB
  886. glFramebufferTexture2DEXT( GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, params->m_srcTexName, 0);
  887. CheckGLError( __LINE__ );
  888. // blit
  889. int srcxmin = 0;
  890. int srcymin = 0;
  891. int srcxmax = params->m_width;
  892. int srcymax = params->m_height;
  893. // normal blit
  894. int dstxmin = 0;
  895. int dstymin = 0;
  896. int dstxmax = 0;
  897. int dstymax = 0;
  898. SDL_GetWindowSize(m_Window, &dstxmax, &dstymax);
  899. if (gl_blit_halfx.GetInt())
  900. {
  901. // blit right half
  902. srcxmin += srcxmax/2;
  903. dstxmin += dstxmax/2;
  904. }
  905. if (gl_blit_halfy.GetInt())
  906. {
  907. // blit top half
  908. // er, but top on screen is bottom of GL y coord range
  909. srcymax /= 2;
  910. dstymin += dstymax/2;
  911. }
  912. // go NEAREST if sizes match
  913. GLenum filter = ( ((srcxmax-srcxmin)==(dstxmax-dstxmin)) && ((srcymax-srcymin)==(dstymax-dstymin)) ) ? GL_NEAREST : GL_LINEAR;
  914. glBlitFramebufferEXT(
  915. /* src min and maxes xy xy */ srcxmin, srcymin, srcxmax,srcymax,
  916. /* dst min and maxes xy xy */ dstxmin, dstymax, dstxmax,dstymin, // note yflip here
  917. GL_COLOR_BUFFER_BIT, filter );
  918. CheckGLError( __LINE__ );
  919. // detach source tex
  920. glFramebufferTexture2DEXT( GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, 0, 0);
  921. CheckGLError( __LINE__ );
  922. glBindFramebufferEXT( GL_READ_FRAMEBUFFER_EXT, 0);
  923. CheckGLError( __LINE__ );
  924. glBindFramebufferEXT( GL_DRAW_FRAMEBUFFER_EXT, 0); // to the default FB/backbuffer
  925. CheckGLError( __LINE__ );
  926. }
  927. else
  928. {
  929. // old blit - gets very dark output with sRGB sources... not good
  930. bool texing = true;
  931. glUseProgram(NULL);
  932. glDisable( GL_DEPTH_TEST );
  933. glDepthMask( GL_FALSE );
  934. glActiveTexture( GL_TEXTURE0 );
  935. if (texing)
  936. {
  937. Assert( glIsTexture (params->m_srcTexName) );
  938. glEnable(GL_TEXTURE_2D);
  939. glBindTexture( GL_TEXTURE_2D, params->m_srcTexName );
  940. CheckGLError( __LINE__ );
  941. GLint width;
  942. glGetTexLevelParameteriv( GL_TEXTURE_2D, //target
  943. 0, //level,
  944. GL_TEXTURE_WIDTH, //pname
  945. &width
  946. );
  947. CheckGLError( __LINE__ );
  948. }
  949. else
  950. {
  951. glBindTexture( GL_TEXTURE_2D, 0 );
  952. CheckGLError( __LINE__ );
  953. glDisable( GL_TEXTURE_2D );
  954. glColor4f( 1.0, 0.0, 0.0, 1.0 );
  955. }
  956. // immediate mode is fine for a simple textured quad
  957. // later if we switch the Valve side to render into an RBO, then this would turn into an FBO blit
  958. // note, do not check glGetError in between glBegin/glEnd, lol
  959. // flipped
  960. float topv = 0.0;
  961. float botv = 1.0;
  962. glBegin(GL_QUADS);
  963. if (texing)
  964. glTexCoord2f( 0.0, botv );
  965. glVertex3f ( -1.0, -1.0, 0.0 );
  966. if (texing)
  967. glTexCoord2f( 1.0, botv );
  968. glVertex3f ( 1.0, -1.0, 0.0 );
  969. if (texing)
  970. glTexCoord2f( 1.0, topv );
  971. glVertex3f ( 1.0, 1.0, 0.0 );
  972. if (texing)
  973. glTexCoord2f( 0.0, topv );
  974. glVertex3f ( -1.0, 1.0, 0.0 );
  975. glEnd();
  976. CheckGLError( __LINE__ );
  977. if (texing)
  978. {
  979. glBindTexture( GL_TEXTURE_2D, 0 );
  980. CheckGLError( __LINE__ );
  981. glDisable(GL_TEXTURE_2D);
  982. }
  983. }
  984. }
  985. #endif
  986. if ( gl_finish.GetInt() )
  987. {
  988. gGL->glFinish();
  989. }
  990. CheckGLError( __LINE__ );
  991. CFastTimer tm;
  992. tm.Start();
  993. SDL_GL_SwapWindow( m_Window );
  994. m_flPrevGLSwapWindowTime = tm.GetDurationInProgress().GetMillisecondsF();
  995. CheckGLError( __LINE__ );
  996. }
  997. #endif // DX_TO_GL_ABSTRACTION
  998. void CSDLMgr::SetWindowFullScreen( bool bFullScreen, int nWidth, int nHeight )
  999. {
  1000. SDLAPP_FUNC;
  1001. SDL_DisplayMode mode;
  1002. int displayIndex = sdl_displayindex.GetInt();
  1003. if ( bFullScreen )
  1004. {
  1005. if ( SDL_GetDesktopDisplayMode( displayIndex, &mode ) != 0 )
  1006. {
  1007. Assert( 0 );
  1008. SDL_GetDesktopDisplayMode( 0, &mode );
  1009. }
  1010. mode.format = (Uint32)SDL_PIXELFORMAT_RGBX8888;
  1011. m_flMouseXScale = ( float )nWidth / ( float )mode.w;
  1012. m_flMouseYScale = ( float )nHeight / ( float )mode.h;
  1013. }
  1014. else
  1015. {
  1016. mode.format = ( Uint32 )SDL_PIXELFORMAT_RGBX8888;
  1017. mode.refresh_rate = 0;
  1018. mode.w = nWidth;
  1019. mode.h = nHeight;
  1020. mode.driverdata = 0;
  1021. m_flMouseXScale = 1.0f;
  1022. m_flMouseYScale = 1.0f;
  1023. }
  1024. SDL_SetWindowDisplayMode( m_Window, &mode );
  1025. if ( ( m_bFullScreen != bFullScreen ) ||
  1026. ( bFullScreen && ( sdl_displayindex_fullscreen.GetInt() != displayIndex ) ) )
  1027. {
  1028. if ( bFullScreen )
  1029. {
  1030. int x = 0;
  1031. int y = 0;
  1032. // If we have more than one display, center the window in the one we've been assigned to.
  1033. if ( SDL_GetNumVideoDisplays() > 1 )
  1034. {
  1035. SDL_Rect rect = { 0, 0, 0, 0 };
  1036. SDL_GetDisplayBounds( displayIndex, &rect );
  1037. x = rect.x;
  1038. y = rect.y;
  1039. }
  1040. if ( m_bFullScreen == bFullScreen )
  1041. {
  1042. // TODO: Temporary workaround. SDL doesn't support going fullscreen on one monitor to fullscreen
  1043. // on another. So we switch to windowed here, move our window, then go back fullscreen.
  1044. SDL_SetWindowFullscreen( m_Window, SDL_FALSE );
  1045. ThreadSleep( 15 );
  1046. }
  1047. // Move the window to the upper left of whatever display we're on, then size to fullscreen.
  1048. SDL_SetWindowPosition( m_Window, x, y );
  1049. SizeWindow( nWidth, nHeight );
  1050. sdl_displayindex_fullscreen.SetValue( displayIndex );
  1051. }
  1052. else
  1053. {
  1054. sdl_displayindex_fullscreen.SetValue( -1 );
  1055. }
  1056. SDL_SetWindowFullscreen( m_Window, bFullScreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0 );
  1057. m_bFullScreen = bFullScreen;
  1058. }
  1059. }
  1060. void CSDLMgr::MoveWindow( int x, int y )
  1061. {
  1062. SDLAPP_FUNC;
  1063. SDL_SetWindowPosition(m_Window, x, y);
  1064. }
  1065. void CSDLMgr::SizeWindow( int width, int tall )
  1066. {
  1067. SDLAPP_FUNC;
  1068. if ( ( m_WindowWidth == width ) &&
  1069. ( m_WindowHeight == tall ) &&
  1070. ( m_SizeWindowFullScreenState == m_bFullScreen ) &&
  1071. m_WindowShownAndRaised )
  1072. {
  1073. return;
  1074. }
  1075. // Make sure we don't skip doing a SizeWindow when fullscreen state changes.
  1076. m_SizeWindowFullScreenState = m_bFullScreen;
  1077. m_WindowWidth = width;
  1078. m_WindowHeight = tall;
  1079. // Update mouse warp targets (dependent on window size).
  1080. m_nMouseTargetX = m_WindowWidth / 2;
  1081. m_nMouseTargetY = m_WindowHeight / 2;
  1082. m_nWarpDelta = Max( m_WindowHeight / 3, 200 );
  1083. SDL_SetWindowSize( m_Window, width, tall );
  1084. #if defined( DX_TO_GL_ABSTRACTION )
  1085. gGL->glViewport(0, 0, (GLsizei) width, (GLsizei) tall);
  1086. gGL->glScissor( 0,0, (GLsizei) width, (GLsizei) tall );
  1087. #endif
  1088. // If the Window hasn't been shown yet, show it now.
  1089. if ( !m_WindowShownAndRaised )
  1090. {
  1091. SDL_ShowWindow( m_Window );
  1092. SDL_RaiseWindow( m_Window );
  1093. m_WindowShownAndRaised = true;
  1094. }
  1095. else
  1096. {
  1097. SDL_RaiseWindow( m_Window );
  1098. }
  1099. }
  1100. // key input handler
  1101. void CSDLMgr::handleKeyInput( const SDL_Event &event )
  1102. {
  1103. SDLAPP_FUNC;
  1104. Assert( ( event.type == SDL_KEYDOWN ) || ( event.type == SDL_KEYUP ) );
  1105. #ifdef OSX
  1106. if ( event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_TAB &&
  1107. SDL_GetModState()&KMOD_GUI && CommandLine()->FindParm( "-exclusivefs" ) )
  1108. {
  1109. // If we're in exclusive fullscreen mode, and they command-tab, handle
  1110. // that by forcing minimization of the window.
  1111. SDL_MinimizeWindow( m_Window );
  1112. }
  1113. #endif
  1114. const bool bPressed = ( event.type == SDL_KEYDOWN );
  1115. // !!! FIXME: we should be getting text input from a different event...
  1116. CCocoaEvent theEvent;
  1117. theEvent.m_EventType = ( bPressed ) ? CocoaEvent_KeyDown : CocoaEvent_KeyUp;
  1118. theEvent.m_VirtualKeyCode = event.key.keysym.scancode;
  1119. theEvent.m_UnicodeKey = 0;
  1120. theEvent.m_UnicodeKeyUnmodified = 0;
  1121. // Testing for non-qwerty keyboards: work out the key name and use this to
  1122. // calculate the scancode.
  1123. if ( CommandLine()->FindParm( "-nonqwerty" ) )
  1124. {
  1125. const char* keyname = SDL_GetKeyName( event.key.keysym.sym );
  1126. if ( keyname != NULL && strlen( keyname ) == 1) {
  1127. const char c = *keyname;
  1128. if ( c >= 'A' && c <= 'Z' )
  1129. {
  1130. theEvent.m_VirtualKeyCode = SDL_SCANCODE_A + ( c - 'A' );
  1131. }
  1132. else
  1133. {
  1134. switch( c )
  1135. {
  1136. case '=': theEvent.m_VirtualKeyCode = SDL_SCANCODE_EQUALS; break;
  1137. case '-': theEvent.m_VirtualKeyCode = SDL_SCANCODE_MINUS; break;
  1138. case '[': theEvent.m_VirtualKeyCode = SDL_SCANCODE_LEFTBRACKET; break;
  1139. case ']': theEvent.m_VirtualKeyCode = SDL_SCANCODE_RIGHTBRACKET; break;
  1140. case ';': theEvent.m_VirtualKeyCode = SDL_SCANCODE_SEMICOLON; break;
  1141. case '\'': theEvent.m_VirtualKeyCode = SDL_SCANCODE_APOSTROPHE; break;
  1142. case ',': theEvent.m_VirtualKeyCode = SDL_SCANCODE_COMMA; break;
  1143. case '.': theEvent.m_VirtualKeyCode = SDL_SCANCODE_PERIOD; break;
  1144. case '/': theEvent.m_VirtualKeyCode = SDL_SCANCODE_SLASH; break;
  1145. }
  1146. }
  1147. }
  1148. }
  1149. // key modifiers aren't necessarily reliable in all the cases we'd want, so track it ourselves.
  1150. const uint32_t ModCAPSLOCK = (1 << 0);
  1151. const uint32_t ModSHIFTR = (1 << 1);
  1152. const uint32_t ModSHIFTL = (1 << 2);
  1153. const uint32_t ModCTRLR = (1 << 3);
  1154. const uint32_t ModCTRLL = (1 << 4);
  1155. const uint32_t ModALTR = (1 << 5);
  1156. const uint32_t ModALTL = (1 << 6);
  1157. const uint32_t ModGUIR = (1 << 7);
  1158. const uint32_t ModGUIL = (1 << 8);
  1159. #define KEYSYMCASE(mod,side,op,key) \
  1160. case SDLK_##side##mod: \
  1161. m_keyModifiers op Mod##mod##side; \
  1162. theEvent.m_VirtualKeyCode = -key; \
  1163. break
  1164. //bool bDropKey = false;
  1165. if (bPressed)
  1166. {
  1167. switch (event.key.keysym.sym)
  1168. {
  1169. KEYSYMCASE(CAPSLOCK,,|=,KEY_CAPSLOCK);
  1170. KEYSYMCASE(SHIFT,R,|=,KEY_RSHIFT);
  1171. KEYSYMCASE(SHIFT,L,|=,KEY_LSHIFT);
  1172. KEYSYMCASE(CTRL,R,|=,KEY_RCONTROL);
  1173. KEYSYMCASE(CTRL,L,|=,KEY_LCONTROL);
  1174. KEYSYMCASE(GUI,R,|=,KEY_RWIN);
  1175. KEYSYMCASE(GUI,L,|=,KEY_LWIN);
  1176. KEYSYMCASE(ALT,R,|=,KEY_RALT);
  1177. KEYSYMCASE(ALT,L,|=,KEY_LALT);
  1178. default: break; // don't care.
  1179. }
  1180. }
  1181. else
  1182. {
  1183. switch (event.key.keysym.sym)
  1184. {
  1185. KEYSYMCASE(CAPSLOCK,,&= ~,KEY_CAPSLOCK);
  1186. KEYSYMCASE(SHIFT,R,&= ~,KEY_RSHIFT);
  1187. KEYSYMCASE(SHIFT,L,&= ~,KEY_LSHIFT);
  1188. KEYSYMCASE(CTRL,R,&= ~,KEY_RCONTROL);
  1189. KEYSYMCASE(CTRL,L,&= ~,KEY_LCONTROL);
  1190. KEYSYMCASE(GUI,R,&= ~,KEY_RWIN);
  1191. KEYSYMCASE(GUI,L,&= ~,KEY_LWIN);
  1192. KEYSYMCASE(ALT,R,&= ~,KEY_RALT);
  1193. KEYSYMCASE(ALT,L,&= ~,KEY_LALT);
  1194. default: break; // don't care.
  1195. }
  1196. }
  1197. #undef KEYSYMCASE
  1198. m_keyModifierMask = 0;
  1199. if (m_keyModifiers & ModCAPSLOCK)
  1200. m_keyModifierMask |= (1<<eCapsLockKey);
  1201. if (m_keyModifiers & (ModSHIFTR | ModSHIFTL))
  1202. m_keyModifierMask |= (1<<eShiftKey);
  1203. if (m_keyModifiers & (ModCTRLR | ModCTRLL))
  1204. m_keyModifierMask |= (1<<eControlKey);
  1205. if (m_keyModifiers & (ModALTR | ModALTL))
  1206. m_keyModifierMask |= (1<<eAltKey);
  1207. if (m_keyModifiers & (ModGUIR | ModGUIL))
  1208. m_keyModifierMask |= (1<<eCommandKey);
  1209. theEvent.m_ModifierKeyMask = m_keyModifierMask;
  1210. // make a decision about this event - does it go in the normal evt queue or into the debug queue.
  1211. bool debug = IsDebugEvent( theEvent );
  1212. #if GLMDEBUG
  1213. bool bIsShifted = ( ((theEvent.m_ModifierKeyMask & (1<<eCapsLockKey))!=0) || ((theEvent.m_ModifierKeyMask & (1<<eShiftKey))!=0) );
  1214. theEvent.m_UnicodeKeyUnmodified = event.key.keysym.sym;
  1215. if ( bIsShifted )
  1216. {
  1217. switch ( event.key.keysym.sym )
  1218. {
  1219. case '[':
  1220. theEvent.m_UnicodeKeyUnmodified = '{';
  1221. break;
  1222. case ']':
  1223. theEvent.m_UnicodeKeyUnmodified = '}';
  1224. break;
  1225. case 'h':
  1226. theEvent.m_UnicodeKeyUnmodified = 'H';
  1227. break;
  1228. case ',':
  1229. theEvent.m_UnicodeKeyUnmodified = '<';
  1230. break;
  1231. case '.':
  1232. theEvent.m_UnicodeKeyUnmodified = '>';
  1233. break;
  1234. }
  1235. }
  1236. #endif
  1237. PostEvent( theEvent, debug );
  1238. }
  1239. void CSDLMgr::PumpWindowsMessageLoop()
  1240. {
  1241. SDLAPP_FUNC;
  1242. SDL_Event event;
  1243. int nEventsProcessed = 0;
  1244. while ( SDL_PollEvent(&event) && nEventsProcessed < 100 )
  1245. {
  1246. nEventsProcessed++;
  1247. switch ( event.type )
  1248. {
  1249. case SDL_MOUSEMOTION:
  1250. {
  1251. if ( !m_bHasFocus )
  1252. break;
  1253. // We still handle WM_MOUSEMOVE in CInputSystem for regular mouse events, only raw goes through SDL.
  1254. // This is done in order to maintain legacy mouse behaviour for Windows users.
  1255. if ( IsWindows() && !m_bRawInput )
  1256. break;
  1257. // When SDL_WarpMouseInWindow is called, an SDL_MOUSEMOTION
  1258. // event is sent. We want to ignore such 'synthetic'
  1259. // mouse motion events.
  1260. if ( m_bExpectSyntheticMouseMotion &&
  1261. event.motion.x == m_nMouseTargetX &&
  1262. event.motion.y == m_nMouseTargetY )
  1263. {
  1264. m_bExpectSyntheticMouseMotion = false;
  1265. break;
  1266. }
  1267. m_nMouseXDelta += event.motion.xrel;
  1268. m_nMouseYDelta += event.motion.yrel;
  1269. if ( !m_bRawInput && !m_bCursorVisible &&
  1270. (event.motion.x < m_nMouseTargetX - m_nWarpDelta ||
  1271. event.motion.x > m_nMouseTargetX + m_nWarpDelta ||
  1272. event.motion.y < m_nMouseTargetY - m_nWarpDelta ||
  1273. event.motion.y > m_nMouseTargetY + m_nWarpDelta) )
  1274. {
  1275. // We have strayed outside of our desired area, so
  1276. // warp the cursor back to the middle of the window.
  1277. SDL_WarpMouseInWindow( m_Window, m_nMouseTargetX, m_nMouseTargetY );
  1278. m_bExpectSyntheticMouseMotion = true;
  1279. }
  1280. CCocoaEvent theEvent;
  1281. theEvent.m_EventType = CocoaEvent_MouseMove;
  1282. theEvent.m_MousePos[0] = event.motion.x * m_flMouseXScale;
  1283. theEvent.m_MousePos[1] = event.motion.y * m_flMouseYScale;
  1284. theEvent.m_MouseButtonFlags = m_mouseButtons;
  1285. PostEvent( theEvent );
  1286. break;
  1287. }
  1288. case SDL_MOUSEBUTTONUP:
  1289. case SDL_MOUSEBUTTONDOWN:
  1290. {
  1291. // SDL buttons:
  1292. // 1 = Left button
  1293. // 2 = Middle button
  1294. // 3 = Right button
  1295. // 4 = Wheel Forward ; These events are handled by SDL_MOUSEWHEEL and don't come through here.
  1296. // 5 = Wheel Back ;
  1297. // 6 = Wheel Tilt Left ;
  1298. // 7 = Wheel Tilt Right ;
  1299. // 8 = Browser Back
  1300. // 9 = Browser Forward
  1301. // 10 = Task button (probably similar to Alt-Tab)
  1302. // every other platform does left(1), right(2), middle(3)...
  1303. int button;
  1304. switch( event.button.button )
  1305. {
  1306. case 1: button = 1; break;
  1307. case 2: button = 3; break;
  1308. case 3: button = 2; break;
  1309. default:
  1310. // For all buttons above 4, map them to 4 & 5 forever. This is because different mice
  1311. // will use different mappings. Ie, mousewheel mice can do this:
  1312. // 4 = Wheel Forward ; These events are handled by SDL_MOUSEWHEEL and don't come through here.
  1313. // 5 = Wheel Back ;
  1314. // 6 = Wheel Tilt Left ;
  1315. // 7 = Wheel Tilt Right ;
  1316. // 8 = Browser Back
  1317. // 9 = Browser Forward
  1318. // 10 = Task button (probably similar to Alt-Tab)
  1319. // Mice without wheels can do 4/5 as regular 4/5, etc.
  1320. button = 4 + ( event.button.button & 0x1 );
  1321. break;
  1322. }
  1323. const bool bPressed = (event.type == SDL_MOUSEBUTTONDOWN);
  1324. const CocoaMouseButton_t cocoaButton = ( CocoaMouseButton_t )( 1 << (button - 1 ) );
  1325. if (bPressed)
  1326. m_mouseButtons |= cocoaButton;
  1327. else
  1328. m_mouseButtons &= ~cocoaButton;
  1329. bool bDoublePress = false;
  1330. if ( bPressed )
  1331. {
  1332. if ( m_bGotMouseButtonDown &&
  1333. ( (int)( event.button.timestamp - m_MouseButtonDownTimeStamp ) <= sdl_double_click_time.GetInt() ) &&
  1334. ( abs( event.button.x - m_MouseButtonDownX ) <= sdl_double_click_size.GetInt() ) &&
  1335. ( abs( event.button.y - m_MouseButtonDownY ) <= sdl_double_click_size.GetInt() ) )
  1336. {
  1337. bDoublePress = true;
  1338. m_bGotMouseButtonDown = false;
  1339. }
  1340. else
  1341. {
  1342. m_MouseButtonDownTimeStamp = event.button.timestamp;
  1343. m_MouseButtonDownX = event.button.x;
  1344. m_MouseButtonDownY = event.button.y;
  1345. m_bGotMouseButtonDown = true;
  1346. }
  1347. }
  1348. CCocoaEvent theEvent;
  1349. theEvent.m_EventType = (bPressed) ? CocoaEvent_MouseButtonDown : CocoaEvent_MouseButtonUp;
  1350. theEvent.m_MousePos[0] = event.button.x * m_flMouseXScale;
  1351. theEvent.m_MousePos[1] = event.button.y * m_flMouseYScale;
  1352. theEvent.m_MouseButtonFlags = m_mouseButtons;
  1353. theEvent.m_nMouseClickCount = bDoublePress ? 2 : 1;
  1354. theEvent.m_MouseButton = cocoaButton;
  1355. PostEvent( theEvent );
  1356. break;
  1357. }
  1358. case SDL_MOUSEWHEEL:
  1359. {
  1360. if ( event.wheel.y )
  1361. {
  1362. CCocoaEvent theEvent;
  1363. theEvent.m_EventType = CocoaEvent_MouseScroll;
  1364. const int scroll = event.wheel.y;
  1365. theEvent.m_MousePos[0] = scroll;
  1366. theEvent.m_MousePos[1] = scroll;
  1367. PostEvent( theEvent );
  1368. }
  1369. break;
  1370. }
  1371. case SDL_WINDOWEVENT:
  1372. switch (event.window.event)
  1373. {
  1374. case SDL_WINDOWEVENT_EXPOSED:
  1375. {
  1376. /*if ( ev.xexpose.count > 0 )
  1377. break; // multiple expose events queued
  1378. EVENT_LOG( "Got event Expose\n" );
  1379. int iPanel = m_mapWindowToVPanel.Find( ev.xexpose.window );
  1380. if ( iPanel != m_mapWindowToVPanel.InvalidIndex() )
  1381. drawVGUI( m_pXDisplay, ev.xexpose.window, m_mapWindowToVPanel[ iPanel ], m_GLContext );
  1382. m_mapSentInvalidate.RemoveAll();*/
  1383. break;
  1384. }
  1385. case SDL_WINDOWEVENT_FOCUS_GAINED:
  1386. {
  1387. m_bHasFocus = true;
  1388. SDL_ShowCursor( m_bCursorVisible ? 1 : 0 );
  1389. CCocoaEvent theEvent;
  1390. theEvent.m_EventType = CocoaEvent_AppActivate;
  1391. theEvent.m_ModifierKeyMask = 1;
  1392. PostEvent( theEvent );
  1393. break;
  1394. }
  1395. case SDL_WINDOWEVENT_FOCUS_LOST:
  1396. {
  1397. m_bHasFocus = false;
  1398. SDL_ShowCursor(1);
  1399. CCocoaEvent theEvent;
  1400. theEvent.m_EventType = CocoaEvent_AppActivate;
  1401. theEvent.m_ModifierKeyMask = 0;
  1402. PostEvent( theEvent );
  1403. break;
  1404. }
  1405. case SDL_WINDOWEVENT_LEAVE:
  1406. {
  1407. if ( !IsWindows() && !m_bRawInput && !m_bCursorVisible && m_bHasFocus )
  1408. {
  1409. // If the cursor is not visible and the mouse
  1410. // cursor somehow manages to escape the window
  1411. // warp it back to the middle of the window.
  1412. SDL_WarpMouseInWindow( m_Window, m_nMouseTargetX, m_nMouseTargetY );
  1413. m_bExpectSyntheticMouseMotion = true;
  1414. }
  1415. break;
  1416. }
  1417. }
  1418. break;
  1419. case SDL_KEYUP:
  1420. case SDL_KEYDOWN:
  1421. handleKeyInput(event);
  1422. break;
  1423. case SDL_TEXTINPUT:
  1424. {
  1425. char *text = event.text.text;
  1426. if ( text && text[ 0 ] )
  1427. {
  1428. wchar_t WBuf[ SDL_TEXTINPUTEVENT_TEXT_SIZE + 1 ];
  1429. WBuf[ 0 ] = 0;
  1430. V_UTF8ToUnicode( text, WBuf, sizeof( WBuf ) );
  1431. for ( int i = 0; i < SDL_TEXTINPUTEVENT_TEXT_SIZE; i++ )
  1432. {
  1433. wchar_t ch = WBuf[ i ];
  1434. if ( ch == '\0' )
  1435. break;
  1436. CCocoaEvent theEvent;
  1437. theEvent.m_EventType = CocoaEvent_KeyDown;
  1438. theEvent.m_VirtualKeyCode = 0;
  1439. theEvent.m_UnicodeKey = ch;
  1440. theEvent.m_UnicodeKeyUnmodified = ch;
  1441. theEvent.m_ModifierKeyMask = m_keyModifierMask;
  1442. PostEvent( theEvent, false );
  1443. theEvent.m_EventType = CocoaEvent_KeyUp;
  1444. theEvent.m_VirtualKeyCode = 0;
  1445. theEvent.m_UnicodeKey = 0;
  1446. theEvent.m_UnicodeKeyUnmodified = 0;
  1447. theEvent.m_ModifierKeyMask = m_keyModifierMask;
  1448. PostEvent( theEvent, false );
  1449. }
  1450. }
  1451. break;
  1452. }
  1453. case SDL_QUIT:
  1454. {
  1455. CCocoaEvent theEvent;
  1456. theEvent.m_EventType = CocoaEvent_AppQuit;
  1457. PostEvent( theEvent );
  1458. break;
  1459. }
  1460. default:
  1461. break;
  1462. }
  1463. }
  1464. }
  1465. void CSDLMgr::IncWindowRefCount()
  1466. {
  1467. if ( !m_Window )
  1468. return;
  1469. m_nWindowRefCount++;
  1470. }
  1471. void CSDLMgr::DecWindowRefCount()
  1472. {
  1473. if ( !m_Window )
  1474. return;
  1475. Assert( m_nWindowRefCount >= 1 );
  1476. if ( !m_nWindowRefCount )
  1477. return;
  1478. m_nWindowRefCount--;
  1479. if ( !m_nWindowRefCount )
  1480. {
  1481. #if defined( DX_TO_GL_ABSTRACTION )
  1482. if ( m_Window )
  1483. {
  1484. SDL_GL_MakeCurrent( m_Window, m_GLContext );
  1485. }
  1486. if ( gGL && m_readFBO )
  1487. {
  1488. gGL->glDeleteFramebuffersEXT( 1, &m_readFBO );
  1489. }
  1490. m_readFBO = 0;
  1491. SDL_GL_DeleteContext( m_GLContext );
  1492. #if !defined( OSX ) && defined( DBGFLAG_ASSERT )
  1493. // Clear the GL entrypoint pointers, ensuring we crash if someone tries to call GL after we delete the context.
  1494. Msg( "%s: Calling ClearOpenGLEntryPoints. Should crash if someone calls GL after this.\n", __FUNCTION__ );
  1495. ClearOpenGLEntryPoints();
  1496. #endif
  1497. m_GLContext = NULL;
  1498. #endif // DX_TO_GL_ABSTRACTION
  1499. SDL_SetWindowFullscreen(m_Window, SDL_FALSE); // just in case.
  1500. SDL_SetWindowGrab(m_Window, SDL_FALSE); // just in case.
  1501. SDL_DestroyWindow(m_Window);
  1502. m_Window = NULL;
  1503. SetAssertDialogParent( NULL );
  1504. }
  1505. }
  1506. void CSDLMgr::DestroyGameWindow()
  1507. {
  1508. SDLAPP_FUNC;
  1509. if ( m_Window )
  1510. {
  1511. DecWindowRefCount();
  1512. }
  1513. }
  1514. void CSDLMgr::SetApplicationIcon( const char *pchAppIconFile )
  1515. {
  1516. SDLAPP_FUNC;
  1517. SDL_Surface *icon = SDL_LoadBMP(pchAppIconFile);
  1518. if (icon)
  1519. {
  1520. SDL_SetWindowIcon(m_Window, icon);
  1521. SDL_FreeSurface(icon);
  1522. }
  1523. }
  1524. void CSDLMgr::GetMouseDelta( int &x, int &y, bool bIgnoreNextMouseDelta )
  1525. {
  1526. SDLAPP_FUNC;
  1527. x = m_nMouseXDelta;
  1528. y = m_nMouseYDelta;
  1529. m_nMouseXDelta = m_nMouseYDelta = 0;
  1530. }
  1531. // Returns the resolution of the nth display. 0 is the default display.
  1532. //
  1533. void CSDLMgr::GetNativeDisplayInfo( int nDisplay, uint &nWidth, uint &nHeight, uint &nRefreshHz )
  1534. {
  1535. SDL_DisplayMode mode;
  1536. if ( nDisplay == -1 )
  1537. {
  1538. if ( g_bSDLDisplayindexSet )
  1539. {
  1540. nDisplay = sdl_displayindex.GetInt();
  1541. }
  1542. else
  1543. {
  1544. // sdl_displayindex hasn't been parsed yet. This can happen in CMaterialSystem::ModInit()
  1545. // before the config files have been read, etc. So in this case, just grab the largest
  1546. // display we can find and return with that.
  1547. int Width, Height;
  1548. nDisplay = GetLargestDisplaySize( Width, Height );
  1549. }
  1550. }
  1551. if ( SDL_GetDesktopDisplayMode( nDisplay, &mode ) != 0 )
  1552. {
  1553. Assert( 0 );
  1554. SDL_GetDesktopDisplayMode( 0, &mode );
  1555. }
  1556. nRefreshHz = mode.refresh_rate;
  1557. nWidth = mode.w;
  1558. nHeight = mode.h;
  1559. }
  1560. void CSDLMgr::RenderedSize( uint &width, uint &height, bool set )
  1561. {
  1562. SDLAPP_FUNC;
  1563. if (set)
  1564. {
  1565. m_renderedWidth = width;
  1566. m_rendererHeight = height; // latched from NotifyRenderedSize
  1567. }
  1568. else
  1569. {
  1570. width = m_renderedWidth;
  1571. height = m_rendererHeight;
  1572. }
  1573. }
  1574. void CSDLMgr::DisplayedSize( uint &width, uint &height )
  1575. {
  1576. SDLAPP_FUNC;
  1577. int w, h;
  1578. SDL_GetWindowSize(m_Window, &w, &h);
  1579. width = (uint) w;
  1580. height = (uint) h;
  1581. }
  1582. void CSDLMgr::GetStackCrawl( CStackCrawlParams *params )
  1583. {
  1584. SDLAPP_FUNC;
  1585. }
  1586. void CSDLMgr::WaitUntilUserInput( int msSleepTime )
  1587. {
  1588. SDLAPP_FUNC;
  1589. SDL_WaitEventTimeout(NULL, msSleepTime);
  1590. }
  1591. //===============================================================================
  1592. void CSDLMgr::SetGammaRamp( const uint16 *pRed, const uint16 *pGreen, const uint16 *pBlue )
  1593. {
  1594. if ( m_Window )
  1595. {
  1596. int nResult = SDL_SetWindowGammaRamp( m_Window, pRed, pGreen, pBlue );
  1597. if ( nResult != 0 )
  1598. {
  1599. ConMsg( "SDL_SetWindowGammaRamp failed: %d\n", nResult );
  1600. }
  1601. }
  1602. }
  1603. //===============================================================================
  1604. #if defined( DX_TO_GL_ABSTRACTION )
  1605. void CSDLMgr::GetDesiredPixelFormatAttribsAndRendererInfo( uint **ptrOut, uint *countOut, GLMRendererInfoFields *rendInfoOut )
  1606. {
  1607. SDLAPP_FUNC;
  1608. Assert( m_pixelFormatAttribCount > 0 );
  1609. if (ptrOut) *ptrOut = (uint *) m_pixelFormatAttribs;
  1610. if (countOut) *countOut = m_pixelFormatAttribCount;
  1611. if (rendInfoOut)
  1612. {
  1613. GLMDisplayDB *db = GetDisplayDB();
  1614. #ifdef OSX
  1615. *rendInfoOut = db->m_renderers->Head()->m_info;
  1616. #else
  1617. *rendInfoOut = db->m_renderer.m_info;
  1618. #endif
  1619. }
  1620. }
  1621. GLMDisplayMode::GLMDisplayMode( uint width, uint height, uint refreshHz )
  1622. {
  1623. SDLAPP_FUNC;
  1624. Init( width, height, refreshHz );
  1625. }
  1626. GLMDisplayMode::~GLMDisplayMode()
  1627. {
  1628. SDLAPP_FUNC;
  1629. // empty
  1630. }
  1631. void GLMDisplayMode::Init( uint width, uint height, uint refreshHz )
  1632. {
  1633. SDLAPP_FUNC;
  1634. m_info.m_modePixelWidth = width;
  1635. m_info.m_modePixelHeight = height;
  1636. m_info.m_modeRefreshHz = refreshHz;
  1637. }
  1638. void GLMDisplayMode::Dump( int which )
  1639. {
  1640. SDLAPP_FUNC;
  1641. GLMPRINTF(("\n # %-2d width=%-4d height=%-4d refreshHz=%-2d",
  1642. which, m_info.m_modePixelWidth, m_info.m_modePixelHeight, m_info.m_modeRefreshHz ));
  1643. }
  1644. GLMDisplayDB *CSDLMgr::GetDisplayDB( void )
  1645. {
  1646. SDLAPP_FUNC;
  1647. if ( !m_displayDB )
  1648. {
  1649. m_displayDB = new GLMDisplayDB; // creating the DB object does not do much other than init it to a good state.
  1650. m_displayDB->Populate(); // populate the tree
  1651. #if defined( OSX )
  1652. // side effect: we fill in m_force_vsync..
  1653. {
  1654. GLMRendererInfoFields info;
  1655. m_displayDB->GetRendererInfo( 0, &info );
  1656. // m_leopard = (info.m_osComboVersion < 0x000A0600);
  1657. m_force_vsync = info.m_badDriver1064NV; // just force it if it's the bum NV driver
  1658. }
  1659. #endif
  1660. }
  1661. return m_displayDB;
  1662. }
  1663. #ifndef OSX
  1664. # include "glmdisplaydb_linuxwin.inl"
  1665. #endif
  1666. #endif // DX_TO_GL_ABSTRACTION
  1667. #endif // !DEDICATED