Team Fortress 2 Source Code as on 22/4/2020
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.

885 lines
28 KiB

  1. //========= Copyright 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. #include "bone_setup.h"
  13. using namespace vgui;
  14. extern float GetAutoPlayTime( void );
  15. DECLARE_BUILD_FACTORY( CBaseModelPanel );
  16. //-----------------------------------------------------------------------------
  17. // Purpose:
  18. //-----------------------------------------------------------------------------
  19. CBaseModelPanel::CBaseModelPanel( vgui::Panel *pParent, const char *pName )
  20. : BaseClass( pParent, pName )
  21. , m_nActiveSequence( ACT_INVALID )
  22. , m_flActiveSequenceDuration( 0.f )
  23. {
  24. m_bForcePos = false;
  25. m_bMousePressed = false;
  26. m_bAllowRotation = false;
  27. m_bAllowPitch = false;
  28. m_bAllowFullManipulation = false;
  29. m_bApplyManipulators = false;
  30. m_bForcedCameraPosition = false;
  31. }
  32. //-----------------------------------------------------------------------------
  33. // Purpose:
  34. //-----------------------------------------------------------------------------
  35. CBaseModelPanel::~CBaseModelPanel()
  36. {
  37. }
  38. //-----------------------------------------------------------------------------
  39. // Purpose: Load in the model portion of the panel's resource file.
  40. //-----------------------------------------------------------------------------
  41. void CBaseModelPanel::ApplySettings( KeyValues *inResourceData )
  42. {
  43. BaseClass::ApplySettings( inResourceData );
  44. // Set whether we render to texture
  45. m_bRenderToTexture = inResourceData->GetBool( "render_texture", true );
  46. m_bUseParticle = inResourceData->GetBool( "use_particle", false );
  47. // Grab and set the camera FOV.
  48. float flFOV = GetCameraFOV();
  49. m_BMPResData.m_flFOV = inResourceData->GetInt( "fov", flFOV );
  50. SetCameraFOV( m_BMPResData.m_flFOV );
  51. // Do we allow rotation on these panels.
  52. m_bAllowRotation = inResourceData->GetBool( "allow_rot", false );
  53. m_bAllowPitch = inResourceData->GetBool( "allow_pitch", false );
  54. // Do we allow full manipulation on these panels.
  55. m_bAllowFullManipulation = inResourceData->GetBool( "allow_manip", false );
  56. // Parse our resource file and apply all necessary updates to the MDL.
  57. for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() )
  58. {
  59. if ( !Q_stricmp( pData->GetName(), "model" ) )
  60. {
  61. ParseModelResInfo( pData );
  62. }
  63. }
  64. SetMouseInputEnabled( m_bAllowFullManipulation || m_bAllowRotation || m_bAllowPitch );
  65. }
  66. //-----------------------------------------------------------------------------
  67. // Purpose:
  68. //-----------------------------------------------------------------------------
  69. void CBaseModelPanel::ParseModelResInfo( KeyValues *inResourceData )
  70. {
  71. m_bForcePos = ( inResourceData->GetInt( "force_pos", 0 ) == 1 );
  72. m_BMPResData.m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
  73. m_BMPResData.m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" );
  74. m_BMPResData.m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" );
  75. m_BMPResData.m_angModelPoseRot.Init( inResourceData->GetFloat( "angles_x", 0.0f ), inResourceData->GetFloat( "angles_y", 0.0f ), inResourceData->GetFloat( "angles_z", 0.0f ) );
  76. m_BMPResData.m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) );
  77. 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 ) );
  78. m_BMPResData.m_vecViewportOffset.Init();
  79. m_BMPResData.m_nSkin = inResourceData->GetInt( "skin", -1 );
  80. m_BMPResData.m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 );
  81. m_angPlayer = m_BMPResData.m_angModelPoseRot;
  82. m_vecPlayerPos = m_BMPResData.m_vecOriginOffset;
  83. for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
  84. {
  85. if ( !Q_stricmp( pData->GetName(), "animation" ) )
  86. {
  87. ParseModelAnimInfo( pData );
  88. }
  89. else if ( !Q_stricmp( pData->GetName(), "attached_model" ) )
  90. {
  91. ParseModelAttachInfo( pData );
  92. }
  93. }
  94. SetupModelDefaults();
  95. }
  96. //-----------------------------------------------------------------------------
  97. // Purpose:
  98. //-----------------------------------------------------------------------------
  99. void CBaseModelPanel::ParseModelAnimInfo( KeyValues *inResourceData )
  100. {
  101. if ( !inResourceData )
  102. return;
  103. int iAnim = m_BMPResData.m_aAnimations.AddToTail();
  104. if ( iAnim == m_BMPResData.m_aAnimations.InvalidIndex() )
  105. return;
  106. m_BMPResData.m_aAnimations[iAnim].m_pszName = ReadAndAllocStringValue( inResourceData, "name" );
  107. m_BMPResData.m_aAnimations[iAnim].m_pszSequence = ReadAndAllocStringValue( inResourceData, "sequence" );
  108. m_BMPResData.m_aAnimations[iAnim].m_pszActivity = ReadAndAllocStringValue( inResourceData, "activity" );
  109. m_BMPResData.m_aAnimations[iAnim].m_bDefault = inResourceData->GetBool( "default" );
  110. for ( KeyValues *pAnimData = inResourceData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() )
  111. {
  112. if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) )
  113. {
  114. m_BMPResData.m_aAnimations[iAnim].m_pPoseParameters = pAnimData->MakeCopy();
  115. }
  116. }
  117. }
  118. //-----------------------------------------------------------------------------
  119. // Purpose:
  120. //-----------------------------------------------------------------------------
  121. void CBaseModelPanel::ParseModelAttachInfo( KeyValues *inResourceData )
  122. {
  123. if ( !inResourceData )
  124. return;
  125. int iAttach = m_BMPResData.m_aAttachModels.AddToTail();
  126. if ( iAttach == m_BMPResData.m_aAttachModels.InvalidIndex() )
  127. return;
  128. m_BMPResData.m_aAttachModels[iAttach].m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
  129. m_BMPResData.m_aAttachModels[iAttach].m_nSkin = inResourceData->GetInt( "skin", -1 );
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose:
  133. //-----------------------------------------------------------------------------
  134. void CBaseModelPanel::SetupModelDefaults( void )
  135. {
  136. SetupModelAnimDefaults();
  137. }
  138. //-----------------------------------------------------------------------------
  139. // Purpose:
  140. //-----------------------------------------------------------------------------
  141. void CBaseModelPanel::SetupModelAnimDefaults( void )
  142. {
  143. // Set the move_x parameter so the run activity works
  144. SetPoseParameterByName( "move_x", 1.0f );
  145. // Verify that we have animations for this model.
  146. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  147. if ( nAnimCount == 0 )
  148. return;
  149. // Find the default animation if one exists.
  150. int iIndex = FindDefaultAnim();
  151. if ( iIndex == -1 )
  152. return;
  153. SetModelAnim( iIndex );
  154. }
  155. //-----------------------------------------------------------------------------
  156. // Purpose:
  157. //-----------------------------------------------------------------------------
  158. int CBaseModelPanel::FindDefaultAnim( void )
  159. {
  160. int iIndex = -1;
  161. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  162. for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim )
  163. {
  164. if ( m_BMPResData.m_aAnimations[iAnim].m_bDefault )
  165. return iAnim;
  166. }
  167. return iIndex;
  168. }
  169. //-----------------------------------------------------------------------------
  170. // Purpose:
  171. //-----------------------------------------------------------------------------
  172. int CBaseModelPanel::FindAnimByName( const char *pszName )
  173. {
  174. int iIndex = -1;
  175. if ( !pszName )
  176. return iIndex;
  177. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  178. for ( int iAnim = 0; iAnim < nAnimCount; ++iAnim )
  179. {
  180. if ( !Q_stricmp( m_BMPResData.m_aAnimations[iAnim].m_pszName, pszName ) )
  181. return iAnim;
  182. }
  183. return iIndex;
  184. }
  185. //-----------------------------------------------------------------------------
  186. // Purpose:
  187. //-----------------------------------------------------------------------------
  188. int CBaseModelPanel::FindSequenceFromActivity( CStudioHdr *pStudioHdr, const char *pszActivity )
  189. {
  190. if ( !pStudioHdr )
  191. return -1;
  192. for ( int iSeq = 0; iSeq < pStudioHdr->GetNumSeq(); ++iSeq )
  193. {
  194. mstudioseqdesc_t &seqDesc = pStudioHdr->pSeqdesc( iSeq );
  195. if ( !V_stricmp( seqDesc.pszActivityName(), pszActivity ) )
  196. {
  197. return iSeq;
  198. }
  199. }
  200. return -1;
  201. }
  202. //-----------------------------------------------------------------------------
  203. // Purpose:
  204. //-----------------------------------------------------------------------------
  205. void CBaseModelPanel::SetModelAnim( int iAnim )
  206. {
  207. int nAnimCount = m_BMPResData.m_aAnimations.Count();
  208. if ( nAnimCount == 0 || !m_BMPResData.m_aAnimations.IsValidIndex( iAnim ) )
  209. return;
  210. MDLCACHE_CRITICAL_SECTION();
  211. // Get the studio header of the root model.
  212. studiohdr_t *pStudioHdr = m_RootMDL.m_MDL.GetStudioHdr();
  213. if ( !pStudioHdr )
  214. return;
  215. CStudioHdr studioHdr( pStudioHdr, g_pMDLCache );
  216. // Do we have an activity or a sequence?
  217. int iSequence = ACT_INVALID;
  218. if ( m_BMPResData.m_aAnimations[iAnim].m_pszActivity && m_BMPResData.m_aAnimations[iAnim].m_pszActivity[0] )
  219. {
  220. iSequence = FindSequenceFromActivity( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszActivity );
  221. }
  222. else if ( m_BMPResData.m_aAnimations[iAnim].m_pszSequence && m_BMPResData.m_aAnimations[iAnim].m_pszSequence[0] )
  223. {
  224. iSequence = LookupSequence( &studioHdr, m_BMPResData.m_aAnimations[iAnim].m_pszSequence );
  225. }
  226. if ( iSequence != ACT_INVALID )
  227. {
  228. SetSequence( iSequence, true );
  229. }
  230. }
  231. //-----------------------------------------------------------------------------
  232. // Purpose:
  233. //-----------------------------------------------------------------------------
  234. void CBaseModelPanel::SetMDL( MDLHandle_t handle, void *pProxyData )
  235. {
  236. MDLCACHE_CRITICAL_SECTION();
  237. studiohdr_t *pHdr = g_pMDLCache->GetStudioHdr( handle );
  238. if ( pHdr )
  239. {
  240. // SetMDL will cause the base CMdl code to set our localtoglobal indices if they aren't set.
  241. // We set them up here so that they're left alone by that code.
  242. CStudioHdr studioHdr( pHdr, g_pMDLCache );
  243. if (studioHdr.numflexcontrollers() > 0 && studioHdr.pFlexcontroller( LocalFlexController_t(0) )->localToGlobal == -1)
  244. {
  245. for (LocalFlexController_t i = LocalFlexController_t(0); i < studioHdr.numflexcontrollers(); i++)
  246. {
  247. int j = C_BaseFlex::AddGlobalFlexController( studioHdr.pFlexcontroller( i )->pszName() );
  248. studioHdr.pFlexcontroller( i )->localToGlobal = j;
  249. }
  250. }
  251. }
  252. else
  253. {
  254. handle = MDLHANDLE_INVALID;
  255. }
  256. // Clear our current sequence
  257. SetSequence( ACT_IDLE );
  258. BaseClass::SetMDL( handle, pProxyData );
  259. SetupModelDefaults();
  260. // Need to invalidate the layout so the panel will adjust is LookAt for the new model.
  261. InvalidateLayout();
  262. }
  263. //-----------------------------------------------------------------------------
  264. // Purpose:
  265. //-----------------------------------------------------------------------------
  266. void CBaseModelPanel::SetModelAnglesAndPosition( const QAngle &angRot, const Vector &vecPos )
  267. {
  268. BaseClass::SetModelAnglesAndPosition( angRot, vecPos );
  269. // Cache
  270. m_vecPlayerPos = vecPos;
  271. m_angPlayer = angRot;
  272. }
  273. //-----------------------------------------------------------------------------
  274. // Purpose:
  275. //-----------------------------------------------------------------------------
  276. void CBaseModelPanel::SetMDL( const char *pMDLName, void *pProxyData )
  277. {
  278. BaseClass::SetMDL( pMDLName, pProxyData );
  279. // Need to invalidate the layout so the panel will adjust is LookAt for the new model.
  280. // InvalidateLayout();
  281. }
  282. //-----------------------------------------------------------------------------
  283. // Purpose:
  284. //-----------------------------------------------------------------------------
  285. void CBaseModelPanel::PerformLayout()
  286. {
  287. BaseClass::PerformLayout();
  288. if ( m_bForcedCameraPosition )
  289. {
  290. return;
  291. }
  292. if ( m_bAllowFullManipulation )
  293. {
  294. // Set this to true if you want to keep the current rotation when changing models or poses
  295. const bool bPreserveManipulation = false;
  296. // Need to look at the target so we can rotate around it
  297. const Vector kVecFocalPoint( 0.0f, 0.0f, 60.0f );
  298. ResetCameraPivot();
  299. SetCameraOffset( -(m_vecPlayerPos + kVecFocalPoint) );
  300. SetCameraPositionAndAngles( kVecFocalPoint, vec3_angle, !bPreserveManipulation );
  301. // We want to move the player to the origin and facing the correct way,
  302. // but don't clobber m_angPlayer and m_vecPlayerPos, so use BaseClass.
  303. BaseClass::SetModelAnglesAndPosition( m_angPlayer, vec3_origin );
  304. // Once a manual transform has been done we want to apply it
  305. if ( m_bApplyManipulators )
  306. {
  307. ApplyManipulation();
  308. }
  309. else
  310. {
  311. SyncManipulation();
  312. }
  313. return;
  314. }
  315. if ( m_bForcePos )
  316. {
  317. ResetCameraPivot();
  318. SetCameraOffset( Vector( 0.0f, 0.0f, 0.0f ) );
  319. SetCameraPositionAndAngles( vec3_origin, vec3_angle );
  320. SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
  321. }
  322. // Center and fill the frame with the model?
  323. if ( m_bStartFramed )
  324. {
  325. Vector vecBoundsMin, vecBoundsMax;
  326. if ( GetBoundingBox( vecBoundsMin, vecBoundsMax ) )
  327. {
  328. LookAtBounds( vecBoundsMin, vecBoundsMax );
  329. }
  330. }
  331. }
  332. //-----------------------------------------------------------------------------
  333. //-----------------------------------------------------------------------------
  334. void CBaseModelPanel::OnTick()
  335. {
  336. // Cycle stuff gets handled in mdlpanel::OnTick, so we want to fix up
  337. // what our sequence is before it gets called.
  338. // Check if we have a active sequence, and if it's expired and we need
  339. // to run our default
  340. if ( m_nActiveSequence != ACT_INVALID )
  341. {
  342. float flElapsedTime = GetAutoPlayTime() - m_RootMDL.m_flCycleStartTime;
  343. if ( flElapsedTime >= m_flActiveSequenceDuration )
  344. {
  345. m_nActiveSequence = ACT_INVALID;
  346. m_flActiveSequenceDuration = 0.f;
  347. SetupModelDefaults();
  348. }
  349. }
  350. BaseClass::OnTick();
  351. }
  352. //-----------------------------------------------------------------------------
  353. //-----------------------------------------------------------------------------
  354. void CBaseModelPanel::OnKeyCodePressed ( vgui::KeyCode code )
  355. {
  356. if ( m_bAllowFullManipulation )
  357. {
  358. BaseClass::OnKeyCodePressed( code );
  359. return;
  360. }
  361. }
  362. //-----------------------------------------------------------------------------
  363. //-----------------------------------------------------------------------------
  364. void CBaseModelPanel::OnKeyCodeReleased( vgui::KeyCode code )
  365. {
  366. if ( m_bAllowFullManipulation )
  367. {
  368. BaseClass::OnKeyCodeReleased( code );
  369. return;
  370. }
  371. }
  372. //-----------------------------------------------------------------------------
  373. //-----------------------------------------------------------------------------
  374. void CBaseModelPanel::OnMousePressed ( vgui::MouseCode code )
  375. {
  376. if ( m_bAllowFullManipulation )
  377. {
  378. BaseClass::OnMousePressed( code );
  379. return;
  380. }
  381. if ( !m_bAllowRotation && !m_bAllowPitch )
  382. return;
  383. RequestFocus();
  384. EnableMouseCapture( true, code );
  385. // Save where they clicked
  386. input()->GetCursorPosition( m_nClickStartX, m_nClickStartY );
  387. // Warp the mouse to the center of the screen
  388. int width, height;
  389. GetSize( width, height );
  390. int x = width / 2;
  391. int y = height / 2;
  392. int xpos = x;
  393. int ypos = y;
  394. LocalToScreen( xpos, ypos );
  395. input()->SetCursorPos( xpos, ypos );
  396. m_nManipStartX = xpos;
  397. m_nManipStartY = ypos;
  398. m_bMousePressed = true;
  399. }
  400. //-----------------------------------------------------------------------------
  401. //-----------------------------------------------------------------------------
  402. void CBaseModelPanel::OnMouseReleased( vgui::MouseCode code )
  403. {
  404. if ( m_bAllowFullManipulation )
  405. {
  406. BaseClass::OnMouseReleased( code );
  407. return;
  408. }
  409. if ( !m_bAllowRotation && !m_bAllowPitch )
  410. return;
  411. EnableMouseCapture( false );
  412. m_bMousePressed = false;
  413. // Restore the cursor to where the clicked
  414. input()->SetCursorPos( m_nClickStartX, m_nClickStartY );
  415. }
  416. //-----------------------------------------------------------------------------
  417. //-----------------------------------------------------------------------------
  418. void CBaseModelPanel::OnCursorMoved( int x, int y )
  419. {
  420. if ( m_bAllowFullManipulation )
  421. {
  422. if ( m_pCurrentManip )
  423. {
  424. m_bApplyManipulators = true;
  425. }
  426. BaseClass::OnCursorMoved( x, y );
  427. return;
  428. }
  429. if ( !m_bAllowRotation && !m_bAllowPitch )
  430. return;
  431. if ( m_bMousePressed )
  432. {
  433. WarpMouse( x, y );
  434. int xpos, ypos;
  435. input()->GetCursorPos( xpos, ypos );
  436. if ( m_bAllowRotation )
  437. {
  438. // Only want the x delta.
  439. float flDelta = xpos - m_nManipStartX;
  440. // Apply the delta and rotate the player.
  441. RotateYaw( flDelta );
  442. }
  443. if ( m_bAllowPitch )
  444. {
  445. // Only want the y delta.
  446. float flDelta = ypos - m_nManipStartY;
  447. // Apply the delta and rotate the player.
  448. RotatePitch( flDelta );
  449. }
  450. }
  451. }
  452. //-----------------------------------------------------------------------------
  453. //-----------------------------------------------------------------------------
  454. void CBaseModelPanel::RotateYaw( float flDelta )
  455. {
  456. m_angPlayer.y += flDelta;
  457. if ( m_angPlayer.y > 360.0f )
  458. {
  459. m_angPlayer.y = m_angPlayer.y - 360.0f;
  460. }
  461. else if ( m_angPlayer.y < -360.0f )
  462. {
  463. m_angPlayer.y = m_angPlayer.y + 360.0f;
  464. }
  465. SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
  466. }
  467. //-----------------------------------------------------------------------------
  468. //-----------------------------------------------------------------------------
  469. void CBaseModelPanel::RotatePitch( float flDelta )
  470. {
  471. m_angPlayer.x += flDelta;
  472. if ( m_angPlayer.x > m_flMaxPitch )
  473. {
  474. m_angPlayer.x = m_flMaxPitch;
  475. }
  476. else if ( m_angPlayer.x < -m_flMaxPitch )
  477. {
  478. m_angPlayer.x = -m_flMaxPitch;
  479. }
  480. SetModelAnglesAndPosition( m_angPlayer, m_vecPlayerPos );
  481. }
  482. //-----------------------------------------------------------------------------
  483. //-----------------------------------------------------------------------------
  484. Vector CBaseModelPanel::GetPlayerPos() const
  485. {
  486. return m_vecPlayerPos;
  487. }
  488. //-----------------------------------------------------------------------------
  489. //-----------------------------------------------------------------------------
  490. QAngle CBaseModelPanel::GetPlayerAngles() const
  491. {
  492. return m_angPlayer;
  493. }
  494. //-----------------------------------------------------------------------------
  495. //-----------------------------------------------------------------------------
  496. void CBaseModelPanel::PlaySequence( const char *pszSequenceName )
  497. {
  498. CStudioHdr studioHDR( GetStudioHdr(), g_pMDLCache );
  499. int iSeq = ::LookupSequence( &studioHDR, pszSequenceName );
  500. if ( iSeq != ACT_INVALID )
  501. {
  502. m_nActiveSequence = iSeq;
  503. m_flActiveSequenceDuration = Studio_Duration( &studioHDR, iSeq, NULL );
  504. SetSequence( m_nActiveSequence, true );
  505. }
  506. }
  507. //-----------------------------------------------------------------------------
  508. //-----------------------------------------------------------------------------
  509. void CBaseModelPanel::OnMouseWheeled( int delta )
  510. {
  511. if ( m_bAllowFullManipulation )
  512. {
  513. BaseClass::OnMouseWheeled( delta );
  514. return;
  515. }
  516. }
  517. //-----------------------------------------------------------------------------
  518. // Purpose: Set the camera to a distance that allows the object to fill the model panel.
  519. //-----------------------------------------------------------------------------
  520. void CBaseModelPanel::LookAtBounds( const Vector &vecBoundsMin, const Vector &vecBoundsMax )
  521. {
  522. // Get the model space render bounds.
  523. Vector vecMin = vecBoundsMin;
  524. Vector vecMax = vecBoundsMax;
  525. Vector vecCenter = ( vecMax + vecMin ) * 0.5f;
  526. vecMin -= vecCenter;
  527. vecMax -= vecCenter;
  528. // Get the bounds points and transform them by the desired model panel rotation.
  529. Vector aBoundsPoints[8];
  530. aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z );
  531. aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z );
  532. aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z );
  533. aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z );
  534. aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z );
  535. aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z );
  536. aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z );
  537. aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z );
  538. // Translated center point (offset from camera center).
  539. Vector vecTranslateCenter = -vecCenter;
  540. // Build the rotation matrix.
  541. matrix3x4_t matRotation;
  542. AngleMatrix( m_BMPResData.m_angModelPoseRot, matRotation );
  543. Vector aXFormPoints[8];
  544. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  545. {
  546. VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] );
  547. }
  548. Vector vecXFormCenter;
  549. VectorTransform( -vecTranslateCenter, matRotation, vecXFormCenter );
  550. int w, h;
  551. GetSize( w, h );
  552. float flW = (float)w;
  553. float flH = (float)h;
  554. float flFOVx = DEG2RAD( m_BMPResData.m_flFOV * 0.5f );
  555. float flFOVy = CalcFovY( ( m_BMPResData.m_flFOV * 0.5f ), flW/flH );
  556. flFOVy = DEG2RAD( flFOVy );
  557. float flTanFOVx = tan( flFOVx );
  558. float flTanFOVy = tan( flFOVy );
  559. // Find the max value of x, y, or z
  560. Vector2D dist[8];
  561. float flDist = 0.0f;
  562. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  563. {
  564. float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx ) - aXFormPoints[iPoint].x;
  565. float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy ) - aXFormPoints[iPoint].x;
  566. dist[iPoint].x = flDistY;
  567. dist[iPoint].y = flDistZ;
  568. float flTestDist = MAX( flDistZ, flDistY );
  569. flDist = MAX( flDist, flTestDist );
  570. }
  571. // Screen space points.
  572. Vector2D aScreenPoints[8];
  573. Vector aCameraPoints[8];
  574. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  575. {
  576. aCameraPoints[iPoint] = aXFormPoints[iPoint];
  577. aCameraPoints[iPoint].x += flDist;
  578. aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x );
  579. aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x );
  580. aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW;
  581. aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH;
  582. }
  583. // Find the min/max and center of the 2D bounding box of the object.
  584. Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f );
  585. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  586. {
  587. vecScreenMin.x = MIN( vecScreenMin.x, aScreenPoints[iPoint].x );
  588. vecScreenMin.y = MIN( vecScreenMin.y, aScreenPoints[iPoint].y );
  589. vecScreenMax.x = MAX( vecScreenMax.x, aScreenPoints[iPoint].x );
  590. vecScreenMax.y = MAX( vecScreenMax.y, aScreenPoints[iPoint].y );
  591. }
  592. // Offset the model to the be the correct distance away from the camera.
  593. Vector vecModelPos;
  594. vecModelPos.x = flDist - vecXFormCenter.x;
  595. vecModelPos.y = -vecXFormCenter.y;
  596. vecModelPos.z = -vecXFormCenter.z;
  597. SetModelAnglesAndPosition( m_BMPResData.m_angModelPoseRot, vecModelPos );
  598. m_vecPlayerPos = vecModelPos;
  599. // Back project to figure out the camera offset to center the model.
  600. Vector2D vecPanelCenter( ( flW * 0.5f ), ( flH * 0.5f ) );
  601. Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f;
  602. Vector2D vecPanelCenterCamera, vecScreenCenterCamera;
  603. vecPanelCenterCamera.x = ( ( vecPanelCenter.x / flW ) * 2.0f ) - 0.5f;
  604. vecPanelCenterCamera.y = ( ( vecPanelCenter.y / flH ) * 2.0f ) - 0.5f;
  605. vecPanelCenterCamera.x *= ( flTanFOVx * flDist );
  606. vecPanelCenterCamera.y *= ( flTanFOVy * flDist );
  607. vecScreenCenterCamera.x = ( ( vecScreenCenter.x / flW ) * 2.0f ) - 0.5f;
  608. vecScreenCenterCamera.y = ( ( vecScreenCenter.y / flH ) * 2.0f ) - 0.5f;
  609. vecScreenCenterCamera.x *= ( flTanFOVx * flDist );
  610. vecScreenCenterCamera.y *= ( flTanFOVy * flDist );
  611. Vector2D vecCameraOffset( 0.0f, 0.0f );
  612. vecCameraOffset.x = vecPanelCenterCamera.x - vecScreenCenterCamera.x;
  613. vecCameraOffset.y = vecPanelCenterCamera.y - vecScreenCenterCamera.y;
  614. // Clear the camera pivot and set position matrix.
  615. ResetCameraPivot();
  616. if (m_bAllowRotation || m_bAllowPitch )
  617. {
  618. vecCameraOffset.x = 0.0f;
  619. }
  620. SetCameraOffset( Vector( 0.0f, -vecCameraOffset.x, -vecCameraOffset.y ) );
  621. UpdateCameraTransform();
  622. }
  623. //-----------------------------------------------------------------------------
  624. // Purpose:
  625. //-----------------------------------------------------------------------------
  626. CBaseModelPanel::particle_data_t::~particle_data_t()
  627. {
  628. if ( m_pParticleSystem )
  629. {
  630. delete m_pParticleSystem;
  631. m_pParticleSystem = NULL;
  632. }
  633. }
  634. //-----------------------------------------------------------------------------
  635. // Purpose: Allocate particle data
  636. //-----------------------------------------------------------------------------
  637. void CBaseModelPanel::particle_data_t::UpdateControlPoints( CStudioHdr *pStudioHdr, matrix3x4_t *pWorldMatrix, const CUtlVector< int >& vecAttachments, int iDefaultBone /*= 0*/, const Vector& vecParticleOffset /*= vec3_origin*/ )
  638. {
  639. if ( m_pParticleSystem )
  640. {
  641. // Update control points which is updating the position of the particles
  642. matrix3x4_t matAttachToWorld;
  643. Vector vecPosition, vecForward, vecRight, vecUp;
  644. if ( vecAttachments.Count() )
  645. {
  646. for ( int i = 0; i < vecAttachments.Count(); ++i )
  647. {
  648. const mstudioattachment_t& attach = pStudioHdr->pAttachment( vecAttachments[i] );
  649. MatrixMultiply( pWorldMatrix[ attach.localbone ], attach.local, matAttachToWorld );
  650. MatrixVectors( matAttachToWorld, &vecForward, &vecRight, &vecUp );
  651. MatrixPosition( matAttachToWorld, vecPosition );
  652. m_pParticleSystem->SetControlPointOrientation( i, vecForward, vecRight, vecUp );
  653. m_pParticleSystem->SetControlPoint( i, vecPosition + vecParticleOffset );
  654. }
  655. }
  656. else
  657. {
  658. matAttachToWorld = pWorldMatrix[iDefaultBone];
  659. MatrixVectors( matAttachToWorld, &vecForward, &vecRight, &vecUp );
  660. MatrixPosition( matAttachToWorld, vecPosition );
  661. m_pParticleSystem->SetControlPointOrientation( 0, vecForward, vecRight, vecUp );
  662. m_pParticleSystem->SetControlPoint( 0, vecPosition + vecParticleOffset );
  663. }
  664. }
  665. m_bIsUpdateToDate = true;
  666. }
  667. //-----------------------------------------------------------------------------
  668. // Purpose: Allocate particle data
  669. //-----------------------------------------------------------------------------
  670. CBaseModelPanel::particle_data_t *CBaseModelPanel::CreateParticleData( const char *pszParticleName )
  671. {
  672. Assert( m_bUseParticle );
  673. if ( !m_bUseParticle )
  674. return NULL;
  675. CParticleCollection *pParticle = g_pParticleSystemMgr->CreateParticleCollection( pszParticleName );
  676. if ( !pParticle )
  677. return NULL;
  678. particle_data_t *pData = new particle_data_t;
  679. pData->m_bIsUpdateToDate = false;
  680. pData->m_pParticleSystem = pParticle;
  681. m_particleList.AddToTail( pData );
  682. return pData;
  683. }
  684. //-----------------------------------------------------------------------------
  685. // Purpose: remove and delete particle data
  686. //-----------------------------------------------------------------------------
  687. bool CBaseModelPanel::SafeDeleteParticleData( particle_data_t **pData )
  688. {
  689. if ( !m_bUseParticle )
  690. return false;
  691. if ( *pData )
  692. {
  693. FOR_EACH_VEC( m_particleList, i )
  694. {
  695. if ( *pData == m_particleList[i] )
  696. {
  697. delete *pData;
  698. *pData = NULL;
  699. m_particleList.FastRemove( i );
  700. return true;
  701. }
  702. }
  703. }
  704. return false;
  705. }
  706. //-----------------------------------------------------------------------------
  707. // Purpose:
  708. //-----------------------------------------------------------------------------
  709. void CBaseModelPanel::PrePaint3D( IMatRenderContext *pRenderContext )
  710. {
  711. if ( !m_bUseParticle )
  712. return;
  713. // mark all effects need to be updated
  714. FOR_EACH_VEC( m_particleList, i )
  715. {
  716. m_particleList[i]->m_bIsUpdateToDate = false;
  717. }
  718. }
  719. //-----------------------------------------------------------------------------
  720. // Purpose:
  721. //-----------------------------------------------------------------------------
  722. void CBaseModelPanel::PostPaint3D( IMatRenderContext *pRenderContext )
  723. {
  724. if ( !m_bUseParticle )
  725. return;
  726. // This needs calling to reset various counters.
  727. g_pParticleSystemMgr->SetLastSimulationTime( gpGlobals->curtime );
  728. // Render Particles
  729. pRenderContext->MatrixMode( MATERIAL_MODEL );
  730. pRenderContext->PushMatrix();
  731. pRenderContext->LoadIdentity( );
  732. FOR_EACH_VEC( m_particleList, i )
  733. {
  734. if ( m_particleList[i]->m_bIsUpdateToDate )
  735. {
  736. m_particleList[i]->m_pParticleSystem->Simulate( gpGlobals->frametime, false );
  737. m_particleList[i]->m_pParticleSystem->Render( pRenderContext );
  738. m_particleList[i]->m_bIsUpdateToDate = false;
  739. }
  740. }
  741. pRenderContext->MatrixMode( MATERIAL_MODEL );
  742. pRenderContext->PopMatrix();
  743. }