Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

951 lines
28 KiB

  1. //===== Copyright � 1996-2005, Valve Corporation, All rights reserved. ======//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include "networkstringtable_clientdll.h"
  9. #include <keyvalues.h>
  10. #include "panelmetaclassmgr.h"
  11. #include <vgui_controls/Controls.h>
  12. #include "mathlib/vmatrix.h"
  13. #include "VGuiMatSurface/IMatSystemSurface.h"
  14. #include "view.h"
  15. #include "collisionutils.h"
  16. #include <vgui/IInput.h>
  17. #include <vgui/IPanel.h>
  18. #include <vgui/IVGui.h>
  19. #include "ienginevgui.h"
  20. #include "in_buttons.h"
  21. #include <vgui/MouseCode.h>
  22. #include "materialsystem/imesh.h"
  23. #include "precache_register.h"
  24. #include "c_vguiscreen.h"
  25. #include "iclientmode.h"
  26. #include "vgui_bitmapbutton.h"
  27. #include "vgui_bitmappanel.h"
  28. #include "filesystem.h"
  29. #include "iinput.h"
  30. #include "inputsystem/iinputsystem.h"
  31. #include "inputsystem/iinputstacksystem.h"
  32. #include "engine/ivdebugoverlay.h"
  33. #include "iviewrender.h"
  34. #include <vgui/IInputInternal.h>
  35. extern vgui::IInputInternal *g_InputInternal;
  36. // memdbgon must be the last include file in a .cpp file!!!
  37. #include "tier0/memdbgon.h"
  38. #define VGUI_SCREEN_MODE_RADIUS 80
  39. //Precache the materials
  40. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectVGuiScreen )
  41. PRECACHE( MATERIAL, "engine/writez" )
  42. PRECACHE_REGISTER_END()
  43. ConVar cl_showVGUIAttachments( "cl_showVGUIAttachments", "0", FCVAR_DEVELOPMENTONLY, "Shows the base attachment location of the vgui widget" );
  44. // ----------------------------------------------------------------------------- //
  45. // This is a cache of preloaded keyvalues.
  46. // ----------------------------------------------------------------------------- //
  47. CUtlDict<KeyValues*, int> g_KeyValuesCache;
  48. KeyValues* CacheKeyValuesForFile( const char *pFilename )
  49. {
  50. MEM_ALLOC_CREDIT();
  51. int i = g_KeyValuesCache.Find( pFilename );
  52. if ( i == g_KeyValuesCache.InvalidIndex() )
  53. {
  54. KeyValues *rDat = new KeyValues( pFilename );
  55. rDat->LoadFromFile( filesystem, pFilename, NULL );
  56. g_KeyValuesCache.Insert( pFilename, rDat );
  57. return rDat;
  58. }
  59. else
  60. {
  61. return g_KeyValuesCache[i];
  62. }
  63. }
  64. void ClearKeyValuesCache()
  65. {
  66. MEM_ALLOC_CREDIT();
  67. for ( int i=g_KeyValuesCache.First(); i != g_KeyValuesCache.InvalidIndex(); i=g_KeyValuesCache.Next( i ) )
  68. {
  69. g_KeyValuesCache[i]->deleteThis();
  70. }
  71. g_KeyValuesCache.Purge();
  72. }
  73. IMPLEMENT_CLIENTCLASS_DT(C_VGuiScreen, DT_VGuiScreen, CVGuiScreen)
  74. RecvPropFloat( RECVINFO(m_flWidth) ),
  75. RecvPropFloat( RECVINFO(m_flHeight) ),
  76. RecvPropInt( RECVINFO(m_fScreenFlags) ),
  77. RecvPropInt( RECVINFO(m_nPanelName) ),
  78. RecvPropIntWithMinusOneFlag( RECVINFO(m_nAttachmentIndex) ),
  79. RecvPropInt( RECVINFO(m_nOverlayMaterial) ),
  80. RecvPropEHandle( RECVINFO(m_hPlayerOwner) ),
  81. END_RECV_TABLE()
  82. //-----------------------------------------------------------------------------
  83. // Constructor
  84. //-----------------------------------------------------------------------------
  85. C_VGuiScreen::C_VGuiScreen()
  86. {
  87. m_nOldPanelName = m_nPanelName = -1;
  88. m_nOldOverlayMaterial = m_nOverlayMaterial = -1;
  89. m_nOldPx = m_nOldPy = -1;
  90. m_nButtonState = 0;
  91. m_bLoseThinkNextFrame = false;
  92. m_bAcceptsInput = true;
  93. m_WriteZMaterial.Init( "engine/writez", TEXTURE_GROUP_VGUI );
  94. m_OverlayMaterial.Init( m_WriteZMaterial );
  95. }
  96. C_VGuiScreen::~C_VGuiScreen()
  97. {
  98. DestroyVguiScreen();
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Network updates
  102. //-----------------------------------------------------------------------------
  103. void C_VGuiScreen::PreDataUpdate( DataUpdateType_t updateType )
  104. {
  105. BaseClass::PreDataUpdate( updateType );
  106. m_nOldPanelName = m_nPanelName;
  107. m_nOldOverlayMaterial = m_nOverlayMaterial;
  108. }
  109. void C_VGuiScreen::OnDataChanged( DataUpdateType_t type )
  110. {
  111. BaseClass::OnDataChanged( type );
  112. if ((type == DATA_UPDATE_CREATED) || (m_nPanelName != m_nOldPanelName))
  113. {
  114. CreateVguiScreen( PanelName() );
  115. m_nButtonState = 0;
  116. }
  117. RenderWithViewModels( IsAttachedToViewModel() );
  118. OnTranslucencyTypeChanged();
  119. // Set up the overlay material
  120. if (m_nOldOverlayMaterial != m_nOverlayMaterial)
  121. {
  122. m_OverlayMaterial.Shutdown();
  123. const char *pMaterialName = GetMaterialNameFromIndex(m_nOverlayMaterial);
  124. if (pMaterialName)
  125. {
  126. m_OverlayMaterial.Init( pMaterialName, TEXTURE_GROUP_VGUI );
  127. }
  128. else
  129. {
  130. m_OverlayMaterial.Init( m_WriteZMaterial );
  131. }
  132. }
  133. }
  134. void FormatViewModelAttachment( C_BasePlayer *pPlayer, Vector &vOrigin, bool bInverse );
  135. //-----------------------------------------------------------------------------
  136. // Returns the attachment render origin + origin
  137. //-----------------------------------------------------------------------------
  138. void C_VGuiScreen::GetAimEntOrigin( IClientEntity *pAttachedTo, Vector *pOrigin, QAngle *pAngles )
  139. {
  140. C_BaseEntity *pEnt = pAttachedTo->GetBaseEntity();
  141. if (pEnt && (m_nAttachmentIndex > 0))
  142. {
  143. {
  144. C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true );
  145. pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles );
  146. }
  147. #if defined ( CSTRIKE15 )
  148. // For some reason FormatViewModelAttachment is causing bad transforms on the attachment position.
  149. // We will probably need to fix this for split screen support.
  150. // If we add back in split screen support to the game, throw an assert here.
  151. AssertMsg( MAX_SPLITSCREEN_PLAYERS == 1, "FormatViewModelAttachment must be fixed and reenabled for proper split screen support." );
  152. #else
  153. if ( IsAttachedToViewModel() )
  154. {
  155. C_BasePlayer *pOwner = ToBasePlayer( ((C_BaseViewModel *)pEnt)->GetOwner() );
  156. Assert( pOwner );
  157. FormatViewModelAttachment( pOwner, *pOrigin, true );
  158. }
  159. #endif
  160. }
  161. else
  162. {
  163. BaseClass::GetAimEntOrigin( pAttachedTo, pOrigin, pAngles );
  164. }
  165. }
  166. //-----------------------------------------------------------------------------
  167. // Create, destroy vgui panels...
  168. //-----------------------------------------------------------------------------
  169. void C_VGuiScreen::CreateVguiScreen( const char *pTypeName )
  170. {
  171. // Clear out any old screens.
  172. DestroyVguiScreen();
  173. #if defined ( CSTRIKE15 )
  174. // Asserts were firing for screens because they had EFL_USE_PARTITION_WHEN_NOT_SOLID but no physics data.
  175. SetSolid( SOLID_NONE );
  176. RemoveEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  177. #else
  178. AddEFlags( EFL_USE_PARTITION_WHEN_NOT_SOLID );
  179. #endif
  180. // Create the new screen...
  181. VGuiScreenInitData_t initData( this );
  182. m_PanelWrapper.Activate( pTypeName, NULL, 0, &initData );
  183. // Retrieve the panel dimensions
  184. vgui::Panel *pPanel = m_PanelWrapper.GetPanel();
  185. if (pPanel)
  186. {
  187. int x, y;
  188. pPanel->GetBounds( x, y, m_nPixelWidth, m_nPixelHeight );
  189. }
  190. else
  191. {
  192. m_nPixelWidth = m_nPixelHeight = 0;
  193. }
  194. }
  195. void C_VGuiScreen::DestroyVguiScreen( )
  196. {
  197. m_PanelWrapper.Deactivate();
  198. }
  199. int C_VGuiScreen::GetScreenFlags( void ) const
  200. {
  201. return m_fScreenFlags;
  202. }
  203. //-----------------------------------------------------------------------------
  204. // Is the screen active?
  205. //-----------------------------------------------------------------------------
  206. bool C_VGuiScreen::IsActive() const
  207. {
  208. return (m_fScreenFlags & VGUI_SCREEN_ACTIVE) != 0;
  209. }
  210. //-----------------------------------------------------------------------------
  211. // Purpose:
  212. // Output : Returns true on success, false on failure.
  213. //-----------------------------------------------------------------------------
  214. bool C_VGuiScreen::IsAttachedToViewModel() const
  215. {
  216. return (m_fScreenFlags & VGUI_SCREEN_ATTACHED_TO_VIEWMODEL) != 0;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose:
  220. // Output : Returns true on success, false on failure.
  221. //-----------------------------------------------------------------------------
  222. bool C_VGuiScreen::AcceptsInput() const
  223. {
  224. return m_bAcceptsInput;
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. // Input : acceptsinput -
  229. //-----------------------------------------------------------------------------
  230. void C_VGuiScreen::SetAcceptsInput( bool acceptsinput )
  231. {
  232. m_bAcceptsInput = acceptsinput;
  233. }
  234. //-----------------------------------------------------------------------------
  235. // Are we only visible to teammates?
  236. //-----------------------------------------------------------------------------
  237. bool C_VGuiScreen::IsVisibleOnlyToTeammates() const
  238. {
  239. return (m_fScreenFlags & VGUI_SCREEN_VISIBLE_TO_TEAMMATES) != 0;
  240. }
  241. //-----------------------------------------------------------------------------
  242. // Are we visible to someone on this team?
  243. //-----------------------------------------------------------------------------
  244. bool C_VGuiScreen::IsVisibleToTeam( int nTeam )
  245. {
  246. // FIXME: Should this maybe go into a derived class of some sort?
  247. // Don't bother with screens on the wrong team
  248. if (IsVisibleOnlyToTeammates() && (nTeam > 0))
  249. {
  250. // Hmmm... sort of a hack...
  251. C_BaseEntity *pOwner = GetOwnerEntity();
  252. if ( pOwner && (nTeam != pOwner->GetTeamNumber()) )
  253. return false;
  254. }
  255. return true;
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Activate, deactivate the view screen
  259. //-----------------------------------------------------------------------------
  260. void C_VGuiScreen::GainFocus( )
  261. {
  262. SetNextClientThink( CLIENT_THINK_ALWAYS );
  263. m_bLoseThinkNextFrame = false;
  264. m_nOldButtonState = 0;
  265. }
  266. void C_VGuiScreen::LoseFocus()
  267. {
  268. m_bLoseThinkNextFrame = true;
  269. m_nOldButtonState = 0;
  270. }
  271. void C_VGuiScreen::SetButtonState( int nButtonState )
  272. {
  273. m_nButtonState = nButtonState;
  274. }
  275. //-----------------------------------------------------------------------------
  276. // Returns the panel name
  277. //-----------------------------------------------------------------------------
  278. const char *C_VGuiScreen::PanelName() const
  279. {
  280. return g_StringTableVguiScreen->GetString( m_nPanelName );
  281. }
  282. //--------------------------------------------------------------------------
  283. // Purpose:
  284. // Given a field of view and mouse/screen positions as well as the current
  285. // render origin and angles, returns a unit vector through the mouse position
  286. // that can be used to trace into the world under the mouse click pixel.
  287. // Input :
  288. // mousex -
  289. // mousey -
  290. // fov -
  291. // vecRenderOrigin -
  292. // vecRenderAngles -
  293. // Output :
  294. // vecPickingRay
  295. //--------------------------------------------------------------------------
  296. void ScreenToWorld( int mousex, int mousey, float fov,
  297. const Vector& vecRenderOrigin,
  298. const QAngle& vecRenderAngles,
  299. Vector& vecPickingRay )
  300. {
  301. float dx, dy;
  302. float c_x, c_y;
  303. float dist;
  304. Vector vpn, vup, vright;
  305. float scaled_fov = ScaleFOVByWidthRatio( fov, engine->GetScreenAspectRatio( ScreenWidth(), ScreenHeight() ) * 0.75f );
  306. c_x = ScreenWidth() / 2;
  307. c_y = ScreenHeight() / 2;
  308. dx = (float)mousex - c_x;
  309. // Invert Y
  310. dy = c_y - (float)mousey;
  311. // Convert view plane distance
  312. dist = c_x / tan( M_PI * scaled_fov / 360.0 );
  313. // Decompose view angles
  314. AngleVectors( vecRenderAngles, &vpn, &vright, &vup );
  315. // Offset forward by view plane distance, and then by pixel offsets
  316. vecPickingRay = vpn * dist + vright * ( dx ) + vup * ( dy );
  317. // Convert to unit vector
  318. VectorNormalize( vecPickingRay );
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose: Deal with input
  322. //-----------------------------------------------------------------------------
  323. void C_VGuiScreen::ClientThink( void )
  324. {
  325. // InputContextHandle_t hContext = engine->GetInputContext( ENGINE_INPUT_CONTEXT_GAME );
  326. int nButtonsChanged = m_nOldButtonState ^ m_nButtonState;
  327. m_nOldButtonState = m_nButtonState;
  328. // Debounced button codes for pressed/released
  329. // UNDONE: Do we need auto-repeat?
  330. m_nButtonPressed = nButtonsChanged & m_nButtonState; // The changed ones still down are "pressed"
  331. m_nButtonReleased = nButtonsChanged & (~m_nButtonState); // The ones not down are "released"
  332. BaseClass::ClientThink();
  333. // FIXME: We should really be taking bob, shake, and roll into account
  334. // but if we did, then all the inputs would be generated multiple times
  335. // if the world was rendered multiple times (for things like water, etc.)
  336. vgui::Panel *pPanel = m_PanelWrapper.GetPanel();
  337. if (!pPanel)
  338. return;
  339. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  340. if (!pLocalPlayer)
  341. return;
  342. // Generate a ray along the view direction
  343. Vector vecEyePosition = pLocalPlayer->EyePosition();
  344. QAngle viewAngles = pLocalPlayer->EyeAngles( );
  345. // Compute cursor position...
  346. Ray_t lookDir;
  347. Vector endPos;
  348. float u, v;
  349. // Viewmodel attached screens that take input need to have a moving cursor
  350. // Do a pick under the cursor as our selection
  351. Vector viewDir;
  352. AngleVectors( viewAngles, &viewDir );
  353. VectorMA( vecEyePosition, 1000.0f, viewDir, endPos );
  354. lookDir.Init( vecEyePosition, endPos );
  355. if (!IntersectWithRay( lookDir, &u, &v, NULL ))
  356. return;
  357. if ( ((u < 0) || (v < 0) || (u > 1) || (v > 1)) && !m_bLoseThinkNextFrame)
  358. return;
  359. // g_pInputStackSystem->SetCursorVisible( hContext, true );
  360. // g_pInputStackSystem->SetCursorIcon( hContext, g_pInputSystem->GetStandardCursor( INPUT_CURSOR_HAND ) );
  361. // This will cause our panel to grab all input!
  362. ACTIVE_SPLITSCREEN_PLAYER_GUARD_VGUI( pLocalPlayer->index );
  363. GetClientMode()->ActivateInGameVGuiContext( pPanel );
  364. // Convert (u,v) into (px,py)
  365. int px = (int)(u * m_nPixelWidth + 0.5f);
  366. int py = (int)(v * m_nPixelHeight + 0.5f);
  367. // Generate mouse input commands
  368. if ((px != m_nOldPx) || (py != m_nOldPy))
  369. {
  370. g_InputInternal->InternalCursorMoved( px, py );
  371. m_nOldPx = px;
  372. m_nOldPy = py;
  373. }
  374. if ( m_nButtonPressed & IN_ATTACK || m_nButtonPressed & IN_USE )
  375. {
  376. g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_PRESSED );
  377. g_InputInternal->InternalMousePressed(MOUSE_LEFT);
  378. }
  379. if (m_nButtonPressed & IN_ATTACK2)
  380. {
  381. g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_PRESSED );
  382. g_InputInternal->InternalMousePressed( MOUSE_RIGHT );
  383. }
  384. if ( (m_nButtonReleased & IN_ATTACK) || ( m_nButtonReleased & IN_USE ) || m_bLoseThinkNextFrame) // for a button release on loosing focus
  385. {
  386. g_InputInternal->SetMouseCodeState( MOUSE_LEFT, vgui::BUTTON_RELEASED );
  387. g_InputInternal->InternalMouseReleased( MOUSE_LEFT );
  388. }
  389. if (m_nButtonReleased & IN_ATTACK2)
  390. {
  391. g_InputInternal->SetMouseCodeState( MOUSE_RIGHT, vgui::BUTTON_RELEASED );
  392. g_InputInternal->InternalMouseReleased( MOUSE_RIGHT );
  393. }
  394. if ( m_bLoseThinkNextFrame == true )
  395. {
  396. m_bLoseThinkNextFrame = false;
  397. SetNextClientThink( CLIENT_THINK_NEVER );
  398. }
  399. GetClientMode()->DeactivateInGameVGuiContext();
  400. }
  401. //-----------------------------------------------------------------------------
  402. // Computes control points of the quad describing the screen
  403. //-----------------------------------------------------------------------------
  404. void C_VGuiScreen::ComputeEdges( Vector *pUpperLeft, Vector *pUpperRight, Vector *pLowerLeft )
  405. {
  406. Vector vecOrigin = GetAbsOrigin();
  407. Vector xaxis, yaxis;
  408. AngleVectors( GetAbsAngles(), &xaxis, &yaxis, NULL );
  409. // NOTE: Have to multiply by -1 here because yaxis goes out the -y axis in AngleVectors actually...
  410. yaxis *= -1.0f;
  411. VectorCopy( vecOrigin, *pLowerLeft );
  412. VectorMA( vecOrigin, m_flHeight, yaxis, *pUpperLeft );
  413. VectorMA( *pUpperLeft, m_flWidth, xaxis, *pUpperRight );
  414. }
  415. //-----------------------------------------------------------------------------
  416. // Return intersection point of ray with screen in barycentric coords
  417. //-----------------------------------------------------------------------------
  418. bool C_VGuiScreen::IntersectWithRay( const Ray_t &ray, float *u, float *v, float *t )
  419. {
  420. // Perform a raycast to see where in barycentric coordinates the ray hits
  421. // the viewscreen; if it doesn't hit it, you're not in the mode
  422. Vector origin, upt, vpt;
  423. ComputeEdges( &origin, &upt, &vpt );
  424. return ComputeIntersectionBarycentricCoordinates( ray, origin, upt, vpt, *u, *v, t );
  425. }
  426. //-----------------------------------------------------------------------------
  427. // Is the vgui screen backfacing?
  428. //-----------------------------------------------------------------------------
  429. bool C_VGuiScreen::IsBackfacing( const Vector &viewOrigin )
  430. {
  431. // Compute a ray from camera to center of the screen..
  432. Vector cameraToScreen;
  433. VectorSubtract( GetAbsOrigin(), viewOrigin, cameraToScreen );
  434. // Figure out the face normal
  435. Vector zaxis;
  436. GetVectors( NULL, NULL, &zaxis );
  437. // The actual backface cull
  438. return (DotProduct( zaxis, cameraToScreen ) > 0.0f);
  439. }
  440. //-----------------------------------------------------------------------------
  441. // Computes the panel center to world transform
  442. //-----------------------------------------------------------------------------
  443. void C_VGuiScreen::ComputePanelToWorld()
  444. {
  445. m_PanelToWorld.SetupMatrixOrgAngles( GetAbsOrigin(), GetAbsAngles() );
  446. }
  447. //-----------------------------------------------------------------------------
  448. // a pass to set the z buffer...
  449. //-----------------------------------------------------------------------------
  450. void C_VGuiScreen::DrawScreenOverlay()
  451. {
  452. CMatRenderContextPtr pRenderContext( materials );
  453. pRenderContext->MatrixMode( MATERIAL_MODEL );
  454. pRenderContext->PushMatrix();
  455. pRenderContext->LoadMatrix( m_PanelToWorld );
  456. unsigned char pColor[4] = {255, 255, 255, 255};
  457. CMeshBuilder meshBuilder;
  458. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_OverlayMaterial );
  459. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  460. meshBuilder.Position3f( 0.0f, 0.0f, 0 );
  461. meshBuilder.TexCoord2f( 0, 0.0f, 0.0f );
  462. meshBuilder.Color4ubv( pColor );
  463. meshBuilder.AdvanceVertex();
  464. meshBuilder.Position3f( m_flWidth, 0.0f, 0 );
  465. meshBuilder.TexCoord2f( 0, 1.0f, 0.0f );
  466. meshBuilder.Color4ubv( pColor );
  467. meshBuilder.AdvanceVertex();
  468. meshBuilder.Position3f( m_flWidth, -m_flHeight, 0 );
  469. meshBuilder.TexCoord2f( 0, 1.0f, 1.0f );
  470. meshBuilder.Color4ubv( pColor );
  471. meshBuilder.AdvanceVertex();
  472. meshBuilder.Position3f( 0.0f, -m_flHeight, 0 );
  473. meshBuilder.TexCoord2f( 0, 0.0f, 1.0f );
  474. meshBuilder.Color4ubv( pColor );
  475. meshBuilder.AdvanceVertex();
  476. meshBuilder.End();
  477. pMesh->Draw();
  478. pRenderContext->PopMatrix();
  479. }
  480. //-----------------------------------------------------------------------------
  481. // Draws the panel using a 3D transform...
  482. //-----------------------------------------------------------------------------
  483. int C_VGuiScreen::DrawModel( int flags, const RenderableInstance_t &instance )
  484. {
  485. vgui::Panel *pPanel = m_PanelWrapper.GetPanel();
  486. if (!pPanel)
  487. return 0;
  488. pPanel->SetEnabled( IsActive() );
  489. if (!IsActive())
  490. return 0;
  491. // Don't bother drawing in the shadow map
  492. if ( flags & DF_SHADOW_DEPTH_MAP )
  493. return 0;
  494. // Don't bother drawing stuff not visible to me...
  495. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  496. if (!pLocalPlayer || !IsVisibleToTeam(pLocalPlayer->GetTeamNumber()) )
  497. return 0;
  498. if ( !IsVisibleToPlayer( pLocalPlayer ) )
  499. {
  500. return 0;
  501. }
  502. // Backface cull the entire panel here...
  503. if (IsBackfacing(CurrentViewOrigin()))
  504. return 0;
  505. // Recompute the panel-to-world center
  506. // FIXME: Can this be cached off?
  507. ComputePanelToWorld();
  508. if ( cl_showVGUIAttachments.GetBool() )
  509. {
  510. // Attachment debug code.
  511. C_BaseEntity *pEnt = GetMoveParent()->GetBaseEntity();
  512. if (pEnt && (m_nAttachmentIndex > 0))
  513. {
  514. studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pEnt->GetModel() );
  515. for ( int i = 1; i <= pStudioHdr->GetNumAttachments(); i++ )
  516. {
  517. Vector vecPos;
  518. QAngle angles;
  519. Vector vecForward, vecRight, vecUp;
  520. char tempstr[256];
  521. C_BaseAnimating::AutoAllowBoneAccess boneaccess( true, true );
  522. //pEnt->GetAttachment( m_nAttachmentIndex, *pOrigin, *pAngles );
  523. bool baseVGuiTransform = ( m_nAttachmentIndex == i );
  524. pEnt->GetAttachment( i, vecPos, angles );
  525. AngleVectors(angles, &vecForward, &vecRight, &vecUp );
  526. // Red - forward, green - right, blue - up
  527. NDebugOverlay::Line( vecPos, vecPos + ( vecForward * 4.0f ), 255, 0, 0, true, 0.05f );
  528. NDebugOverlay::Line( vecPos, vecPos + ( vecRight * 4.0f ), 0, 255, 0, true, 0.05f );
  529. NDebugOverlay::Line( vecPos, vecPos + ( vecUp * 4.0f ), 0, 0, 255, true, 0.05f );
  530. Q_snprintf( tempstr, sizeof(tempstr), " %c %s (%d)", baseVGuiTransform ? '*' : '<', pStudioHdr->pAttachment(i-1).pszName(), i );
  531. NDebugOverlay::Text( vecPos, tempstr, true, 0.05f );
  532. }
  533. }
  534. }
  535. g_pMatSystemSurface->DrawPanelIn3DSpace( pPanel->GetVPanel(), m_PanelToWorld,
  536. m_nPixelWidth, m_nPixelHeight, m_flWidth, m_flHeight );
  537. // Finally, a pass to set the z buffer...
  538. DrawScreenOverlay();
  539. return 1;
  540. }
  541. bool C_VGuiScreen::ShouldDraw( void )
  542. {
  543. return !IsEffectActive(EF_NODRAW);
  544. }
  545. //-----------------------------------------------------------------------------
  546. // Purpose: Hook for vgui screens to determine visibility
  547. //-----------------------------------------------------------------------------
  548. bool C_VGuiScreen::IsVisibleToPlayer( C_BasePlayer *pViewingPlayer )
  549. {
  550. return true;
  551. }
  552. RenderableTranslucencyType_t C_VGuiScreen::ComputeTranslucencyType( void )
  553. {
  554. return ( (m_fScreenFlags & VGUI_SCREEN_TRANSPARENT) != 0 ) ? RENDERABLE_IS_TRANSLUCENT : RENDERABLE_IS_OPAQUE;
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose: Sometimes we only want a specific player to be able to input to a panel
  558. //-----------------------------------------------------------------------------
  559. C_BasePlayer *C_VGuiScreen::GetPlayerOwner( void )
  560. {
  561. return ( C_BasePlayer * )( m_hPlayerOwner.Get() );
  562. }
  563. bool C_VGuiScreen::IsInputOnlyToOwner( void )
  564. {
  565. return (m_fScreenFlags & VGUI_SCREEN_ONLY_USABLE_BY_OWNER) != 0;
  566. }
  567. //-----------------------------------------------------------------------------
  568. //
  569. // Enumator class for finding vgui screens close to the local player
  570. //
  571. //-----------------------------------------------------------------------------
  572. class CVGuiScreenEnumerator : public IPartitionEnumerator
  573. {
  574. DECLARE_CLASS_GAMEROOT( CVGuiScreenEnumerator, IPartitionEnumerator );
  575. public:
  576. virtual IterationRetval_t EnumElement( IHandleEntity *pHandleEntity );
  577. int GetScreenCount();
  578. C_VGuiScreen *GetVGuiScreen( int index );
  579. private:
  580. CUtlVector< CHandle< C_VGuiScreen > > m_VguiScreens;
  581. };
  582. IterationRetval_t CVGuiScreenEnumerator::EnumElement( IHandleEntity *pHandleEntity )
  583. {
  584. C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( pHandleEntity->GetRefEHandle() );
  585. if ( pEnt == NULL )
  586. return ITERATION_CONTINUE;
  587. // FIXME.. pretty expensive...
  588. C_VGuiScreen *pScreen = dynamic_cast<C_VGuiScreen*>(pEnt);
  589. if ( pScreen )
  590. {
  591. int i = m_VguiScreens.AddToTail( );
  592. m_VguiScreens[i].Set( pScreen );
  593. }
  594. return ITERATION_CONTINUE;
  595. }
  596. int CVGuiScreenEnumerator::GetScreenCount()
  597. {
  598. return m_VguiScreens.Count();
  599. }
  600. C_VGuiScreen *CVGuiScreenEnumerator::GetVGuiScreen( int index )
  601. {
  602. return m_VguiScreens[index].Get();
  603. }
  604. //-----------------------------------------------------------------------------
  605. //
  606. // Look for vgui screens, returns true if it found one ...
  607. //
  608. //-----------------------------------------------------------------------------
  609. C_BaseEntity *FindNearbyVguiScreen( const Vector &viewPosition, const QAngle &viewAngle, int nTeam )
  610. {
  611. if ( IsGameConsole() )
  612. {
  613. // X360TBD: Turn this on if feature actually used
  614. return NULL;
  615. }
  616. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  617. Assert( pLocalPlayer );
  618. if ( !pLocalPlayer )
  619. return NULL;
  620. // Get the view direction...
  621. Vector lookDir;
  622. AngleVectors( viewAngle, &lookDir );
  623. // Create a ray used for raytracing
  624. Vector lookEnd;
  625. VectorMA( viewPosition, 2.0f * VGUI_SCREEN_MODE_RADIUS, lookDir, lookEnd );
  626. Ray_t lookRay;
  627. lookRay.Init( viewPosition, lookEnd );
  628. // Look for vgui screens that are close to the player
  629. CVGuiScreenEnumerator localScreens;
  630. ::partition->EnumerateElementsInSphere( PARTITION_CLIENT_NON_STATIC_EDICTS, viewPosition, VGUI_SCREEN_MODE_RADIUS, false, &localScreens );
  631. Vector vecOut, vecViewDelta;
  632. float flBestDist = 2.0f;
  633. C_VGuiScreen *pBestScreen = NULL;
  634. for (int i = localScreens.GetScreenCount(); --i >= 0; )
  635. {
  636. C_VGuiScreen *pScreen = localScreens.GetVGuiScreen(i);
  637. if ( pScreen->IsAttachedToViewModel() )
  638. continue;
  639. // Don't bother with screens I'm behind...
  640. // Hax - don't cancel backfacing with viewmodel attached screens.
  641. // we can get prediction bugs that make us backfacing for one frame and
  642. // it resets the mouse position if we lose focus.
  643. if ( pScreen->IsBackfacing(viewPosition) )
  644. continue;
  645. // Don't bother with screens that are turned off
  646. if (!pScreen->IsActive())
  647. continue;
  648. // FIXME: Should this maybe go into a derived class of some sort?
  649. // Don't bother with screens on the wrong team
  650. if (!pScreen->IsVisibleToTeam(nTeam))
  651. continue;
  652. if ( !pScreen->AcceptsInput() )
  653. continue;
  654. if ( pScreen->IsInputOnlyToOwner() && pScreen->GetPlayerOwner() != pLocalPlayer )
  655. continue;
  656. // Test perpendicular distance from the screen...
  657. pScreen->GetVectors( NULL, NULL, &vecOut );
  658. VectorSubtract( viewPosition, pScreen->GetAbsOrigin(), vecViewDelta );
  659. float flPerpDist = DotProduct(vecViewDelta, vecOut);
  660. if ( (flPerpDist < 0) || (flPerpDist > VGUI_SCREEN_MODE_RADIUS) )
  661. continue;
  662. // Perform a raycast to see where in barycentric coordinates the ray hits
  663. // the viewscreen; if it doesn't hit it, you're not in the mode
  664. float u, v, t;
  665. if (!pScreen->IntersectWithRay( lookRay, &u, &v, &t ))
  666. continue;
  667. // Barycentric test
  668. if ((u < 0) || (v < 0) || (u > 1) || (v > 1))
  669. continue;
  670. if ( t < flBestDist )
  671. {
  672. flBestDist = t;
  673. pBestScreen = pScreen;
  674. }
  675. }
  676. return pBestScreen;
  677. }
  678. void ActivateVguiScreen( C_BaseEntity *pVguiScreenEnt )
  679. {
  680. if (pVguiScreenEnt)
  681. {
  682. Assert( dynamic_cast<C_VGuiScreen*>(pVguiScreenEnt) );
  683. C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pVguiScreenEnt);
  684. pVguiScreen->GainFocus( );
  685. }
  686. }
  687. void SetVGuiScreenButtonState( C_BaseEntity *pVguiScreenEnt, int nButtonState )
  688. {
  689. if (pVguiScreenEnt)
  690. {
  691. Assert( dynamic_cast<C_VGuiScreen*>(pVguiScreenEnt) );
  692. C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pVguiScreenEnt);
  693. pVguiScreen->SetButtonState( nButtonState );
  694. }
  695. }
  696. void DeactivateVguiScreen( C_BaseEntity *pVguiScreenEnt )
  697. {
  698. if (pVguiScreenEnt)
  699. {
  700. Assert( dynamic_cast<C_VGuiScreen*>(pVguiScreenEnt) );
  701. C_VGuiScreen *pVguiScreen = static_cast<C_VGuiScreen*>(pVguiScreenEnt);
  702. pVguiScreen->LoseFocus( );
  703. }
  704. }
  705. CVGuiScreenPanel::CVGuiScreenPanel( vgui::Panel *parent, const char *panelName )
  706. : BaseClass( parent, panelName )
  707. {
  708. m_hEntity = NULL;
  709. }
  710. CVGuiScreenPanel::CVGuiScreenPanel( vgui::Panel *parent, const char *panelName, vgui::HScheme hScheme )
  711. : BaseClass( parent, panelName, hScheme )
  712. {
  713. m_hEntity = NULL;
  714. }
  715. bool CVGuiScreenPanel::Init( KeyValues* pKeyValues, VGuiScreenInitData_t* pInitData )
  716. {
  717. const char *pResFile = pKeyValues->GetString( "resfile" );
  718. if (pResFile[0] != 0)
  719. {
  720. KeyValues *pCachedKeyValues = CacheKeyValuesForFile( pResFile );
  721. LoadControlSettings( pResFile, NULL, pCachedKeyValues );
  722. }
  723. // Dimensions in pixels
  724. int nWidth, nHeight;
  725. nWidth = pKeyValues->GetInt( "pixelswide", 240 );
  726. nHeight = pKeyValues->GetInt( "pixelshigh", 160 );
  727. if ((nWidth <= 0) || (nHeight <= 0))
  728. return false;
  729. // If init data isn't specified, then we're just precaching.
  730. if ( pInitData )
  731. {
  732. m_hEntity.Set( pInitData->m_pEntity );
  733. C_VGuiScreen *screen = dynamic_cast< C_VGuiScreen * >( pInitData->m_pEntity );
  734. if ( screen )
  735. {
  736. bool acceptsInput = pKeyValues->GetBool( "acceptsinput", true );
  737. screen->SetAcceptsInput( acceptsInput );
  738. }
  739. }
  740. SetBounds( 0, 0, nWidth, nHeight );
  741. return true;
  742. }
  743. vgui::Panel *CVGuiScreenPanel::CreateControlByName(const char *controlName)
  744. {
  745. // Check the panel metaclass manager to make these controls...
  746. if ( StringHasPrefixCaseSensitive( controlName, "MaterialImage" ) )
  747. {
  748. return new CBitmapPanel(NULL, "BitmapPanel");
  749. }
  750. if ( StringHasPrefixCaseSensitive( controlName, "MaterialButton" ) )
  751. {
  752. return new CBitmapButton(NULL, "BitmapButton", "");
  753. }
  754. // Didn't find it? Just use the default stuff
  755. return BaseClass::CreateControlByName( controlName );
  756. }
  757. //-----------------------------------------------------------------------------
  758. // Purpose: Called when the user presses a button
  759. //-----------------------------------------------------------------------------
  760. void CVGuiScreenPanel::OnCommand( const char *command)
  761. {
  762. if ( Q_stricmp( command, "vguicancel" ) )
  763. {
  764. engine->ClientCmd( const_cast<char *>( command ) );
  765. }
  766. BaseClass::OnCommand(command);
  767. }
  768. DECLARE_VGUI_SCREEN_FACTORY( CVGuiScreenPanel, "vgui_screen_panel" );