//===== Copyright © 1996-2005, Valve Corporation, All rights reserved. ======// // // Purpose: // // $NoKeywords: $ //===========================================================================// #include "cbase.h" #include "networkstringtable_clientdll.h" #include #include "PanelMetaClassMgr.h" #include #include "mathlib/VMatrix.h" #include "VGUIMatSurface/IMatSystemSurface.h" #include "view.h" #include "CollisionUtils.h" #include #include #include #include "ienginevgui.h" #include "in_buttons.h" #include #include "materialsystem/IMesh.h" #include "precache_register.h" #include "C_VGuiScreen.h" #include "IClientMode.h" #include "vgui_bitmapbutton.h" #include "vgui_bitmappanel.h" #include "filesystem.h" #include "iinput.h" #include extern vgui::IInputInternal *g_InputInternal; // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #define VGUI_SCREEN_MODE_RADIUS 80 //Precache the materials PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectVGuiScreen ) PRECACHE( MATERIAL, "engine/writez" ) PRECACHE_REGISTER_END() // ----------------------------------------------------------------------------- // // This is a cache of preloaded keyvalues. // ----------------------------------------------------------------------------- // CUtlDict g_KeyValuesCache; KeyValues* CacheKeyValuesForFile( const char *pFilename ) { MEM_ALLOC_CREDIT(); int i = g_KeyValuesCache.Find( pFilename ); if ( i == g_KeyValuesCache.InvalidIndex() ) { KeyValues *rDat = new KeyValues( pFilename ); rDat->LoadFromFile( filesystem, pFilename, NULL ); g_KeyValuesCache.Insert( pFilename, rDat ); return rDat; } else { return g_KeyValuesCache[i]; } } void ClearKeyValuesCache() { MEM_ALLOC_CREDIT(); for ( int i=g_KeyValuesCache.First(); i != g_KeyValuesCache.InvalidIndex(); i=g_KeyValuesCache.Next( i ) ) { g_KeyValuesCache[i]->deleteThis(); } g_KeyValuesCache.Purge(); } IMPLEMENT_CLIENTCLASS_DT(C_VGuiScreen, DT_VGuiScreen, CVGuiScreen) RecvPropFloat( RECVINFO(m_flWidth) ), RecvPropFloat( RECVINFO(m_flHeight) ), RecvPropInt( RECVINFO(m_fScreenFlags) ), RecvPropInt( RECVINFO(m_nPanelName) ), RecvPropIntWithMinusOneFlag( RECVINFO(m_nAttachmentIndex) ), RecvPropInt( RECVINFO(m_nOverlayMaterial) ), RecvPropEHandle( RECVINFO(m_hPlayerOwner) ), END_RECV_TABLE() //----------------------------------------------------------------------------- // Constructor //----------------------------------------------------------------------------- C_VGuiScreen::C_VGuiScreen() { m_nOldPanelName = m_nPanelName = -1; m_nOldOverlayMaterial = m_nOverlayMaterial = -1; m_nOldPx = m_nOldPy = -1; m_nButtonState = 0; m_bLoseThinkNextFrame = false; m_bAcceptsInput = true; m_WriteZMaterial.Init( "engine/writez", TEXTURE_GROUP_VGUI ); m_OverlayMaterial.Init( m_WriteZMaterial ); } C_VGuiScreen::~C_VGuiScreen() { DestroyVguiScreen(); } //----------------------------------------------------------------------------- // Network updates //----------------------------------------------------------------------------- void C_VGuiScreen::PreDataUpdate( DataUpdateType_t updateType ) { BaseClass::PreDataUpdate( updateType ); m_nOldPanelName = m_nPanelName; m_nOldOverlayMaterial = m_nOverlayMaterial; } void C_VGuiScreen::OnDataChanged( DataUpdateType_t type ) { BaseClass::OnDataChanged( type ); if ((type == DATA_UPDATE_CREATED) || (m_nPanelName != m_nOldPanelName)) { CreateVguiScreen( PanelName() ); m_nButtonState = 0; } RenderWithViewModels( IsAttachedToViewModel() ); OnTranslucencyTypeChanged(); // Set up the overlay material if (m_nOldOverlayMaterial != m_nOverlayMaterial) { m_OverlayMaterial.Shutdown(); const char *pMaterialName = GetMaterialNameFromIndex(m_nOverlayMaterial); if (pMaterialName) { m_OverlayMaterial.Init( pMaterialName, TEXTURE_GROUP_VGUI ); } else { m_OverlayMaterial.Init( m_WriteZMaterial ); } } } void FormatViewModelAttachment( C_BasePlayer *pPlayer, Vector &vOrigin, bool bInverse ); //----------------------------------------------------------------------------- // Returns the attachment render origin + origin //----------------------------------------------------------------------------- void C_VGuiScreen::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles ) { C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity(); if (pEnt && (m_nAttachmentIndex > 0)) { { C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true ); pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles ); } if ( IsAttachedToViewModel() ) { C_BasePlayer *pOwner = ToBasePlayer( ((C_BaseViewModel *)pEnt)->GetOwner() ); Assert( pOwner ); FormatViewModelAttachment( pOwner, *pOrigin, true ); } } else { BaseClass::GetAimEntOrigin( pAttachedTo, pOrigin, pAngles ); } } //----------------------------------------------------------------------------- // Create, destroy vgui panels... //----------------------------------------------------------------------------- void C_VGuiScreen::CreateVguiScreen( const char *pTypeName ) { // Clear out any old screens. DestroyVguiScreen(); AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID ); // Create the new screen... VGuiScreenInitData_t initData( this ); m_PanelWrapper.Activate( pTypeName, NULL, 0, &initData ); // Retrieve the panel dimensions vgui::Panel *pPanel = m_PanelWrapper.GetPanel(); if (pPanel) { int x, y; pPanel->GetBounds( x, y, m_nPixelWidth, m_nPixelHeight ); } else { m_nPixelWidth = m_nPixelHeight = 0; } } void C_VGuiScreen::DestroyVguiScreen( ) { m_PanelWrapper.Deactivate(); } //----------------------------------------------------------------------------- // Is the screen active? //----------------------------------------------------------------------------- bool C_VGuiScreen::IsActive() const { return (m_fScreenFlags & VGUI_SCREEN_ACTIVE) != 0; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool C_VGuiScreen::IsAttachedToViewModel() const { return (m_fScreenFlags & VGUI_SCREEN_ATTACHED_TO_VIEWMODEL) != 0; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool C_VGuiScreen::AcceptsInput() const { return m_bAcceptsInput; } //----------------------------------------------------------------------------- // Purpose: // Input : acceptsinput - //----------------------------------------------------------------------------- void C_VGuiScreen::SetAcceptsInput( bool acceptsinput ) { m_bAcceptsInput = acceptsinput; } //----------------------------------------------------------------------------- // Are we only visible to teammates? //----------------------------------------------------------------------------- bool C_VGuiScreen::IsVisibleOnlyToTeammates() const { return (m_fScreenFlags & VGUI_SCREEN_VISIBLE_TO_TEAMMATES) != 0; } //----------------------------------------------------------------------------- // Are we visible to someone on this team? //----------------------------------------------------------------------------- bool C_VGuiScreen::IsVisibleToTeam( int nTeam ) { // FIXME: Should this maybe go into a derived class of some sort? // Don't bother with screens on the wrong team if (IsVisibleOnlyToTeammates() && (nTeam > 0)) { // Hmmm... sort of a hack... C_BaseEntity *pOwner = GetOwnerEntity(); if ( pOwner && (nTeam != pOwner->GetTeamNumber()) ) return false; } return true; } //----------------------------------------------------------------------------- // Activate, deactivate the view screen //----------------------------------------------------------------------------- void C_VGuiScreen::GainFocus( ) { SetNextClientThink( CLIENT_THINK_ALWAYS ); m_bLoseThinkNextFrame = false; m_nOldButtonState = 0; } void C_VGuiScreen::LoseFocus() { m_bLoseThinkNextFrame = true; m_nOldButtonState = 0; } void C_VGuiScreen::SetButtonState( int nButtonState ) { m_nButtonState = nButtonState; } //----------------------------------------------------------------------------- // Returns the panel name //----------------------------------------------------------------------------- const char *C_VGuiScreen::PanelName() const { return g_StringTableVguiScreen->GetString( m_nPanelName ); } //-------------------------------------------------------------------------- // Purpose: // Given a field of view and mouse/screen positions as well as the current // render origin and angles, returns a unit vector through the mouse position // that can be used to trace into the world under the mouse click pixel. // Input : // mousex - // mousey - // fov - // vecRenderOrigin - // vecRenderAngles - // Output : // vecPickingRay //-------------------------------------------------------------------------- void ScreenToWorld( int mousex, int mousey, float fov, const Vector& vecRenderOrigin, const QAngle& vecRenderAngles, Vector& vecPickingRay ) { float dx, dy; float c_x, c_y; float dist; Vector vpn, vup, vright; float scaled_fov = ScaleFOVByWidthRatio( fov, engine->GetScreenAspectRatio( ScreenWidth(), ScreenHeight() ) * 0.75f ); c_x = ScreenWidth() / 2; c_y = ScreenHeight() / 2; dx = (float)mousex - c_x; // Invert Y dy = c_y - (float)mousey; // Convert view plane distance dist = c_x / tan( M_PI * scaled_fov / 360.0 ); // Decompose view angles AngleVectors( vecRenderAngles, &vpn, &vright, &vup ); // Offset forward by view plane distance, and then by pixel offsets vecPickingRay = vpn * dist + vright * ( dx ) + vup * ( dy ); // Convert to unit vector VectorNormalize( vecPickingRay ); } //----------------------------------------------------------------------------- // Purpose: Deal with input //----------------------------------------------------------------------------- void C_VGuiScreen::ClientThink( void ) { int nButtonsChanged = m_nOldButtonState ^ m_nButtonState; m_nOldButtonState = m_nButtonState; // Debounced button codes for pressed/released // UNDONE: Do we need auto-repeat? m_nButtonPressed = nButtonsChanged & m_nButtonState; // The changed ones still down are "pressed" m_nButtonReleased = nButtonsChanged & (~m_nButtonState); // The ones not down are "released" BaseClass::ClientThink(); // FIXME: We should really be taking bob, shake, and roll into account // but if we did, then all the inputs would be generated multiple times // if the world was rendered multiple times (for things like water, etc.) vgui::Panel *pPanel = m_PanelWrapper.GetPanel(); if (!pPanel) return; C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); if (!pLocalPlayer) return; // Generate a ray along the view direction Vector vecEyePosition = pLocalPlayer->EyePosition(); QAngle viewAngles = pLocalPlayer->EyeAngles( ); // Compute cursor position... Ray_t lookDir; Vector endPos; float u, v; // Viewmodel attached screens that take input need to have a moving cursor // Do a pick under the cursor as our selection Vector viewDir; AngleVectors( viewAngles, &viewDir ); VectorMA( vecEyePosition, 1000.0f, viewDir, endPos ); lookDir.Init( vecEyePosition, endPos ); if (!IntersectWithRay( lookDir, &u, &v, NULL )) return; if ( ((u < 0) || (v < 0) || (u > 1) || (v > 1)) && !m_bLoseThinkNextFrame) return; // This will cause our panel to grab all input! GetClientMode()->ActivateInGameVGuiContext( pPanel ); // Convert (u,v) into (px,py) int px = (int)(u * m_nPixelWidth + 0.5f); int py = (int)(v * m_nPixelHeight + 0.5f); // Generate mouse input commands if ((px != m_nOldPx) || (py != m_nOldPy)) { g_InputInternal->InternalCursorMoved( px, py ); m_nOldPx = px; m_nOldPy = py; } if (m_nButtonPressed & IN_ATTACK) { g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED ); g_InputInternal->InternalMousePressed(MOUSE_LEFT); } if (m_nButtonPressed & IN_ATTACK2) { g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_PRESSED ); g_InputInternal->InternalMousePressed( MOUSE_RIGHT ); } if ( (m_nButtonReleased & IN_ATTACK) || m_bLoseThinkNextFrame) // for a button release on loosing focus { g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED ); g_InputInternal->InternalMouseReleased( MOUSE_LEFT ); } if (m_nButtonReleased & IN_ATTACK2) { g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_RELEASED ); g_InputInternal->InternalMouseReleased( MOUSE_RIGHT ); } if ( m_bLoseThinkNextFrame == true ) { m_bLoseThinkNextFrame = false; SetNextClientThink( CLIENT_THINK_NEVER ); } GetClientMode()->DeactivateInGameVGuiContext( ); } //----------------------------------------------------------------------------- // Computes control points of the quad describing the screen //----------------------------------------------------------------------------- void C_VGuiScreen::ComputeEdges( Vector *pUpperLeft, Vector *pUpperRight, Vector *pLowerLeft ) { Vector vecOrigin = GetAbsOrigin(); Vector xaxis, yaxis; AngleVectors( GetAbsAngles(), &xaxis, &yaxis, NULL ); // NOTE: Have to multiply by -1 here because yaxis goes out the -y axis in AngleVectors actually... yaxis *= -1.0f; VectorCopy( vecOrigin, *pLowerLeft ); VectorMA( vecOrigin, m_flHeight, yaxis, *pUpperLeft ); VectorMA( *pUpperLeft, m_flWidth, xaxis, *pUpperRight ); } //----------------------------------------------------------------------------- // Return intersection point of ray with screen in barycentric coords //----------------------------------------------------------------------------- bool C_VGuiScreen::IntersectWithRay( const Ray_t &ray, float *u, float *v, float *t ) { // Perform a raycast to see where in barycentric coordinates the ray hits // the viewscreen; if it doesn't hit it, you're not in the mode Vector origin, upt, vpt; ComputeEdges( &origin, &upt, &vpt ); return ComputeIntersectionBarycentricCoordinates( ray, origin, upt, vpt, *u, *v, t ); } //----------------------------------------------------------------------------- // Is the vgui screen backfacing? //----------------------------------------------------------------------------- bool C_VGuiScreen::IsBackfacing( const Vector &viewOrigin ) { // Compute a ray from camera to center of the screen.. Vector cameraToScreen; VectorSubtract( GetAbsOrigin(), viewOrigin, cameraToScreen ); // Figure out the face normal Vector zaxis; GetVectors( NULL, NULL, &zaxis ); // The actual backface cull return (DotProduct( zaxis, cameraToScreen ) > 0.0f); } //----------------------------------------------------------------------------- // Computes the panel center to world transform //----------------------------------------------------------------------------- void C_VGuiScreen::ComputePanelToWorld() { // The origin is at the upper-left corner of the screen Vector vecOrigin, vecUR, vecLL; ComputeEdges( &vecOrigin, &vecUR, &vecLL ); m_PanelToWorld.SetupMatrixOrgAngles( vecOrigin, GetAbsAngles() ); } //----------------------------------------------------------------------------- // a pass to set the z buffer... //----------------------------------------------------------------------------- void C_VGuiScreen::DrawScreenOverlay() { CMatRenderContextPtr pRenderContext( materials ); pRenderContext->MatrixMode( MATERIAL_MODEL ); pRenderContext->PushMatrix(); pRenderContext->LoadMatrix( m_PanelToWorld ); unsigned char pColor[4] = {255, 255, 255, 255}; CMeshBuilder meshBuilder; IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_OverlayMaterial ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); meshBuilder.Position3f( 0.0f, 0.0f, 0 ); meshBuilder.TexCoord2f( 0, 0.0f, 0.0f ); meshBuilder.Color4ubv( pColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3f( m_flWidth, 0.0f, 0 ); meshBuilder.TexCoord2f( 0, 1.0f, 0.0f ); meshBuilder.Color4ubv( pColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3f( m_flWidth, -m_flHeight, 0 ); meshBuilder.TexCoord2f( 0, 1.0f, 1.0f ); meshBuilder.Color4ubv( pColor ); meshBuilder.AdvanceVertex(); meshBuilder.Position3f( 0.0f, -m_flHeight, 0 ); meshBuilder.TexCoord2f( 0, 0.0f, 1.0f ); meshBuilder.Color4ubv( pColor ); meshBuilder.AdvanceVertex(); meshBuilder.End(); pMesh->Draw(); pRenderContext->PopMatrix(); } //----------------------------------------------------------------------------- // Draws the panel using a 3D transform... //----------------------------------------------------------------------------- int C_VGuiScreen::DrawModel( int flags, const RenderableInstance_t &instance ) { vgui::Panel *pPanel = m_PanelWrapper.GetPanel(); if (!pPanel || !IsActive()) return 0; // Don't bother drawing stuff not visible to me... C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); if (!pLocalPlayer || !IsVisibleToTeam(pLocalPlayer->GetTeamNumber()) ) return 0; if ( !IsVisibleToPlayer( pLocalPlayer ) ) { return 0; } // Backface cull the entire panel here... if (IsBackfacing(CurrentViewOrigin())) return 0; // Recompute the panel-to-world center // FIXME: Can this be cached off? ComputePanelToWorld(); g_pMatSystemSurface->DrawPanelIn3DSpace( pPanel->GetVPanel(), m_PanelToWorld, m_nPixelWidth, m_nPixelHeight, m_flWidth, m_flHeight ); // Finally, a pass to set the z buffer... DrawScreenOverlay(); return 1; } bool C_VGuiScreen::ShouldDraw( void ) { return !IsEffectActive(EF_NODRAW); } //----------------------------------------------------------------------------- // Purpose: Hook for vgui screens to determine visibility //----------------------------------------------------------------------------- bool C_VGuiScreen::IsVisibleToPlayer( C_BasePlayer *pViewingPlayer ) { return true; } RenderableTranslucencyType_t C_VGuiScreen::ComputeTranslucencyType( void ) { return ( (m_fScreenFlags & VGUI_SCREEN_TRANSPARENT) != 0 ) ? RENDERABLE_IS_TRANSLUCENT : RENDERABLE_IS_OPAQUE; } //----------------------------------------------------------------------------- // Purpose: Sometimes we only want a specific player to be able to input to a panel //----------------------------------------------------------------------------- C_BasePlayer *C_VGuiScreen::GetPlayerOwner( void ) { return ( C_BasePlayer * )( m_hPlayerOwner.Get() ); } bool C_VGuiScreen::IsInputOnlyToOwner( void ) { return (m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) != 0; } //----------------------------------------------------------------------------- // // Enumator class for finding vgui screens close to the local player // //----------------------------------------------------------------------------- class CVGuiScreenEnumerator : public IPartitionEnumerator { DECLARE_CLASS_GAMEROOT( CVGuiScreenEnumerator, IPartitionEnumerator ); public: virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity ); int GetScreenCount(); C_VGuiScreen *GetVGuiScreen( int index ); private: CUtlVector< CHandle< C_VGuiScreen > > m_VguiScreens; }; IterationRetval_t CVGuiScreenEnumerator::EnumElement( IHandleEntity *pHandleEntity ) { C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() ); if ( pEnt == NULL ) return ITERATION_CONTINUE; // FIXME.. pretty expensive... C_VGuiScreen *pScreen = dynamic_cast(pEnt); if ( pScreen ) { int i = m_VguiScreens.AddToTail( ); m_VguiScreens[i].Set( pScreen ); } return ITERATION_CONTINUE; } int CVGuiScreenEnumerator::GetScreenCount() { return m_VguiScreens.Count(); } C_VGuiScreen *CVGuiScreenEnumerator::GetVGuiScreen( int index ) { return m_VguiScreens[index].Get(); } //----------------------------------------------------------------------------- // // Look for vgui screens, returns true if it found one ... // //----------------------------------------------------------------------------- C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &viewAngle, int nTeam ) { if ( IsX360() ) { // X360TBD: Turn this on if feature actually used return NULL; } C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer(); Assert( pLocalPlayer ); if ( !pLocalPlayer ) return NULL; // Get the view direction... Vector lookDir; AngleVectors( viewAngle, &lookDir ); // Create a ray used for raytracing Vector lookEnd; VectorMA( viewPosition, 2.0f * VGUI_SCREEN_MODE_RADIUS, lookDir, lookEnd ); Ray_t lookRay; lookRay.Init( viewPosition, lookEnd ); // Look for vgui screens that are close to the player CVGuiScreenEnumerator localScreens; partition->EnumerateElementsInSphere( PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens ); Vector vecOut, vecViewDelta; float flBestDist = 2.0f; C_VGuiScreen *pBestScreen = NULL; for (int i = localScreens.GetScreenCount(); --i >= 0; ) { C_VGuiScreen *pScreen = localScreens.GetVGuiScreen(i); if ( pScreen->IsAttachedToViewModel() ) continue; // Don't bother with screens I'm behind... // Hax - don't cancel backfacing with viewmodel attached screens. // we can get prediction bugs that make us backfacing for one frame and // it resets the mouse position if we lose focus. if ( pScreen->IsBackfacing(viewPosition) ) continue; // Don't bother with screens that are turned off if (!pScreen->IsActive()) continue; // FIXME: Should this maybe go into a derived class of some sort? // Don't bother with screens on the wrong team if (!pScreen->IsVisibleToTeam(nTeam)) continue; if ( !pScreen->AcceptsInput() ) continue; if ( pScreen->IsInputOnlyToOwner() && pScreen->GetPlayerOwner() != pLocalPlayer ) continue; // Test perpendicular distance from the screen... pScreen->GetVectors( NULL, NULL, &vecOut ); VectorSubtract( viewPosition, pScreen->GetAbsOrigin(), vecViewDelta ); float flPerpDist = DotProduct(vecViewDelta, vecOut); if ( (flPerpDist < 0) || (flPerpDist > VGUI_SCREEN_MODE_RADIUS) ) continue; // Perform a raycast to see where in barycentric coordinates the ray hits // the viewscreen; if it doesn't hit it, you're not in the mode float u, v, t; if (!pScreen->IntersectWithRay( lookRay, &u, &v, &t )) continue; // Barycentric test if ((u < 0) || (v < 0) || (u > 1) || (v > 1)) continue; if ( t < flBestDist ) { flBestDist = t; pBestScreen = pScreen; } } return pBestScreen; } void ActivateVguiScreen( C_BaseEntity *pVguiScreenEnt ) { if (pVguiScreenEnt) { Assert( dynamic_cast(pVguiScreenEnt) ); C_VGuiScreen *pVguiScreen = static_cast(pVguiScreenEnt); pVguiScreen->GainFocus( ); } } void SetVGuiScreenButtonState( C_BaseEntity *pVguiScreenEnt, int nButtonState ) { if (pVguiScreenEnt) { Assert( dynamic_cast(pVguiScreenEnt) ); C_VGuiScreen *pVguiScreen = static_cast(pVguiScreenEnt); pVguiScreen->SetButtonState( nButtonState ); } } void DeactivateVguiScreen( C_BaseEntity *pVguiScreenEnt ) { if (pVguiScreenEnt) { Assert( dynamic_cast(pVguiScreenEnt) ); C_VGuiScreen *pVguiScreen = static_cast(pVguiScreenEnt); pVguiScreen->LoseFocus( ); } } CVGuiScreenPanel::CVGuiScreenPanel( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName ) { m_hEntity = NULL; } CVGuiScreenPanel::CVGuiScreenPanel( vgui::Panel *parent, const char *panelName, vgui::HScheme hScheme ) : BaseClass( parent, panelName, hScheme ) { m_hEntity = NULL; } bool CVGuiScreenPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData ) { const char *pResFile = pKeyValues->GetString( "resfile" ); if (pResFile[0] != 0) { KeyValues *pCachedKeyValues = CacheKeyValuesForFile( pResFile ); LoadControlSettings( pResFile, NULL, pCachedKeyValues ); } // Dimensions in pixels int nWidth, nHeight; nWidth = pKeyValues->GetInt( "pixelswide", 240 ); nHeight = pKeyValues->GetInt( "pixelshigh", 160 ); if ((nWidth <= 0) || (nHeight <= 0)) return false; // If init data isn't specified, then we're just precaching. if ( pInitData ) { m_hEntity.Set( pInitData->m_pEntity ); C_VGuiScreen *screen = dynamic_cast< C_VGuiScreen * >( pInitData->m_pEntity ); if ( screen ) { bool acceptsInput = pKeyValues->GetBool( "acceptsinput", true ); screen->SetAcceptsInput( acceptsInput ); } } SetBounds( 0, 0, nWidth, nHeight ); return true; } vgui::Panel *CVGuiScreenPanel::CreateControlByName(const char *controlName) { // Check the panel metaclass manager to make these controls... if (!Q_strncmp(controlName, "MaterialImage", 20)) { return new CBitmapPanel(NULL, "BitmapPanel"); } if (!Q_strncmp(controlName, "MaterialButton", 20)) { return new CBitmapButton(NULL, "BitmapButton", ""); } // Didn't find it? Just use the default stuff return BaseClass::CreateControlByName( controlName ); } //----------------------------------------------------------------------------- // Purpose: Called when the user presses a button //----------------------------------------------------------------------------- void CVGuiScreenPanel::OnCommand( const char *command) { if ( Q_stricmp( command, "vguicancel" ) ) { engine->ClientCmd( const_cast( command ) ); } BaseClass::OnCommand(command); } DECLARE_VGUI_SCREEN_FACTORY( CVGuiScreenPanel, "vgui_screen_panel" );