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.

908 lines
25 KiB

  1. //========= Copyright � 1996-2006, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include <KeyValues.h>
  8. #include <vgui/ISurface.h>
  9. #include <vgui/ISystem.h>
  10. #include <vgui/IScheme.h>
  11. #include <vgui_controls/AnimationController.h>
  12. #include <vgui_controls/EditablePanel.h>
  13. #include <vgui_controls/ImagePanel.h>
  14. #include <vgui/ISurface.h>
  15. #include <vgui/IImage.h>
  16. #include <vgui_controls/Label.h>
  17. #include "materialsystem/imaterialsystem.h"
  18. #include "engine/ivmodelinfo.h"
  19. #include "c_sceneentity.h"
  20. #include "gamestringpool.h"
  21. #include "model_types.h"
  22. #include "view_shared.h"
  23. #include "view.h"
  24. #include "ivrenderview.h"
  25. #include "iefx.h"
  26. #include "dlight.h"
  27. #include "activitylist.h"
  28. #include "basemodelpanel.h"
  29. #include "vgui_int.h"
  30. // NOTE: This has to be the last file included!
  31. #include "tier0/memdbgon.h"
  32. bool UseHWMorphModels();
  33. using namespace vgui;
  34. DECLARE_BUILD_FACTORY( CModelPanel );
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. //-----------------------------------------------------------------------------
  38. CModelPanel::CModelPanel( vgui::Panel *pParent, const char *pName ) : vgui::EditablePanel( pParent, pName )
  39. {
  40. m_nFOV = 54;
  41. m_hModel = NULL;
  42. m_pModelInfo = NULL;
  43. m_hScene = NULL;
  44. m_iDefaultAnimation = 0;
  45. m_bPanelDirty = true;
  46. m_bStartFramed = false;
  47. m_bAllowOffscreen = false;
  48. ListenForGameEvent( "game_newmap" );
  49. }
  50. //-----------------------------------------------------------------------------
  51. // Purpose:
  52. //-----------------------------------------------------------------------------
  53. CModelPanel::~CModelPanel()
  54. {
  55. if ( m_pModelInfo )
  56. {
  57. delete m_pModelInfo;
  58. m_pModelInfo = NULL;
  59. }
  60. DeleteVCDData();
  61. DeleteModelData();
  62. }
  63. //-----------------------------------------------------------------------------
  64. // Purpose:
  65. //-----------------------------------------------------------------------------
  66. void CModelPanel::ApplySettings( KeyValues *inResourceData )
  67. {
  68. BaseClass::ApplySettings( inResourceData );
  69. m_nFOV = inResourceData->GetInt( "fov", 54 );
  70. m_bStartFramed = inResourceData->GetBool( "start_framed", false );
  71. m_bAllowOffscreen = inResourceData->GetBool( "allow_offscreen", false );
  72. // do we have a valid "model" section in the .res file?
  73. for ( KeyValues *pData = inResourceData->GetFirstSubKey() ; pData != NULL ; pData = pData->GetNextKey() )
  74. {
  75. if ( !Q_stricmp( pData->GetName(), "model" ) )
  76. {
  77. ParseModelInfo( pData );
  78. }
  79. }
  80. }
  81. //-----------------------------------------------------------------------------
  82. // Purpose:
  83. //-----------------------------------------------------------------------------
  84. void CModelPanel::ParseModelInfo( KeyValues *inResourceData )
  85. {
  86. // delete any current info
  87. if ( m_pModelInfo )
  88. {
  89. delete m_pModelInfo;
  90. m_pModelInfo = NULL;
  91. }
  92. m_pModelInfo = new CModelPanelModelInfo;
  93. if ( !m_pModelInfo )
  94. return;
  95. m_pModelInfo->m_pszModelName = ReadAndAllocStringValue( inResourceData, "modelname" );
  96. m_pModelInfo->m_pszModelName_HWM = ReadAndAllocStringValue( inResourceData, "modelname_hwm" );
  97. m_pModelInfo->m_nSkin = inResourceData->GetInt( "skin", -1 );
  98. m_pModelInfo->m_vecAbsAngles.Init( inResourceData->GetFloat( "angles_x", 0.0 ), inResourceData->GetFloat( "angles_y", 0.0 ), inResourceData->GetFloat( "angles_z", 0.0 ) );
  99. m_pModelInfo->m_vecOriginOffset.Init( inResourceData->GetFloat( "origin_x", 110.0 ), inResourceData->GetFloat( "origin_y", 5.0 ), inResourceData->GetFloat( "origin_z", 5.0 ) );
  100. m_pModelInfo->m_vecFramedOriginOffset.Init( inResourceData->GetFloat( "frame_origin_x", 110.0 ), inResourceData->GetFloat( "frame_origin_y", 5.0 ), inResourceData->GetFloat( "frame_origin_z", 5.0 ) );
  101. m_pModelInfo->m_pszVCD = ReadAndAllocStringValue( inResourceData, "vcd" );
  102. m_pModelInfo->m_bUseSpotlight = ( inResourceData->GetInt( "spotlight", 0 ) == 1 );
  103. m_pModelInfo->m_vecViewportOffset.Init();
  104. for ( KeyValues *pData = inResourceData->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
  105. {
  106. if ( !Q_stricmp( pData->GetName(), "animation" ) )
  107. {
  108. OnAddAnimation( pData );
  109. }
  110. else if ( !Q_stricmp( pData->GetName(), "attached_model" ) )
  111. {
  112. CModelPanelAttachedModelInfo *pAttachedModelInfo = new CModelPanelAttachedModelInfo;
  113. if ( pAttachedModelInfo )
  114. {
  115. pAttachedModelInfo->m_pszModelName = ReadAndAllocStringValue( pData, "modelname" );
  116. pAttachedModelInfo->m_nSkin = pData->GetInt( "skin", -1 );
  117. m_pModelInfo->m_AttachedModelsInfo.AddToTail( pAttachedModelInfo );
  118. }
  119. }
  120. }
  121. m_bPanelDirty = true;
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose:
  125. //-----------------------------------------------------------------------------
  126. void CModelPanel::OnAddAnimation( KeyValues *pData )
  127. {
  128. if ( !pData )
  129. return;
  130. CModelPanelModelAnimation *pAnimation = new CModelPanelModelAnimation;
  131. if ( pAnimation )
  132. {
  133. pAnimation->m_pszName = ReadAndAllocStringValue( pData, "name" );
  134. pAnimation->m_pszSequence = ReadAndAllocStringValue( pData, "sequence" );
  135. pAnimation->m_pszActivity = ReadAndAllocStringValue( pData, "activity" );
  136. pAnimation->m_bDefault = ( pData->GetInt( "default", 0 ) == 1 );
  137. for ( KeyValues *pAnimData = pData->GetFirstSubKey(); pAnimData != NULL; pAnimData = pAnimData->GetNextKey() )
  138. {
  139. if ( !Q_stricmp( pAnimData->GetName(), "pose_parameters" ) )
  140. {
  141. pAnimation->m_pPoseParameters = pAnimData->MakeCopy();
  142. }
  143. }
  144. m_pModelInfo->m_Animations.AddToTail( pAnimation );
  145. if ( pAnimation->m_bDefault )
  146. {
  147. m_iDefaultAnimation = m_pModelInfo->m_Animations.Find( pAnimation );
  148. }
  149. }
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. //-----------------------------------------------------------------------------
  154. void CModelPanel::FireGameEvent( IGameEvent * event )
  155. {
  156. const char *type = event->GetName();
  157. if ( Q_strcmp( type, "game_newmap" ) == 0 )
  158. {
  159. // force the models to re-setup themselves
  160. m_bPanelDirty = true;
  161. }
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Purpose:
  165. //-----------------------------------------------------------------------------
  166. void CModelPanel::SetDefaultAnimation( const char *pszName )
  167. {
  168. if ( m_pModelInfo )
  169. {
  170. for ( int i = 0; i < m_pModelInfo->m_Animations.Count(); i++ )
  171. {
  172. if ( m_pModelInfo->m_Animations[i] && m_pModelInfo->m_Animations[i]->m_pszName )
  173. {
  174. if ( !Q_stricmp( m_pModelInfo->m_Animations[i]->m_pszName, pszName ) )
  175. {
  176. m_iDefaultAnimation = i;
  177. return;
  178. }
  179. }
  180. }
  181. }
  182. Assert( 0 );
  183. }
  184. //-----------------------------------------------------------------------------
  185. // Purpose: Replaces the current model with a new one, without changing the camera settings
  186. //-----------------------------------------------------------------------------
  187. void CModelPanel::SwapModel( const char *pszName, const char *pszAttached )
  188. {
  189. if ( !m_pModelInfo || !pszName || !pszName[0] )
  190. return;
  191. int len = Q_strlen( pszName ) + 1;
  192. char *pAlloced = new char[ len ];
  193. Assert( pAlloced );
  194. Q_strncpy( pAlloced, pszName, len );
  195. m_pModelInfo->m_pszModelName = pAlloced;
  196. ClearAttachedModelInfos();
  197. if ( pszAttached )
  198. {
  199. CModelPanelAttachedModelInfo *pAttachedModelInfo = new CModelPanelAttachedModelInfo;
  200. if ( pAttachedModelInfo )
  201. {
  202. len = Q_strlen( pszAttached ) + 1;
  203. pAlloced = new char[ len ];
  204. Assert( pAlloced );
  205. Q_strncpy( pAlloced, pszAttached, len );
  206. pAttachedModelInfo->m_pszModelName = pAlloced;
  207. pAttachedModelInfo->m_nSkin = 0;
  208. m_pModelInfo->m_AttachedModelsInfo.AddToTail( pAttachedModelInfo );
  209. }
  210. }
  211. m_bPanelDirty = true;
  212. }
  213. //-----------------------------------------------------------------------------
  214. // Purpose:
  215. //-----------------------------------------------------------------------------
  216. void CModelPanel::DeleteVCDData( void )
  217. {
  218. if ( m_hScene.Get() )
  219. {
  220. m_hScene->StopClientOnlyScene();
  221. m_hScene->Remove();
  222. m_hScene = NULL;
  223. }
  224. }
  225. //-----------------------------------------------------------------------------
  226. // Purpose:
  227. //-----------------------------------------------------------------------------
  228. void CModelPanel::SetupVCD( void )
  229. {
  230. if ( !m_pModelInfo )
  231. return;
  232. DeleteVCDData();
  233. C_SceneEntity *pEnt = new class C_SceneEntity;
  234. if ( !pEnt )
  235. return;
  236. if ( pEnt->InitializeAsClientEntity( "", false ) == false )
  237. {
  238. // we failed to initialize this entity so just return gracefully
  239. pEnt->Remove();
  240. return;
  241. }
  242. g_pClientLeafSystem->EnableRendering( pEnt->RenderHandle(), false );
  243. // setup the handle
  244. m_hScene = pEnt;
  245. // setup the scene
  246. pEnt->SetupClientOnlyScene( m_pModelInfo->m_pszVCD, m_hModel, true );
  247. }
  248. //-----------------------------------------------------------------------------
  249. // Purpose:
  250. //-----------------------------------------------------------------------------
  251. void CModelPanel::ClearAttachedModelInfos( void )
  252. {
  253. if ( m_pModelInfo )
  254. {
  255. m_pModelInfo->m_AttachedModelsInfo.PurgeAndDeleteElements();
  256. }
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose:
  260. //-----------------------------------------------------------------------------
  261. void CModelPanel::DeleteModelData( void )
  262. {
  263. if ( m_hModel.Get() )
  264. {
  265. m_hModel->Remove();
  266. m_hModel = NULL;
  267. m_flFrameDistance = 0;
  268. }
  269. for ( int i = 0 ; i < m_AttachedModels.Count() ; i++ )
  270. {
  271. if ( m_AttachedModels[i].Get() )
  272. {
  273. m_AttachedModels[i]->Remove();
  274. }
  275. m_AttachedModels.Remove( i );
  276. }
  277. }
  278. //-----------------------------------------------------------------------------
  279. // Purpose:
  280. //-----------------------------------------------------------------------------
  281. const char *CModelPanel::GetModelName( void )
  282. {
  283. if ( !m_pModelInfo )
  284. return NULL;
  285. // check to see if we want to use a HWM model
  286. if ( UseHWMorphModels() )
  287. {
  288. // do we have a valid HWM model filename
  289. if ( m_pModelInfo->m_pszModelName_HWM && ( Q_strlen( m_pModelInfo->m_pszModelName_HWM ) > 0 ) )
  290. {
  291. // does the file exist
  292. model_t *pModel = (model_t *)engine->LoadModel( m_pModelInfo->m_pszModelName_HWM );
  293. if ( pModel )
  294. {
  295. return m_pModelInfo->m_pszModelName_HWM;
  296. }
  297. }
  298. }
  299. return m_pModelInfo->m_pszModelName;
  300. }
  301. //-----------------------------------------------------------------------------
  302. // Purpose:
  303. //-----------------------------------------------------------------------------
  304. void CModelPanel::SetupModel( void )
  305. {
  306. if ( !m_pModelInfo )
  307. return;
  308. MDLCACHE_CRITICAL_SECTION();
  309. // remove any current models we're using
  310. DeleteModelData();
  311. const char *pszModelName = GetModelName();
  312. if ( !pszModelName || !pszModelName[0] )
  313. return;
  314. // create the new model
  315. CModelPanelModel *pEnt = new CModelPanelModel;
  316. if ( !pEnt )
  317. return;
  318. if ( pEnt->InitializeAsClientEntity( pszModelName, false ) == false )
  319. {
  320. // we failed to initialize this entity so just return gracefully
  321. pEnt->Remove();
  322. return;
  323. }
  324. // setup the handle
  325. m_hModel = pEnt;
  326. pEnt->DontRecordInTools();
  327. pEnt->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
  328. if ( m_pModelInfo->m_nSkin >= 0 )
  329. {
  330. pEnt->SetSkin( m_pModelInfo->m_nSkin );
  331. }
  332. // do we have any animation information?
  333. if ( m_pModelInfo->m_Animations.Count() > 0 && m_pModelInfo->m_Animations.IsValidIndex( m_iDefaultAnimation ) )
  334. {
  335. CModelPanelModelAnimation *pAnim = m_pModelInfo->m_Animations[ m_iDefaultAnimation ];
  336. int sequence = ACT_INVALID;
  337. if ( pAnim->m_pszActivity && pAnim->m_pszActivity[0] )
  338. {
  339. Activity activity = (Activity)ActivityList_IndexForName( pAnim->m_pszActivity );
  340. sequence = pEnt->SelectWeightedSequence( activity );
  341. }
  342. else if ( pAnim->m_pszSequence && pAnim->m_pszSequence[0] )
  343. {
  344. sequence = pEnt->LookupSequence( pAnim->m_pszSequence );
  345. }
  346. if ( sequence != ACT_INVALID )
  347. {
  348. pEnt->ResetSequence( sequence );
  349. pEnt->SetCycle( 0 );
  350. if ( pAnim->m_pPoseParameters )
  351. {
  352. for ( KeyValues *pData = pAnim->m_pPoseParameters->GetFirstSubKey(); pData != NULL; pData = pData->GetNextKey() )
  353. {
  354. const char *pName = pData->GetName();
  355. float flValue = pData->GetFloat();
  356. pEnt->SetPoseParameter( pName, flValue );
  357. }
  358. }
  359. pEnt->m_flAnimTime = gpGlobals->curtime;
  360. }
  361. }
  362. // setup any attached models
  363. for ( int i = 0 ; i < m_pModelInfo->m_AttachedModelsInfo.Count() ; i++ )
  364. {
  365. CModelPanelAttachedModelInfo *pInfo = m_pModelInfo->m_AttachedModelsInfo[i];
  366. C_BaseAnimating *pTemp = new C_BaseAnimating;
  367. if ( pTemp )
  368. {
  369. if ( pTemp->InitializeAsClientEntity( pInfo->m_pszModelName, false ) == false )
  370. {
  371. // we failed to initialize this model so just skip it
  372. pTemp->Remove();
  373. continue;
  374. }
  375. pTemp->DontRecordInTools();
  376. pTemp->AddEffects( EF_NODRAW ); // don't let the renderer draw the model normally
  377. pTemp->FollowEntity( m_hModel.Get() ); // attach to parent model
  378. if ( pInfo->m_nSkin >= 0 )
  379. {
  380. pTemp->SetSkin( pInfo->m_nSkin );
  381. }
  382. pTemp->m_flAnimTime = gpGlobals->curtime;
  383. m_AttachedModels.AddToTail( pTemp );
  384. }
  385. }
  386. CalculateFrameDistance();
  387. }
  388. //-----------------------------------------------------------------------------
  389. // Purpose:
  390. //-----------------------------------------------------------------------------
  391. void CModelPanel::InitCubeMaps()
  392. {
  393. ITexture *pCubemapTexture;
  394. // Deal with the default cubemap
  395. if ( g_pMaterialSystemHardwareConfig->GetHDREnabled() )
  396. {
  397. pCubemapTexture = materials->FindTexture( "editor/cubemap.hdr", NULL, true );
  398. m_DefaultHDREnvCubemap.Init( pCubemapTexture );
  399. }
  400. else
  401. {
  402. pCubemapTexture = materials->FindTexture( "editor/cubemap", NULL, true );
  403. m_DefaultEnvCubemap.Init( pCubemapTexture );
  404. }
  405. }
  406. void CModelPanel::UpdateIfDirty()
  407. {
  408. if ( !m_bPanelDirty )
  409. {
  410. return;
  411. }
  412. InitCubeMaps();
  413. SetupModel();
  414. // are we trying to play a VCD?
  415. if ( Q_strlen( m_pModelInfo->m_pszVCD ) > 0 )
  416. {
  417. SetupVCD();
  418. }
  419. m_bPanelDirty = false;
  420. }
  421. //-----------------------------------------------------------------------------
  422. // Purpose:
  423. //-----------------------------------------------------------------------------
  424. void CModelPanel::Paint()
  425. {
  426. BaseClass::Paint();
  427. ASSERT_LOCAL_PLAYER_RESOLVABLE();
  428. VGUI_ABSPOS_SPLITSCREEN_GUARD( GET_ACTIVE_SPLITSCREEN_SLOT() );
  429. C_BasePlayer *pLocalPlayer = C_BasePlayer::GetLocalPlayer();
  430. if ( !pLocalPlayer || !m_pModelInfo )
  431. return;
  432. MDLCACHE_CRITICAL_SECTION();
  433. UpdateIfDirty();
  434. if ( !m_hModel.Get() )
  435. return;
  436. int i = 0;
  437. int x, y, w, h;
  438. GetBounds( x, y, w, h );
  439. // ParentLocalToScreen( x, y );
  440. if ( !m_bAllowOffscreen && x < 0 )
  441. {
  442. // prevent x from being pushed off the left side of the screen
  443. // for modes like 1280 x 1024 (prevents model from being drawn in the panel)
  444. x = 0;
  445. }
  446. Vector vecExtraModelOffset( 0, 0, 0 );
  447. int dummyx, dummyy;
  448. int sw, sh;
  449. VGui_GetHudBounds( GET_ACTIVE_SPLITSCREEN_SLOT(), dummyx, dummyy, sw, sh );
  450. x += dummyx;
  451. y += dummyy;
  452. float aspect = (float)sw/(float)sh;
  453. float flWidthRatio = aspect / ( 4.0f / 3.0f );
  454. // is this a player model?
  455. if ( Q_strstr( GetModelName(), "models/player/" ) )
  456. {
  457. // need to know if the ratio is not 4/3
  458. // HACK! HACK! to get our player models to appear the way they do in 4/3 if we're using other aspect ratios
  459. if ( flWidthRatio > 1.05f )
  460. {
  461. vecExtraModelOffset.Init( -60, 0, 0 );
  462. }
  463. else if ( flWidthRatio < 0.95f )
  464. {
  465. vecExtraModelOffset.Init( 15, 0, 0 );
  466. }
  467. }
  468. m_hModel->SetAbsOrigin( m_pModelInfo->m_vecOriginOffset + vecExtraModelOffset );
  469. m_hModel->SetAbsAngles( QAngle( m_pModelInfo->m_vecAbsAngles.x, m_pModelInfo->m_vecAbsAngles.y, m_pModelInfo->m_vecAbsAngles.z ) );
  470. // do we have a valid sequence?
  471. if ( m_hModel->GetSequence() != -1 )
  472. {
  473. m_hModel->FrameAdvance( gpGlobals->frametime );
  474. }
  475. // Now draw it.
  476. CViewSetup view;
  477. view.x = x + m_pModelInfo->m_vecViewportOffset.x;
  478. view.y = y + m_pModelInfo->m_vecViewportOffset.y;
  479. view.width = w;
  480. view.height = h;
  481. view.m_bOrtho = false;
  482. // scale the FOV for aspect ratios other than 4/3
  483. view.fov = ScaleFOVByWidthRatio( m_nFOV, flWidthRatio );
  484. view.origin = vec3_origin;
  485. view.angles.Init();
  486. view.zNear = VIEW_NEARZ;
  487. view.zFar = 1000;
  488. CMatRenderContextPtr pRenderContext( materials );
  489. // Not supported by queued material system - doesn't appear to be necessary
  490. // ITexture *pLocalCube = pRenderContext->GetLocalCubemap();
  491. if ( g_pMaterialSystemHardwareConfig->GetHDREnabled() )
  492. {
  493. pRenderContext->BindLocalCubemap( m_DefaultHDREnvCubemap );
  494. }
  495. else
  496. {
  497. pRenderContext->BindLocalCubemap( m_DefaultEnvCubemap );
  498. }
  499. pRenderContext->SetLightingOrigin( vec3_origin );
  500. static Vector white[6] =
  501. {
  502. Vector( 0.4, 0.4, 0.4 ),
  503. Vector( 0.4, 0.4, 0.4 ),
  504. Vector( 0.4, 0.4, 0.4 ),
  505. Vector( 0.4, 0.4, 0.4 ),
  506. Vector( 0.4, 0.4, 0.4 ),
  507. Vector( 0.4, 0.4, 0.4 ),
  508. };
  509. g_pStudioRender->SetAmbientLightColors( white );
  510. g_pStudioRender->SetLocalLights( 0, NULL );
  511. if ( m_pModelInfo->m_bUseSpotlight )
  512. {
  513. Vector vecMins, vecMaxs;
  514. m_hModel->GetRenderBounds( vecMins, vecMaxs );
  515. LightDesc_t spotLight( vec3_origin + Vector( 0, 0, 200 ), Vector( 1, 1, 1 ), m_hModel->GetAbsOrigin() + Vector( 0, 0, ( vecMaxs.z - vecMins.z ) * 0.75 ), 0.035, 0.873 );
  516. g_pStudioRender->SetLocalLights( 1, &spotLight );
  517. }
  518. Frustum dummyFrustum;
  519. render->Push3DView( view, 0, NULL, dummyFrustum );
  520. modelrender->SuppressEngineLighting( true );
  521. float color[3] = { 1.0f, 1.0f, 1.0f };
  522. render->SetColorModulation( color );
  523. render->SetBlend( 1.0f );
  524. RenderableInstance_t instance;
  525. instance.m_nAlpha = 255;
  526. m_hModel->DrawModel( STUDIO_RENDER, instance );
  527. for ( i = 0 ; i < m_AttachedModels.Count() ; i++ )
  528. {
  529. if ( m_AttachedModels[i].Get() )
  530. {
  531. m_AttachedModels[i]->DrawModel( STUDIO_RENDER, instance );
  532. }
  533. }
  534. modelrender->SuppressEngineLighting( false );
  535. render->PopView( dummyFrustum );
  536. pRenderContext->BindLocalCubemap( NULL );
  537. /*
  538. vgui::surface()->DrawSetColor( Color(0,0,0,255) );
  539. vgui::surface()->DrawOutlinedRect( 0,0, GetWide(), GetTall() );
  540. */
  541. }
  542. //-----------------------------------------------------------------------------
  543. // Purpose:
  544. //-----------------------------------------------------------------------------
  545. int CModelPanel::FindAnimByName( const char *pszName )
  546. {
  547. // first try to find the sequence using pszName as the friendly name
  548. for ( int iIndex = 0 ; iIndex < m_pModelInfo->m_Animations.Count() ; iIndex++ )
  549. {
  550. CModelPanelModelAnimation *pAnimation = m_pModelInfo->m_Animations[ iIndex ];
  551. if ( FStrEq( pAnimation->m_pszName, pszName ) )
  552. return iIndex;
  553. }
  554. return -1;
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose:
  558. //-----------------------------------------------------------------------------
  559. bool CModelPanel::SetSequence( const char *pszName )
  560. {
  561. bool bRetVal = false;
  562. const char *pszAnim = NULL;
  563. MDLCACHE_CRITICAL_SECTION();
  564. if ( m_pModelInfo )
  565. {
  566. int iIndex = FindAnimByName(pszName);
  567. if ( iIndex != -1 )
  568. {
  569. pszAnim = m_pModelInfo->m_Animations[iIndex]->m_pszSequence;
  570. }
  571. else
  572. {
  573. // if not, just use the passed name as the sequence
  574. pszAnim = pszName;
  575. }
  576. if ( m_hModel.Get() )
  577. {
  578. int sequence = m_hModel->LookupSequence( pszAnim );
  579. if ( sequence != ACT_INVALID )
  580. {
  581. m_hModel->ResetSequence( sequence );
  582. m_hModel->SetCycle( 0 );
  583. bRetVal = true;
  584. }
  585. }
  586. }
  587. return bRetVal;
  588. }
  589. //-----------------------------------------------------------------------------
  590. // Purpose:
  591. //-----------------------------------------------------------------------------
  592. void CModelPanel::OnSetAnimation( KeyValues *data )
  593. {
  594. UpdateIfDirty();
  595. // If there's no model, these commands will be ignored.
  596. Assert(m_hModel);
  597. if ( data )
  598. {
  599. const char *pszAnimation = data->GetString( "animation", "" );
  600. const char *pszActivity = data->GetString( "activity", "" );
  601. if ( pszActivity && pszActivity[0] )
  602. {
  603. if ( m_hModel )
  604. {
  605. int iIndex = FindAnimByName(pszActivity);
  606. if ( iIndex != -1 )
  607. {
  608. pszActivity = m_pModelInfo->m_Animations[iIndex]->m_pszActivity;
  609. }
  610. Activity activity = (Activity)ActivityList_IndexForName( pszActivity );
  611. int sequence = m_hModel->SelectWeightedSequence( activity );
  612. if ( sequence != ACT_INVALID )
  613. {
  614. m_hModel->ResetSequence( sequence );
  615. m_hModel->SetCycle( 0 );
  616. }
  617. }
  618. }
  619. else
  620. {
  621. SetSequence( pszAnimation );
  622. }
  623. }
  624. }
  625. void CModelPanel::CalculateFrameDistanceInternal( const model_t *pModel )
  626. {
  627. // Get the model space render bounds.
  628. Vector vecMin, vecMax;
  629. modelinfo->GetModelRenderBounds( pModel, vecMin, vecMax );
  630. Vector vecCenter = ( vecMax + vecMin ) * 0.5f;
  631. vecMin -= vecCenter;
  632. vecMax -= vecCenter;
  633. // Get the bounds points and transform them by the desired model panel rotation.
  634. Vector aBoundsPoints[8];
  635. aBoundsPoints[0].Init( vecMax.x, vecMax.y, vecMax.z );
  636. aBoundsPoints[1].Init( vecMin.x, vecMax.y, vecMax.z );
  637. aBoundsPoints[2].Init( vecMax.x, vecMin.y, vecMax.z );
  638. aBoundsPoints[3].Init( vecMin.x, vecMin.y, vecMax.z );
  639. aBoundsPoints[4].Init( vecMax.x, vecMax.y, vecMin.z );
  640. aBoundsPoints[5].Init( vecMin.x, vecMax.y, vecMin.z );
  641. aBoundsPoints[6].Init( vecMax.x, vecMin.y, vecMin.z );
  642. aBoundsPoints[7].Init( vecMin.x, vecMin.y, vecMin.z );
  643. // Translated center point (offset from camera center).
  644. Vector vecTranslateCenter = -vecCenter;
  645. // Build the rotation matrix.
  646. QAngle angPanelAngles( m_pModelInfo->m_vecAbsAngles.x, m_pModelInfo->m_vecAbsAngles.y, m_pModelInfo->m_vecAbsAngles.z );
  647. matrix3x4_t matRotation;
  648. AngleMatrix( angPanelAngles, matRotation );
  649. Vector aXFormPoints[8];
  650. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  651. {
  652. VectorTransform( aBoundsPoints[iPoint], matRotation, aXFormPoints[iPoint] );
  653. }
  654. Vector vecXFormCenter;
  655. VectorTransform( -vecTranslateCenter, matRotation, vecXFormCenter );
  656. int w, h;
  657. GetSize( w, h );
  658. float flW = (float)w;
  659. float flH = (float)h;
  660. float flFOVx = DEG2RAD( m_nFOV * 0.5f );
  661. float flFOVy = CalcFovY( ( m_nFOV * 0.5f ), flW/flH );
  662. flFOVy = DEG2RAD( flFOVy );
  663. float flTanFOVx = tan( flFOVx );
  664. float flTanFOVy = tan( flFOVy );
  665. // Find the max value of x, y, or z
  666. float flDist = 0.0f;
  667. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  668. {
  669. float flDistZ = fabs( aXFormPoints[iPoint].z / flTanFOVy - aXFormPoints[iPoint].x );
  670. float flDistY = fabs( aXFormPoints[iPoint].y / flTanFOVx - aXFormPoints[iPoint].x );
  671. float flTestDist = MAX( flDistZ, flDistY );
  672. flDist = MAX( flDist, flTestDist );
  673. }
  674. // Scale the object down by 10%.
  675. flDist *= 1.10f;
  676. // Add the framing offset.
  677. vecXFormCenter += m_pModelInfo->m_vecFramedOriginOffset;
  678. // Zoom to the frame distance
  679. m_pModelInfo->m_vecOriginOffset.x = flDist - vecXFormCenter.x;
  680. m_pModelInfo->m_vecOriginOffset.y = -vecXFormCenter.y;
  681. m_pModelInfo->m_vecOriginOffset.z = -vecXFormCenter.z;
  682. // Screen space points.
  683. Vector2D aScreenPoints[8];
  684. Vector aCameraPoints[8];
  685. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  686. {
  687. aCameraPoints[iPoint] = aXFormPoints[iPoint];
  688. aCameraPoints[iPoint].x += flDist;
  689. aScreenPoints[iPoint].x = aCameraPoints[iPoint].y / ( flTanFOVx * aCameraPoints[iPoint].x );
  690. aScreenPoints[iPoint].y = aCameraPoints[iPoint].z / ( flTanFOVy * aCameraPoints[iPoint].x );
  691. aScreenPoints[iPoint].x = ( aScreenPoints[iPoint].x * 0.5f + 0.5f ) * flW;
  692. aScreenPoints[iPoint].y = ( aScreenPoints[iPoint].y * 0.5f + 0.5f ) * flH;
  693. }
  694. // Find the min/max and center of the 2D bounding box of the object.
  695. Vector2D vecScreenMin( 99999.0f, 99999.0f ), vecScreenMax( -99999.0f, -99999.0f );
  696. for ( int iPoint = 0; iPoint < 8; ++iPoint )
  697. {
  698. vecScreenMin.x = MIN( vecScreenMin.x, aScreenPoints[iPoint].x );
  699. vecScreenMin.y = MIN( vecScreenMin.y, aScreenPoints[iPoint].y );
  700. vecScreenMax.x = MAX( vecScreenMax.x, aScreenPoints[iPoint].x );
  701. vecScreenMax.y = MAX( vecScreenMax.y, aScreenPoints[iPoint].y );
  702. }
  703. vecScreenMin.x = clamp( vecScreenMin.x, 0.0f, flW );
  704. vecScreenMin.y = clamp( vecScreenMin.y, 0.0f, flH );
  705. vecScreenMax.x = clamp( vecScreenMax.x, 0.0f, flW );
  706. vecScreenMax.y = clamp( vecScreenMax.y, 0.0f, flH );
  707. // Offset the view port based on the calculated model 2D center and the center of the viewport.
  708. Vector2D vecScreenCenter = ( vecScreenMax + vecScreenMin ) * 0.5f;
  709. m_pModelInfo->m_vecViewportOffset.x = -( ( flW * 0.5f ) - vecScreenCenter.x );
  710. m_pModelInfo->m_vecViewportOffset.y = -( ( flH * 0.5f ) - vecScreenCenter.y );
  711. }
  712. //-----------------------------------------------------------------------------
  713. // Purpose: Calculates the distance the camera should be at to frame the model on the screen.
  714. //-----------------------------------------------------------------------------
  715. void CModelPanel::CalculateFrameDistance( void )
  716. {
  717. m_flFrameDistance = 0;
  718. if ( !m_hModel )
  719. return;
  720. // Compute a bounding radius for the model
  721. const model_t *mod = modelinfo->GetModel( m_hModel->GetModelIndex() );
  722. if ( !mod )
  723. return;
  724. if ( m_bStartFramed )
  725. {
  726. CalculateFrameDistanceInternal( mod );
  727. }
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Purpose: Moves the camera forward/backward along the current view angle to
  731. // frame the model on the screen.
  732. //-----------------------------------------------------------------------------
  733. void CModelPanel::ZoomToFrameDistance( void )
  734. {
  735. if ( !m_flFrameDistance || !m_hModel )
  736. return;
  737. const model_t *mod = modelinfo->GetModel( m_hModel->GetModelIndex() );
  738. if ( !mod )
  739. return;
  740. // Move the model to the midpoint
  741. Vector mins, maxs, vecModelCenter;
  742. modelinfo->GetModelRenderBounds( mod, mins, maxs );
  743. VectorLerp( mins, maxs, 0.5f, vecModelCenter );
  744. vecModelCenter += m_pModelInfo->m_vecFramedOriginOffset;
  745. // Zoom to the frame distance
  746. m_pModelInfo->m_vecOriginOffset.x = m_flFrameDistance;
  747. m_pModelInfo->m_vecOriginOffset.y = -vecModelCenter.y;
  748. m_pModelInfo->m_vecOriginOffset.z = -vecModelCenter.z;
  749. }