diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /vguimatsurface/Cursor.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'vguimatsurface/Cursor.cpp')
| -rw-r--r-- | vguimatsurface/Cursor.cpp | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/vguimatsurface/Cursor.cpp b/vguimatsurface/Cursor.cpp new file mode 100644 index 0000000..5451541 --- /dev/null +++ b/vguimatsurface/Cursor.cpp @@ -0,0 +1,565 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Methods associated with the cursor +// +// $Revision: $ +// $NoKeywords: $ +//===========================================================================// + +#if !defined( _X360 ) + #define OEMRESOURCE //for OCR_* cursor junk + #include "winlite.h" +#endif +#include <appframework/ilaunchermgr.h> + +#if defined( USE_SDL ) +#undef M_PI +#include "SDL.h" +#endif + +#include "tier0/dbg.h" +#include "tier0/vcrmode.h" +#include "tier0/icommandline.h" +#include "tier1/utldict.h" +#include "Cursor.h" +#include "vguimatsurface.h" +#include "MatSystemSurface.h" +#include "filesystem.h" +#if defined( _X360 ) +#include "xbox/xbox_win32stubs.h" +#endif + +#if defined( USE_SDL ) +#include "materialsystem/imaterialsystem.h" +#endif + +#include "inputsystem/iinputsystem.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +using namespace vgui; +#if defined( USE_SDL ) +static SDL_Cursor *s_pDefaultCursor[ dc_last ]; +static SDL_Cursor *s_hCurrentCursor = NULL; +static SDL_Cursor *s_hCurrentlySetCursor = NULL; +#elif defined( WIN32 ) +static HICON s_pDefaultCursor[ dc_last ]; +static HICON s_hCurrentCursor = NULL; +#endif +static bool s_bCursorLocked = false; +static bool s_bCursorVisible = true; +static int s_nForceCursorVisibleCount = 0; +static bool s_bSoftwareCursorActive = false; +static int s_nSoftwareCursorTexture = -1; +static float s_fSoftwareCursorOffsetX = 0; +static float s_fSoftwareCursorOffsetY = 0; +static int s_rnSoftwareCursorID[20]; +static float s_rfSoftwareCursorOffset[20][2]; +static bool s_bSoftwareCursorsInitialized = false; + +extern CMatSystemSurface g_MatSystemSurface; + +//----------------------------------------------------------------------------- +// Initializes cursors +//----------------------------------------------------------------------------- +void InitCursors() +{ + // load up all default cursors +#if defined( USE_SDL ) + + s_pDefaultCursor[ dc_none ] = NULL; + s_pDefaultCursor[ dc_arrow ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_ARROW ); + s_pDefaultCursor[ dc_ibeam ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_IBEAM ); + s_pDefaultCursor[ dc_hourglass ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_WAIT ); + s_pDefaultCursor[ dc_crosshair ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_CROSSHAIR ); + s_pDefaultCursor[ dc_waitarrow ]= SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_WAITARROW ); + s_pDefaultCursor[ dc_sizenwse ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENWSE ); + s_pDefaultCursor[ dc_sizenesw ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENESW ); + s_pDefaultCursor[ dc_sizewe ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZEWE ); + s_pDefaultCursor[ dc_sizens ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZENS ); + s_pDefaultCursor[ dc_sizeall ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_SIZEALL ); + s_pDefaultCursor[ dc_no ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_NO ); + s_pDefaultCursor[ dc_hand ] = SDL_CreateSystemCursor( SDL_SYSTEM_CURSOR_HAND ); + + s_hCurrentCursor = s_pDefaultCursor[ dc_arrow ]; + +#elif defined( WIN32 ) + + s_pDefaultCursor[ dc_none ] = NULL; + s_pDefaultCursor[ dc_arrow ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_NORMAL); + s_pDefaultCursor[ dc_ibeam ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_IBEAM); + s_pDefaultCursor[ dc_hourglass ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_WAIT); + s_pDefaultCursor[ dc_crosshair ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_CROSS); + s_pDefaultCursor[ dc_waitarrow ] =(HICON)LoadCursor(NULL, (LPCTSTR)32650); + s_pDefaultCursor[ dc_up ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_UP); + s_pDefaultCursor[ dc_sizenwse ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENWSE); + s_pDefaultCursor[ dc_sizenesw ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENESW); + s_pDefaultCursor[ dc_sizewe ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZEWE); + s_pDefaultCursor[ dc_sizens ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZENS); + s_pDefaultCursor[ dc_sizeall ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_SIZEALL); + s_pDefaultCursor[ dc_no ] =(HICON)LoadCursor(NULL, (LPCTSTR)OCR_NO); + s_pDefaultCursor[ dc_hand ] =(HICON)LoadCursor(NULL, (LPCTSTR)32649); + + s_hCurrentCursor = s_pDefaultCursor[ dc_arrow ]; + +#endif + + s_bCursorLocked = false; + s_bCursorVisible = true; + s_nForceCursorVisibleCount = 0; +} + + +#define USER_CURSOR_MASK 0x80000000 + +#ifdef WIN32 +//----------------------------------------------------------------------------- +// Purpose: Simple manager for user loaded windows cursors in vgui +//----------------------------------------------------------------------------- +class CUserCursorManager +{ +public: + void Shutdown(); + vgui::HCursor CreateCursorFromFile( char const *curOrAniFile, char const *pPathID ); + bool LookupCursor( vgui::HCursor cursor, HCURSOR& handle ); +private: + CUtlDict< HCURSOR, int > m_UserCursors; +}; + +void CUserCursorManager::Shutdown() +{ + for ( int i = m_UserCursors.First() ; i != m_UserCursors.InvalidIndex(); i = m_UserCursors.Next( i ) ) + { + ::DestroyCursor( m_UserCursors[ i ] ); + } + m_UserCursors.RemoveAll(); +} + +vgui::HCursor CUserCursorManager::CreateCursorFromFile( char const *curOrAniFile, char const *pPathID ) +{ + char fn[ 512 ]; + Q_strncpy( fn, curOrAniFile, sizeof( fn ) ); + Q_strlower( fn ); + Q_FixSlashes( fn ); + + int cursorIndex = m_UserCursors.Find( fn ); + if ( cursorIndex != m_UserCursors.InvalidIndex() ) + { + return cursorIndex | USER_CURSOR_MASK; + } + + g_pFullFileSystem->GetLocalCopy( fn ); + + char fullpath[ 512 ]; + g_pFullFileSystem->RelativePathToFullPath( fn, pPathID, fullpath, sizeof( fullpath ) ); + + HCURSOR newCursor = (HCURSOR)LoadCursorFromFile( fullpath ); + cursorIndex = m_UserCursors.Insert( fn, newCursor ); + return cursorIndex | USER_CURSOR_MASK; +} + +bool CUserCursorManager::LookupCursor( vgui::HCursor cursor, HCURSOR& handle ) +{ + if ( !( (int)cursor & USER_CURSOR_MASK ) ) + { + handle = 0; + return false; + } + + int cursorIndex = (int)cursor & ~USER_CURSOR_MASK; + if ( !m_UserCursors.IsValidIndex( cursorIndex ) ) + { + handle = 0; + return false; + } + + handle = m_UserCursors[ cursorIndex ]; + return true; +} + +static CUserCursorManager g_UserCursors; +#endif + +vgui::HCursor Cursor_CreateCursorFromFile( char const *curOrAniFile, char const *pPathID ) +{ +#ifdef WIN32 + return g_UserCursors.CreateCursorFromFile( curOrAniFile, pPathID ); +#else + return dc_user; +#endif +} + + +void Cursor_ClearUserCursors() +{ +#ifdef WIN32 + g_UserCursors.Shutdown(); +#endif +} + + +//----------------------------------------------------------------------------- +// Initializes all the textures for software cursors +//----------------------------------------------------------------------------- +int InitSoftwareCursorTexture( const char *pchFilename ) +{ + if( !pchFilename || !*pchFilename ) + return -1; + + int nTextureID = g_MatSystemSurface.DrawGetTextureId( pchFilename ); + if( nTextureID == -1 ) + { + nTextureID = g_MatSystemSurface.CreateNewTextureID(); + g_MatSystemSurface.DrawSetTextureFile( nTextureID, pchFilename, true, false ); + } + return nTextureID; +} + +void InitSoftwareCursors() +{ + if( s_bSoftwareCursorsInitialized ) + return; + + memset( s_rfSoftwareCursorOffset, 0, sizeof( s_rfSoftwareCursorOffset ) ); + + s_rnSoftwareCursorID[dc_none] = -1; + s_rnSoftwareCursorID[dc_arrow] =InitSoftwareCursorTexture( "vgui/cursors/arrow" ); + s_rnSoftwareCursorID[dc_ibeam] =InitSoftwareCursorTexture( "vgui/cursors/ibeam" ); + s_rnSoftwareCursorID[dc_hourglass]=InitSoftwareCursorTexture( "vgui/cursors/hourglass" ); + s_rnSoftwareCursorID[dc_crosshair]=InitSoftwareCursorTexture( "vgui/cursors/crosshair" ); + s_rnSoftwareCursorID[dc_waitarrow]=InitSoftwareCursorTexture( "vgui/cursors/waitarrow" ); + s_rnSoftwareCursorID[dc_up] =InitSoftwareCursorTexture( "vgui/cursors/up" ); + s_rnSoftwareCursorID[dc_sizenwse] =InitSoftwareCursorTexture( "vgui/cursors/sizenwse" ); + s_rnSoftwareCursorID[dc_sizenesw] =InitSoftwareCursorTexture( "vgui/cursors/sizenesw" ); + s_rnSoftwareCursorID[dc_sizewe] =InitSoftwareCursorTexture( "vgui/cursors/sizewe" ); + s_rnSoftwareCursorID[dc_sizens] =InitSoftwareCursorTexture( "vgui/cursors/sizens" ); + s_rnSoftwareCursorID[dc_sizeall] =InitSoftwareCursorTexture( "vgui/cursors/sizeall" ); + s_rnSoftwareCursorID[dc_no] =InitSoftwareCursorTexture( "vgui/cursors/no" ); + s_rnSoftwareCursorID[dc_hand] =InitSoftwareCursorTexture( "vgui/cursors/hand" ); + + // handle the cursor hotspots not being at their origin + s_rfSoftwareCursorOffset[dc_arrow][0] = -0.1; + s_rfSoftwareCursorOffset[dc_arrow][1] = -0.1; + s_rfSoftwareCursorOffset[dc_ibeam][0] = -0.5; + s_rfSoftwareCursorOffset[dc_ibeam][1] = -0.8; + s_rfSoftwareCursorOffset[dc_hourglass][0] = -0.5; + s_rfSoftwareCursorOffset[dc_hourglass][1] = -0.5; + s_rfSoftwareCursorOffset[dc_crosshair][0] = -0.5; + s_rfSoftwareCursorOffset[dc_crosshair][1] = -0.5; + s_rfSoftwareCursorOffset[dc_waitarrow][0] = -0.1; + s_rfSoftwareCursorOffset[dc_waitarrow][1] = -0.1; + s_rfSoftwareCursorOffset[dc_up][0] = -0.5; + s_rfSoftwareCursorOffset[dc_up][1] = -0.5; + s_rfSoftwareCursorOffset[dc_sizenwse][0] = -0.5; + s_rfSoftwareCursorOffset[dc_sizenwse][1] = -0.5; + s_rfSoftwareCursorOffset[dc_sizenesw][0] = -0.5; + s_rfSoftwareCursorOffset[dc_sizenesw][1] = -0.5; + s_rfSoftwareCursorOffset[dc_sizewe][0] = -0.5; + s_rfSoftwareCursorOffset[dc_sizewe][1] = -0.5; + s_rfSoftwareCursorOffset[dc_sizens][0] = -0.5; + s_rfSoftwareCursorOffset[dc_sizens][1] = -0.5; + s_rfSoftwareCursorOffset[dc_sizeall][0] = -0.5; + s_rfSoftwareCursorOffset[dc_sizeall][1] = -0.5; + s_rfSoftwareCursorOffset[dc_no][0] = -0.5; + s_rfSoftwareCursorOffset[dc_no][1] = -0.5; + s_rfSoftwareCursorOffset[dc_hand][0] = -0.5; + s_rfSoftwareCursorOffset[dc_hand][1] = -0.5; + + s_bSoftwareCursorsInitialized = true; +} + + +//----------------------------------------------------------------------------- +// Selects a cursor +//----------------------------------------------------------------------------- +void CursorSelect(HCursor hCursor) +{ + if ( ( hCursor == dc_alwaysvisible_push ) || ( hCursor == dc_alwaysvisible_pop ) ) + { + // CConPanel in engine/console.cpp does a SetCursor(null). So when the TF2 chat window pops up + // and there are console commands showing and fading out in the top left, our chat window + // will have a cursor show/hide fight with them. So the cursor flickers or doesn't show up + // at all. Unfortunately on Linux, it's even worse since we recenter the mouse when it's + // not shown - so we added this API call which causes cursor.cpp to always show the cursor. + s_nForceCursorVisibleCount += ( hCursor == dc_alwaysvisible_push ? 1 : -1 ); + Assert( s_nForceCursorVisibleCount >= 0 ); + + if( ( s_nForceCursorVisibleCount && !s_bCursorVisible ) || + ( !s_nForceCursorVisibleCount && s_bCursorVisible ) ) + { + ActivateCurrentCursor(); + } + return; + } + + if (s_bCursorLocked) + return; + +#if defined( WIN32 ) && !defined( USE_SDL ) + s_bCursorVisible = true; + switch (hCursor) + { + case dc_user: + case dc_none: + case dc_blank: + s_bCursorVisible = false; + break; + + case dc_arrow: + case dc_waitarrow: + case dc_ibeam: + case dc_hourglass: + case dc_crosshair: + case dc_up: + case dc_sizenwse: + case dc_sizenesw: + case dc_sizewe: + case dc_sizens: + case dc_sizeall: + case dc_no: + case dc_hand: + if( !s_bSoftwareCursorActive ) + { + s_hCurrentCursor = s_pDefaultCursor[hCursor]; + } + else + { + s_nSoftwareCursorTexture = s_rnSoftwareCursorID[ hCursor ]; + s_fSoftwareCursorOffsetX = s_rfSoftwareCursorOffset[ hCursor ][0]; + s_fSoftwareCursorOffsetY = s_rfSoftwareCursorOffset[ hCursor ][1]; + } + break; + + default: + { + HCURSOR custom = 0; + if ( g_UserCursors.LookupCursor( hCursor, custom ) && custom != 0 ) + { + s_hCurrentCursor = custom; + } + else + { + s_bCursorVisible = false; + Assert(0); + } + } + break; + } + + ActivateCurrentCursor(); + +#elif defined( USE_SDL ) + + switch (hCursor) + { + case dc_user: + case dc_none: + case dc_blank: + s_bCursorVisible = false; + break; + + default: + // We don't support custom cursors at the moment (but could, if necessary). + // Fall through and use the arrow for now... + Assert(0); + hCursor = dc_arrow; + + case dc_arrow: + case dc_waitarrow: + case dc_ibeam: + case dc_hourglass: + case dc_crosshair: + case dc_up: + case dc_sizenwse: + case dc_sizenesw: + case dc_sizewe: + case dc_sizens: + case dc_sizeall: + case dc_no: + case dc_hand: + s_bCursorVisible = true; + if( !s_bSoftwareCursorActive ) + { + s_hCurrentCursor = s_pDefaultCursor[hCursor]; + } + else + { + s_nSoftwareCursorTexture = s_rnSoftwareCursorID[ hCursor ]; + s_fSoftwareCursorOffsetX = s_rfSoftwareCursorOffset[ hCursor ][0]; + s_fSoftwareCursorOffsetY = s_rfSoftwareCursorOffset[ hCursor ][1]; + } + break; + } + + ActivateCurrentCursor(); + +#else +#error +#endif + +} + + +//----------------------------------------------------------------------------- +// Hides the hardware cursor +//----------------------------------------------------------------------------- +void HideHardwareCursor() +{ +#if defined( WIN32 ) && !defined( USE_SDL ) + ::SetCursor(NULL); +#elif defined( USE_SDL ) + //if ( s_hCurrentlySetCursor != s_pDefaultCursor[ dc_none ] ) + { + s_hCurrentlySetCursor = s_pDefaultCursor[ dc_none ]; + g_pLauncherMgr->SetMouseCursor( s_hCurrentlySetCursor ); + g_pLauncherMgr->SetMouseVisible( false ); + } +#else +#error +#endif +} + + +//----------------------------------------------------------------------------- +// Activates the current cursor +//----------------------------------------------------------------------------- +void ActivateCurrentCursor() +{ + if( s_bSoftwareCursorActive ) + { + HideHardwareCursor(); + return; + } + + if ( s_bCursorVisible || ( s_nForceCursorVisibleCount > 0 ) ) + { +#if defined( WIN32 ) && !defined( USE_SDL ) + ::SetCursor(s_hCurrentCursor); +#elif defined( USE_SDL ) + if (s_hCurrentlySetCursor != s_hCurrentCursor ) + { + s_hCurrentlySetCursor = s_hCurrentCursor; + g_pLauncherMgr->SetMouseCursor( s_hCurrentlySetCursor ); + g_pLauncherMgr->SetMouseVisible( true ); + } +#else +#error +#endif + } + else + { + HideHardwareCursor(); + } +} + + +//----------------------------------------------------------------------------- +// Purpose: prevents vgui from changing the cursor +//----------------------------------------------------------------------------- +void LockCursor( bool bEnable ) +{ + s_bCursorLocked = bEnable; + ActivateCurrentCursor(); +} + + +//----------------------------------------------------------------------------- +// Purpose: unlocks the cursor state +//----------------------------------------------------------------------------- +bool IsCursorLocked() +{ + return s_bCursorLocked; +} + + +//----------------------------------------------------------------------------- +// handles mouse movement +//----------------------------------------------------------------------------- +void CursorSetPos( void *hwnd, int x, int y ) +{ +#if defined( USE_SDL ) + if ( s_bCursorVisible ) +#endif + g_pInputSystem->SetCursorPosition( x, y ); +} + +void CursorGetPos(void *hwnd, int &x, int &y) +{ +#if defined ( USE_SDL ) && !defined( PLATFORM_WINDOWS ) + if ( s_bCursorVisible ) + { + SDL_GetMouseState( &x, &y ); + + int windowHeight = 0; + int windowWidth = 0; + //unsigned int ignored; + SDL_GetWindowSize( ( SDL_Window * )g_pLauncherMgr->GetWindowRef(), &windowWidth, &windowHeight ); + + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + int rx, ry, width, height; + pRenderContext->GetViewport( rx, ry, width, height ); + + if ( !s_bSoftwareCursorActive && (width != windowWidth || height != windowHeight ) ) + { + // scale the x/y back into the co-ords of the back buffer, not the scaled up window + //DevMsg( "Mouse x:%d y:%d %d %d %d %d\n", x, y, width, windowWidth, height, abs( height - windowHeight ) ); + x = x * (float)width/windowWidth; + y = y * (float)height/windowHeight; + } + } + else + { + // cursor is invisible, just say we have it pinned to the middle of the screen + CMatRenderContextPtr pRenderContext( g_pMaterialSystem ); + int rx, ry, width, height; + pRenderContext->GetViewport( rx, ry, width, height ); + x = rx + width/2; + y = ry + height/2; + //printf( "Mouse(inv) x:%d y:%d %d %d\n", x, y, width, height ); + } +#else + POINT pt; + + // Default implementation + VCRHook_GetCursorPos( &pt ); + VCRHook_ScreenToClient((HWND)hwnd, &pt); + x = pt.x; y = pt.y; +#endif +} + + +void EnableSoftwareCursor( bool bEnable ) +{ + if( bEnable ) + InitSoftwareCursors(); + + bool bWasEnabled = s_bSoftwareCursorActive; + s_bSoftwareCursorActive = bEnable; + + // set the cursor to the arrow (or none if appropriate) if we're activating the + // software cursor. VGUI will likely update it again soon, but this will give + // us some kind of cursor in the meantime + if( !bWasEnabled && bEnable ) + { + if( s_bCursorVisible ) + CursorSelect( dc_arrow ); + } +} + +bool ShouldDrawSoftwareCursor() +{ + return s_bSoftwareCursorActive && s_bCursorVisible; +} + +int GetSoftwareCursorTexture( float *px, float *py ) +{ + if( px && py ) + { + *px = s_fSoftwareCursorOffsetX; + *py = s_fSoftwareCursorOffsetY; + } + return s_nSoftwareCursorTexture; +} + + |