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
1587 lines
42 KiB
//========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
|
|
//
|
|
// Purpose:
|
|
//
|
|
// $NoKeywords: $
|
|
//=============================================================================//
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "tier1/keyvalues.h"
|
|
#include "matchmaking/imatchframework.h"
|
|
#include "GFx_AMP.h"
|
|
|
|
#if defined( _PS3 )
|
|
#include "ps3/ps3_console.h"
|
|
#include "tls_ps3.h"
|
|
#endif
|
|
|
|
// NOTE: This must be the last file included!!!
|
|
#include "tier0/memdbgon.h"
|
|
|
|
using namespace SF::GFx;
|
|
using namespace SF::Render;
|
|
|
|
CON_COMMAND( sf4_meshcache_stats, "Outputs Scaleform 4 mesh cache stats" )
|
|
{
|
|
ScaleformUIImpl::m_Instance.DumpMeshCacheStats();
|
|
}
|
|
|
|
bool g_bScaleformIMEDetailedLogging = false;
|
|
#ifndef Log_Detailed
|
|
#define Log_Detailed( Channel, /* [LoggingMetaData_t *], [Color], Message, */ ... ) do { if (g_bScaleformIMEDetailedLogging) InternalMsg( Channel, LS_MESSAGE, /* [Color], Message, */ ##__VA_ARGS__ ); } while( 0 )
|
|
#endif
|
|
|
|
DECLARE_LOGGING_CHANNEL( LOG_SCALEFORM_IME );
|
|
|
|
DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_SCALEFORM_IME, "Scaleform IME" );
|
|
|
|
static XUID NormalizeXuidForAccountID( XUID xuid )
|
|
{
|
|
if ( ( xuid & 0xFFFFFFFFull ) == xuid )
|
|
return xuid; // AccountID only only
|
|
|
|
CSteamID steamID( xuid );
|
|
if ( steamID.IsValid() && steamID.BIndividualAccount() )
|
|
return steamID.GetAccountID(); // trim upper part of SteamID
|
|
|
|
return xuid;
|
|
}
|
|
|
|
void ScaleformUIImpl::InitHighLevelImpl( void )
|
|
{
|
|
m_iLastMouseX = -1;
|
|
m_iLastMouseY = -1;
|
|
|
|
m_iKeyboardSlot = 0;
|
|
|
|
m_bEatPS3MouseEvent = true;
|
|
|
|
V_memset( m_fJoyValues, 0, sizeof( m_fJoyValues ) );
|
|
V_memset( m_iJoyAxisButtonsDown, 0, sizeof( m_iJoyAxisButtonsDown ) );
|
|
|
|
SetDefLessFunc( m_mapUserXuidToAvatar );
|
|
SetDefLessFunc( m_mapItemIdToImage );
|
|
SetDefLessFunc( m_mapImageIdToChromeImage );
|
|
|
|
#if !defined( NO_STEAM )
|
|
m_bSteamCallbacksConfigured = false;
|
|
#endif
|
|
|
|
#if defined( CSTRIKE15 ) && !defined( _X360 )
|
|
// $TODO: Figure out why we aren't properly loading the default texture on Xbox
|
|
// Load the default avatar image bits and store them in a raw buffer
|
|
CUtlBuffer bufFile;
|
|
static const char* cDefaultAvatarImageFileName = "materials/vgui/avatar_default_64" PLATFORM_EXT ".vtf";
|
|
if ( g_pFullFileSystem->ReadFile( cDefaultAvatarImageFileName, NULL, bufFile ) )
|
|
{
|
|
m_pDefaultAvatarTexture = CreateVTFTexture();
|
|
#if !defined( _GAMECONSOLE )
|
|
if ( !m_pDefaultAvatarTexture->Unserialize( bufFile ) )
|
|
#else
|
|
if ( !m_pDefaultAvatarTexture->UnserializeFromBuffer( bufFile, true, false, false, 0 ) )
|
|
#endif
|
|
{
|
|
Warning( "Invalid or corrupt default avatar image (%s)\n", cDefaultAvatarImageFileName );
|
|
DestroyVTFTexture( m_pDefaultAvatarTexture );
|
|
m_pDefaultAvatarTexture = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Warning( "Failed to read the default avatar image file (%s)\n", cDefaultAvatarImageFileName );
|
|
}
|
|
|
|
// Load the default inventory image bits and store them in a raw buffer
|
|
bufFile.Clear();
|
|
static const char* cDefaultInventoryImageFileName = "materials/vgui/inventory_default" PLATFORM_EXT ".vtf";
|
|
if ( g_pFullFileSystem->ReadFile( cDefaultInventoryImageFileName, NULL, bufFile ) )
|
|
{
|
|
m_pDefaultInventoryTexture = CreateVTFTexture();
|
|
#if !defined( _GAMECONSOLE )
|
|
if ( !m_pDefaultInventoryTexture->Unserialize( bufFile ) )
|
|
#else
|
|
if ( !m_pDefaultInventoryTexture->UnserializeFromBuffer( bufFile, true, false, false, 0 ) )
|
|
#endif
|
|
{
|
|
Warning( "Invalid or corrupt default inventory image (%s)\n", cDefaultInventoryImageFileName );
|
|
DestroyVTFTexture( m_pDefaultInventoryTexture );
|
|
m_pDefaultInventoryTexture = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Warning( "Failed to read the default inventory image file (%s)\n", cDefaultInventoryImageFileName );
|
|
}
|
|
#endif // CSTRIKE15
|
|
|
|
m_CurrentKey = BUTTON_CODE_INVALID;
|
|
}
|
|
|
|
#if !defined( NO_STEAM )
|
|
void ScaleformUIImpl::EnsureSteamCallbacksConfigured()
|
|
{
|
|
if ( m_bSteamCallbacksConfigured )
|
|
return;
|
|
m_bSteamCallbacksConfigured = true;
|
|
|
|
m_CallbackPersonaStateChanged.Register( this, &ScaleformUIImpl::Steam_OnPersonaStateChanged );
|
|
m_CallbackAvatarImageLoaded.Register( this, &ScaleformUIImpl::Steam_OnAvatarImageLoaded );
|
|
}
|
|
|
|
void ScaleformUIImpl::Steam_OnAvatarImageLoaded( AvatarImageLoaded_t *pParam )
|
|
{
|
|
if ( pParam )
|
|
{
|
|
AvatarImageReload( pParam->m_steamID.ConvertToUint64(), NULL );
|
|
}
|
|
}
|
|
|
|
void ScaleformUIImpl::Steam_OnPersonaStateChanged( PersonaStateChange_t *pParam )
|
|
{
|
|
if ( pParam && ( pParam->m_nChangeFlags & k_EPersonaChangeAvatar ) )
|
|
{
|
|
AvatarImageReload( pParam->m_ulSteamID, NULL );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
void ScaleformUIImpl::ShutdownHighLevelImpl( void )
|
|
{
|
|
if ( m_pDefaultAvatarTexture )
|
|
{
|
|
DestroyVTFTexture( m_pDefaultAvatarTexture );
|
|
m_pDefaultAvatarTexture = NULL;
|
|
}
|
|
|
|
if ( m_pDefaultAvatarImage )
|
|
{
|
|
delete m_pDefaultAvatarImage;
|
|
m_pDefaultAvatarImage = NULL;
|
|
}
|
|
|
|
if ( m_pDefaultInventoryTexture )
|
|
{
|
|
DestroyVTFTexture( m_pDefaultInventoryTexture );
|
|
m_pDefaultInventoryTexture = NULL;
|
|
}
|
|
|
|
if ( m_pDefaultInventoryImage )
|
|
{
|
|
delete m_pDefaultInventoryImage;
|
|
m_pDefaultInventoryImage = NULL;
|
|
}
|
|
|
|
if ( m_pDefaultChromeHTMLImage )
|
|
{
|
|
delete m_pDefaultChromeHTMLImage;
|
|
m_pDefaultChromeHTMLImage = NULL;
|
|
}
|
|
|
|
#ifdef USE_DEFAULT_INVENTORY_ICON_BACKGROUNDS
|
|
for ( CUtlHashFast< DefaultInventoryIcon_t >::UtlHashFastIterator_t i = m_defaultInventoryIcons.First(); m_defaultInventoryIcons.IsValidIterator( i ); i = m_defaultInventoryIcons.Next( i ) )
|
|
{
|
|
if ( m_defaultInventoryIcons[ i ].m_pTexture )
|
|
{
|
|
DestroyVTFTexture( m_defaultInventoryIcons[ i ].m_pTexture );
|
|
m_defaultInventoryIcons[ i ].m_pTexture = NULL;
|
|
}
|
|
if ( m_defaultInventoryIcons[ i ].m_pImage )
|
|
{
|
|
delete m_defaultInventoryIcons[ i ].m_pImage;
|
|
m_defaultInventoryIcons[ i ].m_pImage = NULL;
|
|
}
|
|
}
|
|
m_defaultInventoryIcons.RemoveAll();
|
|
#endif
|
|
|
|
m_CurrentKey = BUTTON_CODE_INVALID;
|
|
}
|
|
|
|
void ScaleformUIImpl::ClearCache( void )
|
|
{
|
|
// Do not clear the cache straight away. We need to ensure that we are clearing the mesh cache on the
|
|
// render thread => cache being actually cleared in RenderSlot.
|
|
m_bClearMeshCacheQueued = true;
|
|
}
|
|
|
|
const char* ScaleformUIImpl::CorrectFlashFileName( const char * name )
|
|
{
|
|
|
|
// make sure the name is long enough to have an extension, but not too long
|
|
int len = V_strlen( name );
|
|
|
|
if ( len < 4 || len >= TEMPORARY_BUFFER_SIZE )
|
|
{
|
|
return name;
|
|
}
|
|
|
|
#if 1
|
|
|
|
//
|
|
// Allow -customswf to override directory from which SWF files are loaded
|
|
// otherwise load directly from main resource directory
|
|
//
|
|
|
|
static char const *szSwfDirOverride = CommandLine()->ParmValue( "-customswf", ( const char * ) NULL );
|
|
static int nSwfDirOverrideLen = szSwfDirOverride ? V_strlen( szSwfDirOverride ) : 0;
|
|
if ( szSwfDirOverride && *szSwfDirOverride && ( len + nSwfDirOverrideLen + 4 < TEMPORARY_BUFFER_SIZE ) )
|
|
{
|
|
char const *szDirSeparator = strrchr( name, '/' );
|
|
if ( szDirSeparator )
|
|
{
|
|
V_sprintf_safe( m_cTemporaryBuffer, "%.*s%s%s", ( szDirSeparator - name + 1 ), name, szSwfDirOverride, szDirSeparator );
|
|
if ( g_pFullFileSystem->FileExists( m_cTemporaryBuffer, "GAME" ) )
|
|
{
|
|
DevMsg( "-customswf: %s\n", m_cTemporaryBuffer );
|
|
return m_cTemporaryBuffer;
|
|
}
|
|
}
|
|
}
|
|
|
|
return name;
|
|
|
|
#else
|
|
|
|
// we only want to continue if the filename is a .swf or a .gfx file
|
|
// otherwise we can just use the original name
|
|
|
|
const char* pFirstEXTChar = V_strstr( ".swf.gfx", &name[len-4] );
|
|
|
|
if ( !pFirstEXTChar )
|
|
{
|
|
return name;
|
|
}
|
|
|
|
// point to the first char of the extension so we
|
|
// can test later
|
|
pFirstEXTChar++;
|
|
|
|
// this is a utility variable.
|
|
// we'll use it to point to the actual string we want to
|
|
// use
|
|
const char* namePtr;
|
|
|
|
|
|
// if we're supposed to try SWF's first, see if an
|
|
// SWF file exists
|
|
if ( m_bTrySWFFirst )
|
|
{
|
|
if ( *pFirstEXTChar == 's' )
|
|
{
|
|
namePtr = name;
|
|
}
|
|
else
|
|
{
|
|
V_strncpy( m_cTemporaryBuffer, name, TEMPORARY_BUFFER_SIZE );
|
|
V_strcpy( &m_cTemporaryBuffer[len-3], "swf" );
|
|
namePtr = m_cTemporaryBuffer;
|
|
}
|
|
|
|
if ( g_pFullFileSystem->FileExists( namePtr, "GAME" ) )
|
|
{
|
|
return namePtr;
|
|
}
|
|
|
|
}
|
|
|
|
// convert filename extension to gfx
|
|
|
|
if ( *pFirstEXTChar == 'g' )
|
|
{
|
|
namePtr = name;
|
|
}
|
|
else
|
|
{
|
|
V_strncpy( m_cTemporaryBuffer, name, TEMPORARY_BUFFER_SIZE );
|
|
V_strcpy( &m_cTemporaryBuffer[len-3], "gfx" );
|
|
namePtr = m_cTemporaryBuffer;
|
|
}
|
|
|
|
return namePtr;
|
|
#endif
|
|
}
|
|
|
|
void ScaleformUIImpl::SendUIEvent( const char* action, const char* eventData, int slot )
|
|
{
|
|
IGameEvent * pEvent = m_pGameEventManager->CreateEvent( "sfuievent" );
|
|
|
|
if ( pEvent )
|
|
{
|
|
pEvent->SetString( "action", action );
|
|
pEvent->SetString( "data", eventData );
|
|
pEvent->SetInt( "slot", slot );
|
|
m_pGameEventManager->FireEventClientSide( pEvent );
|
|
SFDevMsg("sfuievent action=%s data=%d slot=%d\n", action?action:"", eventData?eventData:"", slot);
|
|
}
|
|
}
|
|
|
|
|
|
float ScaleformUIImpl::GetJoyValue( int slot, int stickIndex, int axis )
|
|
{
|
|
AssertMsg( SF_SS_SLOT( slot ) < MAX_SLOTS, "Invalid slot index in GetJoyValue" );
|
|
|
|
return m_fJoyValues[ JOY_VALUE_INDEX( slot, stickIndex, axis ) ];
|
|
}
|
|
|
|
void ScaleformUIImpl::SetJoyValue( int slot, int stickIndex, int axis, int value )
|
|
{
|
|
AssertMsg( SF_SS_SLOT( slot ) < MAX_SLOTS, "Invalid slot index in SetJoyValue" );
|
|
|
|
m_fJoyValues[ JOY_VALUE_INDEX( slot, stickIndex, axis ) ] = (float)value / 32768.0f;
|
|
}
|
|
|
|
|
|
void ScaleformUIImpl::SetScreenSize( int x, int y )
|
|
{
|
|
MEM_ALLOC_CREDIT();
|
|
m_iScreenWidth = x;
|
|
m_iScreenHeight = y;
|
|
|
|
SetSlotViewport( SF_FULL_SCREEN_SLOT, 0, 0, x, y );
|
|
SetSlotViewport( SF_RESERVED_CURSOR_SLOT, 0, 0, x, y );
|
|
}
|
|
|
|
void ScaleformUIImpl::SetSingleThreadedMode( bool bSingleThreded )
|
|
{
|
|
m_bSingleThreaded = bSingleThreded;
|
|
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return;
|
|
}
|
|
|
|
if ( m_bSingleThreaded )
|
|
{
|
|
m_pRenderHAL->GetTextureManager()->SetRenderThreadIdToCurrentThread();
|
|
}
|
|
else
|
|
{
|
|
// RenderThreadId will be set in RenderSlot - Just reseting for now
|
|
// so that textures are not created on the main thread.
|
|
m_pRenderHAL->GetTextureManager()->ResetRenderThreadId();
|
|
}
|
|
}
|
|
|
|
void ScaleformUIImpl::RunFrame( float time )
|
|
{
|
|
m_fTime = time;
|
|
|
|
#ifndef SF_BUILD_SHIPPING
|
|
if ( m_bPumpScaleformStats )
|
|
{
|
|
AMP::Server::GetInstance().AdvanceFrame();
|
|
}
|
|
#endif
|
|
SNPROF("ScaleformUIImpl::RunFrame");
|
|
|
|
#ifdef _PS3
|
|
if ( GetTLSGlobals()->bNormalQuitRequested )
|
|
{
|
|
return; // do not disconnect recursively on QUIT
|
|
}
|
|
#endif
|
|
|
|
UpdateCursorLazyHide( m_fTime );
|
|
|
|
UpdateAvatarImages();
|
|
|
|
// Removed advance slot from RunFrame. AdvanceSlot is now called just before rendering (fix hud element lagging)
|
|
}
|
|
|
|
bool ScaleformUIImpl::DistributeEvent( Event& event, int slotNumber, bool toAllSlots, bool clearControllerUI )
|
|
{
|
|
bool result = false;
|
|
|
|
CursorSlot* pCursorSlot = ( CursorSlot* )LockSlotPtr( SF_RESERVED_CURSOR_SLOT );
|
|
|
|
if ( pCursorSlot )
|
|
{
|
|
pCursorSlot->m_pMovieView->HandleEvent( event );
|
|
}
|
|
|
|
UnlockSlotPtr( SF_RESERVED_CURSOR_SLOT );
|
|
|
|
int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( slotNumber ) };
|
|
|
|
for ( int i = 0; i < 2; i++ )
|
|
{
|
|
if ( slots[i] < MAX_SLOTS )
|
|
{
|
|
BaseSlot* pSlot = LockSlotPtr( slots[i] );
|
|
|
|
if ( pSlot && pSlot->ConsumesInputEvents() )
|
|
{
|
|
|
|
if ( clearControllerUI )
|
|
{
|
|
bool isKeyOrButtonPress = (event.Type == Event::MouseDown || event.Type == Event::KeyDown );
|
|
pSlot->SetToControllerUI( false, isKeyOrButtonPress );
|
|
}
|
|
|
|
unsigned int code = pSlot->m_pMovieView->HandleEvent( event );
|
|
|
|
if ( code & Movie::HE_NoDefaultAction )
|
|
{
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
UnlockSlotPtr( slots[i] );
|
|
|
|
// [jason] slots are listed in order of priority, so if one has already handled the event it supersedes any other slots
|
|
if ( result && !toAllSlots )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool ScaleformUIImpl::DistributeKeyEvent( bool keyDown, bool fromController, const char* binding, ButtonCode_t code, ButtonCode_t vkey, int slotNumber, bool toAllSlots )
|
|
{
|
|
bool result = false;
|
|
|
|
int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( slotNumber ) };
|
|
|
|
for ( int i = 0; i < 2; i++ )
|
|
{
|
|
if ( slots[i] < MAX_SLOTS )
|
|
{
|
|
BaseSlot* pSlot = LockSlotPtr( slots[i] );
|
|
|
|
if ( pSlot && pSlot->ConsumesInputEvents() )
|
|
{
|
|
bool isButtonPress = keyDown && code < JOYSTICK_FIRST_AXIS_BUTTON;
|
|
pSlot->SetToControllerUI( fromController, isButtonPress );
|
|
result = pSlot->HandleKeyEvent( keyDown, code, vkey, binding, slotNumber ) || result;
|
|
}
|
|
|
|
UnlockSlotPtr( slots[i] );
|
|
|
|
// [jason] slots are listed in order of priority, so if one has already handled the event it supersedes any other slots
|
|
if ( result && !toAllSlots )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool ScaleformUIImpl::DistributeCharTyped( wchar_t code )
|
|
{
|
|
wchar_t msgString[2];
|
|
msgString[0] = code;
|
|
msgString[1] = L'\0';
|
|
|
|
int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( m_iKeyboardSlot ) };
|
|
|
|
bool result = false;
|
|
|
|
for ( int i = 0; i < 2; i++ )
|
|
{
|
|
if ( slots[i] < MAX_SLOTS )
|
|
{
|
|
|
|
BaseSlot* pSlot = LockSlotPtr( slots[i] );
|
|
|
|
if ( pSlot && pSlot->ConsumesInputEvents() )
|
|
{
|
|
pSlot->SetToControllerUI( false, true );
|
|
result = pSlot->HandleCharTyped( msgString, m_iKeyboardSlot ) || result;
|
|
}
|
|
|
|
UnlockSlotPtr( slots[i] );
|
|
|
|
// [jason] slots are listed in order of priority, so if one has already handled the event it supersedes any other slots
|
|
if ( result )
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
bool ScaleformUIImpl::HitTest( int x, int y )
|
|
{
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
bool result = false;
|
|
|
|
int slots[2] = { SF_FULL_SCREEN_SLOT, SF_SS_SLOT( m_iKeyboardSlot ) };
|
|
|
|
for ( int i = 0; i < 2 && !result; i++ )
|
|
{
|
|
if ( slots[i] < MAX_SLOTS )
|
|
{
|
|
BaseSlot* pSlot = LockSlotPtr( slots[i] );
|
|
|
|
if ( pSlot && pSlot->ConsumesInputEvents() )
|
|
{
|
|
if ( pSlot->m_pMovieView->HitTest( x, y, Movie::HitTest_Shapes ) )
|
|
{
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
UnlockSlotPtr( slots[i] );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
bool ScaleformUIImpl::TallyAxisButtonEvent( int slot, int code, bool down )
|
|
{
|
|
bool result = false;
|
|
int sfSlot = SF_SS_SLOT( slot );
|
|
|
|
if ( sfSlot < MAX_SLOTS )
|
|
{
|
|
if ( code >= JOYSTICK_FIRST_AXIS_BUTTON && code <= JOYSTICK_LAST_AXIS_BUTTON )
|
|
{
|
|
int mask = 1 << ( code - JOYSTICK_FIRST_AXIS_BUTTON );
|
|
|
|
if ( down )
|
|
{
|
|
// on a down event, only let us through if we haven't disabled stick navigation
|
|
|
|
if ( !AnalogStickNavigationDisabled( sfSlot ) )
|
|
{
|
|
result = true;
|
|
m_iJoyAxisButtonsDown[slot] |= mask;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// on an up event, we just care about if we captured a previous down event
|
|
result = ( m_iJoyAxisButtonsDown[slot] & mask ) != 0;
|
|
m_iJoyAxisButtonsDown[slot] &= ~mask;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// if this isn't a joystick axis button, then just let it go through
|
|
result = true;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
|
|
|
|
}
|
|
|
|
|
|
bool ScaleformUIImpl::HandleInputEvent( const InputEvent_t &event )
|
|
{
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
// Update cached mouse location always, even if we aren't consuming mouse events.
|
|
// Otherwise we could have a stale value if we start consuming mouse events but the mouse doesn't actually move.
|
|
bool mousePositionChanged = false;
|
|
if ( event.m_nType == IE_AnalogValueChanged && event.m_nData == MOUSE_XY )
|
|
{
|
|
if ( m_iLastMouseX != event.m_nData2 || m_iLastMouseY != event.m_nData3 )
|
|
{
|
|
mousePositionChanged = true;
|
|
m_iLastMouseX = event.m_nData2;
|
|
m_iLastMouseY = event.m_nData3;
|
|
}
|
|
}
|
|
|
|
bool result = false;
|
|
bool isJoystickEvent = ( event.m_nType == IE_AnalogValueChanged ) && ( event.m_nData >= JOYSTICK_FIRST_AXIS ) && ( event.m_nData <= JOYSTICK_LAST_AXIS );
|
|
bool consumesEvents = ConsumesInputEvents();
|
|
const char* buttonBinding;
|
|
|
|
if ( !consumesEvents && !isJoystickEvent )
|
|
{
|
|
return result;
|
|
}
|
|
|
|
// no need to handle input event if the console is visible
|
|
if ( m_pEngine->Con_IsVisible() )
|
|
{
|
|
return result;
|
|
}
|
|
|
|
int slot = 0;
|
|
|
|
switch ( event.m_nType )
|
|
{
|
|
case IE_ButtonDoubleClicked:
|
|
case IE_ButtonPressed:
|
|
{
|
|
// NOTE: data2 is the virtual key code ( data1 contains the scan-code one )
|
|
ButtonCode_t code;
|
|
|
|
m_CurrentKey = ( ButtonCode_t ) event.m_nData;
|
|
|
|
DecodeButtonandSlotFromButtonCode( m_CurrentKey, code, slot );
|
|
buttonBinding = m_pGameUIFuncs->GetBindingForButtonCode( m_CurrentKey );
|
|
|
|
bool bIsFromController = IsJoystickCode( code );
|
|
|
|
if ( bIsFromController )
|
|
{
|
|
ControllerMoved();
|
|
}
|
|
|
|
if ( IsKeyCode( code ) || bIsFromController )
|
|
{
|
|
if ( TallyAxisButtonEvent( slot, code, true ) )
|
|
{
|
|
result = DistributeKeyEvent( true, bIsFromController, buttonBinding, m_CurrentKey, ( ButtonCode_t ) event.m_nData2, slot, false );
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
|
|
}
|
|
|
|
if ( IsMouseCode( code ) && m_iWantCursorShown )
|
|
{
|
|
CursorMoved();
|
|
if ( HitTest( m_iLastMouseX, m_iLastMouseY ) )
|
|
{
|
|
if ( code != MOUSE_LEFT )
|
|
{
|
|
result = DistributeKeyEvent( true, false, buttonBinding, m_CurrentKey, ( ButtonCode_t ) event.m_nData2, slot, false );
|
|
}
|
|
else
|
|
{
|
|
MouseEvent mevent( Event::MouseDown, 0, m_iLastMouseX, m_iLastMouseY );
|
|
result = DistributeEvent( mevent, slot, false );
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
}
|
|
break;
|
|
|
|
case IE_KeyTyped:
|
|
{
|
|
result = DistributeCharTyped( ( wchar_t )event.m_nData );
|
|
}
|
|
break;
|
|
|
|
case IE_ButtonReleased:
|
|
{
|
|
// NOTE: data2 is the virtual key code ( data1 contains the scan-code one )
|
|
ButtonCode_t code;
|
|
|
|
DecodeButtonandSlotFromButtonCode( ( ButtonCode_t ) event.m_nData, code, slot );
|
|
buttonBinding = m_pGameUIFuncs->GetBindingForButtonCode( ( ButtonCode_t ) event.m_nData );
|
|
|
|
bool bIsFromController = IsJoystickCode( code );
|
|
|
|
if ( bIsFromController )
|
|
{
|
|
ControllerMoved();
|
|
}
|
|
|
|
if ( IsKeyCode( code ) || bIsFromController )
|
|
{
|
|
if ( TallyAxisButtonEvent( slot, code, false ) )
|
|
{
|
|
result = DistributeKeyEvent( false, bIsFromController, buttonBinding, code, ( ButtonCode_t ) event.m_nData2, slot, false );
|
|
}
|
|
else
|
|
{
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if ( IsMouseCode( code ) && ( m_iWantCursorShown || code != MOUSE_LEFT ) )
|
|
{
|
|
CursorMoved();
|
|
if ( code != MOUSE_LEFT )
|
|
{
|
|
result = DistributeKeyEvent( false, false, buttonBinding, m_CurrentKey, ( ButtonCode_t ) event.m_nData2, slot, false );
|
|
}
|
|
else
|
|
{
|
|
MouseEvent mevent( Event::MouseUp, 0, m_iLastMouseX, m_iLastMouseY );
|
|
DistributeEvent( mevent, slot, false );
|
|
}
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IE_AnalogValueChanged:
|
|
{
|
|
switch ( event.m_nData )
|
|
{
|
|
case MOUSE_XY:
|
|
if ( mousePositionChanged && m_iWantCursorShown )
|
|
{
|
|
// on the PS3 a single mouse update is queued even when no mouse is connected
|
|
// So on PS3 we'll eat that message and wait for the next one before we actually
|
|
// show the cursor or switch to the keyboard/mouse UI glyphs
|
|
if ( IsPS3() && m_bEatPS3MouseEvent )
|
|
{
|
|
m_bEatPS3MouseEvent = false;
|
|
MouseEvent mevent( Event::MouseMove, 0, m_iLastMouseX, m_iLastMouseY );
|
|
DistributeEvent( mevent, m_iKeyboardSlot, false, false );
|
|
}
|
|
else
|
|
{
|
|
CursorMoved();
|
|
// If we're using the steam controller, assume input coming from the controller and continue to stay in controller UI mode.
|
|
// FIXME : Need latest SteamAPI integration
|
|
//bool bClearControllerUI = steamapicontext && !steamapicontext->SteamController();
|
|
bool bClearControllerUI = false;
|
|
MouseEvent mevent( Event::MouseMove, 0, m_iLastMouseX, m_iLastMouseY );
|
|
DistributeEvent( mevent, m_iKeyboardSlot, false, bClearControllerUI );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case JOYSTICK_AXIS(0, JOY_AXIS_X ):
|
|
SetJoyValue( 0, 0, 0, event.m_nData2 );
|
|
break;
|
|
|
|
case JOYSTICK_AXIS(0, JOY_AXIS_Y ):
|
|
SetJoyValue( 0, 0, 1, event.m_nData2 );
|
|
break;
|
|
|
|
case JOYSTICK_AXIS(0, JOY_AXIS_U ):
|
|
SetJoyValue( 0, 1, 0, event.m_nData2 );
|
|
break;
|
|
|
|
case JOYSTICK_AXIS(0, JOY_AXIS_R ):
|
|
SetJoyValue( 0, 1, 1, event.m_nData2 );
|
|
break;
|
|
case JOYSTICK_AXIS(1, JOY_AXIS_X ):
|
|
SetJoyValue( 1, 0, 0, event.m_nData2 );
|
|
slot = 1;
|
|
break;
|
|
case JOYSTICK_AXIS(1, JOY_AXIS_Y ):
|
|
SetJoyValue( 1, 0, 1, event.m_nData2 );
|
|
slot = 1;
|
|
break;
|
|
case JOYSTICK_AXIS(1, JOY_AXIS_U ):
|
|
SetJoyValue( 1, 1, 0, event.m_nData2 );
|
|
slot = 1;
|
|
break;
|
|
case JOYSTICK_AXIS(1, JOY_AXIS_R ):
|
|
SetJoyValue( 1, 1, 1, event.m_nData2 );
|
|
slot = 1;
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
// always eat key input when IME is up
|
|
if ( !result && m_bIMEEnabled )
|
|
{
|
|
switch ( event.m_nType )
|
|
{
|
|
case IE_ButtonPressed:
|
|
case IE_ButtonReleased:
|
|
{
|
|
ButtonCode_t code;
|
|
m_CurrentKey = (ButtonCode_t)event.m_nData;
|
|
DecodeButtonandSlotFromButtonCode( m_CurrentKey, code, slot );
|
|
|
|
if ( !IsMouseCode( code ) )
|
|
{
|
|
result = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool returnValue;
|
|
|
|
if ( !consumesEvents )
|
|
{
|
|
returnValue = false;
|
|
}
|
|
else if ( SlotDeniesInputToGame( SF_SS_SLOT( slot ) ) )
|
|
{
|
|
returnValue = true;
|
|
}
|
|
else
|
|
{
|
|
returnValue = result;
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
bool ScaleformUIImpl::IsSlotKeyboardAccessible( int slot )
|
|
{
|
|
return ( slot == SF_FULL_SCREEN_SLOT || slot == SF_SS_SLOT( m_iKeyboardSlot ) );
|
|
}
|
|
|
|
|
|
bool ScaleformUIImpl::HandleIMEEvent( size_t hwnd, unsigned int uMsg, unsigned int wParam, long lParam )
|
|
{
|
|
#if defined( PLATFORM_WINDOWS_PC )
|
|
if ( g_bScaleformIMEDetailedLogging )
|
|
{
|
|
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 );
|
|
|
|
CUtlString messageString;
|
|
switch ( uMsg )
|
|
{
|
|
case WM_LBUTTONDOWN:
|
|
messageString = "WM_LBUTTONDOWN";
|
|
break;
|
|
case WM_LBUTTONUP:
|
|
messageString = "WM_LBUTTONUP";
|
|
break;
|
|
case WM_KEYDOWN:
|
|
messageString = "WM_KEYDOWN";
|
|
break;
|
|
case WM_KEYUP:
|
|
messageString = "WM_KEYUP";
|
|
break;
|
|
case WM_CHAR:
|
|
messageString = "WM_CHAR";
|
|
break;
|
|
case WM_DEADCHAR:
|
|
messageString = "WM_DEADCHAR";
|
|
break;
|
|
case WM_SYSKEYDOWN:
|
|
messageString = "WM_SYSKEYDOWN";
|
|
break;
|
|
case WM_SYSKEYUP:
|
|
messageString = "WM_SYSKEYUP";
|
|
break;
|
|
case WM_SYSCHAR:
|
|
messageString = "WM_SYSCHAR";
|
|
break;
|
|
case WM_SYSDEADCHAR:
|
|
messageString = "WM_SYSDEADCHAR";
|
|
break;
|
|
case WM_UNICHAR:
|
|
messageString = "WM_UNICHAR";
|
|
break;
|
|
|
|
case WM_INPUTLANGCHANGE:
|
|
messageString = "WM_INPUTLANGCHANGE";
|
|
break;
|
|
case WM_IME_STARTCOMPOSITION:
|
|
messageString = "WM_IME_STARTCOMPOSITION";
|
|
break;
|
|
case WM_IME_COMPOSITION:
|
|
messageString = "WM_IME_COMPOSITION";
|
|
break;
|
|
case WM_IME_ENDCOMPOSITION:
|
|
messageString = "WM_IME_ENDCOMPOSITION";
|
|
break;
|
|
case WM_IME_NOTIFY:
|
|
messageString = "WM_IME_NOTIFY";
|
|
break;
|
|
case WM_IME_SETCONTEXT:
|
|
messageString = "WM_IME_SETCONTEXT";
|
|
break;
|
|
case WM_IME_CONTROL:
|
|
messageString = "WM_IME_CONTROL";
|
|
break;
|
|
case WM_IME_COMPOSITIONFULL:
|
|
messageString = "WM_IME_COMPOSITIONFULL";
|
|
break;
|
|
case WM_IME_SELECT:
|
|
messageString = "WM_IME_SELECT";
|
|
break;
|
|
case WM_IME_KEYDOWN:
|
|
messageString = "WM_IME_KEYDOWN";
|
|
break;
|
|
case WM_IME_KEYUP:
|
|
messageString = "WM_IME_KEYUP";
|
|
break;
|
|
case WM_IME_CHAR:
|
|
messageString = "WM_IME_CHAR";
|
|
break;
|
|
default:
|
|
messageString.Format( "Unknown IME message" );
|
|
}
|
|
|
|
CUtlString subMessageString;
|
|
if ( uMsg == WM_IME_NOTIFY )
|
|
{
|
|
switch ( wParam )
|
|
{
|
|
case IMN_CLOSESTATUSWINDOW:
|
|
subMessageString = "IMN_CLOSESTATUSWINDOW";
|
|
break;
|
|
case IMN_OPENSTATUSWINDOW:
|
|
subMessageString = "IMN_OPENSTATUSWINDOW";
|
|
break;
|
|
case IMN_CHANGECANDIDATE:
|
|
subMessageString = "IMN_CHANGECANDIDATE";
|
|
break;
|
|
case IMN_CLOSECANDIDATE:
|
|
subMessageString = "IMN_CLOSECANDIDATE";
|
|
break;
|
|
case IMN_OPENCANDIDATE:
|
|
subMessageString = "IMN_OPENCANDIDATE";
|
|
break;
|
|
case IMN_SETCONVERSIONMODE:
|
|
subMessageString = "IMN_SETCONVERSIONMODE";
|
|
break;
|
|
case IMN_SETSENTENCEMODE:
|
|
subMessageString = "IMN_SETSENTENCEMODE";
|
|
break;
|
|
case IMN_SETOPENSTATUS:
|
|
subMessageString = "IMN_SETOPENSTATUS";
|
|
break;
|
|
case IMN_SETCANDIDATEPOS:
|
|
subMessageString = "IMN_SETCANDIDATEPOS";
|
|
break;
|
|
case IMN_SETCOMPOSITIONFONT:
|
|
subMessageString = "IMN_SETCOMPOSITIONFONT";
|
|
break;
|
|
case IMN_SETCOMPOSITIONWINDOW:
|
|
subMessageString = "IMN_SETCOMPOSITIONWINDOW";
|
|
break;
|
|
case IMN_SETSTATUSWINDOWPOS:
|
|
subMessageString = "IMN_SETSTATUSWINDOWPOS";
|
|
break;
|
|
case IMN_GUIDELINE:
|
|
subMessageString = "IMN_GUIDELINE";
|
|
break;
|
|
case IMN_PRIVATE:
|
|
subMessageString = "IMN_PRIVATE";
|
|
break;
|
|
default:
|
|
subMessageString.Format( "Unknown IMN_??? message" );
|
|
}
|
|
}
|
|
Log_Detailed( LOG_SCALEFORM_IME, " HandleIMEEvent: %s %s\n", messageString.Get(), subMessageString.Get() );
|
|
}
|
|
#endif
|
|
|
|
if ( !m_bIMEEnabled )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool bHandled = false;
|
|
#if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
|
|
BaseSlot* pSlot = LockSlotPtr( m_iIMEFocusSlot );
|
|
|
|
if ( pSlot )
|
|
{
|
|
IMEWin32Event ev( IMEWin32Event::IME_Default, (SF::UPInt)hwnd, uMsg, wParam, lParam );
|
|
bHandled = ((pSlot->m_pMovieView->HandleEvent( ev ) & Movie::HE_NoDefaultAction) > 0);
|
|
}
|
|
UnlockSlotPtr( m_iIMEFocusSlot );
|
|
|
|
Log_Detailed( LOG_SCALEFORM_IME, " HandleIMEEvent returns %d\n", bHandled );
|
|
#endif
|
|
return bHandled;
|
|
}
|
|
|
|
bool ScaleformUIImpl::PreProcessKeyboardEvent( size_t hwnd, unsigned int uMsg, unsigned int wParam, long lParam )
|
|
{
|
|
if ( !m_bIMEEnabled )
|
|
return false;
|
|
|
|
bool bHandled = false;
|
|
#if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
|
|
BaseSlot* pSlot = LockSlotPtr( m_iIMEFocusSlot );
|
|
if ( pSlot && pSlot->m_pMovieView )
|
|
{
|
|
IMEWin32Event ev( IMEWin32Event::IME_PreProcessKeyboard, (SF::UPInt)hwnd, uMsg, wParam, lParam );
|
|
bHandled = ((pSlot->m_pMovieView->HandleEvent( ev ) & Movie::HE_NoDefaultAction) > 0);
|
|
}
|
|
UnlockSlotPtr( m_iIMEFocusSlot );
|
|
#endif
|
|
return bHandled;
|
|
}
|
|
|
|
void ScaleformUIImpl::SetIMEEnabled( bool bEnabled )
|
|
{
|
|
if ( m_bIMEEnabled != bEnabled )
|
|
{
|
|
#if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
|
|
Log_Detailed( LOG_SCALEFORM_IME, "%s: %s\n", __FUNCTION__, bEnabled ? "True" : "False" );
|
|
|
|
if ( m_pIMEManager )
|
|
{
|
|
if ( !bEnabled )
|
|
{
|
|
m_pIMEManager->OnFinalize();
|
|
}
|
|
m_pIMEManager->EnableIME( bEnabled );
|
|
}
|
|
#endif
|
|
}
|
|
m_bIMEEnabled = bEnabled;
|
|
}
|
|
|
|
void ScaleformUIImpl::SetIMEFocus( int slot )
|
|
{
|
|
#if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
|
|
if ( m_pIMEManager )
|
|
{
|
|
if ( m_iIMEFocusSlot != slot )
|
|
{
|
|
BaseSlot* pSlot = LockSlotPtr( slot );
|
|
|
|
if ( pSlot && pSlot->m_pMovieView )
|
|
{
|
|
pSlot->m_pMovieView->HandleEvent( Event::SetFocus );
|
|
m_iIMEFocusSlot = slot;
|
|
}
|
|
UnlockSlotPtr( slot );
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ScaleformUIImpl::ShutdownIME()
|
|
{
|
|
#if defined( SF_ENABLE_IME ) && defined( SF_ENABLE_IME_WIN32 )
|
|
if ( m_pIMEManager && m_bIMEEnabled )
|
|
{
|
|
m_bIMEEnabled = false;
|
|
m_pIMEManager->EnableIME( false );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ScaleformUIImpl::UpdateAvatarImages( void )
|
|
{
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
FOR_EACH_MAP_FAST( m_mapUserXuidToAvatar, i )
|
|
{
|
|
m_mapUserXuidToAvatar[i]->Update();
|
|
}
|
|
}
|
|
|
|
bool ScaleformUIImpl::AvatarImageAddRef( XUID playerID )
|
|
{
|
|
EnsureSteamCallbacksConfigured();
|
|
|
|
playerID = NormalizeXuidForAccountID( playerID );
|
|
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return true;
|
|
}
|
|
|
|
Assert( playerID );
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
ScaleformUIAvatarImage *pImage = NULL;
|
|
int iIndex = m_mapUserXuidToAvatar.Find( playerID );
|
|
if ( iIndex == m_mapUserXuidToAvatar.InvalidIndex() )
|
|
{
|
|
if ( m_pDefaultAvatarTexture )
|
|
{
|
|
pImage = new ScaleformUIAvatarImage( playerID, m_pDefaultAvatarTexture->ImageData(), m_pDefaultAvatarTexture->Width(), m_pDefaultAvatarTexture->Height(), m_pDefaultAvatarTexture->Format(), m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
else
|
|
{
|
|
static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
pImage = new ScaleformUIAvatarImage( playerID, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
|
|
if ( !pImage->LoadAvatarImage() )
|
|
{
|
|
Warning( "We failed to load the avatar image for user %llX\n", playerID );
|
|
|
|
#ifndef NO_STEAM
|
|
extern CSteamAPIContext *steamapicontext;
|
|
// We will retry if the user is actually logged into steam, otherwise just use the default avatar image
|
|
if ( steamapicontext && steamapicontext->SteamUser() && steamapicontext->SteamUserStats() && steamapicontext->SteamUser()->BLoggedOn() )
|
|
#endif
|
|
{ // Other platforms should always retry loading the avatar
|
|
Assert( 0 );
|
|
delete pImage;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
iIndex = m_mapUserXuidToAvatar.Insert( playerID, pImage );
|
|
}
|
|
else
|
|
{
|
|
pImage = m_mapUserXuidToAvatar.Element( iIndex );
|
|
}
|
|
|
|
Assert( pImage );
|
|
int nRefcount = pImage->AddRef();
|
|
DevMsg( "Avatar image for user %llX cached [refcount=%d]\n", playerID, nRefcount );
|
|
|
|
return true;
|
|
}
|
|
|
|
void ScaleformUIImpl::AvatarImageRelease( XUID playerID )
|
|
{
|
|
playerID = NormalizeXuidForAccountID( playerID );
|
|
|
|
Assert( playerID );
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
int iIndex = m_mapUserXuidToAvatar.Find( playerID );
|
|
if ( iIndex != m_mapUserXuidToAvatar.InvalidIndex() )
|
|
{
|
|
ScaleformUIAvatarImage *pImage = m_mapUserXuidToAvatar.Element( iIndex );
|
|
int nRemainingRefCount = pImage->Release();
|
|
if ( nRemainingRefCount <= 0 )
|
|
{
|
|
m_mapUserXuidToAvatar.RemoveAt( iIndex );
|
|
}
|
|
DevMsg( "Avatar image for user %llX released [refcount=%d]\n", playerID, nRemainingRefCount );
|
|
}
|
|
else
|
|
{
|
|
// We have a ref count problem if we get here because we tried to release an
|
|
// avatar image that doesn't exist!
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // This is okay if we're in noshaderapi mode (used to transcode demos).
|
|
}
|
|
}
|
|
|
|
void ScaleformUIImpl::AvatarImageReload( XUID playerID, IScaleformAvatarImageProvider *pProvider )
|
|
{
|
|
if ( pProvider && !ScaleformUIAvatarImage::sm_pProvider )
|
|
{
|
|
ScaleformUIAvatarImage::sm_pProvider = pProvider;
|
|
}
|
|
|
|
playerID = NormalizeXuidForAccountID( playerID );
|
|
|
|
Assert( playerID );
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
int iIndex = m_mapUserXuidToAvatar.Find( playerID );
|
|
if ( iIndex != m_mapUserXuidToAvatar.InvalidIndex() )
|
|
{
|
|
ScaleformUIAvatarImage *pImage = m_mapUserXuidToAvatar.Element( iIndex );
|
|
pImage->LoadAvatarImage( pProvider );
|
|
DevMsg( 2, "Avatar image for user %llX reloaded\n", playerID );
|
|
}
|
|
}
|
|
|
|
void ScaleformUIImpl::InventoryImageUpdate( uint64 iItemID, IScaleformInventoryImageProvider *pIScaleformInventoryImageProvider )
|
|
{
|
|
ScaleformUIInventoryImage *pImage = NULL;
|
|
int iIndex = m_mapItemIdToImage.Find( iItemID );
|
|
if ( iIndex != m_mapItemIdToImage.InvalidIndex() )
|
|
{
|
|
pImage = m_mapItemIdToImage.Element( iIndex );
|
|
|
|
IScaleformInventoryImageProvider::ImageInfo_t imgInfo;
|
|
bool bImgInfoValid = pIScaleformInventoryImageProvider->GetInventoryImageInfo( iItemID, &imgInfo );
|
|
|
|
if ( bImgInfoValid && !pImage->LoadInventoryImage( imgInfo.m_bufImageDataRGBA, imgInfo.m_nWidth, imgInfo.m_nHeight, IMAGE_FORMAT_BGRA8888 ) )
|
|
{
|
|
Warning( "We failed to update the inventory image for item %llX\n", iItemID );
|
|
Assert( 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool ScaleformUIImpl::InventoryImageAddRef( uint64 iItemID, IScaleformInventoryImageProvider *pIScaleformInventoryImageProvider )
|
|
{
|
|
Assert( iItemID );
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return true;
|
|
}
|
|
|
|
ScaleformUIInventoryImage *pImage = NULL;
|
|
int iIndex = m_mapItemIdToImage.Find( iItemID );
|
|
if ( iIndex == m_mapItemIdToImage.InvalidIndex() )
|
|
{
|
|
IScaleformInventoryImageProvider::ImageInfo_t imgInfo;
|
|
bool bImgInfoValid = pIScaleformInventoryImageProvider->GetInventoryImageInfo( iItemID, &imgInfo );
|
|
|
|
#ifdef USE_DEFAULT_INVENTORY_ICON_BACKGROUNDS
|
|
if ( bImgInfoValid && imgInfo.m_pDefaultIconName )
|
|
{
|
|
uint nHash = HashStringCaselessConventional( imgInfo.m_pDefaultIconName );
|
|
UtlHashFastHandle_t handle = m_defaultInventoryIcons.Find( nHash );
|
|
if ( handle != m_defaultInventoryIcons.InvalidHandle() )
|
|
{
|
|
DefaultInventoryIcon_t icon = m_defaultInventoryIcons.Element( handle );
|
|
|
|
if ( icon.m_pTexture && icon.m_pTexture->Width() == imgInfo.m_nWidth )
|
|
{
|
|
Assert( imgInfo.m_nHeight <= icon.m_pTexture->Height() );
|
|
pImage = new ScaleformUIInventoryImage( iItemID, icon.m_pTexture->ImageData(), imgInfo.m_nWidth, imgInfo.m_nHeight, icon.m_pTexture->Format(), m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if ( !pImage )
|
|
{
|
|
static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
pImage = new ScaleformUIInventoryImage( iItemID, defaultTextureBits, 2, 2, IMAGE_FORMAT_BGRA8888, m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
|
|
if ( bImgInfoValid && !pImage->LoadInventoryImage( imgInfo.m_bufImageDataRGBA, imgInfo.m_nWidth, imgInfo.m_nHeight, IMAGE_FORMAT_BGRA8888 ) )
|
|
{
|
|
Warning( "We failed to load the inventory image for item %llX\n", iItemID );
|
|
Assert( 0 );
|
|
}
|
|
|
|
iIndex = m_mapItemIdToImage.Insert( iItemID, pImage );
|
|
}
|
|
else
|
|
{
|
|
pImage = m_mapItemIdToImage.Element( iIndex );
|
|
}
|
|
|
|
Assert( pImage );
|
|
int nRefcount = pImage->AddRef();
|
|
DevMsg( "Inventory image for item %llX cached [refcount=%d]\n", iItemID, nRefcount );
|
|
|
|
return true;
|
|
}
|
|
|
|
void ScaleformUIImpl::InventoryImageRelease( uint64 iItemID )
|
|
{
|
|
Assert( iItemID );
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
int iIndex = m_mapItemIdToImage.Find( iItemID );
|
|
if ( iIndex != m_mapItemIdToImage.InvalidIndex() )
|
|
{
|
|
ScaleformUIInventoryImage *pImage = m_mapItemIdToImage.Element( iIndex );
|
|
int nRemainingRefCount = pImage->Release();
|
|
if ( nRemainingRefCount <= 0 )
|
|
{
|
|
m_mapItemIdToImage.RemoveAt( iIndex );
|
|
}
|
|
DevMsg( "Inventory image for item %llX released [refcount=%d]\n", iItemID, nRemainingRefCount );
|
|
}
|
|
else
|
|
{
|
|
// We have a ref count problem if we get here because we tried to release an
|
|
// inventory image that doesn't exist!
|
|
Assert( 0 );
|
|
}
|
|
}
|
|
|
|
#ifdef USE_DEFAULT_INVENTORY_ICON_BACKGROUNDS
|
|
void ScaleformUIImpl::InitInventoryDefaultIcons( CUtlVector< const char * > *vecIconDefaultNames )
|
|
{
|
|
#if defined( CSTRIKE15 )
|
|
CUtlBuffer bufFile;
|
|
// Load the default inventory image bits and store them in a raw buffer
|
|
FOR_EACH_VEC( *vecIconDefaultNames, i )
|
|
{
|
|
uint uHash = HashStringCaselessConventional( vecIconDefaultNames->Element(i) );
|
|
UtlHashFastHandle_t handle = m_defaultInventoryIcons.Find( uHash );
|
|
if ( handle == m_defaultInventoryIcons.InvalidHandle() )
|
|
{
|
|
DefaultInventoryIcon_t icon;
|
|
icon.m_pImage = NULL;
|
|
icon.m_pTexture = NULL;
|
|
bufFile.Clear();
|
|
const char* pDefaultInventoryImageFileName = vecIconDefaultNames->Element(i);
|
|
if ( g_pFullFileSystem->ReadFile( pDefaultInventoryImageFileName, NULL, bufFile ) )
|
|
{
|
|
icon.m_pTexture = CreateVTFTexture();
|
|
#if !defined( _GAMECONSOLE )
|
|
if ( !icon.m_pTexture->Unserialize( bufFile ) )
|
|
#else
|
|
if ( !icon.m_pTexture->UnserializeFromBuffer( bufFile, true, false, false, 0 ) )
|
|
#endif
|
|
{
|
|
Warning( "Invalid or corrupt default inventory image (%s)\n", pDefaultInventoryImageFileName );
|
|
DestroyVTFTexture( icon.m_pTexture );
|
|
icon.m_pTexture = NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Warning( "Failed to read the default inventory image file (%s)\n", pDefaultInventoryImageFileName );
|
|
}
|
|
|
|
if ( icon.m_pTexture )
|
|
{
|
|
m_defaultInventoryIcons.FastInsert( uHash, icon );
|
|
}
|
|
}
|
|
}
|
|
#endif // CSTRIKE15
|
|
|
|
}
|
|
#endif
|
|
|
|
Image* ScaleformUIImpl::CreateImageFromFile( const char *pszFileName, const ImageCreateInfo& info, int width, int height )
|
|
{
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return NULL;
|
|
}
|
|
|
|
if ( pszFileName != NULL )
|
|
{
|
|
return m_pLoader->GetImageCreator()->LoadImageFile( info, SF::String( pszFileName ) );
|
|
}
|
|
else
|
|
{
|
|
return RawImage::Create( Image_R8G8B8A8, 0, ImageSize( width, height ), ImageUse_Update, 0, m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
}
|
|
|
|
void ScaleformUIImpl::AddDeviceDependentObject( IShaderDeviceDependentObject * object )
|
|
{
|
|
if ( m_pShaderDeviceMgr )
|
|
{
|
|
m_pShaderDeviceMgr->AddDeviceDependentObject( object );
|
|
}
|
|
}
|
|
|
|
void ScaleformUIImpl::RemoveDeviceDependentObject( IShaderDeviceDependentObject * object )
|
|
{
|
|
if ( m_pShaderDeviceMgr )
|
|
{
|
|
m_pShaderDeviceMgr->RemoveDeviceDependentObject( object );
|
|
}
|
|
}
|
|
|
|
|
|
ScaleformUIAvatarImage* ScaleformUIImpl::GetAvatarImage( XUID playerID )
|
|
{
|
|
playerID = NormalizeXuidForAccountID( playerID );
|
|
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
ScaleformUIAvatarImage *pImage = NULL;
|
|
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return NULL;
|
|
}
|
|
|
|
if ( playerID )
|
|
{
|
|
int iIndex = m_mapUserXuidToAvatar.Find( playerID );
|
|
if ( iIndex == m_mapUserXuidToAvatar.InvalidIndex() )
|
|
{
|
|
// If you hit this assert then the most likely problem is that the action script
|
|
// file is trying to load an avatar image that hasn't been created yet.
|
|
// To create the avatar image call m_pScaleformUI->AvatarImageAddRef in the client code.
|
|
Assert( 0 );
|
|
Warning( "Error getting avatar image: playerID(%llu), iIndex(%d)\n", playerID, iIndex );
|
|
}
|
|
else
|
|
{
|
|
pImage = m_mapUserXuidToAvatar.Element( iIndex );
|
|
}
|
|
}
|
|
|
|
if ( !pImage )
|
|
{
|
|
if ( !m_pDefaultAvatarImage )
|
|
{
|
|
// Create an avatar image for the player id of 0 (or an avatar we failed to load) to use as a default
|
|
if ( m_pDefaultAvatarTexture )
|
|
{
|
|
m_pDefaultAvatarImage = new ScaleformUIAvatarImage( 0, m_pDefaultAvatarTexture->ImageData(), m_pDefaultAvatarTexture->Width(), m_pDefaultAvatarTexture->Height(), m_pDefaultAvatarTexture->Format(), m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
else
|
|
{
|
|
static const byte defaultTextureBits[] = { 0, 0, 0, 0 };
|
|
m_pDefaultAvatarImage = new ScaleformUIAvatarImage( 0, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
}
|
|
|
|
pImage = m_pDefaultAvatarImage;
|
|
}
|
|
|
|
return pImage;
|
|
}
|
|
|
|
ScaleformUIInventoryImage* ScaleformUIImpl::GetInventoryImage( uint64 iItemID )
|
|
{
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return NULL;
|
|
}
|
|
|
|
ScaleformUIInventoryImage *pImage = NULL;
|
|
|
|
if ( iItemID )
|
|
{
|
|
int iIndex = m_mapItemIdToImage.Find( iItemID );
|
|
if ( iIndex == m_mapItemIdToImage.InvalidIndex() )
|
|
{
|
|
// If you hit this assert then the most likely problem is that the action script
|
|
// file is trying to load an inventory image that hasn't been created yet.
|
|
// To create the inventory image call m_pScaleformUI->InventoryImageAddRef in the client code.
|
|
Assert( 0 );
|
|
Warning( "Error getting inventory image: iItemID(%llu), iIndex(%d)\n", iItemID, iIndex );
|
|
}
|
|
else
|
|
{
|
|
pImage = m_mapItemIdToImage.Element( iIndex );
|
|
}
|
|
}
|
|
|
|
if ( !pImage )
|
|
{
|
|
if ( !m_pDefaultInventoryImage )
|
|
{
|
|
// Create an inventory image for the item id of 0 (or an inventory item we failed to load/generate) to use as a default
|
|
if ( m_pDefaultInventoryTexture )
|
|
{
|
|
m_pDefaultInventoryImage = new ScaleformUIInventoryImage( 0, m_pDefaultInventoryTexture->ImageData(), m_pDefaultInventoryTexture->Width(), m_pDefaultInventoryTexture->Height(), m_pDefaultInventoryTexture->Format(), m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
else
|
|
{
|
|
static const byte defaultTextureBits[] = { 0, 0, 0, 0 };
|
|
m_pDefaultInventoryImage = new ScaleformUIInventoryImage( 0, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
}
|
|
|
|
pImage = m_pDefaultInventoryImage;
|
|
}
|
|
|
|
return pImage;
|
|
}
|
|
|
|
|
|
bool ScaleformUIImpl::ChromeHTMLImageAddRef( uint64 imageID )
|
|
{
|
|
Assert( imageID );
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return true;
|
|
}
|
|
|
|
ScaleformUIChromeHTMLImage *pImage = NULL;
|
|
int iIndex = m_mapImageIdToChromeImage.Find( imageID );
|
|
if ( iIndex == m_mapImageIdToChromeImage.InvalidIndex() )
|
|
{
|
|
static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0};
|
|
pImage = new ScaleformUIChromeHTMLImage( imageID, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
|
|
|
|
iIndex = m_mapImageIdToChromeImage.Insert( imageID, pImage );
|
|
}
|
|
else
|
|
{
|
|
pImage = m_mapImageIdToChromeImage.Element( iIndex );
|
|
}
|
|
|
|
Assert( pImage );
|
|
int nRefcount = pImage->AddRef();
|
|
DevMsg( "Chrome HTML image for id %llX cached [refcount=%d]\n", imageID, nRefcount );
|
|
|
|
return true;
|
|
}
|
|
|
|
void ScaleformUIImpl::ChromeHTMLImageUpdate( uint64 imageID, const byte* rgba, int width, int height, ::ImageFormat format )
|
|
{
|
|
ScaleformUIChromeHTMLImage *pImage = NULL;
|
|
int iIndex = m_mapImageIdToChromeImage.Find( imageID );
|
|
if ( iIndex != m_mapImageIdToChromeImage.InvalidIndex() )
|
|
{
|
|
pImage = m_mapImageIdToChromeImage.Element( iIndex );
|
|
if ( !pImage->LoadChromeHTMLImage( rgba, width, height, format ) )
|
|
{
|
|
Warning( "We failed to update the chrome HTML image for item %llX\n", imageID );
|
|
Assert( 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ScaleformUIImpl::ChromeHTMLImageRelease( uint64 imageID )
|
|
{
|
|
Assert( imageID );
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
int iIndex = m_mapImageIdToChromeImage.Find( imageID );
|
|
if ( iIndex != m_mapImageIdToChromeImage.InvalidIndex() )
|
|
{
|
|
ScaleformUIChromeHTMLImage *pImage = m_mapImageIdToChromeImage.Element( iIndex );
|
|
int nRemainingRefCount = pImage->Release();
|
|
if ( nRemainingRefCount <= 0 )
|
|
{
|
|
m_mapImageIdToChromeImage.RemoveAt( iIndex );
|
|
}
|
|
DevMsg( "Chrome HTML image for id %llX released [refcount=%d]\n", imageID, nRemainingRefCount );
|
|
}
|
|
else
|
|
{
|
|
// We have a ref count problem if we get here because we tried to release an
|
|
// chrome HTML image that doesn't exist!
|
|
Assert( 0 );
|
|
}
|
|
}
|
|
|
|
ScaleformUIChromeHTMLImage* ScaleformUIImpl::GetChromeHTMLImage( uint64 imageID )
|
|
{
|
|
MEM_ALLOC_CREDIT();
|
|
|
|
if ( !m_pRenderHAL )
|
|
{
|
|
Assert( CommandLine()->FindParm( "-noshaderapi" ) ); // For transcoding demos.
|
|
return NULL;
|
|
}
|
|
|
|
ScaleformUIChromeHTMLImage *pImage = NULL;
|
|
|
|
if ( imageID )
|
|
{
|
|
int iIndex = m_mapImageIdToChromeImage.Find( imageID );
|
|
if ( iIndex == m_mapImageIdToChromeImage.InvalidIndex() )
|
|
{
|
|
// If you hit this assert then the most likely problem is that the action script
|
|
// file is trying to load an avatar image that hasn't been created yet.
|
|
// To create the avatar image call m_pScaleformUI->AvatarImageAddRef in the client code.
|
|
Assert( 0 );
|
|
Warning( "Error getting chrome HTML image: imageID(%llu), iIndex(%d)\n", imageID, iIndex );
|
|
}
|
|
else
|
|
{
|
|
pImage = m_mapImageIdToChromeImage.Element( iIndex );
|
|
}
|
|
}
|
|
|
|
if ( !pImage )
|
|
{
|
|
if ( !m_pDefaultChromeHTMLImage )
|
|
{
|
|
static const byte defaultTextureBits[] = { 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0};
|
|
m_pDefaultChromeHTMLImage = new ScaleformUIChromeHTMLImage( 0, defaultTextureBits, 2, 2, IMAGE_FORMAT_RGBA8888, m_pRenderHAL->GetTextureManager() );
|
|
}
|
|
|
|
pImage = m_pDefaultChromeHTMLImage;
|
|
}
|
|
|
|
return pImage;
|
|
}
|