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.

610 lines
20 KiB

  1. //====== Copyright 1996-2008, Valve Corporation, All rights reserved. =======
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "basemodel_panel.h"
  8. #include "activitylist.h"
  9. #include "animation.h"
  10. #include "vgui/IInput.h"
  11. #include "matsys_controls/manipulator.h"
  12. // NOTE: This has to be the last file included!
  13. #include "tier0/memdbgon.h"
  14. using namespace vgui;
  15. DECLARE_BUILD_FACTORY( CBaseModelPanel );
  16. //-----------------------------------------------------------------------------
  17. // Purpose:
  18. //-----------------------------------------------------------------------------
  19. CBaseModelPanel::CBaseModelPanel( vgui::Panel *pParent, const char *pName ): BaseClass( pParent, pName )
  20. {
  21. m_bForcePos = false;
  22. m_bMousePressed = false;
  23. m_bAllowRotation = false;
  24. vgui::SETUP_PANEL( this );
  25. }
  26. //-----------------------------------------------------------------------------
  27. // Purpose:
  28. //-----------------------------------------------------------------------------
  29. CBaseModelPanel::~CBaseModelPanel()
  30. {
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose: Load in the model portion of the panel's resource file.
  34. //-----------------------------------------------------------------------------
  35. void CBaseModelPanel::ApplySettings( KeyValues *inResourceData )
  36. {
  37. BaseClass::ApplySettings( inResourceData );
  38. // Grab and set the camera FOV.
  39. float flFOV = GetCameraFOV();
  40. m_BMPResData.m_flFOV = inResourceData->GetInt( "fov", flFOV );
  41. SetCameraFOV( m_BMPResData.m_flFOV );
  42. // Do we allow rotation on these panels.
  43. m_bAllowRotation = ( inResourceData->GetInt( "allow_rot", 0 ) == 1 );
  44. // Parse our resource file and apply all necessary updates to the MDL.
  45. for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() )
  46. {
  47. if ( !Q_stricmp( pData->GetName(), "model" ) )
  48. {
  49. ParseModelResInfo( pData );
  50. }
  51. }
  52. SetMouseInputEnabled( m_bAllowRotation );
  53. }
  54. //-----------------------------------------------------------------------------
  55. // Purpose:
  56. //-----------------------------------------------------------------------------
  57. void CBaseModelPanel::ParseModelResInfo( KeyValues *inResourceData )
  58. {
  59. m_bForcePos = ( inResourceData->GetInt( "force_pos", 0 ) == 1 );
  60. m_BMPResData.m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
  61. m_BMPResData.m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" );
  62. m_BMPResData.m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" );
  63. m_BMPResData.m_angModelPoseRot.Init( inResourceData->GetFloat( "angles_x", 0.0f ), inResourceData->GetFloat( "angles_y", 0.0f ), inResourceData->GetFloat( "angles_z", 0.0f ) );
  64. m_BMPResData.m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) );
  65. m_BMPResData.m_vecFramedOriginOffset.Init( inResourceData->GetFloat( "frame_origin_x", 110.0 ), inResourceData->GetFloat( "frame_origin_y", 5.0 ), inResourceData->GetFloat( "frame_origin_z", 5.0 ) );
  66. m_BMPResData.m_vecViewportOffset.Init();
  67. m_BMPResData.m_nSkin = inResourceData->GetInt( "skin", -1 );
  68. m_BMPResData.m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 );
  69. m_BMPResData.m_pszModelCameraAttachment = ReadAndAllocStringValue( inResourceData, "model_camera_attachment" );
  70. m_angPlayer = m_BMPResData.m_angModelPoseRot;
  71. m_vecPlayerPos = m_BMPResData.m_vecOriginOffset;
  72. for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
  73. {
  74. if ( !Q_stricmp( pData->GetName(), "animation" ) )
  75. {
  76. ParseModelAnimInfo( pData );
  77. }
  78. else if ( !Q_stricmp( pData->GetName(), "attached_model" ) )
  79. {
  80. ParseModelAttachInfo( pData );
  81. }
  82. }
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. void CBaseModelPanel::ParseModelAnimInfo( KeyValues *inResourceData )
  88. {
  89. if ( !inResourceData )
  90. return;
  91. int iAnim = m_BMPResData.m_aAnimations.AddToTail();
  92. if ( iAnim == m_BMPResData.m_aAnimations.InvalidIndex() )
  93. return;
  94. m_BMPResData.m_aAnimations[iAnim].m_pszName = ReadAndAllocStringValue( inResourceData, "name" );
  95. m_BMPResData.m_aAnimations[iAnim].m_pszSequence = ReadAndAllocStringValue( inResourceData, "sequence" );
  96. m_BMPResData.m_aAnimations[iAnim].m_pszActivity = ReadAndAllocStringValue( inResourceData, "activity" );
  97. m_BMPResData.m_aAnimations[iAnim].m_bDefault = ( inResourceData->GetInt( "default", 0 ) == 1 );
  98. for ( KeyValues *pAnimData = inResourceData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() )
  99. {
  100. if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) )
  101. {
  102. m_BMPResData.m_aAnimations[iAnim].m_pPoseParameters = pAnimData->MakeCopy();
  103. }
  104. }
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. //-----------------------------------------------------------------------------
  109. void CBaseModelPanel::ParseModelAttachInfo( KeyValues *inResourceData )
  110. {
  111. if ( !inResourceData )
  112. return;
  113. int iAttach = m_BMPResData.m_aAttachModels.AddToTail();
  114. if ( iAttach == m_BMPResData.m_aAttachModels.InvalidIndex() )
  115. return;
  116. m_BMPResData.m_aAttachModels[iAttach].m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
  117. m_BMPResData.m_aAttachModels[iAttach].m_nSkin = inResourceData->GetInt( "skin", -1 );
  118. }
  119. //-----------------------------------------------------------------------------
  120. // Purpose:
  121. //-----------------------------------------------------------------------------
  122. void CBaseModelPanel::SetupModelDefaults( void )
  123. {
  124. SetupModelAnimDefaults();
  125. // if the res file wants the model to control the camera position, apply that setting
  126. // now that the model is loaded and attachments are available.
  127. if ( m_BMPResData.m_pszModelCameraAttachment != NULL && m_BMPResData.m_pszModelCameraAttachment[0] )
  128. {
  129. SetCameraAttachment( m_BMPResData.m_pszModelCameraAttachment );
  130. }
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose:
  134. //-----------------------------------------------------------------------------
  135. void CBaseModelPanel::SetupModelAnimDefaults( void )
  136. {
  137. // Verify that we have animations for this model.
  138. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  139. if ( nAnimCount == 0 )
  140. return;
  141. // Find the default animation if one exists.
  142. int iIndex = FindDefaultAnim();
  143. if ( iIndex == -1 )
  144. return;
  145. SetModelAnim( iIndex, true );
  146. }
  147. //-----------------------------------------------------------------------------
  148. // Purpose:
  149. //-----------------------------------------------------------------------------
  150. int CBaseModelPanel::FindDefaultAnim( void )
  151. {
  152. int iIndex = -1;
  153. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  154. for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim )
  155. {
  156. if ( m_BMPResData.m_aAnimations[iAnim].m_bDefault )
  157. return iAnim;
  158. }
  159. return iIndex;
  160. }
  161. //-----------------------------------------------------------------------------
  162. // Purpose:
  163. //-----------------------------------------------------------------------------
  164. int CBaseModelPanel::FindAnimByName( const char *pszName )
  165. {
  166. int iIndex = -1;
  167. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  168. for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim )
  169. {
  170. if ( !Q_stricmp( m_BMPResData.m_aAnimations[iAnim].m_pszName, pszName ) )
  171. return iAnim;
  172. }
  173. return iIndex;
  174. }
  175. //-----------------------------------------------------------------------------
  176. // Purpose:
  177. //-----------------------------------------------------------------------------
  178. int CBaseModelPanel::FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity )
  179. {
  180. if ( !pStudioHdr || !pszActivity )
  181. return -1;
  182. for ( int iSeq = 0; iSeq < pStudioHdr->GetNumSeq(); ++iSeq )
  183. {
  184. mstudioseqdesc_t &seqDesc = pStudioHdr->pSeqdesc( iSeq );
  185. if ( !stricmp( seqDesc.pszActivityName(), pszActivity ) )
  186. {
  187. return iSeq;
  188. }
  189. }
  190. return -1;
  191. }
  192. //-----------------------------------------------------------------------------
  193. // Purpose:
  194. //-----------------------------------------------------------------------------
  195. void CBaseModelPanel::SetModelAnim( int iAnim, bool bUseSequencePlaybackFPS )
  196. {
  197. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  198. if ( nAnimCount == 0 || !m_BMPResData.m_aAnimations.IsValidIndex( iAnim ) )
  199. return;
  200. // Do we have an activity or a sequence?
  201. if ( m_BMPResData.m_aAnimations[iAnim].m_pszActivity && m_BMPResData.m_aAnimations[iAnim].m_pszActivity[0] )
  202. {
  203. SetModelAnim( m_BMPResData.m_aAnimations[iAnim].m_pszActivity, bUseSequencePlaybackFPS );
  204. }
  205. else if ( m_BMPResData.m_aAnimations[iAnim].m_pszSequence && m_BMPResData.m_aAnimations[iAnim].m_pszSequence[0] )
  206. {
  207. SetModelAnim( m_BMPResData.m_aAnimations[iAnim].m_pszSequence, bUseSequencePlaybackFPS );
  208. }
  209. }
  210. void CBaseModelPanel::SetMdlSkinIndex( int nNewSkinIndex )
  211. {
  212. MDLCACHE_CRITICAL_SECTION();
  213. CMDL *pMDL = &m_RootMDL.m_MDL;
  214. if ( !pMDL )
  215. return;
  216. pMDL->m_nSkin = nNewSkinIndex;
  217. }
  218. //-----------------------------------------------------------------------------
  219. // Purpose:
  220. //-----------------------------------------------------------------------------
  221. void CBaseModelPanel::SetModelAnim( const char *pszName, bool bUseSequencePlaybackFPS )
  222. {
  223. MDLCACHE_CRITICAL_SECTION();
  224. if ( !pszName )
  225. return;
  226. // Get the studio header of the root model.
  227. studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr();
  228. if ( !pStudioHdr )
  229. return;
  230. CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );
  231. int iSequence = ACT_INVALID;
  232. iSequence = FindSequenceFromActivity( &studioHdr, pszName );
  233. if ( iSequence == ACT_INVALID )
  234. {
  235. iSequence = LookupSequence( &studioHdr, pszName );
  236. }
  237. if ( iSequence != ACT_INVALID )
  238. {
  239. SetSequence( iSequence, bUseSequencePlaybackFPS );
  240. }
  241. }
  242. void CBaseModelPanel::ClearModelAnimFollowLoop()
  243. {
  244. ClearSequenceFollowLoop();
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose:
  248. //-----------------------------------------------------------------------------
  249. void CBaseModelPanel::AddModelAnimFollowLoop( const char *pszName, bool bUseSequencePlaybackFPS )
  250. {
  251. MDLCACHE_CRITICAL_SECTION();
  252. if ( !pszName )
  253. return;
  254. // Get the studio header of the root model.
  255. studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr();
  256. if ( !pStudioHdr )
  257. return;
  258. CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );
  259. int iSequence = ACT_INVALID;
  260. iSequence = FindSequenceFromActivity( &studioHdr, pszName );
  261. if ( iSequence == ACT_INVALID )
  262. {
  263. iSequence = LookupSequence( &studioHdr, pszName );
  264. }
  265. if ( iSequence != ACT_INVALID )
  266. {
  267. AddSequenceFollowLoop( iSequence, bUseSequencePlaybackFPS );
  268. }
  269. }
  270. //-----------------------------------------------------------------------------
  271. // Purpose:
  272. //-----------------------------------------------------------------------------
  273. void CBaseModelPanel::SetMDL( MDLHandle_t handle, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData )
  274. {
  275. BaseClass::SetMDL( handle, pCustomMaterialOwner, pProxyData );
  276. SetupModelDefaults();
  277. // Need to invalidate the layout so the panel will adjust is LookAt for the new model.
  278. InvalidateLayout();
  279. }
  280. //-----------------------------------------------------------------------------
  281. // Purpose:
  282. //-----------------------------------------------------------------------------
  283. void CBaseModelPanel::SetMDL( const char *pMDLName, CCustomMaterialOwner* pCustomMaterialOwner, void *pProxyData )
  284. {
  285. SetSequence( 0, true );
  286. BaseClass::SetMDL( pMDLName, pCustomMaterialOwner, pProxyData );
  287. // Need to invalidate the layout so the panel will adjust is LookAt for the new model.
  288. // InvalidateLayout();
  289. }
  290. //-----------------------------------------------------------------------------
  291. // Purpose:
  292. //-----------------------------------------------------------------------------
  293. void CBaseModelPanel::PerformLayout()
  294. {
  295. BaseClass::PerformLayout();
  296. if ( m_bForcePos )
  297. {
  298. ResetCameraPivot();
  299. SetCameraOffset( Vector( 0.0f, 0.0f, 0.0f ) );
  300. SetCameraPositionAndAngles( vec3_origin, vec3_angle );
  301. SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
  302. }
  303. // Center and fill the frame with the model?
  304. if ( m_bStartFramed )
  305. {
  306. Vector vecBoundsMin, vecBoundsMax;
  307. if ( GetBoundingBox( vecBoundsMin, vecBoundsMax ) )
  308. {
  309. LookAtBounds( vecBoundsMin, vecBoundsMax );
  310. }
  311. }
  312. }
  313. //-----------------------------------------------------------------------------
  314. //-----------------------------------------------------------------------------
  315. void CBaseModelPanel::OnKeyCodePressed ( vgui::KeyCode code )
  316. {
  317. return;
  318. }
  319. //-----------------------------------------------------------------------------
  320. //-----------------------------------------------------------------------------
  321. void CBaseModelPanel::OnKeyCodeReleased( vgui::KeyCode code )
  322. {
  323. return;
  324. }
  325. //-----------------------------------------------------------------------------
  326. //-----------------------------------------------------------------------------
  327. void CBaseModelPanel::OnMousePressed ( vgui::MouseCode code )
  328. {
  329. if ( !m_bAllowRotation )
  330. return;
  331. RequestFocus();
  332. EnableMouseCapture( true, code );
  333. // Warp the mouse to the center of the screen
  334. int width, height;
  335. GetSize( width, height );
  336. int x = width / 2;
  337. int y = height / 2;
  338. int xpos = x;
  339. int ypos = y;
  340. LocalToScreen( xpos, ypos );
  341. input()->SetCursorPos( xpos, ypos );
  342. m_nManipStartX = xpos;
  343. m_nManipStartY = ypos;
  344. m_bMousePressed = true;
  345. }
  346. //-----------------------------------------------------------------------------
  347. //-----------------------------------------------------------------------------
  348. void CBaseModelPanel::OnMouseReleased( vgui::MouseCode code )
  349. {
  350. if ( !m_bAllowRotation )
  351. return;
  352. EnableMouseCapture( false );
  353. m_bMousePressed = false;
  354. }
  355. //-----------------------------------------------------------------------------
  356. //-----------------------------------------------------------------------------
  357. void CBaseModelPanel::OnCursorMoved( int x, int y )
  358. {
  359. if ( !m_bAllowRotation )
  360. return;
  361. if ( m_bMousePressed )
  362. {
  363. WarpMouse( x, y );
  364. int xpos, ypos;
  365. input()->GetCursorPos( xpos, ypos );
  366. // Only want the x delta.
  367. float flDelta = xpos - m_nManipStartX;
  368. // Apply the delta and rotate the player.
  369. m_angPlayer.y += flDelta;
  370. if ( m_angPlayer.y > 360.0f )
  371. {
  372. m_angPlayer.y = m_angPlayer.y - 360.0f;
  373. }
  374. else if ( m_angPlayer.y < -360.0f )
  375. {
  376. m_angPlayer.y = m_angPlayer.y + 360.0f;
  377. }
  378. SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
  379. }
  380. }
  381. //-----------------------------------------------------------------------------
  382. //-----------------------------------------------------------------------------
  383. void CBaseModelPanel::OnMouseWheeled( int delta )
  384. {
  385. return;
  386. }
  387. //-----------------------------------------------------------------------------
  388. //-----------------------------------------------------------------------------
  389. void CBaseModelPanel::RotateYaw( float flDelta )
  390. {
  391. m_angPlayer.y += flDelta;
  392. if ( m_angPlayer.y > 360.0f )
  393. {
  394. m_angPlayer.y = m_angPlayer.y - 360.0f;
  395. }
  396. else if ( m_angPlayer.y < -360.0f )
  397. {
  398. m_angPlayer.y = m_angPlayer.y + 360.0f;
  399. }
  400. SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Purpose: Set the camera to a distance that allows the object to fill the model panel.
  404. //-----------------------------------------------------------------------------
  405. void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax )
  406. {
  407. // Get the model space render bounds.
  408. Vector vecMin = vecBoundsMin;
  409. Vector vecMax = vecBoundsMax;
  410. Vector vecCenter = ( vecMax + vecMin ) * 0.5f;
  411. vecMin -= vecCenter;
  412. vecMax -= vecCenter;
  413. // Get the bounds points and transform them by the desired model panel rotation.
  414. Vector aBoundsPoints[8];
  415. aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z );
  416. aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z );
  417. aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z );
  418. aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z );
  419. aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z );
  420. aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z );
  421. aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z );
  422. aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z );
  423. // Build the rotation matrix.
  424. matrix3x4_t matRotation;
  425. AngleMatrix( m_BMPResData.m_angModelPoseRot, matRotation );
  426. Vector aXFormPoints[8];
  427. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  428. {
  429. VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] );
  430. }
  431. Vector vecXFormCenter;
  432. VectorTransform( vecCenter, matRotation, vecXFormCenter );
  433. int w, h;
  434. GetSize( w, h );
  435. float flW = (float)w;
  436. float flH = (float)h;
  437. float flFOVx = DEG2RAD( m_BMPResData.m_flFOV * 0.5f );
  438. float flFOVy = CalcFovY( ( m_BMPResData.m_flFOV * 0.5f ), flW/flH );
  439. flFOVy = DEG2RAD( flFOVy );
  440. float flTanFOVx = tan( flFOVx );
  441. float flTanFOVy = tan( flFOVy );
  442. // Find the max value of x, y, or z
  443. Vector2D dist[8];
  444. float flDist = 0.0f;
  445. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  446. {
  447. float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx ) - aXFormPoints[iPoint].x;
  448. float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy ) - aXFormPoints[iPoint].x;
  449. dist[iPoint].x = flDistY;
  450. dist[iPoint].y = flDistZ;
  451. float flTestDist = MAX( flDistZ, flDistY );
  452. flDist = MAX( flDist, flTestDist );
  453. }
  454. // Screen space points.
  455. Vector2D aScreenPoints[8];
  456. Vector aCameraPoints[8];
  457. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  458. {
  459. aCameraPoints[iPoint] = aXFormPoints[iPoint];
  460. aCameraPoints[iPoint].x += flDist;
  461. aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x );
  462. aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x );
  463. aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW;
  464. aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH;
  465. }
  466. // Find the min/max and center of the 2D bounding box of the object.
  467. Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f );
  468. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  469. {
  470. vecScreenMin.x = MIN( vecScreenMin.x, aScreenPoints[iPoint].x );
  471. vecScreenMin.y = MIN( vecScreenMin.y, aScreenPoints[iPoint].y );
  472. vecScreenMax.x = MAX( vecScreenMax.x, aScreenPoints[iPoint].x );
  473. vecScreenMax.y = MAX( vecScreenMax.y, aScreenPoints[iPoint].y );
  474. }
  475. // Offset the model to the be the correct distance away from the camera.
  476. Vector vecModelPos;
  477. vecModelPos.x = flDist - vecXFormCenter.x;
  478. vecModelPos.y = -vecXFormCenter.y;
  479. vecModelPos.z = -vecXFormCenter.z;
  480. SetModelAnglesAndPosition( m_BMPResData.m_angModelPoseRot, vecModelPos );
  481. // Back project to figure out the camera offset to center the model.
  482. Vector2D vecPanelCenter( ( flW * 0.5f ), ( flH * 0.5f ) );
  483. Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f;
  484. Vector2D vecPanelCenterCamera, vecScreenCenterCamera;
  485. vecPanelCenterCamera.x = ( ( vecPanelCenter.x / flW ) * 2.0f ) - 0.5f;
  486. vecPanelCenterCamera.y = ( ( vecPanelCenter.y / flH ) * 2.0f ) - 0.5f;
  487. vecPanelCenterCamera.x *= ( flTanFOVx * flDist );
  488. vecPanelCenterCamera.y *= ( flTanFOVy * flDist );
  489. vecScreenCenterCamera.x = ( ( vecScreenCenter.x / flW ) * 2.0f ) - 0.5f;
  490. vecScreenCenterCamera.y = ( ( vecScreenCenter.y / flH ) * 2.0f ) - 0.5f;
  491. vecScreenCenterCamera.x *= ( flTanFOVx * flDist );
  492. vecScreenCenterCamera.y *= ( flTanFOVy * flDist );
  493. Vector2D vecCameraOffset( 0.0f, 0.0f );
  494. vecCameraOffset.x = vecPanelCenterCamera.x - vecScreenCenterCamera.x;
  495. vecCameraOffset.y = vecPanelCenterCamera.y - vecScreenCenterCamera.y;
  496. // Clear the camera pivot and set position matrix.
  497. ResetCameraPivot();
  498. SetCameraOffset( Vector( 0.0f, -vecCameraOffset.x, -vecCameraOffset.y ) );
  499. UpdateCameraTransform();
  500. }