aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_vguiscreen.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/c_vguiscreen.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/c_vguiscreen.cpp')
-rw-r--r--mp/src/game/client/c_vguiscreen.cpp878
1 files changed, 878 insertions, 0 deletions
diff --git a/mp/src/game/client/c_vguiscreen.cpp b/mp/src/game/client/c_vguiscreen.cpp
new file mode 100644
index 00000000..72c67c77
--- /dev/null
+++ b/mp/src/game/client/c_vguiscreen.cpp
@@ -0,0 +1,878 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#include "cbase.h"
+#include "networkstringtable_clientdll.h"
+#include <KeyValues.h>
+#include "panelmetaclassmgr.h"
+#include <vgui_controls/Controls.h>
+#include "mathlib/vmatrix.h"
+#include "VGuiMatSurface/IMatSystemSurface.h"
+#include "view.h"
+#include "collisionutils.h"
+#include <vgui/IInput.h>
+#include <vgui/IPanel.h>
+#include <vgui/IVGui.h>
+#include "ienginevgui.h"
+#include "in_buttons.h"
+#include <vgui/MouseCode.h>
+#include "materialsystem/imesh.h"
+#include "clienteffectprecachesystem.h"
+#include "c_vguiscreen.h"
+#include "iclientmode.h"
+#include "vgui_bitmapbutton.h"
+#include "vgui_bitmappanel.h"
+#include "filesystem.h"
+#include "iinput.h"
+
+#include <vgui/IInputInternal.h>
+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
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectVGuiScreen )
+CLIENTEFFECT_MATERIAL( "engine/writez" )
+CLIENTEFFECT_REGISTER_END()
+
+
+// ----------------------------------------------------------------------------- //
+// This is a cache of preloaded keyvalues.
+// ----------------------------------------------------------------------------- //
+
+CUtlDict<KeyValues*, int> 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) ),
+ RecvPropInt( 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;
+ }
+
+ // 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( 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() )
+ {
+ FormatViewModelAttachment( *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;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : RenderGroup_t
+//-----------------------------------------------------------------------------
+RenderGroup_t C_VGuiScreen::GetRenderGroup()
+{
+ if ( IsAttachedToViewModel() )
+ return RENDER_GROUP_VIEW_MODEL_TRANSLUCENT;
+
+ return BaseClass::GetRenderGroup();
+}
+
+//-----------------------------------------------------------------------------
+// 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() * 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!
+ g_pClientMode->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 );
+ }
+
+ g_pClientMode->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 )
+{
+ 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;
+}
+
+bool C_VGuiScreen::IsTransparent( void )
+{
+ return (m_fScreenFlags & VGUI_SCREEN_TRANSPARENT) != 0;
+}
+
+//-----------------------------------------------------------------------------
+// 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<C_VGuiScreen*>(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<C_VGuiScreen*>(pVguiScreenEnt) );
+ C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pVguiScreenEnt);
+ pVguiScreen->GainFocus( );
+ }
+}
+
+void SetVGuiScreenButtonState( C_BaseEntity *pVguiScreenEnt, int nButtonState )
+{
+ if (pVguiScreenEnt)
+ {
+ Assert( dynamic_cast<C_VGuiScreen*>(pVguiScreenEnt) );
+ C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pVguiScreenEnt);
+ pVguiScreen->SetButtonState( nButtonState );
+ }
+}
+
+void DeactivateVguiScreen( C_BaseEntity *pVguiScreenEnt )
+{
+ if (pVguiScreenEnt)
+ {
+ Assert( dynamic_cast<C_VGuiScreen*>(pVguiScreenEnt) );
+ C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(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->GetInt( "acceptsinput", 1 ) ? true : false;
+ 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<char *>( command ) );
+ }
+
+ BaseClass::OnCommand(command);
+}
+
+DECLARE_VGUI_SCREEN_FACTORY( CVGuiScreenPanel, "vgui_screen_panel" ); \ No newline at end of file