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.

1587 lines
42 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "stdafx.h"
  8. #include "tier1/keyvalues.h"
  9. #include "matchmaking/imatchframework.h"
  10. #include "GFx_AMP.h"
  11. #if defined( _PS3 )
  12. #include "ps3/ps3_console.h"
  13. #include "tls_ps3.h"
  14. #endif
  15. // NOTE: This must be the last file included!!!
  16. #include "tier0/memdbgon.h"
  17. using namespace SF::GFx;
  18. using namespace SF::Render;
  19. CON_COMMAND( sf4_meshcache_stats, "Outputs Scaleform 4 mesh cache stats" )
  20. {
  21. ScaleformUIImpl::m_Instance.DumpMeshCacheStats();
  22. }
  23. bool g_bScaleformIMEDetailedLogging = false;
  24. #ifndef Log_Detailed
  25. #define Log_Detailed( Channel, /* [LoggingMetaData_t *], [Color], Message, */ ... ) do { if (g_bScaleformIMEDetailedLogging) InternalMsg( Channel, LS_MESSAGE, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 )
  26. #endif
  27. DECLARE_LOGGING_CHANNEL( LOG_SCALEFORM_IME );
  28. DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_SCALEFORM_IME, "Scaleform IME" );
  29. static XUID NormalizeXuidForAccountID( XUID xuid )
  30. {
  31. if ( ( xuid & 0xFFFFFFFFull ) == xuid )
  32. return xuid; // AccountID only only
  33. CSteamID steamID( xuid );
  34. if ( steamID.IsValid() && steamID.BIndividualAccount() )
  35. return steamID.GetAccountID(); // trim upper part of SteamID
  36. return xuid;
  37. }
  38. void ScaleformUIImpl::InitHighLevelImpl( void )
  39. {
  40. m_iLastMouseX = -1;
  41. m_iLastMouseY = -1;
  42. m_iKeyboardSlot = 0;
  43. m_bEatPS3MouseEvent = true;
  44. V_memset( m_fJoyValues, 0, sizeof( m_fJoyValues ) );
  45. V_memset( m_iJoyAxisButtonsDown, 0, sizeof( m_iJoyAxisButtonsDown ) );
  46. SetDefLessFunc( m_mapUserXuidToAvatar );
  47. SetDefLessFunc( m_mapItemIdToImage );
  48. SetDefLessFunc( m_mapImageIdToChromeImage );
  49. #if !defined( NO_STEAM )
  50. m_bSteamCallbacksConfigured = false;
  51. #endif
  52. #if defined( CSTRIKE15 ) && !defined( _X360 )
  53. // $TODO: Figure out why we aren't properly loading the default texture on Xbox
  54. // Load the default avatar image bits and store them in a raw buffer
  55. CUtlBuffer bufFile;
  56. static const char* cDefaultAvatarImageFileName = "materials/vgui/avatar_default_64" PLATFORM_EXT ".vtf";
  57. if ( g_pFullFileSystem->ReadFile( cDefaultAvatarImageFileName, NULL, bufFile ) )
  58. {
  59. m_pDefaultAvatarTexture = CreateVTFTexture();
  60. #if !defined( _GAMECONSOLE )
  61. if ( !m_pDefaultAvatarTexture->Unserialize( bufFile ) )
  62. #else
  63. if ( !m_pDefaultAvatarTexture->UnserializeFromBuffer( bufFile, true, false, false, 0 ) )
  64. #endif
  65. {
  66. Warning( "Invalid or corrupt default avatar image (%s)\n", cDefaultAvatarImageFileName );
  67. DestroyVTFTexture( m_pDefaultAvatarTexture );
  68. m_pDefaultAvatarTexture = NULL;
  69. }
  70. }
  71. else
  72. {
  73. Warning( "Failed to read the default avatar image file (%s)\n", cDefaultAvatarImageFileName );
  74. }
  75. // Load the default inventory image bits and store them in a raw buffer
  76. bufFile.Clear();
  77. static const char* cDefaultInventoryImageFileName = "materials/vgui/inventory_default" PLATFORM_EXT ".vtf";
  78. if ( g_pFullFileSystem->ReadFile( cDefaultInventoryImageFileName, NULL, bufFile ) )
  79. {
  80. m_pDefaultInventoryTexture = CreateVTFTexture();
  81. #if !defined( _GAMECONSOLE )
  82. if ( !m_pDefaultInventoryTexture->Unserialize( bufFile ) )
  83. #else
  84. if ( !m_pDefaultInventoryTexture->UnserializeFromBuffer( bufFile, true, false, false, 0 ) )
  85. #endif
  86. {
  87. Warning( "Invalid or corrupt default inventory image (%s)\n", cDefaultInventoryImageFileName );
  88. DestroyVTFTexture( m_pDefaultInventoryTexture );
  89. m_pDefaultInventoryTexture = NULL;
  90. }
  91. }
  92. else
  93. {
  94. Warning( "Failed to read the default inventory image file (%s)\n", cDefaultInventoryImageFileName );
  95. }
  96. #endif // CSTRIKE15
  97. m_CurrentKey = BUTTON_CODE_INVALID;
  98. }
  99. #if !defined( NO_STEAM )
  100. void ScaleformUIImpl::EnsureSteamCallbacksConfigured()
  101. {
  102. if ( m_bSteamCallbacksConfigured )
  103. return;
  104. m_bSteamCallbacksConfigured = true;
  105. m_CallbackPersonaStateChanged.Register( this, &ScaleformUIImpl::Steam_OnPersonaStateChanged );
  106. m_CallbackAvatarImageLoaded.Register( this, &ScaleformUIImpl::Steam_OnAvatarImageLoaded );
  107. }
  108. void ScaleformUIImpl::Steam_OnAvatarImageLoaded( AvatarImageLoaded_t *pParam )
  109. {
  110. if ( pParam )
  111. {
  112. AvatarImageReload( pParam->m_steamID.ConvertToUint64(), NULL );
  113. }
  114. }
  115. void ScaleformUIImpl::Steam_OnPersonaStateChanged( PersonaStateChange_t *pParam )
  116. {
  117. if ( pParam && ( pParam->m_nChangeFlags & k_EPersonaChangeAvatar ) )
  118. {
  119. AvatarImageReload( pParam->m_ulSteamID, NULL );
  120. }
  121. }
  122. #endif
  123. void ScaleformUIImpl::ShutdownHighLevelImpl( void )
  124. {
  125. if ( m_pDefaultAvatarTexture )
  126. {
  127. DestroyVTFTexture( m_pDefaultAvatarTexture );
  128. m_pDefaultAvatarTexture = NULL;
  129. }
  130. if ( m_pDefaultAvatarImage )
  131. {
  132. delete m_pDefaultAvatarImage;
  133. m_pDefaultAvatarImage = NULL;
  134. }
  135. if ( m_pDefaultInventoryTexture )
  136. {
  137. DestroyVTFTexture( m_pDefaultInventoryTexture );
  138. m_pDefaultInventoryTexture = NULL;
  139. }
  140. if ( m_pDefaultInventoryImage )
  141. {
  142. delete m_pDefaultInventoryImage;
  143. m_pDefaultInventoryImage = NULL;
  144. }
  145. if ( m_pDefaultChromeHTMLImage )
  146. {
  147. delete m_pDefaultChromeHTMLImage;
  148. m_pDefaultChromeHTMLImage = NULL;
  149. }
  150. #ifdef USE_DEFAULT_INVENTORY_ICON_BACKGROUNDS
  151. for ( CUtlHashFast< DefaultInventoryIcon_t >::UtlHashFastIterator_t i = m_defaultInventoryIcons.First(); m_defaultInventoryIcons.IsValidIterator( i ); i = m_defaultInventoryIcons.Next( i ) )
  152. {
  153. if ( m_defaultInventoryIcons[ i ].m_pTexture )
  154. {
  155. DestroyVTFTexture( m_defaultInventoryIcons[ i ].m_pTexture );
  156. m_defaultInventoryIcons[ i ].m_pTexture = NULL;
  157. }
  158. if ( m_defaultInventoryIcons[ i ].m_pImage )
  159. {
  160. delete m_defaultInventoryIcons[ i ].m_pImage;
  161. m_defaultInventoryIcons[ i ].m_pImage = NULL;
  162. }
  163. }
  164. m_defaultInventoryIcons.RemoveAll();
  165. #endif
  166. m_CurrentKey = BUTTON_CODE_INVALID;
  167. }
  168. void ScaleformUIImpl::ClearCache( void )
  169. {
  170. // Do not clear the cache straight away. We need to ensure that we are clearing the mesh cache on the
  171. // render thread => cache being actually cleared in RenderSlot.
  172. m_bClearMeshCacheQueued = true;
  173. }
  174. const char* ScaleformUIImpl::CorrectFlashFileName( const char * name )
  175. {
  176. // make sure the name is long enough to have an extension, but not too long
  177. int len = V_strlen( name );
  178. if ( len < 4 || len >= TEMPORARY_BUFFER_SIZE )
  179. {
  180. return name;
  181. }
  182. #if 1
  183. //
  184. // Allow -customswf to override directory from which SWF files are loaded
  185. // otherwise load directly from main resource directory
  186. //
  187. static char const *szSwfDirOverride = CommandLine()->ParmValue( "-customswf", ( const char * ) NULL );
  188. static int nSwfDirOverrideLen = szSwfDirOverride ? V_strlen( szSwfDirOverride ) : 0;
  189. if ( szSwfDirOverride && *szSwfDirOverride && ( len + nSwfDirOverrideLen + 4 < TEMPORARY_BUFFER_SIZE ) )
  190. {
  191. char const *szDirSeparator = strrchr( name, '/' );
  192. if ( szDirSeparator )
  193. {
  194. V_sprintf_safe( m_cTemporaryBuffer, "%.*s%s%s", ( szDirSeparator - name + 1 ), name, szSwfDirOverride, szDirSeparator );
  195. if ( g_pFullFileSystem->FileExists( m_cTemporaryBuffer, "GAME" ) )
  196. {
  197. DevMsg( "-customswf: %s\n", m_cTemporaryBuffer );
  198. return m_cTemporaryBuffer;
  199. }
  200. }
  201. }
  202. return name;
  203. #else
  204. // we only want to continue if the filename is a .swf or a .gfx file
  205. // otherwise we can just use the original name
  206. const char* pFirstEXTChar = V_strstr( ".swf.gfx", &name[len-4] );
  207. if ( !pFirstEXTChar )
  208. {
  209. return name;
  210. }
  211. // point to the first char of the extension so we
  212. // can test later
  213. pFirstEXTChar++;
  214. // this is a utility variable.
  215. // we'll use it to point to the actual string we want to
  216. // use
  217. const char* namePtr;
  218. // if we're supposed to try SWF's first, see if an
  219. // SWF file exists
  220. if ( m_bTrySWFFirst )
  221. {
  222. if ( *pFirstEXTChar == 's' )
  223. {
  224. namePtr = name;
  225. }
  226. else
  227. {
  228. V_strncpy( m_cTemporaryBuffer, name, TEMPORARY_BUFFER_SIZE );
  229. V_strcpy( &m_cTemporaryBuffer[len-3], "swf" );
  230. namePtr = m_cTemporaryBuffer;
  231. }
  232. if ( g_pFullFileSystem->FileExists( namePtr, "GAME" ) )
  233. {
  234. return namePtr;
  235. }
  236. }
  237. // convert filename extension to gfx
  238. if ( *pFirstEXTChar == 'g' )
  239. {
  240. namePtr = name;
  241. }
  242. else
  243. {
  244. V_strncpy( m_cTemporaryBuffer, name, TEMPORARY_BUFFER_SIZE );
  245. V_strcpy( &m_cTemporaryBuffer[len-3], "gfx" );
  246. namePtr = m_cTemporaryBuffer;
  247. }
  248. return namePtr;
  249. #endif
  250. }
  251. void ScaleformUIImpl::SendUIEvent( const char* action, const char* eventData, int slot )
  252. {
  253. IGameEvent * pEvent = m_pGameEventManager->CreateEvent( "sfuievent" );
  254. if ( pEvent )
  255. {
  256. pEvent->SetString( "action", action );
  257. pEvent->SetString( "data", eventData );
  258. pEvent->SetInt( "slot", slot );
  259. m_pGameEventManager->FireEventClientSide( pEvent );
  260. SFDevMsg("sfuievent action=%s data=%d slot=%d\n", action?action:"", eventData?eventData:"", slot);
  261. }
  262. }
  263. float ScaleformUIImpl::GetJoyValue( int slot, int stickIndex, int axis )
  264. {
  265. AssertMsg( SF_SS_SLOT( slot ) < MAX_SLOTS, "Invalid slot index in GetJoyValue" );
  266. return m_fJoyValues[ JOY_VALUE_INDEX( slot, stickIndex, axis ) ];
  267. }
  268. void ScaleformUIImpl::SetJoyValue( int slot, int stickIndex, int axis, int value )
  269. {
  270. AssertMsg( SF_SS_SLOT( slot ) < MAX_SLOTS, "Invalid slot index in SetJoyValue" );
  271. m_fJoyValues[ JOY_VALUE_INDEX( slot, stickIndex, axis ) ] = (float)value / 32768.0f;
  272. }
  273. void ScaleformUIImpl::SetScreenSize( int x, int y )
  274. {
  275. MEM_ALLOC_CREDIT();
  276. m_iScreenWidth = x;
  277. m_iScreenHeight = y;
  278. SetSlotViewport( SF_FULL_SCREEN_SLOT, 0, 0, x, y );
  279. SetSlotViewport( SF_RESERVED_CURSOR_SLOT, 0, 0, x, y );
  280. }
  281. void ScaleformUIImpl::SetSingleThreadedMode( bool bSingleThreded )
  282. {
  283. m_bSingleThreaded = bSingleThreded;
  284. if ( !m_pRenderHAL )
  285. {
  286. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  287. return;
  288. }
  289. if ( m_bSingleThreaded )
  290. {
  291. m_pRenderHAL->GetTextureManager()->SetRenderThreadIdToCurrentThread();
  292. }
  293. else
  294. {
  295. // RenderThreadId will be set in RenderSlot - Just reseting for now
  296. // so that textures are not created on the main thread.
  297. m_pRenderHAL->GetTextureManager()->ResetRenderThreadId();
  298. }
  299. }
  300. void ScaleformUIImpl::RunFrame( float time )
  301. {
  302. m_fTime = time;
  303. #ifndef SF_BUILD_SHIPPING
  304. if ( m_bPumpScaleformStats )
  305. {
  306. AMP::Server::GetInstance().AdvanceFrame();
  307. }
  308. #endif
  309. SNPROF("ScaleformUIImpl::RunFrame");
  310. #ifdef _PS3
  311. if ( GetTLSGlobals()->bNormalQuitRequested )
  312. {
  313. return; // do not disconnect recursively on QUIT
  314. }
  315. #endif
  316. UpdateCursorLazyHide( m_fTime );
  317. UpdateAvatarImages();
  318. // Removed advance slot from RunFrame. AdvanceSlot is now called just before rendering (fix hud element lagging)
  319. }
  320. bool ScaleformUIImpl::DistributeEvent( Event& event, int slotNumber, bool toAllSlots, bool clearControllerUI )
  321. {
  322. bool result = false;
  323. CursorSlot* pCursorSlot = ( CursorSlot* )LockSlotPtr( SF_RESERVED_CURSOR_SLOT );
  324. if ( pCursorSlot )
  325. {
  326. pCursorSlot->m_pMovieView->HandleEvent( event );
  327. }
  328. UnlockSlotPtr( SF_RESERVED_CURSOR_SLOT );
  329. int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( slotNumber ) };
  330. for ( int i = 0; i < 2; i++ )
  331. {
  332. if ( slots[i] < MAX_SLOTS )
  333. {
  334. BaseSlot* pSlot = LockSlotPtr( slots[i] );
  335. if ( pSlot && pSlot->ConsumesInputEvents() )
  336. {
  337. if ( clearControllerUI )
  338. {
  339. bool isKeyOrButtonPress = (event.Type == Event::MouseDown || event.Type == Event::KeyDown );
  340. pSlot->SetToControllerUI( false, isKeyOrButtonPress );
  341. }
  342. unsigned int code = pSlot->m_pMovieView->HandleEvent( event );
  343. if ( code & Movie::HE_NoDefaultAction )
  344. {
  345. result = true;
  346. }
  347. }
  348. UnlockSlotPtr( slots[i] );
  349. // [jason] slots are listed in order of priority, so if one has already handled the event it supersedes any other slots
  350. if ( result && !toAllSlots )
  351. {
  352. break;
  353. }
  354. }
  355. }
  356. return result;
  357. }
  358. bool ScaleformUIImpl::DistributeKeyEvent( bool keyDown, bool fromController, const char* binding, ButtonCode_t code, ButtonCode_t vkey, int slotNumber, bool toAllSlots )
  359. {
  360. bool result = false;
  361. int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( slotNumber ) };
  362. for ( int i = 0; i < 2; i++ )
  363. {
  364. if ( slots[i] < MAX_SLOTS )
  365. {
  366. BaseSlot* pSlot = LockSlotPtr( slots[i] );
  367. if ( pSlot && pSlot->ConsumesInputEvents() )
  368. {
  369. bool isButtonPress = keyDown && code < JOYSTICK_FIRST_AXIS_BUTTON;
  370. pSlot->SetToControllerUI( fromController, isButtonPress );
  371. result = pSlot->HandleKeyEvent( keyDown, code, vkey, binding, slotNumber ) || result;
  372. }
  373. UnlockSlotPtr( slots[i] );
  374. // [jason] slots are listed in order of priority, so if one has already handled the event it supersedes any other slots
  375. if ( result && !toAllSlots )
  376. {
  377. break;
  378. }
  379. }
  380. }
  381. return result;
  382. }
  383. bool ScaleformUIImpl::DistributeCharTyped( wchar_t code )
  384. {
  385. wchar_t msgString[2];
  386. msgString[0] = code;
  387. msgString[1] = L'\0';
  388. int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( m_iKeyboardSlot ) };
  389. bool result = false;
  390. for ( int i = 0; i < 2; i++ )
  391. {
  392. if ( slots[i] < MAX_SLOTS )
  393. {
  394. BaseSlot* pSlot = LockSlotPtr( slots[i] );
  395. if ( pSlot && pSlot->ConsumesInputEvents() )
  396. {
  397. pSlot->SetToControllerUI( false, true );
  398. result = pSlot->HandleCharTyped( msgString, m_iKeyboardSlot ) || result;
  399. }
  400. UnlockSlotPtr( slots[i] );
  401. // [jason] slots are listed in order of priority, so if one has already handled the event it supersedes any other slots
  402. if ( result )
  403. {
  404. break;
  405. }
  406. }
  407. }
  408. return result;
  409. }
  410. bool ScaleformUIImpl::HitTest( int x, int y )
  411. {
  412. MEM_ALLOC_CREDIT();
  413. bool result = false;
  414. int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( m_iKeyboardSlot ) };
  415. for ( int i = 0; i < 2 && !result; i++ )
  416. {
  417. if ( slots[i] < MAX_SLOTS )
  418. {
  419. BaseSlot* pSlot = LockSlotPtr( slots[i] );
  420. if ( pSlot && pSlot->ConsumesInputEvents() )
  421. {
  422. if ( pSlot->m_pMovieView->HitTest( x, y, Movie::HitTest_Shapes ) )
  423. {
  424. result = true;
  425. }
  426. }
  427. UnlockSlotPtr( slots[i] );
  428. }
  429. }
  430. return result;
  431. }
  432. bool ScaleformUIImpl::TallyAxisButtonEvent( int slot, int code, bool down )
  433. {
  434. bool result = false;
  435. int sfSlot = SF_SS_SLOT( slot );
  436. if ( sfSlot < MAX_SLOTS )
  437. {
  438. if ( code >= JOYSTICK_FIRST_AXIS_BUTTON && code <= JOYSTICK_LAST_AXIS_BUTTON )
  439. {
  440. int mask = 1 << ( code - JOYSTICK_FIRST_AXIS_BUTTON );
  441. if ( down )
  442. {
  443. // on a down event, only let us through if we haven't disabled stick navigation
  444. if ( !AnalogStickNavigationDisabled( sfSlot ) )
  445. {
  446. result = true;
  447. m_iJoyAxisButtonsDown[slot] |= mask;
  448. }
  449. }
  450. else
  451. {
  452. // on an up event, we just care about if we captured a previous down event
  453. result = ( m_iJoyAxisButtonsDown[slot] & mask ) != 0;
  454. m_iJoyAxisButtonsDown[slot] &= ~mask;
  455. }
  456. }
  457. else
  458. {
  459. // if this isn't a joystick axis button, then just let it go through
  460. result = true;
  461. }
  462. }
  463. return result;
  464. }
  465. bool ScaleformUIImpl::HandleInputEvent( const InputEvent_t &event )
  466. {
  467. MEM_ALLOC_CREDIT();
  468. // Update cached mouse location always, even if we aren't consuming mouse events.
  469. // Otherwise we could have a stale value if we start consuming mouse events but the mouse doesn't actually move.
  470. bool mousePositionChanged = false;
  471. if ( event.m_nType == IE_AnalogValueChanged && event.m_nData == MOUSE_XY )
  472. {
  473. if ( m_iLastMouseX != event.m_nData2 || m_iLastMouseY != event.m_nData3 )
  474. {
  475. mousePositionChanged = true;
  476. m_iLastMouseX = event.m_nData2;
  477. m_iLastMouseY = event.m_nData3;
  478. }
  479. }
  480. bool result = false;
  481. bool isJoystickEvent = ( event.m_nType == IE_AnalogValueChanged ) && ( event.m_nData >= JOYSTICK_FIRST_AXIS ) && ( event.m_nData <= JOYSTICK_LAST_AXIS );
  482. bool consumesEvents = ConsumesInputEvents();
  483. const char* buttonBinding;
  484. if ( !consumesEvents && !isJoystickEvent )
  485. {
  486. return result;
  487. }
  488. // no need to handle input event if the console is visible
  489. if ( m_pEngine->Con_IsVisible() )
  490. {
  491. return result;
  492. }
  493. int slot = 0;
  494. switch ( event.m_nType )
  495. {
  496. case IE_ButtonDoubleClicked:
  497. case IE_ButtonPressed:
  498. {
  499. // NOTE: data2 is the virtual key code ( data1 contains the scan-code one )
  500. ButtonCode_t code;
  501. m_CurrentKey = ( ButtonCode_t ) event.m_nData;
  502. DecodeButtonandSlotFromButtonCode( m_CurrentKey, code, slot );
  503. buttonBinding = m_pGameUIFuncs->GetBindingForButtonCode( m_CurrentKey );
  504. bool bIsFromController = IsJoystickCode( code );
  505. if ( bIsFromController )
  506. {
  507. ControllerMoved();
  508. }
  509. if ( IsKeyCode( code ) || bIsFromController )
  510. {
  511. if ( TallyAxisButtonEvent( slot, code, true ) )
  512. {
  513. result = DistributeKeyEvent( true, bIsFromController, buttonBinding, m_CurrentKey, ( ButtonCode_t ) event.m_nData2, slot, false );
  514. }
  515. else
  516. {
  517. result = false;
  518. }
  519. }
  520. if ( IsMouseCode( code ) && m_iWantCursorShown )
  521. {
  522. CursorMoved();
  523. if ( HitTest( m_iLastMouseX, m_iLastMouseY ) )
  524. {
  525. if ( code != MOUSE_LEFT )
  526. {
  527. result = DistributeKeyEvent( true, false, buttonBinding, m_CurrentKey, ( ButtonCode_t ) event.m_nData2, slot, false );
  528. }
  529. else
  530. {
  531. MouseEvent mevent( Event::MouseDown, 0, m_iLastMouseX, m_iLastMouseY );
  532. result = DistributeEvent( mevent, slot, false );
  533. }
  534. }
  535. }
  536. }
  537. break;
  538. case IE_KeyTyped:
  539. {
  540. result = DistributeCharTyped( ( wchar_t )event.m_nData );
  541. }
  542. break;
  543. case IE_ButtonReleased:
  544. {
  545. // NOTE: data2 is the virtual key code ( data1 contains the scan-code one )
  546. ButtonCode_t code;
  547. DecodeButtonandSlotFromButtonCode( ( ButtonCode_t ) event.m_nData, code, slot );
  548. buttonBinding = m_pGameUIFuncs->GetBindingForButtonCode( ( ButtonCode_t ) event.m_nData );
  549. bool bIsFromController = IsJoystickCode( code );
  550. if ( bIsFromController )
  551. {
  552. ControllerMoved();
  553. }
  554. if ( IsKeyCode( code ) || bIsFromController )
  555. {
  556. if ( TallyAxisButtonEvent( slot, code, false ) )
  557. {
  558. result = DistributeKeyEvent( false, bIsFromController, buttonBinding, code, ( ButtonCode_t ) event.m_nData2, slot, false );
  559. }
  560. else
  561. {
  562. result = false;
  563. }
  564. }
  565. if ( IsMouseCode( code ) && ( m_iWantCursorShown || code != MOUSE_LEFT ) )
  566. {
  567. CursorMoved();
  568. if ( code != MOUSE_LEFT )
  569. {
  570. result = DistributeKeyEvent( false, false, buttonBinding, m_CurrentKey, ( ButtonCode_t ) event.m_nData2, slot, false );
  571. }
  572. else
  573. {
  574. MouseEvent mevent( Event::MouseUp, 0, m_iLastMouseX, m_iLastMouseY );
  575. DistributeEvent( mevent, slot, false );
  576. }
  577. }
  578. }
  579. break;
  580. case IE_AnalogValueChanged:
  581. {
  582. switch ( event.m_nData )
  583. {
  584. case MOUSE_XY:
  585. if ( mousePositionChanged && m_iWantCursorShown )
  586. {
  587. // on the PS3 a single mouse update is queued even when no mouse is connected
  588. // So on PS3 we'll eat that message and wait for the next one before we actually
  589. // show the cursor or switch to the keyboard/mouse UI glyphs
  590. if ( IsPS3() && m_bEatPS3MouseEvent )
  591. {
  592. m_bEatPS3MouseEvent = false;
  593. MouseEvent mevent( Event::MouseMove, 0, m_iLastMouseX, m_iLastMouseY );
  594. DistributeEvent( mevent, m_iKeyboardSlot, false, false );
  595. }
  596. else
  597. {
  598. CursorMoved();
  599. // If we're using the steam controller, assume input coming from the controller and continue to stay in controller UI mode.
  600. // FIXME : Need latest SteamAPI integration
  601. //bool bClearControllerUI = steamapicontext && !steamapicontext->SteamController();
  602. bool bClearControllerUI = false;
  603. MouseEvent mevent( Event::MouseMove, 0, m_iLastMouseX, m_iLastMouseY );
  604. DistributeEvent( mevent, m_iKeyboardSlot, false, bClearControllerUI );
  605. }
  606. }
  607. break;
  608. case JOYSTICK_AXIS(0, JOY_AXIS_X ):
  609. SetJoyValue( 0, 0, 0, event.m_nData2 );
  610. break;
  611. case JOYSTICK_AXIS(0, JOY_AXIS_Y ):
  612. SetJoyValue( 0, 0, 1, event.m_nData2 );
  613. break;
  614. case JOYSTICK_AXIS(0, JOY_AXIS_U ):
  615. SetJoyValue( 0, 1, 0, event.m_nData2 );
  616. break;
  617. case JOYSTICK_AXIS(0, JOY_AXIS_R ):
  618. SetJoyValue( 0, 1, 1, event.m_nData2 );
  619. break;
  620. case JOYSTICK_AXIS(1, JOY_AXIS_X ):
  621. SetJoyValue( 1, 0, 0, event.m_nData2 );
  622. slot = 1;
  623. break;
  624. case JOYSTICK_AXIS(1, JOY_AXIS_Y ):
  625. SetJoyValue( 1, 0, 1, event.m_nData2 );
  626. slot = 1;
  627. break;
  628. case JOYSTICK_AXIS(1, JOY_AXIS_U ):
  629. SetJoyValue( 1, 1, 0, event.m_nData2 );
  630. slot = 1;
  631. break;
  632. case JOYSTICK_AXIS(1, JOY_AXIS_R ):
  633. SetJoyValue( 1, 1, 1, event.m_nData2 );
  634. slot = 1;
  635. break;
  636. }
  637. }
  638. break;
  639. default:
  640. return false;
  641. }
  642. // always eat key input when IME is up
  643. if ( !result && m_bIMEEnabled )
  644. {
  645. switch ( event.m_nType )
  646. {
  647. case IE_ButtonPressed:
  648. case IE_ButtonReleased:
  649. {
  650. ButtonCode_t code;
  651. m_CurrentKey = (ButtonCode_t)event.m_nData;
  652. DecodeButtonandSlotFromButtonCode( m_CurrentKey, code, slot );
  653. if ( !IsMouseCode( code ) )
  654. {
  655. result = true;
  656. }
  657. }
  658. }
  659. }
  660. bool returnValue;
  661. if ( !consumesEvents )
  662. {
  663. returnValue = false;
  664. }
  665. else if ( SlotDeniesInputToGame( SF_SS_SLOT( slot ) ) )
  666. {
  667. returnValue = true;
  668. }
  669. else
  670. {
  671. returnValue = result;
  672. }
  673. return returnValue;
  674. }
  675. bool ScaleformUIImpl::IsSlotKeyboardAccessible( int slot )
  676. {
  677. return ( slot == SF_FULL_SCREEN_SLOT || slot == SF_SS_SLOT( m_iKeyboardSlot ) );
  678. }
  679. bool ScaleformUIImpl::HandleIMEEvent( size_t hwnd, unsigned int uMsg, unsigned int wParam, long lParam )
  680. {
  681. #if defined( PLATFORM_WINDOWS_PC )
  682. if ( g_bScaleformIMEDetailedLogging )
  683. {
  684. Log_Detailed( LOG_SCALEFORM_IME, "HandleIMEEvent: hWnd:0x%8.8x, uMsg:0x%8.8x, wParam:0x%8.8x, lParam:0x%8.8x\n", (uint32)hwnd, (uint32)uMsg, (uint32)wParam, (uint32)lParam );
  685. CUtlString messageString;
  686. switch ( uMsg )
  687. {
  688. case WM_LBUTTONDOWN:
  689. messageString = "WM_LBUTTONDOWN";
  690. break;
  691. case WM_LBUTTONUP:
  692. messageString = "WM_LBUTTONUP";
  693. break;
  694. case WM_KEYDOWN:
  695. messageString = "WM_KEYDOWN";
  696. break;
  697. case WM_KEYUP:
  698. messageString = "WM_KEYUP";
  699. break;
  700. case WM_CHAR:
  701. messageString = "WM_CHAR";
  702. break;
  703. case WM_DEADCHAR:
  704. messageString = "WM_DEADCHAR";
  705. break;
  706. case WM_SYSKEYDOWN:
  707. messageString = "WM_SYSKEYDOWN";
  708. break;
  709. case WM_SYSKEYUP:
  710. messageString = "WM_SYSKEYUP";
  711. break;
  712. case WM_SYSCHAR:
  713. messageString = "WM_SYSCHAR";
  714. break;
  715. case WM_SYSDEADCHAR:
  716. messageString = "WM_SYSDEADCHAR";
  717. break;
  718. case WM_UNICHAR:
  719. messageString = "WM_UNICHAR";
  720. break;
  721. case WM_INPUTLANGCHANGE:
  722. messageString = "WM_INPUTLANGCHANGE";
  723. break;
  724. case WM_IME_STARTCOMPOSITION:
  725. messageString = "WM_IME_STARTCOMPOSITION";
  726. break;
  727. case WM_IME_COMPOSITION:
  728. messageString = "WM_IME_COMPOSITION";
  729. break;
  730. case WM_IME_ENDCOMPOSITION:
  731. messageString = "WM_IME_ENDCOMPOSITION";
  732. break;
  733. case WM_IME_NOTIFY:
  734. messageString = "WM_IME_NOTIFY";
  735. break;
  736. case WM_IME_SETCONTEXT:
  737. messageString = "WM_IME_SETCONTEXT";
  738. break;
  739. case WM_IME_CONTROL:
  740. messageString = "WM_IME_CONTROL";
  741. break;
  742. case WM_IME_COMPOSITIONFULL:
  743. messageString = "WM_IME_COMPOSITIONFULL";
  744. break;
  745. case WM_IME_SELECT:
  746. messageString = "WM_IME_SELECT";
  747. break;
  748. case WM_IME_KEYDOWN:
  749. messageString = "WM_IME_KEYDOWN";
  750. break;
  751. case WM_IME_KEYUP:
  752. messageString = "WM_IME_KEYUP";
  753. break;
  754. case WM_IME_CHAR:
  755. messageString = "WM_IME_CHAR";
  756. break;
  757. default:
  758. messageString.Format( "Unknown IME message" );
  759. }
  760. CUtlString subMessageString;
  761. if ( uMsg == WM_IME_NOTIFY )
  762. {
  763. switch ( wParam )
  764. {
  765. case IMN_CLOSESTATUSWINDOW:
  766. subMessageString = "IMN_CLOSESTATUSWINDOW";
  767. break;
  768. case IMN_OPENSTATUSWINDOW:
  769. subMessageString = "IMN_OPENSTATUSWINDOW";
  770. break;
  771. case IMN_CHANGECANDIDATE:
  772. subMessageString = "IMN_CHANGECANDIDATE";
  773. break;
  774. case IMN_CLOSECANDIDATE:
  775. subMessageString = "IMN_CLOSECANDIDATE";
  776. break;
  777. case IMN_OPENCANDIDATE:
  778. subMessageString = "IMN_OPENCANDIDATE";
  779. break;
  780. case IMN_SETCONVERSIONMODE:
  781. subMessageString = "IMN_SETCONVERSIONMODE";
  782. break;
  783. case IMN_SETSENTENCEMODE:
  784. subMessageString = "IMN_SETSENTENCEMODE";
  785. break;
  786. case IMN_SETOPENSTATUS:
  787. subMessageString = "IMN_SETOPENSTATUS";
  788. break;
  789. case IMN_SETCANDIDATEPOS:
  790. subMessageString = "IMN_SETCANDIDATEPOS";
  791. break;
  792. case IMN_SETCOMPOSITIONFONT:
  793. subMessageString = "IMN_SETCOMPOSITIONFONT";
  794. break;
  795. case IMN_SETCOMPOSITIONWINDOW:
  796. subMessageString = "IMN_SETCOMPOSITIONWINDOW";
  797. break;
  798. case IMN_SETSTATUSWINDOWPOS:
  799. subMessageString = "IMN_SETSTATUSWINDOWPOS";
  800. break;
  801. case IMN_GUIDELINE:
  802. subMessageString = "IMN_GUIDELINE";
  803. break;
  804. case IMN_PRIVATE:
  805. subMessageString = "IMN_PRIVATE";
  806. break;
  807. default:
  808. subMessageString.Format( "Unknown IMN_??? message" );
  809. }
  810. }
  811. Log_Detailed( LOG_SCALEFORM_IME, " HandleIMEEvent: %s %s\n", messageString.Get(), subMessageString.Get() );
  812. }
  813. #endif
  814. if ( !m_bIMEEnabled )
  815. {
  816. return false;
  817. }
  818. bool bHandled = false;
  819. #if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
  820. BaseSlot* pSlot = LockSlotPtr( m_iIMEFocusSlot );
  821. if ( pSlot )
  822. {
  823. IMEWin32Event ev( IMEWin32Event::IME_Default, (SF::UPInt)hwnd, uMsg, wParam, lParam );
  824. bHandled = ((pSlot->m_pMovieView->HandleEvent( ev ) & Movie::HE_NoDefaultAction) > 0);
  825. }
  826. UnlockSlotPtr( m_iIMEFocusSlot );
  827. Log_Detailed( LOG_SCALEFORM_IME, " HandleIMEEvent returns %d\n", bHandled );
  828. #endif
  829. return bHandled;
  830. }
  831. bool ScaleformUIImpl::PreProcessKeyboardEvent( size_t hwnd, unsigned int uMsg, unsigned int wParam, long lParam )
  832. {
  833. if ( !m_bIMEEnabled )
  834. return false;
  835. bool bHandled = false;
  836. #if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
  837. BaseSlot* pSlot = LockSlotPtr( m_iIMEFocusSlot );
  838. if ( pSlot && pSlot->m_pMovieView )
  839. {
  840. IMEWin32Event ev( IMEWin32Event::IME_PreProcessKeyboard, (SF::UPInt)hwnd, uMsg, wParam, lParam );
  841. bHandled = ((pSlot->m_pMovieView->HandleEvent( ev ) & Movie::HE_NoDefaultAction) > 0);
  842. }
  843. UnlockSlotPtr( m_iIMEFocusSlot );
  844. #endif
  845. return bHandled;
  846. }
  847. void ScaleformUIImpl::SetIMEEnabled( bool bEnabled )
  848. {
  849. if ( m_bIMEEnabled != bEnabled )
  850. {
  851. #if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
  852. Log_Detailed( LOG_SCALEFORM_IME, "%s: %s\n", __FUNCTION__, bEnabled ? "True" : "False" );
  853. if ( m_pIMEManager )
  854. {
  855. if ( !bEnabled )
  856. {
  857. m_pIMEManager->OnFinalize();
  858. }
  859. m_pIMEManager->EnableIME( bEnabled );
  860. }
  861. #endif
  862. }
  863. m_bIMEEnabled = bEnabled;
  864. }
  865. void ScaleformUIImpl::SetIMEFocus( int slot )
  866. {
  867. #if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
  868. if ( m_pIMEManager )
  869. {
  870. if ( m_iIMEFocusSlot != slot )
  871. {
  872. BaseSlot* pSlot = LockSlotPtr( slot );
  873. if ( pSlot && pSlot->m_pMovieView )
  874. {
  875. pSlot->m_pMovieView->HandleEvent( Event::SetFocus );
  876. m_iIMEFocusSlot = slot;
  877. }
  878. UnlockSlotPtr( slot );
  879. }
  880. }
  881. #endif
  882. }
  883. void ScaleformUIImpl::ShutdownIME()
  884. {
  885. #if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
  886. if ( m_pIMEManager && m_bIMEEnabled )
  887. {
  888. m_bIMEEnabled = false;
  889. m_pIMEManager->EnableIME( false );
  890. }
  891. #endif
  892. }
  893. void ScaleformUIImpl::UpdateAvatarImages( void )
  894. {
  895. MEM_ALLOC_CREDIT();
  896. FOR_EACH_MAP_FAST( m_mapUserXuidToAvatar, i )
  897. {
  898. m_mapUserXuidToAvatar[i]->Update();
  899. }
  900. }
  901. bool ScaleformUIImpl::AvatarImageAddRef( XUID playerID )
  902. {
  903. EnsureSteamCallbacksConfigured();
  904. playerID = NormalizeXuidForAccountID( playerID );
  905. if ( !m_pRenderHAL )
  906. {
  907. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  908. return true;
  909. }
  910. Assert( playerID );
  911. MEM_ALLOC_CREDIT();
  912. ScaleformUIAvatarImage *pImage = NULL;
  913. int iIndex = m_mapUserXuidToAvatar.Find( playerID );
  914. if ( iIndex == m_mapUserXuidToAvatar.InvalidIndex() )
  915. {
  916. if ( m_pDefaultAvatarTexture )
  917. {
  918. pImage = new ScaleformUIAvatarImage( playerID, m_pDefaultAvatarTexture->ImageData(), m_pDefaultAvatarTexture->Width(), m_pDefaultAvatarTexture->Height(), m_pDefaultAvatarTexture->Format(), m_pRenderHAL->GetTextureManager() );
  919. }
  920. else
  921. {
  922. static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  923. pImage = new ScaleformUIAvatarImage( playerID, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
  924. }
  925. if ( !pImage->LoadAvatarImage() )
  926. {
  927. Warning( "We failed to load the avatar image for user %llX\n", playerID );
  928. #ifndef NO_STEAM
  929. extern CSteamAPIContext *steamapicontext;
  930. // We will retry if the user is actually logged into steam, otherwise just use the default avatar image
  931. if ( steamapicontext && steamapicontext->SteamUser() && steamapicontext->SteamUserStats() && steamapicontext->SteamUser()->BLoggedOn() )
  932. #endif
  933. { // Other platforms should always retry loading the avatar
  934. Assert( 0 );
  935. delete pImage;
  936. return false;
  937. }
  938. }
  939. iIndex = m_mapUserXuidToAvatar.Insert( playerID, pImage );
  940. }
  941. else
  942. {
  943. pImage = m_mapUserXuidToAvatar.Element( iIndex );
  944. }
  945. Assert( pImage );
  946. int nRefcount = pImage->AddRef();
  947. DevMsg( "Avatar image for user %llX cached [refcount=%d]\n", playerID, nRefcount );
  948. return true;
  949. }
  950. void ScaleformUIImpl::AvatarImageRelease( XUID playerID )
  951. {
  952. playerID = NormalizeXuidForAccountID( playerID );
  953. Assert( playerID );
  954. MEM_ALLOC_CREDIT();
  955. int iIndex = m_mapUserXuidToAvatar.Find( playerID );
  956. if ( iIndex != m_mapUserXuidToAvatar.InvalidIndex() )
  957. {
  958. ScaleformUIAvatarImage *pImage = m_mapUserXuidToAvatar.Element( iIndex );
  959. int nRemainingRefCount = pImage->Release();
  960. if ( nRemainingRefCount <= 0 )
  961. {
  962. m_mapUserXuidToAvatar.RemoveAt( iIndex );
  963. }
  964. DevMsg( "Avatar image for user %llX released [refcount=%d]\n", playerID, nRemainingRefCount );
  965. }
  966. else
  967. {
  968. // We have a ref count problem if we get here because we tried to release an
  969. // avatar image that doesn't exist!
  970. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // This is okay if we're in noshaderapi mode (used to transcode demos).
  971. }
  972. }
  973. void ScaleformUIImpl::AvatarImageReload( XUID playerID, IScaleformAvatarImageProvider *pProvider )
  974. {
  975. if ( pProvider && !ScaleformUIAvatarImage::sm_pProvider )
  976. {
  977. ScaleformUIAvatarImage::sm_pProvider = pProvider;
  978. }
  979. playerID = NormalizeXuidForAccountID( playerID );
  980. Assert( playerID );
  981. MEM_ALLOC_CREDIT();
  982. int iIndex = m_mapUserXuidToAvatar.Find( playerID );
  983. if ( iIndex != m_mapUserXuidToAvatar.InvalidIndex() )
  984. {
  985. ScaleformUIAvatarImage *pImage = m_mapUserXuidToAvatar.Element( iIndex );
  986. pImage->LoadAvatarImage( pProvider );
  987. DevMsg( 2, "Avatar image for user %llX reloaded\n", playerID );
  988. }
  989. }
  990. void ScaleformUIImpl::InventoryImageUpdate( uint64 iItemID, IScaleformInventoryImageProvider *pIScaleformInventoryImageProvider )
  991. {
  992. ScaleformUIInventoryImage *pImage = NULL;
  993. int iIndex = m_mapItemIdToImage.Find( iItemID );
  994. if ( iIndex != m_mapItemIdToImage.InvalidIndex() )
  995. {
  996. pImage = m_mapItemIdToImage.Element( iIndex );
  997. IScaleformInventoryImageProvider::ImageInfo_t imgInfo;
  998. bool bImgInfoValid = pIScaleformInventoryImageProvider->GetInventoryImageInfo( iItemID, &imgInfo );
  999. if ( bImgInfoValid && !pImage->LoadInventoryImage( imgInfo.m_bufImageDataRGBA, imgInfo.m_nWidth, imgInfo.m_nHeight, IMAGE_FORMAT_BGRA8888 ) )
  1000. {
  1001. Warning( "We failed to update the inventory image for item %llX\n", iItemID );
  1002. Assert( 0 );
  1003. }
  1004. }
  1005. }
  1006. bool ScaleformUIImpl::InventoryImageAddRef( uint64 iItemID, IScaleformInventoryImageProvider *pIScaleformInventoryImageProvider )
  1007. {
  1008. Assert( iItemID );
  1009. MEM_ALLOC_CREDIT();
  1010. if ( !m_pRenderHAL )
  1011. {
  1012. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  1013. return true;
  1014. }
  1015. ScaleformUIInventoryImage *pImage = NULL;
  1016. int iIndex = m_mapItemIdToImage.Find( iItemID );
  1017. if ( iIndex == m_mapItemIdToImage.InvalidIndex() )
  1018. {
  1019. IScaleformInventoryImageProvider::ImageInfo_t imgInfo;
  1020. bool bImgInfoValid = pIScaleformInventoryImageProvider->GetInventoryImageInfo( iItemID, &imgInfo );
  1021. #ifdef USE_DEFAULT_INVENTORY_ICON_BACKGROUNDS
  1022. if ( bImgInfoValid && imgInfo.m_pDefaultIconName )
  1023. {
  1024. uint nHash = HashStringCaselessConventional( imgInfo.m_pDefaultIconName );
  1025. UtlHashFastHandle_t handle = m_defaultInventoryIcons.Find( nHash );
  1026. if ( handle != m_defaultInventoryIcons.InvalidHandle() )
  1027. {
  1028. DefaultInventoryIcon_t icon = m_defaultInventoryIcons.Element( handle );
  1029. if ( icon.m_pTexture && icon.m_pTexture->Width() == imgInfo.m_nWidth )
  1030. {
  1031. Assert( imgInfo.m_nHeight <= icon.m_pTexture->Height() );
  1032. pImage = new ScaleformUIInventoryImage( iItemID, icon.m_pTexture->ImageData(), imgInfo.m_nWidth, imgInfo.m_nHeight, icon.m_pTexture->Format(), m_pRenderHAL->GetTextureManager() );
  1033. }
  1034. }
  1035. }
  1036. #endif
  1037. if ( !pImage )
  1038. {
  1039. static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  1040. pImage = new ScaleformUIInventoryImage( iItemID, defaultTextureBits, 2, 2, IMAGE_FORMAT_BGRA8888, m_pRenderHAL->GetTextureManager() );
  1041. }
  1042. if ( bImgInfoValid && !pImage->LoadInventoryImage( imgInfo.m_bufImageDataRGBA, imgInfo.m_nWidth, imgInfo.m_nHeight, IMAGE_FORMAT_BGRA8888 ) )
  1043. {
  1044. Warning( "We failed to load the inventory image for item %llX\n", iItemID );
  1045. Assert( 0 );
  1046. }
  1047. iIndex = m_mapItemIdToImage.Insert( iItemID, pImage );
  1048. }
  1049. else
  1050. {
  1051. pImage = m_mapItemIdToImage.Element( iIndex );
  1052. }
  1053. Assert( pImage );
  1054. int nRefcount = pImage->AddRef();
  1055. DevMsg( "Inventory image for item %llX cached [refcount=%d]\n", iItemID, nRefcount );
  1056. return true;
  1057. }
  1058. void ScaleformUIImpl::InventoryImageRelease( uint64 iItemID )
  1059. {
  1060. Assert( iItemID );
  1061. MEM_ALLOC_CREDIT();
  1062. int iIndex = m_mapItemIdToImage.Find( iItemID );
  1063. if ( iIndex != m_mapItemIdToImage.InvalidIndex() )
  1064. {
  1065. ScaleformUIInventoryImage *pImage = m_mapItemIdToImage.Element( iIndex );
  1066. int nRemainingRefCount = pImage->Release();
  1067. if ( nRemainingRefCount <= 0 )
  1068. {
  1069. m_mapItemIdToImage.RemoveAt( iIndex );
  1070. }
  1071. DevMsg( "Inventory image for item %llX released [refcount=%d]\n", iItemID, nRemainingRefCount );
  1072. }
  1073. else
  1074. {
  1075. // We have a ref count problem if we get here because we tried to release an
  1076. // inventory image that doesn't exist!
  1077. Assert( 0 );
  1078. }
  1079. }
  1080. #ifdef USE_DEFAULT_INVENTORY_ICON_BACKGROUNDS
  1081. void ScaleformUIImpl::InitInventoryDefaultIcons( CUtlVector< const char * > *vecIconDefaultNames )
  1082. {
  1083. #if defined( CSTRIKE15 )
  1084. CUtlBuffer bufFile;
  1085. // Load the default inventory image bits and store them in a raw buffer
  1086. FOR_EACH_VEC( *vecIconDefaultNames, i )
  1087. {
  1088. uint uHash = HashStringCaselessConventional( vecIconDefaultNames->Element(i) );
  1089. UtlHashFastHandle_t handle = m_defaultInventoryIcons.Find( uHash );
  1090. if ( handle == m_defaultInventoryIcons.InvalidHandle() )
  1091. {
  1092. DefaultInventoryIcon_t icon;
  1093. icon.m_pImage = NULL;
  1094. icon.m_pTexture = NULL;
  1095. bufFile.Clear();
  1096. const char* pDefaultInventoryImageFileName = vecIconDefaultNames->Element(i);
  1097. if ( g_pFullFileSystem->ReadFile( pDefaultInventoryImageFileName, NULL, bufFile ) )
  1098. {
  1099. icon.m_pTexture = CreateVTFTexture();
  1100. #if !defined( _GAMECONSOLE )
  1101. if ( !icon.m_pTexture->Unserialize( bufFile ) )
  1102. #else
  1103. if ( !icon.m_pTexture->UnserializeFromBuffer( bufFile, true, false, false, 0 ) )
  1104. #endif
  1105. {
  1106. Warning( "Invalid or corrupt default inventory image (%s)\n", pDefaultInventoryImageFileName );
  1107. DestroyVTFTexture( icon.m_pTexture );
  1108. icon.m_pTexture = NULL;
  1109. }
  1110. }
  1111. else
  1112. {
  1113. Warning( "Failed to read the default inventory image file (%s)\n", pDefaultInventoryImageFileName );
  1114. }
  1115. if ( icon.m_pTexture )
  1116. {
  1117. m_defaultInventoryIcons.FastInsert( uHash, icon );
  1118. }
  1119. }
  1120. }
  1121. #endif // CSTRIKE15
  1122. }
  1123. #endif
  1124. Image* ScaleformUIImpl::CreateImageFromFile( const char *pszFileName, const ImageCreateInfo& info, int width, int height )
  1125. {
  1126. if ( !m_pRenderHAL )
  1127. {
  1128. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  1129. return NULL;
  1130. }
  1131. if ( pszFileName != NULL )
  1132. {
  1133. return m_pLoader->GetImageCreator()->LoadImageFile( info, SF::String( pszFileName ) );
  1134. }
  1135. else
  1136. {
  1137. return RawImage::Create( Image_R8G8B8A8, 0, ImageSize( width, height ), ImageUse_Update, 0, m_pRenderHAL->GetTextureManager() );
  1138. }
  1139. }
  1140. void ScaleformUIImpl::AddDeviceDependentObject( IShaderDeviceDependentObject * object )
  1141. {
  1142. if ( m_pShaderDeviceMgr )
  1143. {
  1144. m_pShaderDeviceMgr->AddDeviceDependentObject( object );
  1145. }
  1146. }
  1147. void ScaleformUIImpl::RemoveDeviceDependentObject( IShaderDeviceDependentObject * object )
  1148. {
  1149. if ( m_pShaderDeviceMgr )
  1150. {
  1151. m_pShaderDeviceMgr->RemoveDeviceDependentObject( object );
  1152. }
  1153. }
  1154. ScaleformUIAvatarImage* ScaleformUIImpl::GetAvatarImage( XUID playerID )
  1155. {
  1156. playerID = NormalizeXuidForAccountID( playerID );
  1157. MEM_ALLOC_CREDIT();
  1158. ScaleformUIAvatarImage *pImage = NULL;
  1159. if ( !m_pRenderHAL )
  1160. {
  1161. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  1162. return NULL;
  1163. }
  1164. if ( playerID )
  1165. {
  1166. int iIndex = m_mapUserXuidToAvatar.Find( playerID );
  1167. if ( iIndex == m_mapUserXuidToAvatar.InvalidIndex() )
  1168. {
  1169. // If you hit this assert then the most likely problem is that the action script
  1170. // file is trying to load an avatar image that hasn't been created yet.
  1171. // To create the avatar image call m_pScaleformUI->AvatarImageAddRef in the client code.
  1172. Assert( 0 );
  1173. Warning( "Error getting avatar image: playerID(%llu), iIndex(%d)\n", playerID, iIndex );
  1174. }
  1175. else
  1176. {
  1177. pImage = m_mapUserXuidToAvatar.Element( iIndex );
  1178. }
  1179. }
  1180. if ( !pImage )
  1181. {
  1182. if ( !m_pDefaultAvatarImage )
  1183. {
  1184. // Create an avatar image for the player id of 0 (or an avatar we failed to load) to use as a default
  1185. if ( m_pDefaultAvatarTexture )
  1186. {
  1187. m_pDefaultAvatarImage = new ScaleformUIAvatarImage( 0, m_pDefaultAvatarTexture->ImageData(), m_pDefaultAvatarTexture->Width(), m_pDefaultAvatarTexture->Height(), m_pDefaultAvatarTexture->Format(), m_pRenderHAL->GetTextureManager() );
  1188. }
  1189. else
  1190. {
  1191. static const byte defaultTextureBits[] = { 0, 0, 0, 0 };
  1192. m_pDefaultAvatarImage = new ScaleformUIAvatarImage( 0, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
  1193. }
  1194. }
  1195. pImage = m_pDefaultAvatarImage;
  1196. }
  1197. return pImage;
  1198. }
  1199. ScaleformUIInventoryImage* ScaleformUIImpl::GetInventoryImage( uint64 iItemID )
  1200. {
  1201. MEM_ALLOC_CREDIT();
  1202. if ( !m_pRenderHAL )
  1203. {
  1204. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  1205. return NULL;
  1206. }
  1207. ScaleformUIInventoryImage *pImage = NULL;
  1208. if ( iItemID )
  1209. {
  1210. int iIndex = m_mapItemIdToImage.Find( iItemID );
  1211. if ( iIndex == m_mapItemIdToImage.InvalidIndex() )
  1212. {
  1213. // If you hit this assert then the most likely problem is that the action script
  1214. // file is trying to load an inventory image that hasn't been created yet.
  1215. // To create the inventory image call m_pScaleformUI->InventoryImageAddRef in the client code.
  1216. Assert( 0 );
  1217. Warning( "Error getting inventory image: iItemID(%llu), iIndex(%d)\n", iItemID, iIndex );
  1218. }
  1219. else
  1220. {
  1221. pImage = m_mapItemIdToImage.Element( iIndex );
  1222. }
  1223. }
  1224. if ( !pImage )
  1225. {
  1226. if ( !m_pDefaultInventoryImage )
  1227. {
  1228. // Create an inventory image for the item id of 0 (or an inventory item we failed to load/generate) to use as a default
  1229. if ( m_pDefaultInventoryTexture )
  1230. {
  1231. m_pDefaultInventoryImage = new ScaleformUIInventoryImage( 0, m_pDefaultInventoryTexture->ImageData(), m_pDefaultInventoryTexture->Width(), m_pDefaultInventoryTexture->Height(), m_pDefaultInventoryTexture->Format(), m_pRenderHAL->GetTextureManager() );
  1232. }
  1233. else
  1234. {
  1235. static const byte defaultTextureBits[] = { 0, 0, 0, 0 };
  1236. m_pDefaultInventoryImage = new ScaleformUIInventoryImage( 0, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
  1237. }
  1238. }
  1239. pImage = m_pDefaultInventoryImage;
  1240. }
  1241. return pImage;
  1242. }
  1243. bool ScaleformUIImpl::ChromeHTMLImageAddRef( uint64 imageID )
  1244. {
  1245. Assert( imageID );
  1246. MEM_ALLOC_CREDIT();
  1247. if ( !m_pRenderHAL )
  1248. {
  1249. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  1250. return true;
  1251. }
  1252. ScaleformUIChromeHTMLImage *pImage = NULL;
  1253. int iIndex = m_mapImageIdToChromeImage.Find( imageID );
  1254. if ( iIndex == m_mapImageIdToChromeImage.InvalidIndex() )
  1255. {
  1256. static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0,
  1257. 0, 0, 0, 0, 0, 0, 0, 0};
  1258. pImage = new ScaleformUIChromeHTMLImage( imageID, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
  1259. iIndex = m_mapImageIdToChromeImage.Insert( imageID, pImage );
  1260. }
  1261. else
  1262. {
  1263. pImage = m_mapImageIdToChromeImage.Element( iIndex );
  1264. }
  1265. Assert( pImage );
  1266. int nRefcount = pImage->AddRef();
  1267. DevMsg( "Chrome HTML image for id %llX cached [refcount=%d]\n", imageID, nRefcount );
  1268. return true;
  1269. }
  1270. void ScaleformUIImpl::ChromeHTMLImageUpdate( uint64 imageID, const byte* rgba, int width, int height, ::ImageFormat format )
  1271. {
  1272. ScaleformUIChromeHTMLImage *pImage = NULL;
  1273. int iIndex = m_mapImageIdToChromeImage.Find( imageID );
  1274. if ( iIndex != m_mapImageIdToChromeImage.InvalidIndex() )
  1275. {
  1276. pImage = m_mapImageIdToChromeImage.Element( iIndex );
  1277. if ( !pImage->LoadChromeHTMLImage( rgba, width, height, format ) )
  1278. {
  1279. Warning( "We failed to update the chrome HTML image for item %llX\n", imageID );
  1280. Assert( 0 );
  1281. }
  1282. }
  1283. }
  1284. void ScaleformUIImpl::ChromeHTMLImageRelease( uint64 imageID )
  1285. {
  1286. Assert( imageID );
  1287. MEM_ALLOC_CREDIT();
  1288. int iIndex = m_mapImageIdToChromeImage.Find( imageID );
  1289. if ( iIndex != m_mapImageIdToChromeImage.InvalidIndex() )
  1290. {
  1291. ScaleformUIChromeHTMLImage *pImage = m_mapImageIdToChromeImage.Element( iIndex );
  1292. int nRemainingRefCount = pImage->Release();
  1293. if ( nRemainingRefCount <= 0 )
  1294. {
  1295. m_mapImageIdToChromeImage.RemoveAt( iIndex );
  1296. }
  1297. DevMsg( "Chrome HTML image for id %llX released [refcount=%d]\n", imageID, nRemainingRefCount );
  1298. }
  1299. else
  1300. {
  1301. // We have a ref count problem if we get here because we tried to release an
  1302. // chrome HTML image that doesn't exist!
  1303. Assert( 0 );
  1304. }
  1305. }
  1306. ScaleformUIChromeHTMLImage* ScaleformUIImpl::GetChromeHTMLImage( uint64 imageID )
  1307. {
  1308. MEM_ALLOC_CREDIT();
  1309. if ( !m_pRenderHAL )
  1310. {
  1311. Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
  1312. return NULL;
  1313. }
  1314. ScaleformUIChromeHTMLImage *pImage = NULL;
  1315. if ( imageID )
  1316. {
  1317. int iIndex = m_mapImageIdToChromeImage.Find( imageID );
  1318. if ( iIndex == m_mapImageIdToChromeImage.InvalidIndex() )
  1319. {
  1320. // If you hit this assert then the most likely problem is that the action script
  1321. // file is trying to load an avatar image that hasn't been created yet.
  1322. // To create the avatar image call m_pScaleformUI->AvatarImageAddRef in the client code.
  1323. Assert( 0 );
  1324. Warning( "Error getting chrome HTML image: imageID(%llu), iIndex(%d)\n", imageID, iIndex );
  1325. }
  1326. else
  1327. {
  1328. pImage = m_mapImageIdToChromeImage.Element( iIndex );
  1329. }
  1330. }
  1331. if ( !pImage )
  1332. {
  1333. if ( !m_pDefaultChromeHTMLImage )
  1334. {
  1335. static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0,
  1336. 0, 0, 0, 0, 0, 0, 0, 0};
  1337. m_pDefaultChromeHTMLImage = new ScaleformUIChromeHTMLImage( 0, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
  1338. }
  1339. pImage = m_pDefaultChromeHTMLImage;
  1340. }
  1341. return pImage;
  1342. }