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.

947 lines
27 KiB

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