|
|
//===== Copyright � 1996-2005, 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 "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 "inputsystem/iinputsystem.h"
#include "inputsystem/iinputstacksystem.h"
#include "engine/ivdebugoverlay.h"
#include "iviewrender.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
PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectVGuiScreen ) PRECACHE( MATERIAL, "engine/writez" ) PRECACHE_REGISTER_END()
ConVar cl_showVGUIAttachments( "cl_showVGUIAttachments", "0", FCVAR_DEVELOPMENTONLY, "Shows the base attachment location of the vgui widget" );
// ----------------------------------------------------------------------------- //
// 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) ), 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 defined ( CSTRIKE15 )
// For some reason FormatViewModelAttachment is causing bad transforms on the attachment position.
// We will probably need to fix this for split screen support.
// If we add back in split screen support to the game, throw an assert here.
AssertMsg( MAX_SPLITSCREEN_PLAYERS == 1, "FormatViewModelAttachment must be fixed and reenabled for proper split screen support." );
#else
if ( IsAttachedToViewModel() ) { C_BasePlayer *pOwner = ToBasePlayer( ((C_BaseViewModel *)pEnt)->GetOwner() ); Assert( pOwner ); FormatViewModelAttachment( pOwner, *pOrigin, true ); }
#endif
} else { BaseClass::GetAimEntOrigin( pAttachedTo, pOrigin, pAngles ); } }
//-----------------------------------------------------------------------------
// Create, destroy vgui panels...
//-----------------------------------------------------------------------------
void C_VGuiScreen::CreateVguiScreen( const char *pTypeName ) { // Clear out any old screens.
DestroyVguiScreen();
#if defined ( CSTRIKE15 )
// Asserts were firing for screens because they had EFL_USE_PARTITION_WHEN_NOT_SOLID but no physics data.
SetSolid( SOLID_NONE ); RemoveEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
#else
AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
#endif
// 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(); }
int C_VGuiScreen::GetScreenFlags( void ) const { return m_fScreenFlags; }
//-----------------------------------------------------------------------------
// 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 ) { // InputContextHandle_t hContext = engine->GetInputContext( ENGINE_INPUT_CONTEXT_GAME );
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;
// g_pInputStackSystem->SetCursorVisible( hContext, true );
// g_pInputStackSystem->SetCursorIcon( hContext, g_pInputSystem->GetStandardCursor( INPUT_CURSOR_HAND ) );
// This will cause our panel to grab all input!
ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( pLocalPlayer->index ); 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 || m_nButtonPressed & IN_USE ) { 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_nButtonReleased & IN_USE ) || 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() { m_PanelToWorld.SetupMatrixOrgAngles( GetAbsOrigin(), 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) return 0;
pPanel->SetEnabled( IsActive() ); if (!IsActive()) return 0;
// Don't bother drawing in the shadow map
if ( flags & DF_SHADOW_DEPTH_MAP ) 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();
if ( cl_showVGUIAttachments.GetBool() ) { // Attachment debug code.
C_BaseEntity *pEnt = GetMoveParent()->GetBaseEntity(); if (pEnt && (m_nAttachmentIndex > 0)) { studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pEnt->GetModel() ); for ( int i = 1; i <= pStudioHdr->GetNumAttachments(); i++ ) { Vector vecPos; QAngle angles; Vector vecForward, vecRight, vecUp; char tempstr[256];
C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true ); //pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles );
bool baseVGuiTransform = ( m_nAttachmentIndex == i ); pEnt->GetAttachment( i, vecPos, angles ); AngleVectors(angles, &vecForward, &vecRight, &vecUp ); // Red - forward, green - right, blue - up
NDebugOverlay::Line( vecPos, vecPos + ( vecForward * 4.0f ), 255, 0, 0, true, 0.05f ); NDebugOverlay::Line( vecPos, vecPos + ( vecRight * 4.0f ), 0, 255, 0, true, 0.05f ); NDebugOverlay::Line( vecPos, vecPos + ( vecUp * 4.0f ), 0, 0, 255, true, 0.05f ); Q_snprintf( tempstr, sizeof(tempstr), " %c %s (%d)", baseVGuiTransform ? '*' : '<', pStudioHdr->pAttachment(i-1).pszName(), i ); NDebugOverlay::Text( vecPos, tempstr, true, 0.05f ); } } }
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<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 ( IsGameConsole() ) { // 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->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 ( StringHasPrefixCaseSensitive( controlName, "MaterialImage" ) ) { return new CBitmapPanel(NULL, "BitmapPanel"); }
if ( StringHasPrefixCaseSensitive( controlName, "MaterialButton" ) ) { 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" );
|