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

2137 lines
55 KiB

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