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.

1076 lines
32 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "dme_controls/BaseAnimationSetEditor.h"
  7. #include "tier1/KeyValues.h"
  8. #include "tier2/fileutils.h"
  9. #include "vgui_controls/Splitter.h"
  10. #include "vgui_controls/Menu.h"
  11. #include "vgui_controls/Label.h"
  12. #include "vgui_controls/ToggleButton.h"
  13. #include "vgui_controls/ComboBox.h"
  14. #include "vgui_controls/FileOpenDialog.h"
  15. #include "vgui_controls/MessageBox.h"
  16. #include "vgui_controls/perforcefilelistframe.h"
  17. #include "studio.h"
  18. #include "dme_controls/BaseAnimSetAttributeSliderPanel.h"
  19. #include "dme_controls/BaseAnimSetPresetFaderPanel.h"
  20. #include "dme_controls/BaseAnimSetControlGroupPanel.h"
  21. #include "dme_controls/dmecontrols_utils.h"
  22. #include "dme_controls/dmepicker.h"
  23. #include "sfmobjects/exportfacialanimation.h"
  24. #include "movieobjects/dmechannel.h"
  25. #include "movieobjects/dmeanimationset.h"
  26. #include "movieobjects/dmeclip.h"
  27. #include "movieobjects/dmeanimationlist.h"
  28. #include "movieobjects/dmegamemodel.h"
  29. // memdbgon must be the last include file in a .cpp file!!!
  30. #include "tier0/memdbgon.h"
  31. using namespace vgui;
  32. #define ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT 38
  33. #define ANIMATION_SET_EDITOR_BUTTONTRAY_YPOS 12
  34. #define ANIMATION_SET_BUTTON_INSET 0
  35. struct AnimSetLayout_t
  36. {
  37. CBaseAnimationSetEditor::EAnimSetLayout_t type;
  38. const char *shortname;
  39. const char *contextmenulabel;
  40. };
  41. static AnimSetLayout_t g_AnimSetLayout[] =
  42. {
  43. { CBaseAnimationSetEditor::LAYOUT_SPLIT, "split", "#BxAnimSetSplitLayout" },
  44. { CBaseAnimationSetEditor::LAYOUT_VERTICAL, "vertical", "#BxAnimSetVerticalLayout" },
  45. { CBaseAnimationSetEditor::LAYOUT_HORIZONTAL, "horizontal", "#BxAnimSetHorizontalLayout" },
  46. };
  47. static const char *NameForLayout( CBaseAnimationSetEditor::EAnimSetLayout_t layout, bool menu )
  48. {
  49. int c = ARRAYSIZE( g_AnimSetLayout );
  50. for ( int i = 0; i < c; ++i )
  51. {
  52. const AnimSetLayout_t& data = g_AnimSetLayout[ i ];
  53. if ( data.type == layout )
  54. {
  55. return menu ? data.contextmenulabel : data.shortname;
  56. }
  57. }
  58. Assert( 0 );
  59. return menu ? g_AnimSetLayout[ 0 ].contextmenulabel : g_AnimSetLayout[ 0 ].shortname;
  60. }
  61. static CBaseAnimationSetEditor::EAnimSetLayout_t LayoutForName( const char *name )
  62. {
  63. int c = ARRAYSIZE( g_AnimSetLayout );
  64. for ( int i = 0; i < c; ++i )
  65. {
  66. const AnimSetLayout_t& data = g_AnimSetLayout[ i ];
  67. if ( !Q_stricmp( data.shortname, name ) )
  68. {
  69. return data.type;
  70. }
  71. }
  72. Assert( 0 );
  73. return CBaseAnimationSetEditor::LAYOUT_SPLIT;
  74. }
  75. CBaseAnimationSetEditor::CBaseAnimationSetEditor( vgui::Panel *parent, const char *className, bool bShowGroups ) :
  76. BaseClass( parent, className ),
  77. m_Layout( LAYOUT_SPLIT ),
  78. m_Images( false )
  79. {
  80. const char *modes[] =
  81. {
  82. "AS_OFF",
  83. "AS_PREVIEW",
  84. "AS_RECORD",
  85. "AS_PLAYBACK",
  86. };
  87. const char *imagefiles[] =
  88. {
  89. "tools/ifm/icon_recordingmode_off",
  90. "tools/ifm/icon_recordingmode_preview",
  91. "tools/ifm/icon_recordingmode_record",
  92. "tools/ifm/icon_recordingmode_playback",
  93. };
  94. int i;
  95. for ( i = 0 ; i < NUM_AS_RECORDING_STATES; ++i )
  96. {
  97. m_pState[ i ] = new ToggleButton( this, modes[ i ], "" );
  98. m_pState[ i ]->SetContentAlignment( Label::a_center );
  99. m_pState[ i ]->AddActionSignalTarget( this );
  100. m_pState[ i ]->SetVisible( bShowGroups );
  101. m_pState[ i ]->SetKeyBoardInputEnabled( false );
  102. }
  103. m_pSelectionModeType = new ToggleButton( this, "AnimSetSelectionModeType", "" );
  104. m_pSelectionModeType->SetContentAlignment( Label::a_center );
  105. m_pSelectionModeType->AddActionSignalTarget( this );
  106. m_pSelectionModeType->SetSelected( false );
  107. m_pSelectionModeType->SetKeyBoardInputEnabled( false );
  108. m_pComboBox = new ComboBox( this, "AnimationSets", 10, false );
  109. // m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_lock", false ) );
  110. // m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_eyedropper", false ) );
  111. // m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_selectionmodeactive", false ) );
  112. m_Images.AddImage( scheme()->GetImage( "tools/ifm/icon_selectionmodeattached", false ) );
  113. for ( i = 0; i < NUM_AS_RECORDING_STATES; ++i )
  114. {
  115. m_Images.AddImage( scheme()->GetImage( imagefiles[ i ], false ) );
  116. }
  117. int w, h;
  118. m_Images.GetImage( 1 )->GetContentSize( w, h );
  119. m_Images.GetImage( 1 )->SetSize( w, h );
  120. m_Images.GetImage( 2 )->GetContentSize( w, h );
  121. m_Images.GetImage( 2 )->SetSize( w, h );
  122. // SETUP_PANEL( this );
  123. PostMessage( GetVPanel(), new KeyValues( "OnChangeLayout", "value", m_Layout ) );
  124. PostMessage( GetVPanel(), new KeyValues( "PopulateAnimationSetsChoice" ) );
  125. m_pSelectionModeType->SetVisible( bShowGroups );
  126. m_pComboBox->SetVisible( bShowGroups );
  127. SetRecordingState( bShowGroups ? AS_PLAYBACK : AS_PREVIEW, true );
  128. m_hFileOpenStateMachine = new vgui::FileOpenStateMachine( this, this );
  129. m_hFileOpenStateMachine->AddActionSignalTarget( this );
  130. }
  131. CBaseAnimationSetEditor::~CBaseAnimationSetEditor()
  132. {
  133. }
  134. void CBaseAnimationSetEditor::CreateToolsSubPanels()
  135. {
  136. m_hControlGroup = new CBaseAnimSetControlGroupPanel( (Panel *)NULL, "AnimSetControlGroup", this );
  137. m_hPresetFader = new CBaseAnimSetPresetFaderPanel( (Panel *)NULL, "AnimSetPresetFader", this );
  138. m_hAttributeSlider = new CBaseAnimSetAttributeSliderPanel( (Panel *)NULL, "AnimSetAttributeSliderPanel", this );
  139. }
  140. void CBaseAnimationSetEditor::OnButtonToggled( KeyValues *params )
  141. {
  142. Panel *ptr = reinterpret_cast< Panel * >( params->GetPtr( "panel" ) );
  143. /*
  144. if ( ptr == m_pSelectionModeType )
  145. {
  146. // FIXME, could do this with MESSAGE_FUNC_PARAMS and look up "panel" ptr and compare to figure out which button was manipulated...
  147. g_pMovieMaker->SetTimeSelectionModeType( !m_pSelectionModeType->IsSelected() ? CIFMTool::MODE_DETACHED : CIFMTool::MODE_ATTACHED );
  148. }
  149. else
  150. */
  151. {
  152. for ( int i = 0; i < NUM_AS_RECORDING_STATES; ++i )
  153. {
  154. if ( ptr == m_pState[ i ] )
  155. {
  156. SetRecordingState( (RecordingState_t)i, true );
  157. break;
  158. }
  159. }
  160. }
  161. }
  162. void CBaseAnimationSetEditor::ChangeLayout( EAnimSetLayout_t newLayout )
  163. {
  164. int i;
  165. m_Layout = newLayout;
  166. // Make sure these don't get blown away...
  167. m_hControlGroup->SetParent( (Panel *)NULL );
  168. m_hPresetFader->SetParent( (Panel *)NULL );
  169. m_hAttributeSlider->SetParent( (Panel *)NULL );
  170. delete m_Splitter.Get();
  171. m_Splitter = NULL;
  172. CUtlVector< Panel * > list;
  173. list.AddToTail( m_hControlGroup.Get() );
  174. list.AddToTail( m_hPresetFader.Get() );
  175. list.AddToTail( m_hAttributeSlider.Get() );
  176. Splitter *sub = NULL;
  177. switch ( m_Layout )
  178. {
  179. default:
  180. case LAYOUT_SPLIT:
  181. {
  182. m_Splitter = new Splitter( this, "AnimSetEditorMainSplitter", SPLITTER_MODE_VERTICAL, 1 );
  183. m_Splitter->SetAutoResize
  184. (
  185. Panel::PIN_TOPLEFT,
  186. Panel::AUTORESIZE_DOWNANDRIGHT,
  187. 0, ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT,
  188. 0, 0
  189. );
  190. m_Splitter->SetBounds( 0, ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT, GetWide(), GetTall() - ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT );
  191. m_Splitter->SetSplitterColor( Color(32, 32, 32, 255) );
  192. // m_Splitter->EnableBorders( false );
  193. m_hControlGroup->SetParent( m_Splitter->GetChild( 0 ) );
  194. m_hControlGroup->SetAutoResize
  195. (
  196. Panel::PIN_TOPLEFT,
  197. Panel::AUTORESIZE_DOWNANDRIGHT,
  198. 0, 0,
  199. 0, 0
  200. );
  201. sub = new Splitter( m_Splitter->GetChild( 1 ), "AnimSetEditorSubSplitter", SPLITTER_MODE_HORIZONTAL, 1 );
  202. sub->SetAutoResize
  203. (
  204. Panel::PIN_TOPLEFT,
  205. Panel::AUTORESIZE_DOWNANDRIGHT,
  206. 0, 0,
  207. 0, 0
  208. );
  209. m_hPresetFader->SetParent( sub->GetChild( 0 ) );
  210. m_hPresetFader->SetAutoResize
  211. (
  212. Panel::PIN_TOPLEFT,
  213. Panel::AUTORESIZE_DOWNANDRIGHT,
  214. 0, 0,
  215. 0, 0
  216. );
  217. m_hAttributeSlider->SetParent( sub->GetChild( 1 ) );
  218. m_hAttributeSlider->SetAutoResize
  219. (
  220. Panel::PIN_TOPLEFT,
  221. Panel::AUTORESIZE_DOWNANDRIGHT,
  222. 0, 0,
  223. 0, 0
  224. );
  225. }
  226. break;
  227. case LAYOUT_VERTICAL:
  228. {
  229. m_Splitter = new Splitter( this, "AnimSetEditorMainSplitter", SPLITTER_MODE_VERTICAL, 2 );
  230. m_Splitter->SetSplitterColor( Color(32, 32, 32, 255) );
  231. m_Splitter->SetAutoResize
  232. (
  233. Panel::PIN_TOPLEFT,
  234. Panel::AUTORESIZE_DOWNANDRIGHT,
  235. 0, ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT,
  236. 0, 0
  237. );
  238. m_Splitter->SetBounds( 0, ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT, GetWide(), GetTall() - ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT );
  239. for ( i = 0; i < list.Count(); ++i )
  240. {
  241. list[ i ]->SetParent( m_Splitter->GetChild( i ) );
  242. list[ i ]->SetSize( m_Splitter->GetChild( i )->GetWide(), m_Splitter->GetChild( i )->GetTall() );
  243. list[ i ]->SetAutoResize
  244. (
  245. Panel::PIN_TOPLEFT,
  246. Panel::AUTORESIZE_DOWNANDRIGHT,
  247. 0, 0,
  248. 0, 0
  249. );
  250. }
  251. m_Splitter->EvenlyRespaceSplitters();
  252. }
  253. break;
  254. case LAYOUT_HORIZONTAL:
  255. {
  256. m_Splitter = new Splitter( this, "AnimSetEditorMainSplitter", SPLITTER_MODE_HORIZONTAL, 2 );
  257. m_Splitter->SetSplitterColor( Color(32, 32, 32, 255) );
  258. m_Splitter->SetAutoResize
  259. (
  260. Panel::PIN_TOPLEFT,
  261. Panel::AUTORESIZE_DOWNANDRIGHT,
  262. 0, ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT,
  263. 0, 0
  264. );
  265. m_Splitter->SetBounds( 0, ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT, GetWide(), GetTall() - ANIMATION_SET_EDITOR_BUTTONTRAY_HEIGHT );
  266. for ( i = 0; i < list.Count(); ++i )
  267. {
  268. list[ i ]->SetParent( m_Splitter->GetChild( i ) );
  269. list[ i ]->SetSize( m_Splitter->GetChild( i )->GetWide(), m_Splitter->GetChild( i )->GetTall() );
  270. list[ i ]->SetAutoResize
  271. (
  272. Panel::PIN_TOPLEFT,
  273. Panel::AUTORESIZE_DOWNANDRIGHT,
  274. 0, 0,
  275. 0, 0
  276. );
  277. }
  278. m_Splitter->EvenlyRespaceSplitters();
  279. }
  280. break;
  281. }
  282. if ( sub )
  283. {
  284. sub->OnSizeChanged( sub->GetWide(), sub->GetTall() );
  285. sub->EvenlyRespaceSplitters();
  286. }
  287. }
  288. void CBaseAnimationSetEditor::PerformLayout()
  289. {
  290. BaseClass::PerformLayout();
  291. int w, h;
  292. GetSize( w, h );
  293. int ypos = ANIMATION_SET_EDITOR_BUTTONTRAY_YPOS;
  294. int xpos = w - 25;
  295. m_pSelectionModeType->SetBounds( xpos, ypos, 20, 20 );
  296. for ( int i = NUM_AS_RECORDING_STATES - 1; i >= 0 ; --i )
  297. {
  298. xpos -= 23;
  299. m_pState[ i ]->SetBounds( xpos, ypos, 20, 20 );
  300. }
  301. m_pComboBox->SetBounds( 10, ypos, xpos - 10- 5, 20 );
  302. }
  303. void CBaseAnimationSetEditor::OnChangeLayout( int value )
  304. {
  305. ChangeLayout( ( EAnimSetLayout_t )value );
  306. }
  307. //-----------------------------------------------------------------------------
  308. // Finds a channel in the animation set to overwrite with import data
  309. //-----------------------------------------------------------------------------
  310. CDmeChannel* CBaseAnimationSetEditor::FindImportChannel( CDmeChannel *pChannel, CDmeChannelsClip *pChannelsClip )
  311. {
  312. CDmElement *pTargetElement = pChannel->GetToElement();
  313. if ( !pTargetElement )
  314. return NULL;
  315. CDmAttribute *pTargetAttribute = pChannel->GetToAttribute();
  316. if ( !pTargetAttribute )
  317. return NULL;
  318. const char *pTarget = pTargetAttribute->GetName();
  319. const char *pTargetName = pTargetElement->GetName();
  320. CDmeLog *pTargetLog = pChannel->GetLog();
  321. int nCount = pChannelsClip->m_Channels.Count();
  322. for ( int j = 0; j < nCount; ++j )
  323. {
  324. CDmeChannel *pImportChannel = pChannelsClip->m_Channels[j];
  325. if ( !pImportChannel )
  326. continue;
  327. CDmeLog *pImportLog = pImportChannel->GetLog();
  328. if ( !pImportLog )
  329. continue;
  330. if ( pTargetLog && ( pImportLog->GetType() != pTargetLog->GetType() ) )
  331. continue;
  332. if ( !pImportChannel->GetToAttribute() )
  333. continue;
  334. const char *pImportTarget = pImportChannel->GetToAttribute()->GetName();
  335. // Attribute to write into has to match exactly
  336. if ( Q_stricmp( pTarget, pImportTarget ) )
  337. continue;
  338. CDmElement *pImportTargetElement = pImportChannel->GetToElement();
  339. const char *pImportName = pImportTargetElement->GetName();
  340. // Element name has to match exactly or be of the form *(channel name)*
  341. if ( !Q_stricmp( pTargetName, pImportName ) )
  342. return pImportChannel;
  343. char pTemp[512];
  344. const char *pParen = strrchr( pTargetName, '(' );
  345. if ( !pParen )
  346. continue;
  347. Q_strncpy( pTemp, pParen+1, sizeof(pTemp) );
  348. char *pParen2 = strchr( pTemp, ')' );
  349. if ( !pParen2 )
  350. continue;
  351. *pParen2 = 0;
  352. if ( !Q_stricmp( pImportName, pTemp ) )
  353. return pImportChannel;
  354. }
  355. return NULL;
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Transforms an imported channel, if necessary
  359. //-----------------------------------------------------------------------------
  360. void CBaseAnimationSetEditor::TransformImportedChannel( CDmeChannel *pChannel )
  361. {
  362. CDmElement *pTarget = pChannel->GetToElement();
  363. const static UtlSymId_t symBones = g_pDataModel->GetSymbol( "bones" );
  364. CDmeGameModel *pGameModel = FindReferringElement<CDmeGameModel>( pTarget, symBones );
  365. if ( !pGameModel )
  366. return;
  367. int nBoneIndex = pGameModel->FindBone( CastElement< CDmeTransform >( pTarget ) );
  368. if ( nBoneIndex < 0 )
  369. return;
  370. // If we've got logs that have been imported, we need to compute our bounds.
  371. pGameModel->m_bComputeBounds = true;
  372. DmAttributeType_t logType = pChannel->GetLog()->GetDataType();
  373. int nLayerCount = pChannel->GetLog()->GetNumLayers();
  374. bool bHasPreTransform = false;
  375. bool bHasPostTransform = false;
  376. matrix3x4_t preTransform, postTransform;
  377. if ( pGameModel->GetSrcBoneTransforms( &preTransform, &postTransform, nBoneIndex ) )
  378. {
  379. bHasPreTransform = true;
  380. bHasPostTransform = true;
  381. }
  382. if ( pGameModel->IsRootTransform( nBoneIndex ) )
  383. {
  384. // NOTE: Root transforms require a pre-multiply of log data
  385. // Deal with the 'up axis' rotation
  386. matrix3x4_t rootTransform;
  387. RadianEuler angles( M_PI / 2.0f, 0.0f, M_PI / 2.0f );
  388. if ( bHasPreTransform )
  389. {
  390. AngleMatrix( angles, rootTransform );
  391. ConcatTransforms( rootTransform, preTransform, preTransform );
  392. }
  393. else
  394. {
  395. AngleMatrix( angles, preTransform );
  396. }
  397. bHasPreTransform = true;
  398. }
  399. if ( !bHasPreTransform && !bHasPostTransform )
  400. return;
  401. for ( int i = 0; i < nLayerCount; ++i )
  402. {
  403. if ( logType == AT_VECTOR3 )
  404. {
  405. CDmeVector3LogLayer *pPositionLog = CastElement< CDmeVector3LogLayer >( pChannel->GetLog()->GetLayer( i ) );
  406. if ( bHasPreTransform )
  407. {
  408. RotatePositionLog( pPositionLog, preTransform );
  409. }
  410. #ifdef _DEBUG
  411. // At the moment, we don't support anything but prerotation.
  412. // This would be tricky because we'd need to read the quat logs
  413. // to figure out how to translate in local space.
  414. if ( bHasPostTransform )
  415. {
  416. Assert( fabs( postTransform[0][3] ) < 1e-3 && fabs( postTransform[1][3] ) < 1e-3 && fabs( postTransform[2][3] ) < 1e-3 );
  417. }
  418. #endif
  419. }
  420. else
  421. {
  422. CDmeQuaternionLogLayer *pOrientationLog = CastElement< CDmeQuaternionLogLayer >( pChannel->GetLog()->GetLayer( i ) );
  423. if ( bHasPreTransform )
  424. {
  425. RotateOrientationLog( pOrientationLog, preTransform, true );
  426. }
  427. if ( bHasPostTransform )
  428. {
  429. RotateOrientationLog( pOrientationLog, postTransform, false );
  430. }
  431. }
  432. }
  433. }
  434. //-----------------------------------------------------------------------------
  435. // Expands channels clip time to encompass log
  436. //-----------------------------------------------------------------------------
  437. void CBaseAnimationSetEditor::FixupChannelsClipTime( CDmeChannelsClip *pChannelsClip, CDmeLog *pLog )
  438. {
  439. // Expand the channels clip to include the entire channel
  440. DmeTime_t st = pLog->GetBeginTime();
  441. DmeTime_t et = pLog->GetEndTime();
  442. st = pChannelsClip->FromChildMediaTime( st, false );
  443. et = pChannelsClip->FromChildMediaTime( et, false );
  444. if ( et < pChannelsClip->GetEndTime() )
  445. {
  446. et = pChannelsClip->GetEndTime();
  447. }
  448. if ( st < pChannelsClip->GetStartTime() )
  449. {
  450. DmeTime_t tDelta = pChannelsClip->GetStartTime() - st;
  451. DmeTime_t tOffset = pChannelsClip->GetTimeOffset();
  452. pChannelsClip->SetStartTime( st );
  453. pChannelsClip->SetTimeOffset( tOffset - tDelta );
  454. }
  455. else
  456. {
  457. st = pChannelsClip->GetStartTime();
  458. }
  459. DmeTime_t duration = et - st;
  460. if ( duration > pChannelsClip->GetDuration() )
  461. {
  462. pChannelsClip->SetDuration( duration );
  463. }
  464. }
  465. //-----------------------------------------------------------------------------
  466. // Expands channels clip time to encompass log
  467. //-----------------------------------------------------------------------------
  468. void CBaseAnimationSetEditor::FixupChannelsClipTime( CDmeChannel *pChannel, CDmeLog *pLog )
  469. {
  470. CUtlVector< CDmeChannelsClip* > clips;
  471. FindAncestorsReferencingElement( pChannel, clips );
  472. int nCount = clips.Count();
  473. for ( int i = 0; i < nCount; ++i )
  474. {
  475. FixupChannelsClipTime( clips[i], pLog );
  476. }
  477. }
  478. //-----------------------------------------------------------------------------
  479. // Imports a specific channels clip into the animation set
  480. //-----------------------------------------------------------------------------
  481. void CBaseAnimationSetEditor::OnImportConfirmed( KeyValues *pParams )
  482. {
  483. KeyValues *pImportParams = pParams->FindKey( "context" );
  484. CDmeChannelsClip *pChannelsClip = GetElementKeyValue< CDmeChannelsClip >( pImportParams, "channelsClip" );
  485. if ( pParams->GetInt( "operationPerformed" ) == 0 )
  486. {
  487. CDisableUndoScopeGuard sg;
  488. g_pDataModel->RemoveFileId( pChannelsClip->GetFileId() );
  489. return;
  490. }
  491. bool bVisibleOnly = pImportParams->GetInt( "visibleOnly" ) != 0;
  492. CUtlVector< LogPreview_t > controls;
  493. int nCount = bVisibleOnly ? BuildVisibleControlList( controls ) : BuildFullControlList( controls );
  494. CUndoScopeGuard guard( "Import Animation" );
  495. for ( int i = 0; i < nCount; ++i )
  496. {
  497. for ( int k = 0; k < LOG_PREVIEW_MAX_CHANNEL_COUNT; ++k )
  498. {
  499. CDmeChannel *pChannel = controls[i].m_hChannels[k];
  500. if ( !pChannel )
  501. continue;
  502. CDmeChannel *pImportChannel = FindImportChannel( pChannel, pChannelsClip );
  503. if ( !pImportChannel )
  504. continue;
  505. // Switch the log over
  506. CDmeLog *pImportLog = pImportChannel->GetLog();
  507. pChannel->SetLog( pImportLog );
  508. pImportChannel->SetLog( NULL );
  509. pImportLog->SetFileId( pChannel->GetFileId(), TD_DEEP );
  510. TransformImportedChannel( pChannel );
  511. // Expand the channels clip to include the entire channel
  512. FixupChannelsClipTime( pChannel, pChannel->GetLog() );
  513. }
  514. }
  515. guard.Release();
  516. // Cleanup the file
  517. CDisableUndoScopeGuard sg;
  518. g_pDataModel->RemoveFileId( pChannelsClip->GetFileId() );
  519. }
  520. //-----------------------------------------------------------------------------
  521. // Imports a specific channels clip into the animation set
  522. //-----------------------------------------------------------------------------
  523. void CBaseAnimationSetEditor::ImportAnimation( CDmeChannelsClip *pChannelsClip, bool bVisibleOnly )
  524. {
  525. CUtlVector< LogPreview_t > controls;
  526. int nCount = bVisibleOnly ? BuildVisibleControlList( controls ) : BuildFullControlList( controls );
  527. COperationFileListFrame *pStatusFrame = new COperationFileListFrame( this,
  528. "Import the Following Channels?", "Target Control", false );
  529. pStatusFrame->SetCloseButtonVisible( false );
  530. pStatusFrame->SetOperationColumnHeaderText( "Source Channel" );
  531. int nSrcCount = pChannelsClip->m_Channels.Count();
  532. CDmeChannel** ppFoundChannels = (CDmeChannel**)_alloca( nSrcCount * sizeof(CDmeChannel*) );
  533. int nFoundCount = 0;
  534. for ( int i = 0; i < nCount; ++i )
  535. {
  536. for ( int k = 0; k < LOG_PREVIEW_MAX_CHANNEL_COUNT; ++k )
  537. {
  538. CDmeChannel *pChannel = controls[i].m_hChannels[k];
  539. if ( !pChannel || pChannel->GetToElement() == NULL )
  540. continue;
  541. char pChannelInfo[512];
  542. Q_snprintf( pChannelInfo, sizeof(pChannelInfo), "\"%s\" : %s",
  543. pChannel->GetToElement()->GetName(), pChannel->GetToAttribute()->GetName() );
  544. CDmeChannel *pImportChannel = FindImportChannel( pChannel, pChannelsClip );
  545. if ( !pImportChannel )
  546. {
  547. pStatusFrame->AddOperation( "No source channel", pChannelInfo, Color( 255, 0, 0, 255 ) );
  548. continue;
  549. }
  550. ppFoundChannels[nFoundCount++] = pImportChannel;
  551. char pImportInfo[512];
  552. Q_snprintf( pImportInfo, sizeof(pImportInfo), "\"%s\" : %s",
  553. pImportChannel->GetToElement()->GetName(), pImportChannel->GetToAttribute()->GetName() );
  554. pStatusFrame->AddOperation( pImportInfo, pChannelInfo, Color( 0, 255, 0, 255 ) );
  555. }
  556. }
  557. for ( int i = 0; i < nSrcCount; ++i )
  558. {
  559. CDmeChannel *pMissingChannel = pChannelsClip->m_Channels[i];
  560. int j;
  561. for ( j = 0; j < nFoundCount; ++j )
  562. {
  563. if ( ppFoundChannels[j] == pMissingChannel )
  564. break;
  565. }
  566. if ( j != nFoundCount )
  567. continue;
  568. char pImportInfo[512];
  569. Q_snprintf( pImportInfo, sizeof(pImportInfo), "\"%s\" : %s",
  570. pMissingChannel->GetToElement()->GetName(), pMissingChannel->GetToAttribute()->GetName() );
  571. pStatusFrame->AddOperation( pImportInfo, "No destination control", Color( 255, 255, 0, 255 ) );
  572. }
  573. KeyValues *pContext = new KeyValues( "context" );
  574. SetElementKeyValue( pContext, "channelsClip", pChannelsClip );
  575. pContext->SetInt( "visibleOnly", bVisibleOnly );
  576. pStatusFrame->DoModal( pContext, "ImportConfirmed" );
  577. }
  578. //-----------------------------------------------------------------------------
  579. // Called by CDmePickerFrame in SelectImportAnimation
  580. //-----------------------------------------------------------------------------
  581. void CBaseAnimationSetEditor::OnImportAnimationSelected( KeyValues *pParams )
  582. {
  583. KeyValues *pContextKeyValues = pParams->FindKey( "context" );
  584. CDmeChannelsClip *pChannelsClip = GetElementKeyValue< CDmeChannelsClip >( pParams, "dme" );
  585. if ( pChannelsClip )
  586. {
  587. bool bVisibleOnly = pContextKeyValues->GetInt( "visibleOnly" ) != 0;
  588. ImportAnimation( pChannelsClip, bVisibleOnly );
  589. }
  590. else
  591. {
  592. OnImportAnimationCancelled( pParams );
  593. }
  594. }
  595. //-----------------------------------------------------------------------------
  596. // Called by CDmePickerFrame in SelectImportAnimation
  597. //-----------------------------------------------------------------------------
  598. void CBaseAnimationSetEditor::OnImportAnimationCancelled( KeyValues *pParams )
  599. {
  600. KeyValues *pContextKeyValues = pParams->FindKey( "context" );
  601. CDmElement *pAnimationList = GetElementKeyValue<CDmElement>( pContextKeyValues, "animationList" );
  602. // Cleanup the file
  603. if ( pAnimationList )
  604. {
  605. CDisableUndoScopeGuard sg;
  606. g_pDataModel->RemoveFileId( pAnimationList->GetFileId() );
  607. }
  608. }
  609. //-----------------------------------------------------------------------------
  610. // Selects an animation to import
  611. //-----------------------------------------------------------------------------
  612. void CBaseAnimationSetEditor::SelectImportAnimation( CDmeAnimationList *pAnimationList, bool bVisibleOnly )
  613. {
  614. KeyValues *pContextKeyValues = new KeyValues( "context" );
  615. SetElementKeyValue( pContextKeyValues, "animationList", pAnimationList );
  616. pContextKeyValues->SetInt( "visibleOnly", bVisibleOnly );
  617. int nCount = pAnimationList->GetAnimationCount();
  618. CUtlVector< DmePickerInfo_t > choices( 0, nCount );
  619. for ( int i = 0; i < nCount; ++i )
  620. {
  621. CDmeChannelsClip *pAnimation = pAnimationList->GetAnimation( i );
  622. if ( !pAnimation )
  623. continue;
  624. int j = choices.AddToTail();
  625. DmePickerInfo_t& info = choices[j];
  626. info.m_hElement = pAnimation->GetHandle();
  627. info.m_pChoiceString = pAnimation->GetName();
  628. }
  629. CDmePickerFrame *pAnimationPicker = new CDmePickerFrame( this, "Select Animation To Import" );
  630. pAnimationPicker->DoModal( choices, pContextKeyValues );
  631. }
  632. //-----------------------------------------------------------------------------
  633. // Called by the FileOpenDialog in OnImportAnimation
  634. //-----------------------------------------------------------------------------
  635. void CBaseAnimationSetEditor::OnFileSelected( KeyValues *kv )
  636. {
  637. KeyValues *pContextKeyValues = kv->FindKey( "ImportAnimation" );
  638. if ( !pContextKeyValues )
  639. return;
  640. bool bVisibleOnly = pContextKeyValues->GetInt( "visibleOnly" );
  641. if ( bVisibleOnly )
  642. {
  643. CUtlVector< LogPreview_t > controls;
  644. int nCount = BuildVisibleControlList( controls );
  645. if ( nCount == 0 )
  646. {
  647. vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Error Importing Animations\n",
  648. "Cannot import because there are no visible controls!\n", GetParent() );
  649. pMessageBox->DoModal( );
  650. return;
  651. }
  652. }
  653. const char *pFileName = kv->GetString( "fullpath", NULL );
  654. if ( !pFileName )
  655. return;
  656. CDmElement *pRoot;
  657. CDisableUndoScopeGuard guard;
  658. DmFileId_t fileId = g_pDataModel->RestoreFromFile( pFileName, NULL, NULL, &pRoot, CR_FORCE_COPY );
  659. guard.Release();
  660. if ( fileId == DMFILEID_INVALID )
  661. return;
  662. CDmeChannelsClip *pChannelsClip = CastElement< CDmeChannelsClip >( pRoot );
  663. if ( pChannelsClip )
  664. {
  665. ImportAnimation( pChannelsClip, bVisibleOnly );
  666. return;
  667. }
  668. CDmeAnimationList* pAnimationList = CastElement< CDmeAnimationList >( pRoot );
  669. if ( !pAnimationList )
  670. {
  671. pAnimationList = pRoot->GetValueElement< CDmeAnimationList >( "animationList" );
  672. }
  673. if ( !pAnimationList || pAnimationList->GetAnimationCount() == 0 )
  674. {
  675. char pBuf[1024];
  676. Q_snprintf( pBuf, sizeof(pBuf), "File \"%s\" contains no animations!\n", pFileName );
  677. vgui::MessageBox *pMessageBox = new vgui::MessageBox( "Error Importing Animations\n", pBuf, GetParent() );
  678. pMessageBox->DoModal( );
  679. CDisableUndoScopeGuard sg;
  680. g_pDataModel->RemoveFileId( pRoot->GetFileId() );
  681. sg.Release();
  682. return;
  683. }
  684. if ( pAnimationList->GetAnimationCount() == 1 )
  685. {
  686. ImportAnimation( pAnimationList->GetAnimation( 0 ), bVisibleOnly );
  687. }
  688. else
  689. {
  690. SelectImportAnimation( pAnimationList, bVisibleOnly );
  691. }
  692. }
  693. //-----------------------------------------------------------------------------
  694. // Called by the context menu to import animation files
  695. //-----------------------------------------------------------------------------
  696. void CBaseAnimationSetEditor::OnImportAnimation( KeyValues *pParams )
  697. {
  698. // Compute starting directory
  699. CDmeGameModel *pGameModel = m_AnimSet->GetValueElement< CDmeGameModel >( "gameModel" );
  700. char pStartingDir[ MAX_PATH ];
  701. if ( !pGameModel )
  702. {
  703. GetModContentSubdirectory( "models", pStartingDir, sizeof(pStartingDir) );
  704. }
  705. else
  706. {
  707. char pModelName[ MAX_PATH ];
  708. studiohdr_t *pStudioHdr = pGameModel->GetStudioHdr();
  709. Q_StripExtension( pStudioHdr->pszName(), pModelName, sizeof(pModelName) );
  710. char pRelativePath[ MAX_PATH ];
  711. Q_snprintf( pRelativePath, sizeof(pRelativePath), "models/%s/animations/dmx", pModelName );
  712. GetModContentSubdirectory( pRelativePath, pStartingDir, sizeof(pStartingDir) );
  713. if ( !g_pFullFileSystem->IsDirectory( pStartingDir ) )
  714. {
  715. Q_snprintf( pRelativePath, sizeof(pRelativePath), "models/%s", pModelName );
  716. GetModContentSubdirectory( pRelativePath, pStartingDir, sizeof(pStartingDir) );
  717. if ( !g_pFullFileSystem->IsDirectory( pStartingDir ) )
  718. {
  719. GetModContentSubdirectory( "models", pStartingDir, sizeof(pStartingDir) );
  720. }
  721. }
  722. }
  723. KeyValues *pContextKeyValues = new KeyValues( "ImportAnimation", "visibleOnly", pParams->GetInt( "visibleOnly" ) );
  724. FileOpenDialog *pDialog = new FileOpenDialog( this, "Select Animation File Name", true, pContextKeyValues );
  725. pDialog->SetStartDirectoryContext( "animation_set_import_animation", pStartingDir );
  726. pDialog->AddFilter( "*.*", "All Files (*.*)", false );
  727. pDialog->AddFilter( "*.dmx", "Animation file (*.dmx)", true );
  728. pDialog->SetDeleteSelfOnClose( true );
  729. pDialog->AddActionSignalTarget( this );
  730. pDialog->DoModal( );
  731. }
  732. //-----------------------------------------------------------------------------
  733. // Main entry point for exporting facial animation
  734. //-----------------------------------------------------------------------------
  735. void CBaseAnimationSetEditor::SetupFileOpenDialog( vgui::FileOpenDialog *pDialog,
  736. bool bOpenFile, const char *pFileFormat, KeyValues *pContextKeyValues )
  737. {
  738. // Compute starting directory
  739. char pStartingDir[ MAX_PATH ];
  740. GetModSubdirectory( "scenes", pStartingDir, sizeof(pStartingDir) );
  741. Assert( !bOpenFile );
  742. pDialog->SetTitle( "Save Facial Animation As", true );
  743. Assert( !V_strcmp( pFileFormat, "facial_animation" ) );
  744. pDialog->SetStartDirectoryContext( "facial_animation_export", pStartingDir );
  745. pDialog->AddFilter( "*.*", "All Files (*.*)", false );
  746. pDialog->AddFilter( "*.dmx", "Facial animation file (*.dmx)", true, pFileFormat );
  747. }
  748. bool CBaseAnimationSetEditor::OnReadFileFromDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
  749. {
  750. Assert( 0 );
  751. return false;
  752. }
  753. //-----------------------------------------------------------------------------
  754. // Called when it's time to write the file
  755. //-----------------------------------------------------------------------------
  756. bool CBaseAnimationSetEditor::OnWriteFileToDisk( const char *pFileName, const char *pFileFormat, KeyValues *pContextKeyValues )
  757. {
  758. // Recompute relative paths for each source now that we know the file name
  759. // NOTE: This also updates the name of the fileID in the datamodel system
  760. CDisableUndoScopeGuard guard;
  761. bool bOk = ExportFacialAnimation( pFileName, GetRootClip(), GetAnimationSetClip(), m_AnimSet );
  762. return bOk;
  763. }
  764. //-----------------------------------------------------------------------------
  765. // Main entry point for exporting facial animation
  766. //-----------------------------------------------------------------------------
  767. void CBaseAnimationSetEditor::OnExportFacialAnimation()
  768. {
  769. KeyValues *pContextKeyValues = new KeyValues( "ExportFacialAnimation" );
  770. m_hFileOpenStateMachine->SaveFile( pContextKeyValues, NULL, "facial_animation", FOSM_SHOW_PERFORCE_DIALOGS );
  771. }
  772. void CBaseAnimationSetEditor::OnOpenContextMenu( KeyValues *params )
  773. {
  774. if ( m_hContextMenu.Get() )
  775. {
  776. delete m_hContextMenu.Get();
  777. m_hContextMenu = NULL;
  778. }
  779. m_hContextMenu = new Menu( this, "ActionMenu" );
  780. int c = ARRAYSIZE( g_AnimSetLayout );
  781. for ( int i = 0; i < c; ++i )
  782. {
  783. const AnimSetLayout_t& data = g_AnimSetLayout[ i ];
  784. m_hContextMenu->AddMenuItem( data.contextmenulabel, new KeyValues( "OnChangeLayout", "value", (int)data.type ), this );
  785. }
  786. if ( m_AnimSet.Get() )
  787. {
  788. m_hContextMenu->AddSeparator( );
  789. m_hContextMenu->AddMenuItem( "#ImportAnimation", new KeyValues( "ImportAnimation" ), this );
  790. m_hContextMenu->AddMenuItem( "#ReattachToModel", new KeyValues( "ReattachToModel" ), this );
  791. m_hContextMenu->AddMenuItem( "#ExportFacialAnimation", new KeyValues( "ExportFacialAnimation" ), this );
  792. }
  793. Panel *rpanel = reinterpret_cast< Panel * >( params->GetPtr( "contextlabel" ) );
  794. if ( rpanel )
  795. {
  796. // force the menu to compute required width/height
  797. m_hContextMenu->PerformLayout();
  798. m_hContextMenu->PositionRelativeToPanel( rpanel, Menu::DOWN, 0, true );
  799. }
  800. else
  801. {
  802. Menu::PlaceContextMenu( this, m_hContextMenu.Get() );
  803. }
  804. }
  805. void CBaseAnimationSetEditor::ApplySchemeSettings( vgui::IScheme *pScheme )
  806. {
  807. BaseClass::ApplySchemeSettings( pScheme );
  808. // Have to manually apply settings here if they aren't attached in hierarchy
  809. if ( m_hControlGroup->GetParent() != this )
  810. {
  811. m_hControlGroup->ApplySchemeSettings( pScheme );
  812. }
  813. if ( m_hPresetFader->GetParent() != this )
  814. {
  815. m_hPresetFader->ApplySchemeSettings( pScheme );
  816. }
  817. if ( m_hAttributeSlider->GetParent() != this )
  818. {
  819. m_hAttributeSlider->ApplySchemeSettings( pScheme );
  820. }
  821. m_pSelectionModeType->ClearImages();
  822. m_pSelectionModeType->AddImage( m_Images.GetImage( 1 ), 0 );
  823. for ( int i = 0; i < NUM_AS_RECORDING_STATES; ++i )
  824. {
  825. m_pState[ i ]->ClearImages();
  826. m_pState[ i ]->AddImage( m_Images.GetImage( i + 2 ), 0 );
  827. }
  828. m_pComboBox->SetFont( pScheme->GetFont( "DefaultBold" ) );
  829. }
  830. CBaseAnimSetControlGroupPanel *CBaseAnimationSetEditor::GetControlGroup()
  831. {
  832. return m_hControlGroup.Get();
  833. }
  834. CBaseAnimSetPresetFaderPanel *CBaseAnimationSetEditor::GetPresetFader()
  835. {
  836. return m_hPresetFader.Get();
  837. }
  838. CBaseAnimSetAttributeSliderPanel *CBaseAnimationSetEditor::GetAttributeSlider()
  839. {
  840. return m_hAttributeSlider.Get();
  841. }
  842. void CBaseAnimationSetEditor::ChangeAnimationSet( CDmeAnimationSet *newAnimSet )
  843. {
  844. m_AnimSet = newAnimSet;
  845. if ( newAnimSet )
  846. {
  847. CUndoScopeGuard guard( "Auto-create Procedural Presets" );
  848. newAnimSet->EnsureProceduralPresets();
  849. }
  850. // send to sub controls
  851. m_hControlGroup->ChangeAnimationSet( newAnimSet );
  852. m_hPresetFader->ChangeAnimationSet( newAnimSet );
  853. m_hAttributeSlider->ChangeAnimationSet( newAnimSet );
  854. }
  855. void CBaseAnimationSetEditor::OnDataChanged()
  856. {
  857. }
  858. void CBaseAnimationSetEditor::OnTextChanged()
  859. {
  860. KeyValues *kv = m_pComboBox->GetActiveItemUserData();
  861. if ( !kv )
  862. return;
  863. CDmeAnimationSet *set = GetElementKeyValue< CDmeAnimationSet >( kv, "handle" );
  864. if ( set )
  865. {
  866. ChangeAnimationSet( set );
  867. }
  868. }
  869. void CBaseAnimationSetEditor::SetRecordingState( RecordingState_t state, bool /*updateSettings*/ )
  870. {
  871. m_RecordingState = state;
  872. // Reset buttons as needed
  873. for ( int i = 0; i < NUM_AS_RECORDING_STATES; ++i )
  874. {
  875. if ( (RecordingState_t)i == state )
  876. {
  877. m_pState[ i ]->SetSelected( true );
  878. m_pState[ i ]->ForceDepressed( true );
  879. }
  880. else
  881. {
  882. m_pState[ i ]->SetSelected( false );
  883. m_pState[ i ]->ForceDepressed( false );
  884. }
  885. }
  886. }
  887. RecordingState_t CBaseAnimationSetEditor::GetRecordingState() const
  888. {
  889. return m_RecordingState;
  890. }
  891. CDmeAnimationSet *CBaseAnimationSetEditor::GetAnimationSet()
  892. {
  893. return m_AnimSet;
  894. }
  895. int CBaseAnimationSetEditor::BuildVisibleControlList( CUtlVector< LogPreview_t >& list )
  896. {
  897. return m_hAttributeSlider->BuildVisibleControlList( list );
  898. }
  899. int CBaseAnimationSetEditor::BuildFullControlList( CUtlVector< LogPreview_t >& list )
  900. {
  901. return m_hAttributeSlider->BuildFullControlList( list );
  902. }
  903. void CBaseAnimationSetEditor::RecomputePreview()
  904. {
  905. m_hAttributeSlider->RecomputePreview();
  906. }