aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/c_vguiscreen.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/c_vguiscreen.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/c_vguiscreen.cpp')
-rw-r--r--mp/src/game/client/c_vguiscreen.cpp1754
1 files changed, 877 insertions, 877 deletions
diff --git a/mp/src/game/client/c_vguiscreen.cpp b/mp/src/game/client/c_vguiscreen.cpp
index 72c67c77..adf8830c 100644
--- a/mp/src/game/client/c_vguiscreen.cpp
+++ b/mp/src/game/client/c_vguiscreen.cpp
@@ -1,878 +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);
-}
-
+//========= 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