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.

11647 lines
262 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //===========================================================================//
  7. #include "cbase.h"
  8. #include <stdio.h>
  9. #include <mxtk/mxWindow.h>
  10. #include "mdlviewer.h"
  11. #include "hlfaceposer.h"
  12. #include "StudioModel.h"
  13. #include "expressions.h"
  14. #include "expclass.h"
  15. #include "ChoreoView.h"
  16. #include "choreoevent.h"
  17. #include "choreoactor.h"
  18. #include "choreochannel.h"
  19. #include "choreoscene.h"
  20. #include "choreowidget.h"
  21. #include "choreoactorwidget.h"
  22. #include "choreochannelwidget.h"
  23. #include "choreoglobaleventwidget.h"
  24. #include "choreowidgetdrawhelper.h"
  25. #include "choreoeventwidget.h"
  26. #include "viewerSettings.h"
  27. #include "filesystem.h"
  28. #include "choreoviewcolors.h"
  29. #include "ActorProperties.h"
  30. #include "ChannelProperties.h"
  31. #include "EventProperties.h"
  32. #include "GlobalEventProperties.h"
  33. #include "ifaceposersound.h"
  34. #include "snd_wave_source.h"
  35. #include "ifaceposerworkspace.h"
  36. #include "PhonemeEditor.h"
  37. #include "iscenetokenprocessor.h"
  38. #include "InputProperties.h"
  39. #include "filesystem.h"
  40. #include "ExpressionTool.h"
  41. #include "ControlPanel.h"
  42. #include "faceposer_models.h"
  43. #include "choiceproperties.h"
  44. #include "MatSysWin.h"
  45. #include "tier1/strtools.h"
  46. #include "GestureTool.h"
  47. #include "npcevent.h"
  48. #include "RampTool.h"
  49. #include "SceneRampTool.h"
  50. #include "KeyValues.h"
  51. #include "SoundEmitterSystem/isoundemittersystembase.h"
  52. #include "cclookup.h"
  53. #include "iclosecaptionmanager.h"
  54. #include "AddSoundEntry.h"
  55. #include "isoundcombiner.h"
  56. #include <vgui/ILocalize.h>
  57. #include "scriplib.h"
  58. #include "WaveBrowser.h"
  59. #include "filesystem_init.h"
  60. #include "flexpanel.h"
  61. #include "tier3/choreoutils.h"
  62. #include "tier2/p4helpers.h"
  63. using namespace vgui;
  64. extern vgui::ILocalize *g_pLocalize;
  65. // 10x magnification
  66. #define MAX_TIME_ZOOM 1000
  67. #define TIME_ZOOM_STEP 4
  68. #define PHONEME_FILTER 0.08f
  69. #define PHONEME_DELAY 0.0f
  70. #define SCRUBBER_HEIGHT 15
  71. #define TIMELINE_NUMBERS_HEIGHT 11
  72. #define COPYPASTE_FILENAME "scenes/copydatavcd.txt"
  73. extern double realtime;
  74. extern bool NameLessFunc( const char *const& name1, const char *const& name2 );
  75. // Try to keep shifted times at same absolute time
  76. static void RescaleExpressionTimes( CChoreoEvent *event, float newstart, float newend )
  77. {
  78. if ( !event || event->GetType() != CChoreoEvent::FLEXANIMATION )
  79. return;
  80. // Did it actually change
  81. if ( newstart == event->GetStartTime() &&
  82. newend == event->GetEndTime() )
  83. {
  84. return;
  85. }
  86. float newduration = newend - newstart;
  87. float dt = 0.0f;
  88. //If the end is moving, leave tags stay where they are (dt == 0.0f)
  89. if ( newstart != event->GetStartTime() )
  90. {
  91. // Otherwise, if the new start is later, then tags need to be shifted backwards
  92. dt -= ( newstart - event->GetStartTime() );
  93. }
  94. int count = event->GetNumFlexAnimationTracks();
  95. int i;
  96. for ( i = 0; i < count; i++ )
  97. {
  98. CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
  99. if ( !track )
  100. continue;
  101. for ( int type = 0; type < 2; type++ )
  102. {
  103. int sampleCount = track->GetNumSamples( type );
  104. for ( int sample = sampleCount - 1; sample >= 0 ; sample-- )
  105. {
  106. CExpressionSample *s = track->GetSample( sample, type );
  107. if ( !s )
  108. continue;
  109. s->time += dt;
  110. if ( s->time > newduration || s->time < 0.0f )
  111. {
  112. track->RemoveSample( sample, type );
  113. }
  114. }
  115. }
  116. }
  117. }
  118. static void RescaleRamp( CChoreoEvent *event, float newduration )
  119. {
  120. float oldduration = event->GetDuration();
  121. if ( fabs( oldduration - newduration ) < 0.000001f )
  122. return;
  123. if ( newduration <= 0.0f )
  124. return;
  125. float midpointtime = oldduration * 0.5f;
  126. float newmidpointtime = newduration * 0.5f;
  127. int count = event->GetRampCount();
  128. int i;
  129. for ( i = 0; i < count; i++ )
  130. {
  131. CExpressionSample *sample = event->GetRamp( i );
  132. if ( !sample )
  133. continue;
  134. float t = sample->time;
  135. if ( t < midpointtime )
  136. continue;
  137. float timefromend = oldduration - t;
  138. // There's room to just shift it
  139. if ( timefromend <= newmidpointtime )
  140. {
  141. t = newduration - timefromend;
  142. }
  143. else
  144. {
  145. // No room, rescale them instead
  146. float frac = ( t - midpointtime ) / midpointtime;
  147. t = newmidpointtime + frac * newmidpointtime;
  148. }
  149. sample->time = t;
  150. }
  151. }
  152. bool DoesAnyActorHaveAssociatedModelLoaded( CChoreoScene *scene )
  153. {
  154. if ( !scene )
  155. return false;
  156. int c = scene->GetNumActors();
  157. int i;
  158. for ( i = 0; i < c; i++ )
  159. {
  160. CChoreoActor *a = scene->GetActor( i );
  161. if ( !a )
  162. continue;
  163. char const *modelname = a->GetFacePoserModelName();
  164. if ( !modelname )
  165. continue;
  166. if ( !modelname[ 0 ] )
  167. continue;
  168. char mdlname[ 256 ];
  169. Q_strncpy( mdlname, modelname, sizeof( mdlname ) );
  170. Q_FixSlashes( mdlname );
  171. int idx = models->FindModelByFilename( mdlname );
  172. if ( idx >= 0 )
  173. {
  174. return true;
  175. }
  176. }
  177. return false;
  178. }
  179. //-----------------------------------------------------------------------------
  180. // Purpose:
  181. // Input : *a -
  182. // Output : StudioModel
  183. //-----------------------------------------------------------------------------
  184. StudioModel *FindAssociatedModel( CChoreoScene *scene, CChoreoActor *a )
  185. {
  186. if ( !a || !scene )
  187. return NULL;
  188. Assert( models->GetActiveStudioModel() );
  189. StudioModel *model = NULL;
  190. if ( a->GetFacePoserModelName()[ 0 ] )
  191. {
  192. int idx = models->FindModelByFilename( a->GetFacePoserModelName() );
  193. if ( idx >= 0 )
  194. {
  195. model = models->GetStudioModel( idx );
  196. return model;
  197. }
  198. }
  199. // Is there any loaded model with the actorname in it?
  200. int c = models->Count();
  201. for ( int i = 0; i < c; i++ )
  202. {
  203. char const *modelname = models->GetModelName( i );
  204. if ( !Q_stricmp( modelname, a->GetName() ) )
  205. {
  206. return models->GetStudioModel( i );
  207. }
  208. }
  209. // Does any actor have an associated model which is loaded
  210. if ( DoesAnyActorHaveAssociatedModelLoaded( scene ) )
  211. {
  212. // Then return NULL here so we don't override with the default an actor who has a valid model going
  213. return NULL;
  214. }
  215. // Couldn't find it and nobody else has a loaded associated model, so just use the default model
  216. if ( !model )
  217. {
  218. model = models->GetActiveStudioModel();
  219. }
  220. return model;
  221. }
  222. CChoreoView *g_pChoreoView = 0;
  223. //-----------------------------------------------------------------------------
  224. // Purpose:
  225. // Input : *parent -
  226. // x -
  227. // y -
  228. // w -
  229. // h -
  230. // id -
  231. //-----------------------------------------------------------------------------
  232. CChoreoView::CChoreoView( mxWindow *parent, int x, int y, int w, int h, int id )
  233. : IFacePoserToolWindow( "CChoreoView", "Choreography" ), mxWindow( parent, x, y, w, h )
  234. {
  235. m_bRampOnly = false;
  236. m_bForceProcess = false;
  237. m_bSuppressLayout = true;
  238. SetAutoProcess( true );
  239. m_flLastMouseClickTime = -1.0f;
  240. m_bProcessSequences = true;
  241. m_flPlaybackRate = 1.0f;
  242. m_pScene = NULL;
  243. m_flScrub = 0.0f;
  244. m_flScrubTarget = 0.0f;
  245. m_bCanDraw = false;
  246. m_bRedoPending = false;
  247. m_nUndoLevel = 0;
  248. CChoreoEventWidget::LoadImages();
  249. CChoreoWidget::m_pView = this;
  250. setId( id );
  251. m_flLastSpeedScale = 0.0f;
  252. m_bResetSpeedScale = false;
  253. m_nTopOffset = 0;
  254. m_flLeftOffset = 0.0f;
  255. m_nLastHPixelsNeeded = -1;
  256. m_nLastVPixelsNeeded = -1;
  257. m_nStartRow = 45;
  258. m_nLabelWidth = 140;
  259. m_nRowHeight = 35;
  260. m_bSimulating = false;
  261. m_bPaused = false;
  262. m_bForward = true;
  263. m_flStartTime = 0.0f;
  264. m_flEndTime = 0.0f;
  265. m_flFrameTime = 0.0f;
  266. m_bAutomated = false;
  267. m_nAutomatedAction = SCENE_ACTION_UNKNOWN;
  268. m_flAutomationDelay = 0.0f;
  269. m_flAutomationTime = 0.0f;
  270. m_pVertScrollBar = new mxScrollbar( this, 0, 0, 18, 100, IDC_CHOREOVSCROLL, mxScrollbar::Vertical );
  271. m_pHorzScrollBar = new mxScrollbar( this, 0, 0, 18, 100, IDC_CHOREOHSCROLL, mxScrollbar::Horizontal );
  272. m_bLayoutIsValid = false;
  273. m_flPixelsPerSecond = 150.0f;
  274. m_btnPlay = new mxBitmapButton( this, 2, 4, 16, 16, IDC_PLAYSCENE, "gfx/hlfaceposer/play.bmp" );
  275. m_btnPause = new mxBitmapButton( this, 18, 4, 16, 16, IDC_PAUSESCENE, "gfx/hlfaceposer/pause.bmp" );
  276. m_btnStop = new mxBitmapButton( this, 34, 4, 16, 16, IDC_STOPSCENE, "gfx/hlfaceposer/stop.bmp" );
  277. m_pPlaybackRate = new mxSlider( this, 0, 0, 16, 16, IDC_CHOREO_PLAYBACKRATE );
  278. m_pPlaybackRate->setRange( 0.0, 2.0, 40 );
  279. m_pPlaybackRate->setValue( m_flPlaybackRate );
  280. ShowButtons( false );
  281. m_nFontSize = 12;
  282. for ( int i = 0; i < MAX_ACTORS; i++ )
  283. {
  284. m_ActorExpanded[ i ].expanded = true;
  285. }
  286. SetChoreoFile( "" );
  287. //SetFocus( (HWND)getHandle() );
  288. if ( workspacefiles->GetNumStoredFiles( IWorkspaceFiles::CHOREODATA ) >= 1 )
  289. {
  290. LoadSceneFromFile( workspacefiles->GetStoredFile( IWorkspaceFiles::CHOREODATA, 0 ) );
  291. }
  292. ClearABPoints();
  293. m_pClickedActor = NULL;
  294. m_pClickedChannel = NULL;
  295. m_pClickedEvent = NULL;
  296. m_pClickedGlobalEvent = NULL;
  297. m_nClickedX = 0;
  298. m_nClickedY = 0;
  299. m_nSelectedEvents = 0;
  300. m_nClickedTag = -1;
  301. m_nClickedChannelCloseCaptionButton = CChoreoChannelWidget::CLOSECAPTION_NONE;
  302. // Mouse dragging
  303. m_bDragging = false;
  304. m_xStart = 0;
  305. m_yStart = 0;
  306. m_nDragType = DRAGTYPE_NONE;
  307. m_hPrevCursor = 0;
  308. m_nMinX = 0;
  309. m_nMaxX = 0;
  310. m_bUseBounds = false;
  311. m_nScrollbarHeight = 12;
  312. m_nInfoHeight = 30;
  313. ClearStatusArea();
  314. SetDirty( false );
  315. m_bCanDraw = true;
  316. m_bSuppressLayout = false;
  317. m_flScrubberTimeOffset = 0.0f;
  318. m_bShowCloseCaptionData = true;
  319. }
  320. //-----------------------------------------------------------------------------
  321. // Purpose:
  322. // Input : closing -
  323. //-----------------------------------------------------------------------------
  324. bool CChoreoView::Close( void )
  325. {
  326. if ( m_pScene && m_bDirty )
  327. {
  328. int retval = mxMessageBox( NULL, va( "Save changes to scene '%s'?", GetChoreoFile() ), g_appTitle, MX_MB_YESNOCANCEL );
  329. if ( retval == 2 )
  330. {
  331. return false;
  332. }
  333. if ( retval == 0 )
  334. {
  335. Save();
  336. }
  337. }
  338. if ( m_pScene )
  339. {
  340. UnloadScene();
  341. }
  342. return true;
  343. }
  344. bool CChoreoView::CanClose()
  345. {
  346. if ( m_pScene )
  347. {
  348. workspacefiles->StartStoringFiles( IWorkspaceFiles::CHOREODATA );
  349. workspacefiles->StoreFile( IWorkspaceFiles::CHOREODATA, GetChoreoFile() );
  350. workspacefiles->FinishStoringFiles( IWorkspaceFiles::CHOREODATA );
  351. }
  352. if ( m_pScene && m_bDirty && !Close() )
  353. {
  354. return false;
  355. }
  356. return true;
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose: Called just before window is destroyed
  360. //-----------------------------------------------------------------------------
  361. void CChoreoView::OnDelete()
  362. {
  363. if ( m_pScene )
  364. {
  365. UnloadScene();
  366. }
  367. CChoreoWidget::m_pView = NULL;
  368. CChoreoEventWidget::DestroyImages();
  369. }
  370. //-----------------------------------------------------------------------------
  371. // Purpose:
  372. //-----------------------------------------------------------------------------
  373. CChoreoView::~CChoreoView()
  374. {
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose:
  378. //-----------------------------------------------------------------------------
  379. void CChoreoView::ReportSceneClearToTools( void )
  380. {
  381. if ( m_pScene )
  382. {
  383. m_pScene->ResetSimulation();
  384. }
  385. g_pPhonemeEditor->ClearEvent();
  386. g_pExpressionTool->LayoutItems( true );
  387. g_pExpressionTool->redraw();
  388. g_pGestureTool->redraw();
  389. g_pRampTool->redraw();
  390. g_pSceneRampTool->redraw();
  391. }
  392. //-----------------------------------------------------------------------------
  393. // Purpose: Find a time that's less than input on the granularity:
  394. // e.g., 3.01 granularity 0.05 will be 3.00, 3.05 will be 3.05
  395. // Input : input -
  396. // granularity -
  397. // Output : float
  398. //-----------------------------------------------------------------------------
  399. float SnapTime( float input, float granularity )
  400. {
  401. float base = (float)(int)input;
  402. float multiplier = (float)(int)( 1.0f / granularity );
  403. float fracpart = input - (int)input;
  404. fracpart *= multiplier;
  405. fracpart = (float)(int)fracpart;
  406. fracpart *= granularity;
  407. return base + fracpart;
  408. }
  409. //-----------------------------------------------------------------------------
  410. // Purpose:
  411. // Input : drawHelper -
  412. // rc -
  413. // left -
  414. // right -
  415. //-----------------------------------------------------------------------------
  416. void CChoreoView::DrawTimeLine( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, float left, float right )
  417. {
  418. RECT rcFill = m_rcTimeLine;
  419. rcFill.bottom -= TIMELINE_NUMBERS_HEIGHT;
  420. drawHelper.DrawFilledRect( COLOR_CHOREO_DARKBACKGROUND, rcFill );
  421. RECT rcLabel;
  422. float granularity = 0.5f / ((float)GetTimeZoom( GetToolName() ) / 100.0f);
  423. drawHelper.DrawColoredLine( COLOR_CHOREO_TIMELINE, PS_SOLID, 1, rc.left, GetStartRow() - 1, rc.right, GetStartRow() - 1 );
  424. float f = SnapTime( left, granularity );
  425. while ( f < right )
  426. {
  427. float frac = ( f - left ) / ( right - left );
  428. if ( frac >= 0.0f && frac <= 1.0f )
  429. {
  430. rcLabel.left = GetLabelWidth() + (int)( frac * ( rc.right - GetLabelWidth() ) );
  431. rcLabel.bottom = GetStartRow() - 1;
  432. rcLabel.top = rcLabel.bottom - 10;
  433. if ( f != left )
  434. {
  435. drawHelper.DrawColoredLine( RGB( 220, 220, 240 ), PS_DOT, 1,
  436. rcLabel.left, GetStartRow(), rcLabel.left, h2() );
  437. }
  438. char sz[ 32 ];
  439. sprintf( sz, "%.2f", f );
  440. int textWidth = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  441. rcLabel.right = rcLabel.left + textWidth;
  442. OffsetRect( &rcLabel, -textWidth / 2, 0 );
  443. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, COLOR_CHOREO_TEXT, rcLabel, sz );
  444. }
  445. f += granularity;
  446. }
  447. }
  448. //-----------------------------------------------------------------------------
  449. // Purpose:
  450. // Output : Returns true on success, false on failure.
  451. //-----------------------------------------------------------------------------
  452. bool CChoreoView::PaintBackground( void )
  453. {
  454. redraw();
  455. return false;
  456. }
  457. //-----------------------------------------------------------------------------
  458. // Purpose:
  459. // Input : drawHelper -
  460. //-----------------------------------------------------------------------------
  461. void CChoreoView::DrawSceneABTicks( CChoreoWidgetDrawHelper& drawHelper )
  462. {
  463. RECT rcThumb;
  464. float scenestart = m_rgABPoints[ 0 ].active ? m_rgABPoints[ 0 ].time : 0.0f;
  465. float sceneend = m_rgABPoints[ 1 ].active ? m_rgABPoints[ 1 ].time : 0.0f;
  466. if ( scenestart )
  467. {
  468. int markerstart = GetPixelForTimeValue( scenestart );
  469. rcThumb.left = markerstart - 4;
  470. rcThumb.right = markerstart + 4;
  471. rcThumb.top = 2 + GetCaptionHeight() + SCRUBBER_HEIGHT;
  472. rcThumb.bottom = rcThumb.top + 8;
  473. drawHelper.DrawTriangleMarker( rcThumb, COLOR_CHOREO_TICKAB );
  474. }
  475. if ( sceneend )
  476. {
  477. int markerend = GetPixelForTimeValue( sceneend );
  478. rcThumb.left = markerend - 4;
  479. rcThumb.right = markerend + 4;
  480. rcThumb.top = 2 + GetCaptionHeight() + SCRUBBER_HEIGHT;
  481. rcThumb.bottom = rcThumb.top + 8;
  482. drawHelper.DrawTriangleMarker( rcThumb, COLOR_CHOREO_TICKAB );
  483. }
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose:
  487. // Input : drawHelper -
  488. // rc -
  489. //-----------------------------------------------------------------------------
  490. void CChoreoView::DrawRelativeTagLines( CChoreoWidgetDrawHelper& drawHelper, RECT& rc )
  491. {
  492. if ( !m_pScene )
  493. return;
  494. RECT rcClip;
  495. GetClientRect( (HWND)getHandle(), &rcClip );
  496. rcClip.top = GetStartRow();
  497. rcClip.bottom -= ( m_nInfoHeight + m_nScrollbarHeight );
  498. rcClip.right -= m_nScrollbarHeight;
  499. drawHelper.StartClipping( rcClip );
  500. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  501. {
  502. CChoreoActorWidget *a = m_SceneActors[ i ];
  503. if ( !a )
  504. continue;
  505. for ( int j = 0; j < a->GetNumChannels(); j++ )
  506. {
  507. CChoreoChannelWidget *c = a->GetChannel( j );
  508. if ( !c )
  509. continue;
  510. for ( int k = 0; k < c->GetNumEvents(); k++ )
  511. {
  512. CChoreoEventWidget *e = c->GetEvent( k );
  513. if ( !e )
  514. continue;
  515. CChoreoEvent *event = e->GetEvent();
  516. if ( !event )
  517. continue;
  518. if ( !event->IsUsingRelativeTag() )
  519. continue;
  520. // Using it, find the tag and figure out the time for it
  521. CEventRelativeTag *tag = m_pScene->FindTagByName(
  522. event->GetRelativeWavName(),
  523. event->GetRelativeTagName() );
  524. if ( !tag )
  525. continue;
  526. // Found it, draw a vertical line
  527. //
  528. float tagtime = tag->GetStartTime();
  529. // Convert to pixel value
  530. bool clipped = false;
  531. int pixel = GetPixelForTimeValue( tagtime, &clipped );
  532. if ( clipped )
  533. continue;
  534. drawHelper.DrawColoredLine( RGB( 180, 180, 220 ), PS_SOLID, 1,
  535. pixel, rcClip.top, pixel, rcClip.bottom );
  536. }
  537. }
  538. }
  539. drawHelper.StopClipping();
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Purpose: Draw the background markings (actor names, etc)
  543. // Input : drawHelper -
  544. // rc -
  545. //-----------------------------------------------------------------------------
  546. void CChoreoView::DrawBackground( CChoreoWidgetDrawHelper& drawHelper, RECT& rc )
  547. {
  548. RECT rcClip;
  549. GetClientRect( (HWND)getHandle(), &rcClip );
  550. rcClip.top = GetStartRow();
  551. rcClip.bottom -= ( m_nInfoHeight + m_nScrollbarHeight );
  552. rcClip.right -= m_nScrollbarHeight;
  553. int i;
  554. for ( i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  555. {
  556. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  557. if ( event )
  558. {
  559. event->redraw( drawHelper );
  560. }
  561. }
  562. drawHelper.StartClipping( rcClip );
  563. for ( i = 0; i < m_SceneActors.Size(); i++ )
  564. {
  565. CChoreoActorWidget *actorW = m_SceneActors[ i ];
  566. if ( !actorW )
  567. continue;
  568. actorW->redraw( drawHelper );
  569. }
  570. drawHelper.StopClipping();
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose:
  574. //-----------------------------------------------------------------------------
  575. void CChoreoView::redraw()
  576. {
  577. if ( !ToolCanDraw() )
  578. return;
  579. if ( m_bSuppressLayout )
  580. return;
  581. LayoutScene();
  582. CChoreoWidgetDrawHelper drawHelper( this, COLOR_CHOREO_BACKGROUND );
  583. HandleToolRedraw( drawHelper );
  584. if ( !m_bCanDraw )
  585. return;
  586. RECT rc;
  587. rc.left = 0;
  588. rc.top = GetCaptionHeight();
  589. rc.right = drawHelper.GetWidth();
  590. rc.bottom = drawHelper.GetHeight();
  591. RECT rcInfo;
  592. rcInfo.left = rc.left;
  593. rcInfo.right = rc.right - m_nScrollbarHeight;
  594. rcInfo.bottom = rc.bottom - m_nScrollbarHeight;
  595. rcInfo.top = rcInfo.bottom - m_nInfoHeight;
  596. drawHelper.StartClipping( rcInfo );
  597. RedrawStatusArea( drawHelper, rcInfo );
  598. drawHelper.StopClipping();
  599. RECT rcClip = rc;
  600. rcClip.bottom -= ( m_nInfoHeight + m_nScrollbarHeight );
  601. drawHelper.StartClipping( rcClip );
  602. if ( !m_pScene )
  603. {
  604. char sz[ 256 ];
  605. sprintf( sz, "No choreography scene file (.vcd) loaded" );
  606. int pointsize = 18;
  607. int textlen = drawHelper.CalcTextWidth( "Arial", pointsize, FW_NORMAL, sz );
  608. RECT rcText;
  609. rcText.top = ( rc.bottom - rc.top ) / 2 - pointsize / 2;
  610. rcText.bottom = rcText.top + pointsize + 10;
  611. rcText.left = rc.right / 2 - textlen / 2;
  612. rcText.right = rcText.left + textlen;
  613. drawHelper.DrawColoredText( "Arial", pointsize, FW_NORMAL, COLOR_CHOREO_LIGHTTEXT, rcText, sz );
  614. drawHelper.StopClipping();
  615. return;
  616. }
  617. DrawTimeLine( drawHelper, rc, m_flStartTime, m_flEndTime );
  618. bool clipped = false;
  619. int finishx = GetPixelForTimeValue( m_pScene->FindStopTime(), &clipped );
  620. if ( !clipped )
  621. {
  622. drawHelper.DrawColoredLine( COLOR_CHOREO_ENDTIME, PS_DOT, 1, finishx, rc.top + GetStartRow(), finishx, rc.bottom );
  623. }
  624. DrawRelativeTagLines( drawHelper, rc );
  625. DrawBackground( drawHelper, rc );
  626. DrawSceneABTicks( drawHelper );
  627. drawHelper.StopClipping();
  628. if ( m_UndoStack.Size() > 0 )
  629. {
  630. int length = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL,
  631. "undo %i/%i", m_nUndoLevel, m_UndoStack.Size() );
  632. RECT rcText = rc;
  633. rcText.top = rc.top + 48;
  634. rcText.bottom = rcText.top + 10;
  635. rcText.left = GetLabelWidth() - length - 20;
  636. rcText.right = rcText.left + length;
  637. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, RGB( 100, 180, 100 ), rcText,
  638. "undo %i/%i", m_nUndoLevel, m_UndoStack.Size() );
  639. }
  640. DrawScrubHandle( drawHelper );
  641. char sz[ 48 ];
  642. sprintf( sz, "Speed: %.2fx", m_flPlaybackRate );
  643. int fontsize = 9;
  644. int length = drawHelper.CalcTextWidth( "Arial", fontsize, FW_NORMAL, sz);
  645. RECT rcText = rc;
  646. rcText.top = rc.top + 25;
  647. rcText.bottom = rcText.top + 10;
  648. rcText.left = GetLabelWidth() + 20;
  649. rcText.right = rcText.left + length;
  650. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL,
  651. RGB( 50, 50, 50 ), rcText, sz );
  652. sprintf( sz, "Zoom: %.2fx", (float)GetTimeZoom( GetToolName() ) / 100.0f );
  653. length = drawHelper.CalcTextWidth( "Arial", fontsize, FW_NORMAL, sz);
  654. rcText = rc;
  655. rcText.left = 5;
  656. rcText.top = rc.top + 48;
  657. rcText.bottom = rcText.top + 10;
  658. rcText.right = rcText.left + length;
  659. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL,
  660. RGB( 50, 50, 50 ), rcText, sz );
  661. }
  662. //-----------------------------------------------------------------------------
  663. // Purpose:
  664. // Input : current -
  665. // number -
  666. // Output : int
  667. //-----------------------------------------------------------------------------
  668. void CChoreoView::GetUndoLevels( int& current, int& number )
  669. {
  670. current = m_nUndoLevel;
  671. number = m_UndoStack.Size();
  672. }
  673. //-----------------------------------------------------------------------------
  674. // Purpose:
  675. // Input : time -
  676. // *clipped -
  677. // Output : int
  678. //-----------------------------------------------------------------------------
  679. int CChoreoView::GetPixelForTimeValue( float time, bool *clipped /*=NULL*/ )
  680. {
  681. if ( clipped )
  682. {
  683. *clipped = false;
  684. }
  685. float frac = ( time - m_flStartTime ) / ( m_flEndTime - m_flStartTime );
  686. if ( frac < 0.0 || frac > 1.0 )
  687. {
  688. if ( clipped )
  689. {
  690. *clipped = true;
  691. }
  692. }
  693. int pixel = GetLabelWidth() + (int)( frac * ( w2() - GetLabelWidth() ) );
  694. return pixel;
  695. }
  696. //-----------------------------------------------------------------------------
  697. // Purpose:
  698. // Input : mx -
  699. // clip -
  700. // Output : float
  701. //-----------------------------------------------------------------------------
  702. float CChoreoView::GetTimeValueForMouse( int mx, bool clip /*=false*/)
  703. {
  704. RECT rc = m_rcTimeLine;
  705. rc.left = GetLabelWidth();
  706. if ( clip )
  707. {
  708. if ( mx < rc.left )
  709. {
  710. return m_flStartTime;
  711. }
  712. if ( mx > rc.right )
  713. {
  714. return m_flEndTime;
  715. }
  716. }
  717. float frac = (float)( mx - rc.left ) / (float)( rc.right - rc.left );
  718. return m_flStartTime + frac * ( m_flEndTime - m_flStartTime );
  719. }
  720. //-----------------------------------------------------------------------------
  721. // Purpose:
  722. // Input : time -
  723. //-----------------------------------------------------------------------------
  724. void CChoreoView::SetStartTime( float time )
  725. {
  726. m_flStartTime = time;
  727. InvalidateLayout();
  728. }
  729. //-----------------------------------------------------------------------------
  730. // Purpose:
  731. // Output : float
  732. //-----------------------------------------------------------------------------
  733. float CChoreoView::GetStartTime( void )
  734. {
  735. return m_flStartTime;
  736. }
  737. //-----------------------------------------------------------------------------
  738. // Purpose:
  739. // Output : float
  740. //-----------------------------------------------------------------------------
  741. float CChoreoView::GetEndTime( void )
  742. {
  743. return m_flEndTime;
  744. }
  745. //-----------------------------------------------------------------------------
  746. // Purpose:
  747. // Output : float
  748. //-----------------------------------------------------------------------------
  749. float CChoreoView::GetPixelsPerSecond( void )
  750. {
  751. return m_flPixelsPerSecond * (float)GetTimeZoom( GetToolName() ) / 100.0f;
  752. }
  753. //-----------------------------------------------------------------------------
  754. // Purpose:
  755. // Input : mx -
  756. // origmx -
  757. // Output : float
  758. //-----------------------------------------------------------------------------
  759. float CChoreoView::GetTimeDeltaForMouseDelta( int mx, int origmx )
  760. {
  761. float t1, t2;
  762. t2 = GetTimeValueForMouse( mx );
  763. t1 = GetTimeValueForMouse( origmx );
  764. return t2 - t1;
  765. }
  766. //-----------------------------------------------------------------------------
  767. // Purpose:
  768. // Input : mx -
  769. //-----------------------------------------------------------------------------
  770. void CChoreoView::PlaceABPoint( int mx )
  771. {
  772. m_rgABPoints[ ( m_nCurrentABPoint) & 0x01 ].time = GetTimeValueForMouse( mx );
  773. m_rgABPoints[ ( m_nCurrentABPoint) & 0x01 ].active = true;
  774. m_nCurrentABPoint++;
  775. if ( m_rgABPoints[ 0 ].active && m_rgABPoints [ 1 ].active &&
  776. m_rgABPoints[ 0 ].time > m_rgABPoints[ 1 ].time )
  777. {
  778. float temp = m_rgABPoints[ 0 ].time;
  779. m_rgABPoints[ 0 ].time = m_rgABPoints[ 1 ].time;
  780. m_rgABPoints[ 1 ].time = temp;
  781. }
  782. }
  783. //-----------------------------------------------------------------------------
  784. // Purpose:
  785. //-----------------------------------------------------------------------------
  786. void CChoreoView::ClearABPoints( void )
  787. {
  788. memset( m_rgABPoints, 0, sizeof( m_rgABPoints ) );
  789. m_nCurrentABPoint = 0;
  790. }
  791. //-----------------------------------------------------------------------------
  792. // Purpose:
  793. // Input : mx -
  794. // my -
  795. // Output : Returns true on success, false on failure.
  796. //-----------------------------------------------------------------------------
  797. bool CChoreoView::IsMouseOverTimeline( int mx, int my )
  798. {
  799. POINT pt;
  800. pt.x = mx;
  801. pt.y = my;
  802. RECT rcCheck = m_rcTimeLine;
  803. rcCheck.bottom -= TIMELINE_NUMBERS_HEIGHT;
  804. if ( PtInRect( &rcCheck, pt ) )
  805. return true;
  806. return false;
  807. }
  808. //-----------------------------------------------------------------------------
  809. // Purpose:
  810. // Input : mx -
  811. // my -
  812. //-----------------------------------------------------------------------------
  813. void CChoreoView::ShowContextMenu( int mx, int my )
  814. {
  815. CChoreoActorWidget *a = NULL;
  816. CChoreoChannelWidget *c = NULL;
  817. CChoreoEventWidget *e = NULL;
  818. CChoreoGlobalEventWidget *ge = NULL;
  819. int ct = -1;
  820. CEventAbsoluteTag *at = NULL;
  821. int clickedCloseCaptionButton = CChoreoChannelWidget::CLOSECAPTION_NONE;
  822. GetObjectsUnderMouse( mx, my, &a, &c, &e, &ge, &ct, &at, &clickedCloseCaptionButton );
  823. m_pClickedActor = a;
  824. m_pClickedChannel = c;
  825. m_pClickedEvent = e;
  826. m_pClickedGlobalEvent = ge;
  827. m_nClickedX = mx;
  828. m_nClickedY = my;
  829. m_nClickedTag = ct;
  830. m_pClickedAbsoluteTag = at;
  831. m_nClickedChannelCloseCaptionButton = clickedCloseCaptionButton;
  832. // Construct main
  833. mxPopupMenu *pop = new mxPopupMenu();
  834. if ( a && c )
  835. {
  836. if (!e)
  837. {
  838. pop->add( "Expression...", IDC_ADDEVENT_EXPRESSION );
  839. pop->add( "WAV File...", IDC_ADDEVENT_SPEAK );
  840. pop->add( "Gesture...", IDC_ADDEVENT_GESTURE );
  841. pop->add( "NULL Gesture...", IDC_ADDEVENT_NULLGESTURE );
  842. pop->add( "Look at actor...", IDC_ADDEVENT_LOOKAT );
  843. pop->add( "Move to actor...", IDC_ADDEVENT_MOVETO );
  844. pop->add( "Face actor...", IDC_ADDEVENT_FACE );
  845. pop->add( "Fire Trigger...", IDC_ADDEVENT_FIRETRIGGER );
  846. pop->add( "Generic(AI)...", IDC_ADDEVENT_GENERIC );
  847. pop->add( "Sequence...", IDC_ADDEVENT_SEQUENCE );
  848. pop->add( "Flex animation...", IDC_ADDEVENT_FLEXANIMATION );
  849. pop->add( "Sub-scene...", IDC_ADDEVENT_SUBSCENE );
  850. pop->add( "Interrupt...", IDC_ADDEVENT_INTERRUPT );
  851. pop->add( "Permit Responses...", IDC_ADDEVENT_PERMITRESPONSES );
  852. pop->addSeparator();
  853. }
  854. else
  855. {
  856. pop->add( va( "Edit Event '%s'...", e->GetEvent()->GetName() ), IDC_EDITEVENT );
  857. switch ( e->GetEvent()->GetType() )
  858. {
  859. default:
  860. break;
  861. case CChoreoEvent::FLEXANIMATION:
  862. {
  863. pop->add( va( "Edit Event '%s' in expression tool", e->GetEvent()->GetName() ), IDC_EXPRESSIONTOOL );
  864. }
  865. break;
  866. case CChoreoEvent::GESTURE:
  867. {
  868. pop->add( va( "Edit Event '%s' in gesture tool", e->GetEvent()->GetName() ), IDC_GESTURETOOL );
  869. }
  870. break;
  871. }
  872. if ( e->GetEvent()->HasEndTime() )
  873. {
  874. pop->add( "Timing Tag...", IDC_ADDTIMINGTAG );
  875. }
  876. pop->addSeparator();
  877. }
  878. }
  879. // Construct "New..."
  880. mxPopupMenu *newMenu = new mxPopupMenu();
  881. {
  882. newMenu->add( "Actor...", IDC_ADDACTOR );
  883. if ( a )
  884. {
  885. newMenu->add( "Channel...", IDC_ADDCHANNEL );
  886. }
  887. newMenu->add( "Section Pause...", IDC_ADDEVENT_PAUSE );
  888. newMenu->add( "Loop...", IDC_ADDEVENT_LOOP );
  889. newMenu->add( "Fire Completion...", IDC_ADDEVENT_STOPPOINT );
  890. }
  891. pop->addMenu( "New", newMenu );
  892. // Now construct "Edit..."
  893. if ( a || c || e || ge )
  894. {
  895. mxPopupMenu *editMenu = new mxPopupMenu();
  896. {
  897. if ( a )
  898. {
  899. editMenu->add( va( "Actor '%s'...", a->GetActor()->GetName() ), IDC_EDITACTOR );
  900. }
  901. if ( c )
  902. {
  903. editMenu->add( va( "Channel '%s'...", c->GetChannel()->GetName() ), IDC_EDITCHANNEL );
  904. }
  905. if ( ge )
  906. {
  907. switch ( ge->GetEvent()->GetType() )
  908. {
  909. default:
  910. break;
  911. case CChoreoEvent::SECTION:
  912. {
  913. editMenu->add( va( "Section Pause '%s'...", ge->GetEvent()->GetName() ), IDC_EDITGLOBALEVENT );
  914. }
  915. break;
  916. case CChoreoEvent::LOOP:
  917. {
  918. editMenu->add( va( "Loop Point '%s'...", ge->GetEvent()->GetName() ), IDC_EDITGLOBALEVENT );
  919. }
  920. break;
  921. case CChoreoEvent::STOPPOINT:
  922. {
  923. editMenu->add( va( "Fire Completion '%s'...", ge->GetEvent()->GetName() ), IDC_EDITGLOBALEVENT );
  924. }
  925. break;
  926. }
  927. }
  928. }
  929. pop->addMenu( "Edit", editMenu );
  930. }
  931. // Move up/down
  932. if ( a || c )
  933. {
  934. mxPopupMenu *moveUpMenu = new mxPopupMenu();
  935. mxPopupMenu *moveDownMenu = new mxPopupMenu();
  936. if ( a )
  937. {
  938. moveUpMenu->add( va( "Move '%s' up", a->GetActor()->GetName() ), IDC_MOVEACTORUP );
  939. moveDownMenu->add( va( "Move '%s' down", a->GetActor()->GetName() ), IDC_MOVEACTORDOWN );
  940. }
  941. if ( c )
  942. {
  943. moveUpMenu->add( va( "Move '%s' up", c->GetChannel()->GetName() ), IDC_MOVECHANNELUP );
  944. moveDownMenu->add( va( "Move '%s' down", c->GetChannel()->GetName() ), IDC_MOVECHANNELDOWN );
  945. }
  946. pop->addMenu( "Move Up", moveUpMenu );
  947. pop->addMenu( "Move Down", moveDownMenu );
  948. }
  949. // Delete
  950. if ( a || c || e || ge || (ct != -1) )
  951. {
  952. mxPopupMenu *deleteMenu = new mxPopupMenu();
  953. if ( a )
  954. {
  955. deleteMenu->add( va( "Actor '%s'", a->GetActor()->GetName() ), IDC_DELETEACTOR );
  956. }
  957. if ( c )
  958. {
  959. deleteMenu->add( va( "Channel '%s'", c->GetChannel()->GetName() ), IDC_DELETECHANNEL );
  960. }
  961. if ( e )
  962. {
  963. deleteMenu->add( va( "Event '%s'", e->GetEvent()->GetName() ), IDC_DELETEEVENT );
  964. }
  965. if ( ge )
  966. {
  967. switch ( ge->GetEvent()->GetType() )
  968. {
  969. default:
  970. break;
  971. case CChoreoEvent::SECTION:
  972. {
  973. deleteMenu->add( va( "Section Pause '%s'...", ge->GetEvent()->GetName() ), IDC_DELETEGLOBALEVENT );
  974. }
  975. break;
  976. case CChoreoEvent::LOOP:
  977. {
  978. deleteMenu->add( va( "Loop Point '%s'...", ge->GetEvent()->GetName() ), IDC_DELETEGLOBALEVENT );
  979. }
  980. break;
  981. case CChoreoEvent::STOPPOINT:
  982. {
  983. deleteMenu->add( va( "Fire Completion '%s'...", ge->GetEvent()->GetName() ), IDC_DELETEGLOBALEVENT );
  984. }
  985. break;
  986. }
  987. }
  988. if ( e && ct != -1 )
  989. {
  990. CEventRelativeTag *tag = e->GetEvent()->GetRelativeTag( ct );
  991. if ( tag )
  992. {
  993. deleteMenu->add( va( "Relative Tag '%s'...", tag->GetName() ), IDC_DELETERELATIVETAG );
  994. }
  995. }
  996. pop->addMenu( "Delete", deleteMenu );
  997. }
  998. // Select
  999. {
  1000. mxPopupMenu *selectMenu = new mxPopupMenu();
  1001. selectMenu->add( "Select All", IDC_SELECTALL );
  1002. selectMenu->add( "Deselect All", IDC_DESELECTALL );
  1003. selectMenu->addSeparator();
  1004. selectMenu->add( "All events before", IDC_SELECTEVENTS_ALL_BEFORE );
  1005. selectMenu->add( "All events after", IDC_SELECTEVENTS_ALL_AFTER );
  1006. selectMenu->add( "Active events before", IDC_SELECTEVENTS_ACTIVE_BEFORE );
  1007. selectMenu->add( "Active events after", IDC_SELECTEVENTS_ACTIVE_AFTER );
  1008. selectMenu->add( "Channel events before", IDC_SELECTEVENTS_CHANNEL_BEFORE );
  1009. selectMenu->add( "Channel events after", IDC_SELECTEVENTS_CHANNEL_AFTER );
  1010. if ( a || c )
  1011. {
  1012. selectMenu->addSeparator();
  1013. if ( a )
  1014. {
  1015. selectMenu->add( va( "All events in actor '%s'", a->GetActor()->GetName() ), IDC_CV_ALLEVENTS_ACTOR );
  1016. }
  1017. if ( c )
  1018. {
  1019. selectMenu->add( va( "All events in channel '%s'", c->GetChannel()->GetName() ), IDC_CV_ALLEVENTS_CHANNEL );
  1020. }
  1021. }
  1022. pop->addMenu( "Select/Deselect", selectMenu );
  1023. }
  1024. // Quick delete for events
  1025. if ( e )
  1026. {
  1027. pop->addSeparator();
  1028. switch ( e->GetEvent()->GetType() )
  1029. {
  1030. default:
  1031. break;
  1032. case CChoreoEvent::FLEXANIMATION:
  1033. {
  1034. pop->add( va( "Edit event '%s' in expression tool", e->GetEvent()->GetName() ), IDC_EXPRESSIONTOOL );
  1035. }
  1036. break;
  1037. case CChoreoEvent::GESTURE:
  1038. {
  1039. pop->add( va( "Edit event '%s' in gesture tool", e->GetEvent()->GetName() ), IDC_GESTURETOOL );
  1040. }
  1041. break;
  1042. }
  1043. pop->add( va( "Move event '%s' to back", e->GetEvent()->GetName() ), IDC_MOVETOBACK );
  1044. if ( CountSelectedEvents() > 1 )
  1045. {
  1046. pop->add( va( "Delete events" ), IDC_DELETEEVENT );
  1047. pop->addSeparator();
  1048. pop->add( "Enable events", IDC_CV_ENABLEEVENTS );
  1049. pop->add( "Disable events", IDC_CV_DISABLEEVENTS );
  1050. }
  1051. else
  1052. {
  1053. pop->add( va( "Delete event '%s'", e->GetEvent()->GetName() ), IDC_DELETEEVENT );
  1054. pop->addSeparator();
  1055. if ( e->GetEvent()->GetActive() )
  1056. {
  1057. pop->add( va( "Disable event '%s'", e->GetEvent()->GetName() ), IDC_CV_DISABLEEVENTS );
  1058. }
  1059. else
  1060. {
  1061. pop->add( va( "Enable event '%s'", e->GetEvent()->GetName() ), IDC_CV_ENABLEEVENTS );
  1062. }
  1063. }
  1064. }
  1065. if ( m_rgABPoints[ 0 ].active && m_rgABPoints[ 1 ].active )
  1066. {
  1067. pop->addSeparator();
  1068. mxPopupMenu *timeMenu = new mxPopupMenu();
  1069. timeMenu->add( "Insert empty space between marks (shifts events right)", IDC_INSERT_TIME );
  1070. timeMenu->add( "Delete events between marks (shifts remaining events left)", IDC_DELETE_TIME );
  1071. pop->addMenu( "Time Marks", timeMenu );
  1072. }
  1073. // Copy/paste
  1074. if ( CanPaste() || e )
  1075. {
  1076. pop->addSeparator();
  1077. if ( CountSelectedEvents() > 1 )
  1078. {
  1079. pop->add( va( "Copy events to clipboard" ), IDC_COPYEVENTS );
  1080. }
  1081. else if ( e )
  1082. {
  1083. pop->add( va( "Copy event '%s' to clipboard", e->GetEvent()->GetName() ), IDC_COPYEVENTS );
  1084. }
  1085. if ( CanPaste() )
  1086. {
  1087. pop->add( va( "Paste events" ), IDC_PASTEEVENTS );
  1088. }
  1089. }
  1090. // Export / import
  1091. pop->addSeparator();
  1092. if ( e )
  1093. {
  1094. mxPopupMenu *exportMenu = new mxPopupMenu();
  1095. if ( CountSelectedEvents() > 1 )
  1096. {
  1097. exportMenu->add( va( "Export events to .vce..." ), IDC_EXPORTEVENTS );
  1098. }
  1099. else if ( e )
  1100. {
  1101. exportMenu->add( va( "Export event '%s' to .vce...", e->GetEvent()->GetName() ), IDC_EXPORTEVENTS );
  1102. }
  1103. exportMenu->add( va( "Export as .vcd..." ), IDC_EXPORT_VCD );
  1104. pop->addMenu( "Export", exportMenu );
  1105. }
  1106. mxPopupMenu *importMenu = new mxPopupMenu();
  1107. importMenu->add( va( "Import events from .vce..." ), IDC_IMPORTEVENTS );
  1108. importMenu->add( va( "Merge from .vcd..." ), IDC_IMPORT_VCD );
  1109. pop->addMenu( "Import", importMenu );
  1110. bool bShowAlignLeft = ( CountSelectedEvents() + CountSelectedGlobalEvents() ) > 1 ? true : false;
  1111. if ( e && ( ( CountSelectedEvents() > 1 ) || bShowAlignLeft ) )
  1112. {
  1113. pop->addSeparator();
  1114. mxPopupMenu *alignMenu = new mxPopupMenu();
  1115. alignMenu->add( "Align Left", IDC_CV_ALIGN_LEFT );
  1116. if ( CountSelectedEvents() > 1 )
  1117. {
  1118. alignMenu->add( "Align Right", IDC_CV_ALIGN_RIGHT );
  1119. alignMenu->add( "Size to Smallest", IDC_CV_SAMESIZE_SMALLEST );
  1120. alignMenu->add( "Size to Largest", IDC_CV_SAMESIZE_LARGEST );
  1121. }
  1122. pop->addMenu( "Align", alignMenu );
  1123. }
  1124. // Misc.
  1125. pop->addSeparator();
  1126. pop->add( va( "Change scale..." ), IDC_CV_CHANGESCALE );
  1127. pop->add( va( "Check sequences" ), IDC_CV_CHECKSEQLENGTHS );
  1128. pop->add( va( "Process sequences" ), IDC_CV_PROCESSSEQUENCES );
  1129. pop->add( va( m_bRampOnly ? "Ramp normal" : "Ramp only" ), IDC_CV_TOGGLERAMPONLY );
  1130. pop->setChecked( IDC_CV_PROCESSSEQUENCES, m_bProcessSequences );
  1131. bool onmaster= ( m_pClickedChannel &&
  1132. m_pClickedChannel->GetCaptionClickedEvent() &&
  1133. m_pClickedChannel->GetCaptionClickedEvent()->GetCloseCaptionType() == CChoreoEvent::CC_MASTER ) ? true : false;
  1134. bool ondisabled = ( m_pClickedChannel &&
  1135. m_pClickedChannel->GetCaptionClickedEvent() &&
  1136. m_pClickedChannel->GetCaptionClickedEvent()->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED ) ? true : false;
  1137. // The close captioning menu
  1138. if ( m_bShowCloseCaptionData && ( AreSelectedEventsCombinable() || AreSelectedEventsInSpeakGroup() || onmaster || ondisabled ) )
  1139. {
  1140. pop->addSeparator();
  1141. if ( AreSelectedEventsCombinable() )
  1142. {
  1143. pop->add( "Combine Speak Events", IDC_CV_COMBINESPEAKEVENTS );
  1144. }
  1145. if ( AreSelectedEventsInSpeakGroup() )
  1146. {
  1147. pop->add( "Uncombine Speak Events", IDC_CV_REMOVESPEAKEVENTFROMGROUP );
  1148. }
  1149. if ( onmaster )
  1150. {
  1151. // Can only change tokens for "combined" files
  1152. if ( m_pClickedChannel->GetCaptionClickedEvent()->GetNumSlaves() >= 1 )
  1153. {
  1154. pop->add( "Change Token", IDC_CV_CHANGECLOSECAPTIONTOKEN );
  1155. }
  1156. pop->add( "Disable captions", IDC_CV_TOGGLECLOSECAPTIONS );
  1157. }
  1158. if ( ondisabled )
  1159. {
  1160. pop->add( "Enable captions", IDC_CV_TOGGLECLOSECAPTIONS );
  1161. }
  1162. }
  1163. // Undo/redo
  1164. if ( CanUndo() || CanRedo() )
  1165. {
  1166. pop->addSeparator();
  1167. if ( CanUndo() )
  1168. {
  1169. pop->add( va( "Undo %s", GetUndoDescription() ), IDC_CVUNDO );
  1170. }
  1171. if ( CanRedo() )
  1172. {
  1173. pop->add( va( "Redo %s", GetRedoDescription() ), IDC_CVREDO );
  1174. }
  1175. }
  1176. if ( m_pScene )
  1177. {
  1178. // Associate map file
  1179. pop->addSeparator();
  1180. pop->add( va( "Associate .bsp (%s)", m_pScene->GetMapname() ), IDC_ASSOCIATEBSP );
  1181. if ( a )
  1182. {
  1183. if ( a->GetActor() && a->GetActor()->GetFacePoserModelName()[0] )
  1184. {
  1185. pop->add( va( "Change .mdl for %s", a->GetActor()->GetName() ), IDC_ASSOCIATEMODEL );
  1186. }
  1187. else
  1188. {
  1189. pop->add( va( "Associate .mdl with %s", a->GetActor()->GetName() ), IDC_ASSOCIATEMODEL );
  1190. }
  1191. }
  1192. }
  1193. pop->popup( this, mx, my );
  1194. }
  1195. //-----------------------------------------------------------------------------
  1196. // Purpose:
  1197. //-----------------------------------------------------------------------------
  1198. void CChoreoView::AssociateModel( void )
  1199. {
  1200. if ( !m_pScene )
  1201. return;
  1202. CChoreoActorWidget *actor = m_pClickedActor;
  1203. if ( !actor )
  1204. return;
  1205. CChoreoActor *a = actor->GetActor();
  1206. if ( !a )
  1207. return;
  1208. CChoiceParams params;
  1209. strcpy( params.m_szDialogTitle, "Associate Model" );
  1210. params.m_bPositionDialog = false;
  1211. params.m_nLeft = 0;
  1212. params.m_nTop = 0;
  1213. strcpy( params.m_szPrompt, "Choose model:" );
  1214. params.m_Choices.RemoveAll();
  1215. params.m_nSelected = -1;
  1216. int oldsel = -1;
  1217. int c = models->Count();
  1218. ChoiceText text;
  1219. for ( int i = 0; i < c; i++ )
  1220. {
  1221. char const *modelname = models->GetModelName( i );
  1222. strcpy( text.choice, modelname );
  1223. if ( !stricmp( a->GetName(), modelname ) )
  1224. {
  1225. params.m_nSelected = i;
  1226. oldsel = -1;
  1227. }
  1228. params.m_Choices.AddToTail( text );
  1229. }
  1230. // Add an extra entry which is "No association"
  1231. strcpy( text.choice, "No Associated Model" );
  1232. params.m_Choices.AddToTail( text );
  1233. if ( !ChoiceProperties( &params ) )
  1234. return;
  1235. if ( params.m_nSelected == oldsel )
  1236. return;
  1237. // Chose something new...
  1238. if ( params.m_nSelected >= 0 &&
  1239. params.m_nSelected < params.m_Choices.Count() )
  1240. {
  1241. AssociateModelToActor( a, params.m_nSelected );
  1242. }
  1243. else
  1244. {
  1245. // Chose "No association"
  1246. AssociateModelToActor( a, -1 );
  1247. }
  1248. }
  1249. //-----------------------------------------------------------------------------
  1250. // Purpose:
  1251. // Input : *actor -
  1252. // modelindex -
  1253. //-----------------------------------------------------------------------------
  1254. void CChoreoView::AssociateModelToActor( CChoreoActor *actor, int modelindex )
  1255. {
  1256. Assert( actor );
  1257. SetDirty( true );
  1258. PushUndo( "Associate model" );
  1259. // Chose something new...
  1260. if ( modelindex >= 0 &&
  1261. modelindex < models->Count() )
  1262. {
  1263. actor->SetFacePoserModelName( models->GetModelFileName( modelindex ) );
  1264. }
  1265. else
  1266. {
  1267. // Chose "No Associated Model"
  1268. actor->SetFacePoserModelName( "" );
  1269. }
  1270. RecomputeWaves();
  1271. PushRedo( "Associate model" );
  1272. }
  1273. void CChoreoView::AssociateBSP( void )
  1274. {
  1275. if ( !m_pScene )
  1276. return;
  1277. // Strip game directory and slash
  1278. char mapname[ 512 ];
  1279. if ( !FacePoser_ShowOpenFileNameDialog( mapname, sizeof( mapname ), "maps", "*.bsp" ) )
  1280. {
  1281. return;
  1282. }
  1283. m_pScene->SetMapname( mapname );
  1284. redraw();
  1285. }
  1286. //-----------------------------------------------------------------------------
  1287. // Purpose:
  1288. //-----------------------------------------------------------------------------
  1289. void CChoreoView::DrawFocusRect( void )
  1290. {
  1291. HDC dc = GetDC( NULL );
  1292. for ( int i = 0; i < m_FocusRects.Size(); i++ )
  1293. {
  1294. RECT rc = m_FocusRects[ i ].m_rcFocus;
  1295. ::DrawFocusRect( dc, &rc );
  1296. }
  1297. ReleaseDC( NULL, dc );
  1298. }
  1299. int CChoreoView::GetSelectedEventWidgets( CUtlVector< CChoreoEventWidget * >& events )
  1300. {
  1301. events.RemoveAll();
  1302. int c = 0;
  1303. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  1304. {
  1305. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1306. if ( !actor )
  1307. continue;
  1308. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1309. {
  1310. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1311. if ( !channel )
  1312. continue;
  1313. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1314. {
  1315. CChoreoEventWidget *event = channel->GetEvent( k );
  1316. if ( !event )
  1317. continue;
  1318. if ( event->IsSelected() )
  1319. {
  1320. events.AddToTail( event );
  1321. c++;
  1322. }
  1323. }
  1324. }
  1325. }
  1326. return c;
  1327. }
  1328. //-----------------------------------------------------------------------------
  1329. // Purpose:
  1330. // Input : events -
  1331. // Output : int
  1332. //-----------------------------------------------------------------------------
  1333. int CChoreoView::GetSelectedEvents( CUtlVector< CChoreoEvent * >& events )
  1334. {
  1335. events.RemoveAll();
  1336. int c = 0;
  1337. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  1338. {
  1339. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1340. if ( !actor )
  1341. continue;
  1342. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1343. {
  1344. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1345. if ( !channel )
  1346. continue;
  1347. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1348. {
  1349. CChoreoEventWidget *event = channel->GetEvent( k );
  1350. if ( !event )
  1351. continue;
  1352. if ( event->IsSelected() )
  1353. {
  1354. events.AddToTail( event->GetEvent() );
  1355. c++;
  1356. }
  1357. }
  1358. }
  1359. }
  1360. return c;
  1361. }
  1362. int CChoreoView::CountSelectedGlobalEvents( void )
  1363. {
  1364. int c = 0;
  1365. for ( int i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  1366. {
  1367. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  1368. if ( !event || !event->IsSelected() )
  1369. continue;
  1370. ++c;
  1371. }
  1372. return c;
  1373. }
  1374. //-----------------------------------------------------------------------------
  1375. // Purpose:
  1376. // Output : int
  1377. //-----------------------------------------------------------------------------
  1378. int CChoreoView::CountSelectedEvents( void )
  1379. {
  1380. int c = 0;
  1381. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  1382. {
  1383. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1384. if ( !actor )
  1385. continue;
  1386. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1387. {
  1388. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1389. if ( !channel )
  1390. continue;
  1391. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1392. {
  1393. CChoreoEventWidget *event = channel->GetEvent( k );
  1394. if ( !event )
  1395. continue;
  1396. if ( event->IsSelected() )
  1397. c++;
  1398. }
  1399. }
  1400. }
  1401. return c;
  1402. }
  1403. bool CChoreoView::IsMouseOverEvent( CChoreoEventWidget *ew, int mx, int my )
  1404. {
  1405. int tolerance = DRAG_EVENT_EDGE_TOLERANCE;
  1406. RECT bounds = ew->getBounds();
  1407. mx -= bounds.left;
  1408. my -= bounds.top;
  1409. if ( mx <= -tolerance )
  1410. {
  1411. return false;
  1412. }
  1413. CChoreoEvent *event = ew->GetEvent();
  1414. if ( event )
  1415. {
  1416. if ( event->HasEndTime() )
  1417. {
  1418. int rightside = ew->GetDurationRightEdge() ? ew->GetDurationRightEdge() : ew->w();
  1419. if ( mx > rightside + tolerance )
  1420. {
  1421. return false;
  1422. }
  1423. }
  1424. }
  1425. return true;
  1426. }
  1427. bool CChoreoView::IsMouseOverEventEdge( CChoreoEventWidget *ew, bool bLeftEdge, int mx, int my )
  1428. {
  1429. int tolerance = DRAG_EVENT_EDGE_TOLERANCE;
  1430. RECT bounds = ew->getBounds();
  1431. mx -= bounds.left;
  1432. my -= bounds.top;
  1433. CChoreoEvent *event = ew->GetEvent();
  1434. if ( event && event->HasEndTime() )
  1435. {
  1436. if ( mx > -tolerance && mx <= tolerance )
  1437. {
  1438. return bLeftEdge;
  1439. }
  1440. int rightside = ew->GetDurationRightEdge() ? ew->GetDurationRightEdge() : ew->w();
  1441. if ( mx >= rightside - tolerance )
  1442. {
  1443. if ( mx > rightside + tolerance )
  1444. {
  1445. return false;
  1446. }
  1447. else
  1448. {
  1449. return !bLeftEdge;
  1450. }
  1451. }
  1452. }
  1453. return false;
  1454. }
  1455. int CChoreoView::GetEarliestEventIndex( CUtlVector< CChoreoEventWidget * >& events )
  1456. {
  1457. int best = -1;
  1458. float minTime = FLT_MAX;
  1459. int c = events.Count();
  1460. for ( int i = 0; i < c; ++i )
  1461. {
  1462. CChoreoEvent *e = events[ i ]->GetEvent();
  1463. float t = e->GetStartTime();
  1464. if ( t < minTime )
  1465. {
  1466. minTime = t;
  1467. best = i;
  1468. }
  1469. }
  1470. return best;
  1471. }
  1472. int CChoreoView::GetLatestEventIndex( CUtlVector< CChoreoEventWidget * >& events )
  1473. {
  1474. int best = -1;
  1475. float maxTime = FLT_MIN;
  1476. int c = events.Count();
  1477. for ( int i = 0; i < c; ++i )
  1478. {
  1479. CChoreoEvent *e = events[ i ]->GetEvent();
  1480. float t = e->GetEndTime();
  1481. if ( t > maxTime )
  1482. {
  1483. maxTime = t;
  1484. best = i;
  1485. }
  1486. }
  1487. return best;
  1488. }
  1489. //-----------------------------------------------------------------------------
  1490. // Purpose:
  1491. // Input : mx -
  1492. // Output : int
  1493. //-----------------------------------------------------------------------------
  1494. int CChoreoView::ComputeEventDragType( int mx, int my )
  1495. {
  1496. int tolerance = DRAG_EVENT_EDGE_TOLERANCE;
  1497. // Iterate the events and see who's closest
  1498. CChoreoEventWidget *ew = GetEventUnderCursorPos( mx, my );
  1499. if ( !ew )
  1500. {
  1501. return DRAGTYPE_NONE;
  1502. }
  1503. // Deal with small windows by lowering tolerance
  1504. if ( ew->w() < 4 * tolerance )
  1505. {
  1506. tolerance = 2;
  1507. }
  1508. int tagnum = GetTagUnderCursorPos( ew, mx, my );
  1509. if ( tagnum != -1 && CountSelectedEvents() <= 1 )
  1510. {
  1511. return DRAGTYPE_EVENTTAG_MOVE;
  1512. }
  1513. CEventAbsoluteTag *tag = GetAbsoluteTagUnderCursorPos( ew, mx, my );
  1514. if ( tag != NULL && CountSelectedEvents() <= 1 )
  1515. {
  1516. return DRAGTYPE_EVENTABSTAG_MOVE;
  1517. }
  1518. if ( CountSelectedEvents() > 1 )
  1519. {
  1520. CUtlVector< CChoreoEventWidget * > events;
  1521. GetSelectedEventWidgets( events );
  1522. int iStart, iEnd;
  1523. iStart = GetEarliestEventIndex( events );
  1524. iEnd = GetLatestEventIndex( events );
  1525. if ( events.IsValidIndex( iStart ) )
  1526. {
  1527. // See if mouse is over left edge of starting event
  1528. if ( IsMouseOverEventEdge( events[ iStart ], true, mx, my ) )
  1529. {
  1530. return DRAGTYPE_RESCALELEFT;
  1531. }
  1532. }
  1533. if ( events.IsValidIndex( iEnd ) )
  1534. {
  1535. if ( IsMouseOverEventEdge( events[ iEnd ], false, mx, my ) )
  1536. {
  1537. return DRAGTYPE_RESCALERIGHT;
  1538. }
  1539. }
  1540. return DRAGTYPE_EVENT_MOVE;
  1541. }
  1542. CChoreoEvent *event = ew->GetEvent();
  1543. if ( event )
  1544. {
  1545. if ( event->IsFixedLength() || !event->HasEndTime() )
  1546. {
  1547. return DRAGTYPE_EVENT_MOVE;
  1548. }
  1549. }
  1550. if ( IsMouseOverEventEdge( ew, true, mx, my ) )
  1551. {
  1552. if ( GetAsyncKeyState( VK_SHIFT ) )
  1553. return DRAGTYPE_EVENT_STARTTIME_RESCALE;
  1554. return DRAGTYPE_EVENT_STARTTIME;
  1555. }
  1556. if ( IsMouseOverEventEdge( ew, false, mx, my ) )
  1557. {
  1558. if ( GetAsyncKeyState( VK_SHIFT ) )
  1559. return DRAGTYPE_EVENT_ENDTIME_RESCALE;
  1560. return DRAGTYPE_EVENT_ENDTIME;
  1561. }
  1562. if ( IsMouseOverEvent( ew, mx, my ) )
  1563. {
  1564. return DRAGTYPE_EVENT_MOVE;
  1565. }
  1566. return DRAGTYPE_NONE;
  1567. }
  1568. void CChoreoView::StartDraggingSceneEndTime( int mx, int my )
  1569. {
  1570. m_nDragType = DRAGTYPE_SCENE_ENDTIME;
  1571. m_FocusRects.Purge();
  1572. RECT rcFocus;
  1573. rcFocus.left = mx;
  1574. rcFocus.top = 0;
  1575. rcFocus.bottom = h2();
  1576. rcFocus.right = rcFocus.left + 2;
  1577. POINT offset;
  1578. offset.x = 0;
  1579. offset.y = 0;
  1580. ClientToScreen( (HWND)getHandle(), &offset );
  1581. OffsetRect( &rcFocus, offset.x, offset.y );
  1582. CFocusRect fr;
  1583. fr.m_rcFocus = rcFocus;
  1584. fr.m_rcOrig = rcFocus;
  1585. // Relative tag events don't move
  1586. m_FocusRects.AddToTail( fr );
  1587. m_xStart = mx;
  1588. m_yStart = my;
  1589. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1590. DrawFocusRect();
  1591. m_bDragging = true;
  1592. }
  1593. //-----------------------------------------------------------------------------
  1594. // Purpose:
  1595. //-----------------------------------------------------------------------------
  1596. void CChoreoView::StartDraggingEvent( int mx, int my )
  1597. {
  1598. m_nDragType = ComputeEventDragType( mx, my );
  1599. if ( m_nDragType == DRAGTYPE_NONE )
  1600. {
  1601. if( m_pClickedGlobalEvent )
  1602. {
  1603. m_nDragType = DRAGTYPE_EVENT_MOVE;
  1604. }
  1605. else
  1606. {
  1607. return;
  1608. }
  1609. }
  1610. m_FocusRects.Purge();
  1611. // Go through all selected events
  1612. RECT rcFocus;
  1613. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  1614. {
  1615. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1616. if ( !actor )
  1617. continue;
  1618. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1619. {
  1620. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1621. if ( !channel )
  1622. continue;
  1623. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1624. {
  1625. CChoreoEventWidget *event = channel->GetEvent( k );
  1626. if ( !event )
  1627. continue;
  1628. if ( !event->IsSelected() )
  1629. continue;
  1630. if ( event == m_pClickedEvent &&
  1631. ( m_nClickedTag != -1 || m_pClickedAbsoluteTag ) )
  1632. {
  1633. int leftEdge = 0;
  1634. int tagWidth = 1;
  1635. if ( !m_pClickedAbsoluteTag )
  1636. {
  1637. CEventRelativeTag *tag = event->GetEvent()->GetRelativeTag( m_nClickedTag );
  1638. if ( tag )
  1639. {
  1640. // Determine left edcge
  1641. RECT bounds;
  1642. bounds = event->getBounds();
  1643. if ( bounds.right - bounds.left > 0 )
  1644. {
  1645. leftEdge = (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  1646. }
  1647. }
  1648. }
  1649. else
  1650. {
  1651. // Determine left edcge
  1652. RECT bounds;
  1653. bounds = event->getBounds();
  1654. if ( bounds.right - bounds.left > 0 )
  1655. {
  1656. leftEdge = (int)( m_pClickedAbsoluteTag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  1657. }
  1658. }
  1659. rcFocus.left = event->x() + leftEdge - tagWidth;
  1660. rcFocus.top = event->y() - tagWidth;
  1661. rcFocus.right = rcFocus.left + 2 * tagWidth;
  1662. rcFocus.bottom = event->y() + event->h();
  1663. }
  1664. else
  1665. {
  1666. rcFocus.left = event->x();
  1667. rcFocus.top = event->y();
  1668. if ( event->GetDurationRightEdge() )
  1669. {
  1670. rcFocus.right = event->x() + event->GetDurationRightEdge();
  1671. }
  1672. else
  1673. {
  1674. rcFocus.right = rcFocus.left + event->w();
  1675. }
  1676. rcFocus.bottom = rcFocus.top + event->h();
  1677. }
  1678. POINT offset;
  1679. offset.x = 0;
  1680. offset.y = 0;
  1681. ClientToScreen( (HWND)getHandle(), &offset );
  1682. OffsetRect( &rcFocus, offset.x, offset.y );
  1683. CFocusRect fr;
  1684. fr.m_rcFocus = rcFocus;
  1685. fr.m_rcOrig = rcFocus;
  1686. // Relative tag events don't move
  1687. m_FocusRects.AddToTail( fr );
  1688. }
  1689. }
  1690. }
  1691. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  1692. {
  1693. CChoreoGlobalEventWidget *gew = m_SceneGlobalEvents[ i ];
  1694. if ( !gew )
  1695. continue;
  1696. if ( !gew->IsSelected() )
  1697. continue;
  1698. rcFocus.left = gew->x() + gew->w() / 2;
  1699. rcFocus.top = 0;
  1700. rcFocus.right = rcFocus.left + 2;
  1701. rcFocus.bottom = h2();
  1702. POINT offset;
  1703. offset.x = 0;
  1704. offset.y = 0;
  1705. ClientToScreen( (HWND)getHandle(), &offset );
  1706. OffsetRect( &rcFocus, offset.x, offset.y );
  1707. CFocusRect fr;
  1708. fr.m_rcFocus = rcFocus;
  1709. fr.m_rcOrig = rcFocus;
  1710. m_FocusRects.AddToTail( fr );
  1711. }
  1712. m_xStart = mx;
  1713. m_yStart = my;
  1714. m_hPrevCursor = NULL;
  1715. switch ( m_nDragType )
  1716. {
  1717. default:
  1718. break;
  1719. case DRAGTYPE_EVENTTAG_MOVE:
  1720. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1721. break;
  1722. case DRAGTYPE_EVENTABSTAG_MOVE:
  1723. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_IBEAM ) );
  1724. break;
  1725. case DRAGTYPE_EVENT_MOVE:
  1726. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
  1727. break;
  1728. case DRAGTYPE_EVENT_STARTTIME:
  1729. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  1730. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1731. break;
  1732. case DRAGTYPE_EVENT_ENDTIME:
  1733. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  1734. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1735. break;
  1736. case DRAGTYPE_RESCALELEFT:
  1737. case DRAGTYPE_RESCALERIGHT:
  1738. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1739. break;
  1740. }
  1741. DrawFocusRect();
  1742. m_bDragging = true;
  1743. }
  1744. bool CChoreoView::IsMouseOverSceneEndTime( int mx )
  1745. {
  1746. // See if mouse if over scene end time instead
  1747. if ( m_pScene )
  1748. {
  1749. float endtime = m_pScene->FindStopTime();
  1750. bool clip = false;
  1751. int lastpixel = GetPixelForTimeValue( endtime, &clip );
  1752. if ( !clip )
  1753. {
  1754. if ( abs( mx - lastpixel ) < DRAG_EVENT_EDGE_TOLERANCE )
  1755. {
  1756. return true;
  1757. }
  1758. }
  1759. }
  1760. return false;
  1761. }
  1762. //-----------------------------------------------------------------------------
  1763. // Purpose:
  1764. // Input : mx -
  1765. // my -
  1766. //-----------------------------------------------------------------------------
  1767. void CChoreoView::MouseStartDrag( mxEvent *event, int mx, int my )
  1768. {
  1769. bool isrightbutton = event->buttons & mxEvent::MouseRightButton ? true : false;
  1770. if ( m_bDragging )
  1771. {
  1772. return;
  1773. }
  1774. GetObjectsUnderMouse( mx, my, &m_pClickedActor, &m_pClickedChannel, &m_pClickedEvent, &m_pClickedGlobalEvent, &m_nClickedTag, &m_pClickedAbsoluteTag, &m_nClickedChannelCloseCaptionButton );
  1775. if ( m_pClickedEvent )
  1776. {
  1777. CChoreoEvent *e = m_pClickedEvent->GetEvent();
  1778. Assert( e );
  1779. int dtPreview = ComputeEventDragType( mx, my );
  1780. // Shift clicking on exact edge shouldn't toggle selection state
  1781. bool bIsEdgeRescale = ( dtPreview == DRAGTYPE_EVENT_ENDTIME_RESCALE || dtPreview == DRAGTYPE_EVENT_STARTTIME_RESCALE );
  1782. if ( !( event->modifiers & ( mxEvent::KeyCtrl | mxEvent::KeyShift ) ) )
  1783. {
  1784. if ( !m_pClickedEvent->IsSelected() )
  1785. {
  1786. DeselectAll();
  1787. }
  1788. TraverseWidgets( &CChoreoView::Select, m_pClickedEvent );
  1789. }
  1790. else if ( !bIsEdgeRescale )
  1791. {
  1792. m_pClickedEvent->SetSelected( !m_pClickedEvent->IsSelected() );
  1793. }
  1794. switch ( m_pClickedEvent->GetEvent()->GetType() )
  1795. {
  1796. default:
  1797. break;
  1798. case CChoreoEvent::FLEXANIMATION:
  1799. {
  1800. g_pExpressionTool->SetEvent( e );
  1801. g_pFlexPanel->SetEvent( e );
  1802. }
  1803. break;
  1804. case CChoreoEvent::GESTURE:
  1805. {
  1806. g_pGestureTool->SetEvent( e );
  1807. }
  1808. break;
  1809. case CChoreoEvent::SPEAK:
  1810. {
  1811. g_pWaveBrowser->SetEvent( e );
  1812. }
  1813. break;
  1814. }
  1815. if ( e->HasEndTime() )
  1816. {
  1817. g_pRampTool->SetEvent( e );
  1818. }
  1819. redraw();
  1820. StartDraggingEvent( mx, my );
  1821. }
  1822. else if ( m_pClickedGlobalEvent )
  1823. {
  1824. if ( !( event->modifiers & ( mxEvent::KeyCtrl | mxEvent::KeyShift ) ) )
  1825. {
  1826. if ( !m_pClickedGlobalEvent->IsSelected() )
  1827. {
  1828. DeselectAll();
  1829. }
  1830. TraverseWidgets( &CChoreoView::Select, m_pClickedGlobalEvent );
  1831. }
  1832. else
  1833. {
  1834. m_pClickedGlobalEvent->SetSelected( !m_pClickedGlobalEvent->IsSelected() );
  1835. }
  1836. redraw();
  1837. StartDraggingEvent( mx, my );
  1838. }
  1839. else if ( IsMouseOverScrubArea( event ) )
  1840. {
  1841. if ( IsMouseOverScrubHandle( event ) )
  1842. {
  1843. m_nDragType = DRAGTYPE_SCRUBBER;
  1844. m_bDragging = true;
  1845. float t = GetTimeValueForMouse( (short)event->x );
  1846. m_flScrubberTimeOffset = m_flScrub - t;
  1847. float maxoffset = 0.5f * (float)SCRUBBER_HANDLE_WIDTH / GetPixelsPerSecond();
  1848. m_flScrubberTimeOffset = clamp( m_flScrubberTimeOffset, -maxoffset, maxoffset );
  1849. t += m_flScrubberTimeOffset;
  1850. ClampTimeToSelectionInterval( t );
  1851. SetScrubTime( t );
  1852. SetScrubTargetTime( t );
  1853. redraw();
  1854. RECT rcScrub;
  1855. GetScrubHandleRect( rcScrub, true );
  1856. m_FocusRects.Purge();
  1857. // Go through all selected events
  1858. RECT rcFocus;
  1859. rcFocus.top = GetStartRow();
  1860. rcFocus.bottom = h2() - m_nScrollbarHeight - m_nInfoHeight;
  1861. rcFocus.left = ( rcScrub.left + rcScrub.right ) / 2;
  1862. rcFocus.right = rcFocus.left;
  1863. POINT pt;
  1864. pt.x = pt.y = 0;
  1865. ClientToScreen( (HWND)getHandle(), &pt );
  1866. OffsetRect( &rcFocus, pt.x, pt.y );
  1867. CFocusRect fr;
  1868. fr.m_rcFocus = rcFocus;
  1869. fr.m_rcOrig = rcFocus;
  1870. m_FocusRects.AddToTail( fr );
  1871. m_xStart = mx;
  1872. m_yStart = my;
  1873. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1874. DrawFocusRect();
  1875. }
  1876. else
  1877. {
  1878. float t = GetTimeValueForMouse( mx );
  1879. ClampTimeToSelectionInterval( t );
  1880. SetScrubTargetTime( t );
  1881. // Unpause the scene
  1882. m_bPaused = false;
  1883. redraw();
  1884. }
  1885. }
  1886. else if ( IsMouseOverSceneEndTime( mx ) )
  1887. {
  1888. redraw();
  1889. StartDraggingSceneEndTime( mx, my );
  1890. }
  1891. else if ( m_pClickedChannel &&
  1892. m_nClickedChannelCloseCaptionButton != CChoreoChannelWidget::CLOSECAPTION_NONE &&
  1893. m_nClickedChannelCloseCaptionButton != CChoreoChannelWidget::CLOSECAPTION_CAPTION )
  1894. {
  1895. switch ( m_nClickedChannelCloseCaptionButton )
  1896. {
  1897. default:
  1898. case CChoreoChannelWidget::CLOSECAPTION_EXPANDCOLLAPSE:
  1899. {
  1900. OnToggleCloseCaptionTags();
  1901. }
  1902. break;
  1903. case CChoreoChannelWidget::CLOSECAPTION_PREVLANGUAGE:
  1904. {
  1905. // Change language
  1906. int id = GetCloseCaptionLanguageId();
  1907. --id;
  1908. if ( id < 0 )
  1909. {
  1910. id = CC_NUM_LANGUAGES - 1;
  1911. Assert( id >= 0 );
  1912. }
  1913. SetCloseCaptionLanguageId( id );
  1914. redraw();
  1915. }
  1916. break;
  1917. case CChoreoChannelWidget::CLOSECAPTION_NEXTLANGUAGE:
  1918. {
  1919. int id = GetCloseCaptionLanguageId();
  1920. ++id;
  1921. if ( id >= CC_NUM_LANGUAGES )
  1922. {
  1923. id = 0;
  1924. }
  1925. SetCloseCaptionLanguageId( id );
  1926. redraw();
  1927. }
  1928. break;
  1929. case CChoreoChannelWidget::CLOSECAPTION_SELECTOR:
  1930. {
  1931. SetDirty( true );
  1932. PushUndo( "Change selector" );
  1933. m_pClickedChannel->HandleSelectorClicked();
  1934. PushRedo( "Change selector" );
  1935. redraw();
  1936. }
  1937. break;
  1938. }
  1939. }
  1940. else
  1941. {
  1942. if ( !( event->modifiers & ( mxEvent::KeyCtrl | mxEvent::KeyShift ) ) )
  1943. {
  1944. DeselectAll();
  1945. if ( !isrightbutton )
  1946. {
  1947. if ( realtime - m_flLastMouseClickTime < 0.3f )
  1948. {
  1949. OnDoubleClicked();
  1950. m_flLastMouseClickTime = -1.0f;
  1951. }
  1952. else
  1953. {
  1954. m_flLastMouseClickTime = realtime;
  1955. }
  1956. }
  1957. redraw();
  1958. }
  1959. }
  1960. CalcBounds( m_nDragType );
  1961. }
  1962. void CChoreoView::OnDoubleClicked()
  1963. {
  1964. if ( m_pClickedChannel )
  1965. {
  1966. switch (m_nClickedChannelCloseCaptionButton )
  1967. {
  1968. default:
  1969. break;
  1970. case CChoreoChannelWidget::CLOSECAPTION_NONE:
  1971. {
  1972. SetDirty( true );
  1973. PushUndo( "Enable/disable Channel" );
  1974. m_pClickedChannel->GetChannel()->SetActive( !m_pClickedChannel->GetChannel()->GetActive() );
  1975. PushRedo( "Enable/disable Channel" );
  1976. }
  1977. break;
  1978. case CChoreoChannelWidget::CLOSECAPTION_CAPTION:
  1979. {
  1980. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  1981. if ( e && e->GetNumSlaves() >= 1 )
  1982. {
  1983. OnChangeCloseCaptionToken( e );
  1984. }
  1985. }
  1986. break;
  1987. }
  1988. return;
  1989. }
  1990. if ( m_pClickedActor )
  1991. {
  1992. SetDirty( true );
  1993. PushUndo( "Enable/disable Actor" );
  1994. m_pClickedActor->GetActor()->SetActive( !m_pClickedActor->GetActor()->GetActive() );
  1995. PushRedo( "Enable/disable Actor" );
  1996. return;
  1997. }
  1998. }
  1999. //-----------------------------------------------------------------------------
  2000. // Purpose:
  2001. // Input : mx -
  2002. // my -
  2003. //-----------------------------------------------------------------------------
  2004. void CChoreoView::MouseContinueDrag( mxEvent *event, int mx, int my )
  2005. {
  2006. if ( !m_bDragging )
  2007. return;
  2008. DrawFocusRect();
  2009. ApplyBounds( mx, my );
  2010. for ( int i = 0; i < m_FocusRects.Size(); i++ )
  2011. {
  2012. CFocusRect *f = &m_FocusRects[ i ];
  2013. f->m_rcFocus = f->m_rcOrig;
  2014. switch ( m_nDragType )
  2015. {
  2016. default:
  2017. case DRAGTYPE_SCRUBBER:
  2018. {
  2019. float t = GetTimeValueForMouse( mx );
  2020. t += m_flScrubberTimeOffset;
  2021. ClampTimeToSelectionInterval( t );
  2022. float dt = t - m_flScrub;
  2023. SetScrubTargetTime( t );
  2024. m_bSimulating = true;
  2025. ScrubThink( dt, true, this );
  2026. SetScrubTime( t );
  2027. OffsetRect( &f->m_rcFocus, ( mx - m_xStart ), 0 );
  2028. }
  2029. break;
  2030. case DRAGTYPE_EVENT_MOVE:
  2031. case DRAGTYPE_EVENTTAG_MOVE:
  2032. case DRAGTYPE_EVENTABSTAG_MOVE:
  2033. {
  2034. int dx = mx - m_xStart;
  2035. int dy = my - m_yStart;
  2036. if ( m_pClickedEvent )
  2037. {
  2038. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  2039. // Only allow jumping channels if shift is down
  2040. if ( !shiftdown )
  2041. {
  2042. dy = 0;
  2043. }
  2044. if ( abs( dy ) < m_pClickedEvent->GetItemHeight() )
  2045. {
  2046. dy = 0;
  2047. }
  2048. if ( m_nSelectedEvents > 1 )
  2049. {
  2050. dy = 0;
  2051. }
  2052. if ( m_nDragType == DRAGTYPE_EVENTTAG_MOVE || m_nDragType == DRAGTYPE_EVENTABSTAG_MOVE )
  2053. {
  2054. dy = 0;
  2055. }
  2056. if ( m_pClickedEvent->GetEvent()->IsUsingRelativeTag() )
  2057. {
  2058. dx = 0;
  2059. }
  2060. }
  2061. else
  2062. {
  2063. dy = 0;
  2064. }
  2065. OffsetRect( &f->m_rcFocus, dx, dy );
  2066. }
  2067. break;
  2068. case DRAGTYPE_EVENT_STARTTIME:
  2069. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2070. f->m_rcFocus.left += ( mx - m_xStart );
  2071. break;
  2072. case DRAGTYPE_EVENT_ENDTIME:
  2073. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2074. f->m_rcFocus.right += ( mx - m_xStart );
  2075. break;
  2076. case DRAGTYPE_SCENE_ENDTIME:
  2077. OffsetRect( &f->m_rcFocus, ( mx - m_xStart ), 0 );
  2078. break;
  2079. case DRAGTYPE_RESCALELEFT:
  2080. case DRAGTYPE_RESCALERIGHT:
  2081. //f->m_rcFocus.right += ( mx - m_xStart );
  2082. break;
  2083. }
  2084. }
  2085. if ( m_nDragType == DRAGTYPE_RESCALELEFT ||
  2086. m_nDragType == DRAGTYPE_RESCALERIGHT )
  2087. {
  2088. int c = m_FocusRects.Count();
  2089. int m_nStart = INT_MAX;
  2090. int m_nEnd = INT_MIN;
  2091. for ( int i = 0; i < c; ++i )
  2092. {
  2093. CFocusRect *f = &m_FocusRects[ i ];
  2094. if ( f->m_rcFocus.left < m_nStart )
  2095. {
  2096. m_nStart = f->m_rcFocus.left;
  2097. }
  2098. if ( f->m_rcFocus.right > m_nEnd )
  2099. {
  2100. m_nEnd = f->m_rcFocus.right;
  2101. }
  2102. }
  2103. // Now figure out rescaling logic
  2104. int dxPixels = mx - m_xStart;
  2105. int oldSize = m_nEnd - m_nStart;
  2106. if ( oldSize > 0 )
  2107. {
  2108. float rescale = 1.0f;
  2109. if ( m_nDragType == DRAGTYPE_RESCALERIGHT )
  2110. {
  2111. rescale = (float)( oldSize + dxPixels )/(float)oldSize;
  2112. }
  2113. else
  2114. {
  2115. rescale = (float)( oldSize - dxPixels )/(float)oldSize;
  2116. }
  2117. for ( int i = 0; i < c; ++i )
  2118. {
  2119. CFocusRect *f = &m_FocusRects[ i ];
  2120. int w = f->m_rcFocus.right - f->m_rcFocus.left;
  2121. if ( m_nDragType == DRAGTYPE_RESCALERIGHT )
  2122. {
  2123. f->m_rcFocus.left = m_nStart + ( int )( rescale * (float)( f->m_rcFocus.left - m_nStart ) + 0.5f );
  2124. f->m_rcFocus.right = f->m_rcFocus.left + ( int )( rescale * (float)w + 0.5f );
  2125. }
  2126. else
  2127. {
  2128. f->m_rcFocus.right = m_nEnd - ( int )( rescale * (float)( m_nEnd - f->m_rcFocus.right ) + 0.5f );
  2129. f->m_rcFocus.left = f->m_rcFocus.right - ( int )( rescale * (float)w + 0.5f );
  2130. }
  2131. }
  2132. }
  2133. }
  2134. DrawFocusRect();
  2135. }
  2136. //-----------------------------------------------------------------------------
  2137. // Purpose:
  2138. // Input : mx -
  2139. // my -
  2140. //-----------------------------------------------------------------------------
  2141. void CChoreoView::MouseMove( int mx, int my )
  2142. {
  2143. if ( m_bDragging )
  2144. return;
  2145. int dragtype = ComputeEventDragType( mx, my );
  2146. if ( dragtype == DRAGTYPE_NONE )
  2147. {
  2148. CChoreoGlobalEventWidget *ge = NULL;
  2149. GetObjectsUnderMouse( mx, my, NULL, NULL, NULL, &ge, NULL, NULL, NULL );
  2150. if ( ge )
  2151. {
  2152. dragtype = DRAGTYPE_EVENT_MOVE;
  2153. }
  2154. if ( dragtype == DRAGTYPE_NONE )
  2155. {
  2156. if ( IsMouseOverSceneEndTime( mx ) )
  2157. {
  2158. dragtype = DRAGTYPE_SCENE_ENDTIME;
  2159. }
  2160. }
  2161. }
  2162. if ( m_hPrevCursor )
  2163. {
  2164. SetCursor( m_hPrevCursor );
  2165. m_hPrevCursor = NULL;
  2166. }
  2167. switch ( dragtype )
  2168. {
  2169. default:
  2170. break;
  2171. case DRAGTYPE_EVENTTAG_MOVE:
  2172. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  2173. break;
  2174. case DRAGTYPE_EVENTABSTAG_MOVE:
  2175. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_IBEAM ) );
  2176. break;
  2177. case DRAGTYPE_EVENT_MOVE:
  2178. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
  2179. break;
  2180. case DRAGTYPE_EVENT_STARTTIME:
  2181. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2182. case DRAGTYPE_EVENT_ENDTIME:
  2183. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2184. case DRAGTYPE_SCENE_ENDTIME:
  2185. case DRAGTYPE_RESCALELEFT:
  2186. case DRAGTYPE_RESCALERIGHT:
  2187. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  2188. break;
  2189. }
  2190. }
  2191. //-----------------------------------------------------------------------------
  2192. // Purpose:
  2193. // Input : *e -
  2194. // Output : Returns true on success, false on failure.
  2195. //-----------------------------------------------------------------------------
  2196. bool CChoreoView::CheckGestureLength( CChoreoEvent *e, bool bCheckOnly )
  2197. {
  2198. Assert( e );
  2199. if ( !e )
  2200. return false;
  2201. if ( e->GetType() != CChoreoEvent::GESTURE )
  2202. {
  2203. Con_Printf( "CheckGestureLength: called on non-GESTURE event %s\n", e->GetName() );
  2204. return false;
  2205. }
  2206. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2207. if ( !model )
  2208. return false;
  2209. CStudioHdr *pStudioHdr = model->GetStudioHdr();
  2210. if ( !pStudioHdr )
  2211. return false;
  2212. return UpdateGestureLength( e, pStudioHdr, model->GetPoseParameters(), bCheckOnly );
  2213. }
  2214. //-----------------------------------------------------------------------------
  2215. // Purpose:
  2216. // Input : *e -
  2217. // Output : Returns true on success, false on failure.
  2218. //-----------------------------------------------------------------------------
  2219. bool CChoreoView::DefaultGestureLength( CChoreoEvent *e, bool bCheckOnly )
  2220. {
  2221. Assert( e );
  2222. if ( !e )
  2223. return false;
  2224. if ( e->GetType() != CChoreoEvent::GESTURE )
  2225. {
  2226. Con_Printf( "DefaultGestureLength: called on non-GESTURE event %s\n", e->GetName() );
  2227. return false;
  2228. }
  2229. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2230. if ( !model )
  2231. return false;
  2232. if ( !model->GetStudioHdr() )
  2233. return false;
  2234. int iSequence = model->LookupSequence( e->GetParameters() );
  2235. if ( iSequence < 0 )
  2236. return false;
  2237. bool bret = false;
  2238. float seqduration = model->GetDuration( iSequence );
  2239. if ( seqduration != 0.0f )
  2240. {
  2241. bret = true;
  2242. if ( !bCheckOnly )
  2243. {
  2244. e->SetEndTime( e->GetStartTime() + seqduration );
  2245. }
  2246. }
  2247. return bret;
  2248. }
  2249. //-----------------------------------------------------------------------------
  2250. // Purpose:
  2251. // Input : *e -
  2252. // Output : Returns true on success, false on failure.
  2253. //-----------------------------------------------------------------------------
  2254. bool CChoreoView::AutoaddGestureKeys( CChoreoEvent *e, bool bCheckOnly )
  2255. {
  2256. if ( !e )
  2257. return false;
  2258. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2259. if ( !model )
  2260. return false;
  2261. CStudioHdr *pStudioHdr = model->GetStudioHdr();
  2262. if ( !pStudioHdr )
  2263. return false;
  2264. return AutoAddGestureKeys( e, pStudioHdr, model->GetPoseParameters(), bCheckOnly );
  2265. }
  2266. //-----------------------------------------------------------------------------
  2267. // Purpose:
  2268. //-----------------------------------------------------------------------------
  2269. bool CChoreoView::CheckSequenceLength( CChoreoEvent *e, bool bCheckOnly )
  2270. {
  2271. Assert( e );
  2272. if ( !e )
  2273. return false;
  2274. if ( e->GetType() != CChoreoEvent::SEQUENCE )
  2275. {
  2276. Con_Printf( "CheckSequenceLength: called on non-SEQUENCE event %s\n", e->GetName() );
  2277. return false;
  2278. }
  2279. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2280. if ( !model )
  2281. return false;
  2282. CStudioHdr *pStudioHdr = model->GetStudioHdr();
  2283. if ( !pStudioHdr )
  2284. return false;
  2285. return UpdateSequenceLength( e, pStudioHdr, model->GetPoseParameters(), bCheckOnly, true );
  2286. }
  2287. void CChoreoView::FinishDraggingSceneEndTime( mxEvent *event, int mx, int my )
  2288. {
  2289. DrawFocusRect();
  2290. m_FocusRects.Purge();
  2291. m_bDragging = false;
  2292. float mouse_dt = GetTimeDeltaForMouseDelta( mx, m_xStart );
  2293. if ( !mouse_dt )
  2294. {
  2295. return;
  2296. }
  2297. SetDirty( true );
  2298. const char *desc = "Change Scene Duration";
  2299. PushUndo( desc );
  2300. float newendtime = GetTimeValueForMouse( mx );
  2301. float oldendtime = m_pScene->FindStopTime();
  2302. float scene_dt = newendtime - oldendtime;
  2303. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  2304. {
  2305. CChoreoActorWidget *a = m_SceneActors[ i ];
  2306. if ( !a )
  2307. continue;
  2308. for ( int j = 0; j < a->GetNumChannels(); j++ )
  2309. {
  2310. CChoreoChannelWidget *channel = a->GetChannel( j );
  2311. if ( !channel )
  2312. continue;
  2313. int k;
  2314. CChoreoEvent *finalGesture = NULL;
  2315. for ( k = channel->GetNumEvents() - 1; k >= 0; k-- )
  2316. {
  2317. CChoreoEventWidget *event = channel->GetEvent( k );
  2318. CChoreoEvent *e = event->GetEvent();
  2319. if ( e->GetType() != CChoreoEvent::GESTURE )
  2320. continue;
  2321. if ( !finalGesture )
  2322. {
  2323. finalGesture = e;
  2324. }
  2325. else
  2326. {
  2327. if ( e->GetStartTime() > finalGesture->GetStartTime() )
  2328. {
  2329. finalGesture = e;
  2330. }
  2331. }
  2332. }
  2333. for ( k = channel->GetNumEvents() - 1; k >= 0; k-- )
  2334. {
  2335. CChoreoEventWidget *event = channel->GetEvent( k );
  2336. CChoreoEvent *e = event->GetEvent();
  2337. // Event starts after new end time, kill it
  2338. if ( e->GetStartTime() > newendtime )
  2339. {
  2340. channel->GetChannel()->RemoveEvent( e );
  2341. m_pScene->DeleteReferencedObjects( e );
  2342. continue;
  2343. }
  2344. // No change to normal events that end earlier than new time (but do change gestures)
  2345. if ( e->GetEndTime() < newendtime &&
  2346. e != finalGesture )
  2347. {
  2348. continue;
  2349. }
  2350. float dt = scene_dt;
  2351. if ( e->GetType() == CChoreoEvent::GESTURE )
  2352. {
  2353. if ( e->GetEndTime() < newendtime )
  2354. {
  2355. dt = newendtime - e->GetEndTime();
  2356. }
  2357. }
  2358. float newduration = e->GetDuration() + dt;
  2359. RescaleRamp( e, newduration );
  2360. switch ( e->GetType() )
  2361. {
  2362. default:
  2363. break;
  2364. case CChoreoEvent::GESTURE:
  2365. {
  2366. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() + dt, true );
  2367. }
  2368. break;
  2369. case CChoreoEvent::FLEXANIMATION:
  2370. {
  2371. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() + dt );
  2372. }
  2373. break;
  2374. }
  2375. e->OffsetEndTime( dt );
  2376. e->SnapTimes();
  2377. e->ResortRamp();
  2378. }
  2379. }
  2380. }
  2381. // Remove event and move to new object
  2382. DeleteSceneWidgets();
  2383. m_nDragType = DRAGTYPE_NONE;
  2384. if ( m_hPrevCursor )
  2385. {
  2386. SetCursor( m_hPrevCursor );
  2387. m_hPrevCursor = 0;
  2388. }
  2389. PushRedo( desc );
  2390. CreateSceneWidgets();
  2391. InvalidateLayout();
  2392. g_pExpressionTool->LayoutItems( true );
  2393. g_pExpressionTool->redraw();
  2394. g_pGestureTool->redraw();
  2395. g_pRampTool->redraw();
  2396. g_pSceneRampTool->redraw();
  2397. }
  2398. //-----------------------------------------------------------------------------
  2399. // Purpose: Called after association changes to reset .wav file images
  2400. // Input : -
  2401. //-----------------------------------------------------------------------------
  2402. void CChoreoView::RecomputeWaves()
  2403. {
  2404. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  2405. {
  2406. CChoreoActorWidget *a = m_SceneActors[ i ];
  2407. if ( !a )
  2408. continue;
  2409. for ( int j = 0; j < a->GetNumChannels(); j++ )
  2410. {
  2411. CChoreoChannelWidget *c = a->GetChannel( j );
  2412. if ( !c )
  2413. continue;
  2414. for ( int k = 0; k < c->GetNumEvents(); k++ )
  2415. {
  2416. CChoreoEventWidget *e = c->GetEvent( k );
  2417. if ( !e )
  2418. continue;
  2419. e->RecomputeWave();
  2420. }
  2421. }
  2422. }
  2423. }
  2424. //-----------------------------------------------------------------------------
  2425. // Purpose:
  2426. // Input : mx -
  2427. // my -
  2428. //-----------------------------------------------------------------------------
  2429. void CChoreoView::FinishDraggingEvent( mxEvent *event, int mx, int my )
  2430. {
  2431. DrawFocusRect();
  2432. m_FocusRects.Purge();
  2433. m_bDragging = false;
  2434. float dt = GetTimeDeltaForMouseDelta( mx, m_xStart );
  2435. if ( !dt )
  2436. {
  2437. if ( m_pScene && m_pClickedEvent && m_pClickedEvent->GetEvent()->GetType() == CChoreoEvent::SPEAK )
  2438. {
  2439. // Show phone wav in wav viewer
  2440. char sndname[ 512 ];
  2441. Q_strncpy( sndname, FacePoser_TranslateSoundName( m_pClickedEvent->GetEvent() ), sizeof( sndname ) );
  2442. if ( sndname[ 0 ] )
  2443. {
  2444. SetCurrentWaveFile( va( "sound/%s", sndname ), m_pClickedEvent->GetEvent() );
  2445. }
  2446. else
  2447. {
  2448. Warning( "Unable to resolve sound name for '%s', check actor associations\n", m_pClickedEvent->GetEvent()->GetName() );
  2449. }
  2450. }
  2451. return;
  2452. }
  2453. SetDirty( true );
  2454. char const *desc = "";
  2455. switch ( m_nDragType )
  2456. {
  2457. default:
  2458. case DRAGTYPE_EVENT_MOVE:
  2459. desc = "Event Move";
  2460. break;
  2461. case DRAGTYPE_EVENT_STARTTIME:
  2462. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2463. desc = "Change Start Time";
  2464. break;
  2465. case DRAGTYPE_EVENT_ENDTIME:
  2466. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2467. desc = "Change End Time";
  2468. break;
  2469. case DRAGTYPE_EVENTTAG_MOVE:
  2470. desc = "Move Event Tag";
  2471. break;
  2472. case DRAGTYPE_EVENTABSTAG_MOVE:
  2473. desc = "Move Abs Event Tag";
  2474. break;
  2475. case DRAGTYPE_RESCALELEFT:
  2476. case DRAGTYPE_RESCALERIGHT:
  2477. desc = "Rescale Time";
  2478. break;
  2479. }
  2480. PushUndo( desc );
  2481. CUtlVector< CChoreoEvent * > rescaleHelper;
  2482. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  2483. {
  2484. CChoreoActorWidget *actor = m_SceneActors[ i ];
  2485. if ( !actor )
  2486. continue;
  2487. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  2488. {
  2489. CChoreoChannelWidget *channel = actor->GetChannel( j );
  2490. if ( !channel )
  2491. continue;
  2492. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  2493. {
  2494. CChoreoEventWidget *event = channel->GetEvent( k );
  2495. if ( !event )
  2496. continue;
  2497. if ( !event->IsSelected() )
  2498. continue;
  2499. // Figure out true dt
  2500. CChoreoEvent *e = event->GetEvent();
  2501. if ( e )
  2502. {
  2503. switch ( m_nDragType )
  2504. {
  2505. default:
  2506. case DRAGTYPE_EVENT_MOVE:
  2507. e->OffsetTime( dt );
  2508. e->SnapTimes();
  2509. break;
  2510. case DRAGTYPE_EVENT_STARTTIME:
  2511. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2512. {
  2513. float newduration = e->GetDuration() - dt;
  2514. RescaleRamp( e, newduration );
  2515. switch ( e->GetType() )
  2516. {
  2517. default:
  2518. break;
  2519. case CChoreoEvent::GESTURE:
  2520. {
  2521. e->RescaleGestureTimes( e->GetStartTime() + dt, e->GetEndTime(), m_nDragType == DRAGTYPE_EVENT_STARTTIME );
  2522. }
  2523. break;
  2524. case CChoreoEvent::FLEXANIMATION:
  2525. {
  2526. RescaleExpressionTimes( e, e->GetStartTime() + dt, e->GetEndTime() );
  2527. }
  2528. break;
  2529. }
  2530. e->OffsetStartTime( dt );
  2531. e->SnapTimes();
  2532. e->ResortRamp();
  2533. }
  2534. break;
  2535. case DRAGTYPE_EVENT_ENDTIME:
  2536. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2537. {
  2538. float newduration = e->GetDuration() + dt;
  2539. RescaleRamp( e, newduration );
  2540. switch ( e->GetType() )
  2541. {
  2542. default:
  2543. break;
  2544. case CChoreoEvent::GESTURE:
  2545. {
  2546. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() + dt, m_nDragType == DRAGTYPE_EVENT_ENDTIME );
  2547. }
  2548. break;
  2549. case CChoreoEvent::FLEXANIMATION:
  2550. {
  2551. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() + dt );
  2552. }
  2553. break;
  2554. }
  2555. e->OffsetEndTime( dt );
  2556. e->SnapTimes();
  2557. e->ResortRamp();
  2558. }
  2559. break;
  2560. case DRAGTYPE_RESCALELEFT:
  2561. case DRAGTYPE_RESCALERIGHT:
  2562. {
  2563. rescaleHelper.AddToTail( e );
  2564. }
  2565. break;
  2566. case DRAGTYPE_EVENTTAG_MOVE:
  2567. {
  2568. // Get current x position
  2569. if ( m_nClickedTag != -1 )
  2570. {
  2571. CEventRelativeTag *tag = e->GetRelativeTag( m_nClickedTag );
  2572. if ( tag )
  2573. {
  2574. float dx = mx - m_xStart;
  2575. // Determine left edcge
  2576. RECT bounds;
  2577. bounds = event->getBounds();
  2578. if ( bounds.right - bounds.left > 0 )
  2579. {
  2580. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  2581. left += dx;
  2582. if ( left < bounds.left )
  2583. {
  2584. left = bounds.left;
  2585. }
  2586. else if ( left >= bounds.right )
  2587. {
  2588. left = bounds.right - 1;
  2589. }
  2590. // Now convert back to a percentage
  2591. float frac = (float)( left - bounds.left ) / (float)( bounds.right - bounds.left );
  2592. tag->SetPercentage( frac );
  2593. }
  2594. }
  2595. }
  2596. }
  2597. break;
  2598. case DRAGTYPE_EVENTABSTAG_MOVE:
  2599. {
  2600. // Get current x position
  2601. if ( m_pClickedAbsoluteTag != NULL )
  2602. {
  2603. CEventAbsoluteTag *tag = m_pClickedAbsoluteTag;
  2604. if ( tag )
  2605. {
  2606. float dx = mx - m_xStart;
  2607. // Determine left edcge
  2608. RECT bounds;
  2609. bounds = event->getBounds();
  2610. if ( bounds.right - bounds.left > 0 )
  2611. {
  2612. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  2613. left += dx;
  2614. if ( left < bounds.left )
  2615. {
  2616. left = bounds.left;
  2617. }
  2618. else if ( left >= bounds.right )
  2619. {
  2620. left = bounds.right - 1;
  2621. }
  2622. // Now convert back to a percentage
  2623. float frac = (float)( left - bounds.left ) / (float)( bounds.right - bounds.left );
  2624. tag->SetPercentage( frac );
  2625. }
  2626. }
  2627. }
  2628. }
  2629. break;
  2630. }
  2631. }
  2632. switch ( e->GetType() )
  2633. {
  2634. default:
  2635. break;
  2636. case CChoreoEvent::SPEAK:
  2637. {
  2638. // Try and load wav to get length
  2639. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  2640. if ( wave )
  2641. {
  2642. e->SetEndTime( e->GetStartTime() + wave->GetRunningLength() );
  2643. delete wave;
  2644. }
  2645. }
  2646. break;
  2647. case CChoreoEvent::SEQUENCE:
  2648. {
  2649. CheckSequenceLength( e, false );
  2650. }
  2651. break;
  2652. case CChoreoEvent::GESTURE:
  2653. {
  2654. CheckGestureLength( e, false );
  2655. }
  2656. break;
  2657. }
  2658. }
  2659. }
  2660. }
  2661. if ( rescaleHelper.Count() > 0 )
  2662. {
  2663. int i;
  2664. // Determine start and end times for existing "selection"
  2665. float flStart = FLT_MAX;
  2666. float flEnd = FLT_MIN;
  2667. for ( i = 0; i < rescaleHelper.Count(); ++i )
  2668. {
  2669. CChoreoEvent *e = rescaleHelper[ i ];
  2670. float st = e->GetStartTime();
  2671. float ed = e->GetEndTime();
  2672. if ( st < flStart )
  2673. {
  2674. flStart = st;
  2675. }
  2676. if ( ed > flEnd )
  2677. {
  2678. flEnd = ed;
  2679. }
  2680. }
  2681. float flSelectionDuration = flEnd - flStart;
  2682. if ( flSelectionDuration > 0.0f )
  2683. {
  2684. float flNewDuration = 0.0f;
  2685. if ( m_nDragType == DRAGTYPE_RESCALELEFT )
  2686. {
  2687. flNewDuration = max( 0.1f, flSelectionDuration - dt );
  2688. }
  2689. else
  2690. {
  2691. flNewDuration = max( 0.1f, flSelectionDuration + dt );
  2692. }
  2693. float flScale = flNewDuration / flSelectionDuration;
  2694. for ( i = 0; i < rescaleHelper.Count(); ++i )
  2695. {
  2696. CChoreoEvent *e = rescaleHelper[ i ];
  2697. float st = e->GetStartTime();
  2698. float et = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime();
  2699. float flTimeFromStart = st - flStart;
  2700. float flTimeFromEnd = flEnd - et;
  2701. float flDuration = e->GetDuration();
  2702. float flNewStartTime = 0.0f;
  2703. float flNewDuration = 0.0f;
  2704. if ( m_nDragType == DRAGTYPE_RESCALELEFT )
  2705. {
  2706. float flNewEndTime = flEnd - flTimeFromEnd * flScale;
  2707. if ( !e->HasEndTime() || e->IsFixedLength() )
  2708. {
  2709. e->OffsetTime( flNewEndTime - flDuration - st );
  2710. continue;
  2711. }
  2712. flNewDuration = flDuration * flScale;
  2713. flNewStartTime = flNewEndTime - flNewDuration;
  2714. }
  2715. else
  2716. {
  2717. flNewStartTime = flTimeFromStart * flScale + flStart;
  2718. if ( !e->HasEndTime() || e->IsFixedLength() )
  2719. {
  2720. e->OffsetTime( flNewStartTime - st );
  2721. continue;
  2722. }
  2723. flNewDuration = flDuration * flScale;
  2724. }
  2725. RescaleRamp( e, flNewDuration );
  2726. switch ( e->GetType() )
  2727. {
  2728. default:
  2729. break;
  2730. case CChoreoEvent::GESTURE:
  2731. {
  2732. e->RescaleGestureTimes( flNewStartTime, flNewStartTime + flNewDuration, m_nDragType == DRAGTYPE_EVENT_STARTTIME || m_nDragType == DRAGTYPE_EVENT_ENDTIME );
  2733. }
  2734. break;
  2735. case CChoreoEvent::FLEXANIMATION:
  2736. {
  2737. RescaleExpressionTimes( e, flNewStartTime, flNewStartTime + flNewDuration );
  2738. }
  2739. break;
  2740. }
  2741. e->SetStartTime( flNewStartTime );
  2742. Assert( e->HasEndTime() );
  2743. e->SetEndTime( flNewStartTime + flNewDuration );
  2744. }
  2745. }
  2746. }
  2747. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  2748. {
  2749. CChoreoGlobalEventWidget *gew = m_SceneGlobalEvents[ i ];
  2750. if ( !gew || !gew->IsSelected() )
  2751. continue;
  2752. CChoreoEvent *e = gew->GetEvent();
  2753. if ( !e )
  2754. continue;
  2755. e->OffsetTime( dt );
  2756. e->SnapTimes();
  2757. }
  2758. m_nDragType = DRAGTYPE_NONE;
  2759. if ( m_hPrevCursor )
  2760. {
  2761. SetCursor( m_hPrevCursor );
  2762. m_hPrevCursor = 0;
  2763. }
  2764. CChoreoEvent *e = m_pClickedEvent ? m_pClickedEvent->GetEvent() : NULL;
  2765. if ( e )
  2766. {
  2767. // See if event is moving to a new owner
  2768. CChoreoChannelWidget *chOrig, *chNew;
  2769. int dy = my - m_yStart;
  2770. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  2771. if ( !shiftdown )
  2772. {
  2773. dy = 0;
  2774. }
  2775. if ( abs( dy ) < m_pClickedEvent->GetItemHeight() )
  2776. {
  2777. my = m_yStart;
  2778. }
  2779. chNew = GetChannelUnderCursorPos( mx, my );
  2780. InvalidateLayout();
  2781. mx = m_xStart;
  2782. my = m_yStart;
  2783. chOrig = m_pClickedChannel;
  2784. if ( chOrig && chNew && chOrig != chNew )
  2785. {
  2786. // Swap underlying objects
  2787. CChoreoChannel *pOrigChannel, *pNewChannel;
  2788. pOrigChannel = chOrig->GetChannel();
  2789. pNewChannel = chNew->GetChannel();
  2790. Assert( pOrigChannel && pNewChannel );
  2791. // Remove event and move to new object
  2792. DeleteSceneWidgets();
  2793. pOrigChannel->RemoveEvent( e );
  2794. pNewChannel->AddEvent( e );
  2795. e->SetChannel( pNewChannel );
  2796. e->SetActor( pNewChannel->GetActor() );
  2797. CreateSceneWidgets();
  2798. }
  2799. else
  2800. {
  2801. if ( e && e->GetType() == CChoreoEvent::SPEAK )
  2802. {
  2803. // Show phone wav in wav viewer
  2804. SetCurrentWaveFile( va( "sound/%s", FacePoser_TranslateSoundName( e ) ), e );
  2805. }
  2806. }
  2807. }
  2808. PushRedo( desc );
  2809. InvalidateLayout();
  2810. if ( e )
  2811. {
  2812. switch ( e->GetType() )
  2813. {
  2814. default:
  2815. break;
  2816. case CChoreoEvent::FLEXANIMATION:
  2817. {
  2818. g_pExpressionTool->SetEvent( e );
  2819. g_pFlexPanel->SetEvent( e );
  2820. }
  2821. break;
  2822. case CChoreoEvent::GESTURE:
  2823. {
  2824. g_pGestureTool->SetEvent( e );
  2825. }
  2826. break;
  2827. }
  2828. if ( e->HasEndTime() )
  2829. {
  2830. g_pRampTool->SetEvent( e );
  2831. }
  2832. }
  2833. g_pExpressionTool->LayoutItems( true );
  2834. g_pExpressionTool->redraw();
  2835. g_pGestureTool->redraw();
  2836. g_pRampTool->redraw();
  2837. g_pSceneRampTool->redraw();
  2838. }
  2839. //-----------------------------------------------------------------------------
  2840. // Purpose:
  2841. // Input : mx -
  2842. // my -
  2843. //-----------------------------------------------------------------------------
  2844. void CChoreoView::MouseFinishDrag( mxEvent *event, int mx, int my )
  2845. {
  2846. if ( !m_bDragging )
  2847. return;
  2848. ApplyBounds( mx, my );
  2849. switch ( m_nDragType )
  2850. {
  2851. case DRAGTYPE_SCRUBBER:
  2852. {
  2853. DrawFocusRect();
  2854. m_FocusRects.Purge();
  2855. float t = GetTimeValueForMouse( mx );
  2856. t += m_flScrubberTimeOffset;
  2857. m_flScrubberTimeOffset = 0.0f;
  2858. ClampTimeToSelectionInterval( t );
  2859. SetScrubTime( t );
  2860. SetScrubTargetTime( t );
  2861. m_bDragging = false;
  2862. m_nDragType = DRAGTYPE_NONE;
  2863. redraw();
  2864. }
  2865. break;
  2866. case DRAGTYPE_EVENT_MOVE:
  2867. case DRAGTYPE_EVENT_STARTTIME:
  2868. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2869. case DRAGTYPE_EVENT_ENDTIME:
  2870. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2871. case DRAGTYPE_EVENTTAG_MOVE:
  2872. case DRAGTYPE_EVENTABSTAG_MOVE:
  2873. case DRAGTYPE_RESCALELEFT:
  2874. case DRAGTYPE_RESCALERIGHT:
  2875. FinishDraggingEvent( event, mx, my );
  2876. break;
  2877. case DRAGTYPE_SCENE_ENDTIME:
  2878. FinishDraggingSceneEndTime( event, mx, my );
  2879. break;
  2880. default:
  2881. break;
  2882. }
  2883. }
  2884. //-----------------------------------------------------------------------------
  2885. // Purpose:
  2886. // Input : *event -
  2887. // Output : int
  2888. //-----------------------------------------------------------------------------
  2889. int CChoreoView::handleEvent( mxEvent *event )
  2890. {
  2891. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  2892. int iret = 0;
  2893. if ( HandleToolEvent( event ) )
  2894. {
  2895. return iret;
  2896. }
  2897. switch ( event->event )
  2898. {
  2899. case mxEvent::MouseWheeled:
  2900. {
  2901. CChoreoScene *scene = GetScene();
  2902. if ( scene )
  2903. {
  2904. int tz = GetTimeZoom( GetToolName() );
  2905. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  2906. int stepMultipiler = shiftdown ? 5 : 1;
  2907. // Zoom time in / out
  2908. if ( event->height > 0 )
  2909. {
  2910. tz = min( tz + TIME_ZOOM_STEP * stepMultipiler, MAX_TIME_ZOOM );
  2911. }
  2912. else
  2913. {
  2914. tz = max( tz - TIME_ZOOM_STEP * stepMultipiler, TIME_ZOOM_STEP );
  2915. }
  2916. SetTimeZoom( GetToolName(), tz, true );
  2917. CUtlVector< CChoreoEvent * > selected;
  2918. RememberSelectedEvents( selected );
  2919. DeleteSceneWidgets();
  2920. CreateSceneWidgets();
  2921. ReselectEvents( selected );
  2922. InvalidateLayout();
  2923. Con_Printf( "Zoom factor %i %%\n", GetTimeZoom( GetToolName() ) );
  2924. }
  2925. iret = 1;
  2926. }
  2927. break;
  2928. case mxEvent::Size:
  2929. {
  2930. // Force scroll bars to recompute
  2931. ForceScrollBarsToRecompute( false );
  2932. InvalidateLayout();
  2933. PositionControls();
  2934. iret = 1;
  2935. }
  2936. break;
  2937. case mxEvent::MouseDown:
  2938. {
  2939. if ( !m_bDragging )
  2940. {
  2941. if ( event->buttons & mxEvent::MouseRightButton )
  2942. {
  2943. if ( IsMouseOverTimeline( (short)event->x, (short)event->y ) )
  2944. {
  2945. PlaceABPoint( (short)event->x );
  2946. redraw();
  2947. }
  2948. else if ( IsMouseOverScrubArea( event ) )
  2949. {
  2950. float t = GetTimeValueForMouse( (short)event->x );
  2951. ClampTimeToSelectionInterval( t );
  2952. SetScrubTime( t );
  2953. SetScrubTargetTime( t );
  2954. sound->Flush();
  2955. // Unpause the scene
  2956. m_bPaused = false;
  2957. redraw();
  2958. }
  2959. else
  2960. {
  2961. // Show right click menu
  2962. ShowContextMenu( (short)event->x, (short)event->y );
  2963. }
  2964. }
  2965. else
  2966. {
  2967. if ( IsMouseOverTimeline( (short)event->x, (short)event->y ) )
  2968. {
  2969. ClearABPoints();
  2970. redraw();
  2971. }
  2972. else
  2973. {
  2974. // Handle mouse dragging here
  2975. MouseStartDrag( event, (short)event->x, (short)event->y );
  2976. }
  2977. }
  2978. }
  2979. iret = 1;
  2980. }
  2981. break;
  2982. case mxEvent::MouseDrag:
  2983. {
  2984. MouseContinueDrag( event, (short)event->x, (short)event->y );
  2985. iret = 1;
  2986. }
  2987. break;
  2988. case mxEvent::MouseUp:
  2989. {
  2990. MouseFinishDrag( event, (short)event->x, (short)event->y );
  2991. iret = 1;
  2992. }
  2993. break;
  2994. case mxEvent::MouseMove:
  2995. {
  2996. MouseMove( (short)event->x, (short)event->y );
  2997. UpdateStatusArea( (short)event->x, (short)event->y );
  2998. iret = 1;
  2999. }
  3000. break;
  3001. case mxEvent::KeyDown:
  3002. {
  3003. iret = 1;
  3004. switch ( event->key )
  3005. {
  3006. default:
  3007. iret = 0;
  3008. break;
  3009. case 'E':
  3010. if ( GetAsyncKeyState( VK_CONTROL ) )
  3011. {
  3012. OnPlaceNextSpeakEvent();
  3013. }
  3014. break;
  3015. case VK_ESCAPE:
  3016. DeselectAll();
  3017. break;
  3018. case 'C':
  3019. CopyEvents();
  3020. iret = 1;
  3021. break;
  3022. case 'V':
  3023. PasteEvents();
  3024. redraw();
  3025. break;
  3026. case VK_DELETE:
  3027. {
  3028. if ( IsActiveTool() )
  3029. {
  3030. DeleteSelectedEvents();
  3031. }
  3032. }
  3033. break;
  3034. case VK_RETURN:
  3035. {
  3036. CUtlVector< CChoreoEvent * > events;
  3037. GetSelectedEvents( events );
  3038. if ( events.Count() == 1 )
  3039. {
  3040. if ( GetAsyncKeyState( VK_MENU ) )
  3041. {
  3042. EditEvent( events[ 0 ] );
  3043. redraw();
  3044. iret = 1;
  3045. }
  3046. }
  3047. }
  3048. break;
  3049. case 'Z': // Undo/Redo
  3050. {
  3051. if ( GetAsyncKeyState( VK_CONTROL ) )
  3052. {
  3053. if ( GetAsyncKeyState( VK_SHIFT ) )
  3054. {
  3055. if ( CanRedo() )
  3056. {
  3057. Con_Printf( "Redo %s\n", GetRedoDescription() );
  3058. Redo();
  3059. iret = 1;
  3060. }
  3061. }
  3062. else
  3063. {
  3064. if ( CanUndo() )
  3065. {
  3066. Con_Printf( "Undo %s\n", GetUndoDescription() );
  3067. Undo();
  3068. iret = 1;
  3069. }
  3070. }
  3071. }
  3072. }
  3073. break;
  3074. case VK_SPACE:
  3075. {
  3076. if ( IsPlayingScene() )
  3077. {
  3078. StopScene();
  3079. }
  3080. }
  3081. break;
  3082. case 188: // VK_OEM_COMMA:
  3083. {
  3084. SetScrubTargetTime( 0.0f );
  3085. }
  3086. break;
  3087. case 190: // VK_OEM_PERIOD:
  3088. {
  3089. CChoreoScene *scene = GetScene();
  3090. if ( scene )
  3091. {
  3092. SetScrubTargetTime( scene->FindStopTime() );
  3093. }
  3094. }
  3095. break;
  3096. case VK_LEFT:
  3097. {
  3098. CChoreoScene *scene = GetScene();
  3099. if ( scene && scene->GetSceneFPS() > 0 )
  3100. {
  3101. float curscrub = m_flScrub;
  3102. curscrub -= ( 1.0f / (float)scene->GetSceneFPS() );
  3103. curscrub = max( curscrub, 0.0f );
  3104. SetScrubTargetTime( curscrub );
  3105. }
  3106. }
  3107. break;
  3108. case VK_RIGHT:
  3109. {
  3110. CChoreoScene *scene = GetScene();
  3111. if ( scene && scene->GetSceneFPS() > 0 )
  3112. {
  3113. float curscrub = m_flScrub;
  3114. curscrub += ( 1.0f / (float)scene->GetSceneFPS() );
  3115. curscrub = min( curscrub, scene->FindStopTime() );
  3116. SetScrubTargetTime( curscrub );
  3117. }
  3118. }
  3119. break;
  3120. case VK_HOME:
  3121. {
  3122. MoveTimeSliderToPos( 0 );
  3123. }
  3124. break;
  3125. case VK_END:
  3126. {
  3127. float maxtime = m_pScene->FindStopTime() - 1.0f;
  3128. int pixels = (int)( maxtime * GetPixelsPerSecond() );
  3129. MoveTimeSliderToPos( pixels - 1 );
  3130. }
  3131. break;
  3132. case VK_PRIOR: // PgUp
  3133. {
  3134. int window = w2() - GetLabelWidth();
  3135. m_flLeftOffset = max( m_flLeftOffset - (float)window, 0.0f );
  3136. MoveTimeSliderToPos( (int)m_flLeftOffset );
  3137. }
  3138. break;
  3139. case VK_NEXT: // PgDown
  3140. {
  3141. int window = w2() - GetLabelWidth();
  3142. int pixels = ComputeHPixelsNeeded();
  3143. m_flLeftOffset = min( m_flLeftOffset + (float)window, (float)pixels );
  3144. MoveTimeSliderToPos( (int)m_flLeftOffset );
  3145. }
  3146. break;
  3147. }
  3148. }
  3149. break;
  3150. case mxEvent::Action:
  3151. {
  3152. iret = 1;
  3153. switch ( event->action )
  3154. {
  3155. default:
  3156. {
  3157. iret = 0;
  3158. int lang_index = event->action - IDC_CV_CC_LANGUAGESTART;
  3159. if ( lang_index >= 0 && lang_index < CC_NUM_LANGUAGES )
  3160. {
  3161. iret = 1;
  3162. SetCloseCaptionLanguageId( lang_index );
  3163. }
  3164. }
  3165. break;
  3166. case IDC_CV_TOGGLECLOSECAPTIONS:
  3167. {
  3168. OnToggleCloseCaptionsForEvent();
  3169. }
  3170. break;
  3171. case IDC_CV_CHANGECLOSECAPTIONTOKEN:
  3172. {
  3173. if ( m_pClickedChannel )
  3174. {
  3175. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  3176. if ( e && e->GetNumSlaves() >= 1 )
  3177. {
  3178. OnChangeCloseCaptionToken( e );
  3179. }
  3180. }
  3181. }
  3182. break;
  3183. case IDC_CV_REMOVESPEAKEVENTFROMGROUP:
  3184. {
  3185. OnRemoveSpeakEventFromGroup();
  3186. }
  3187. break;
  3188. case IDC_CV_COMBINESPEAKEVENTS:
  3189. {
  3190. OnCombineSpeakEvents();
  3191. }
  3192. break;
  3193. case IDC_CV_CC_SHOW:
  3194. {
  3195. OnToggleCloseCaptionTags();
  3196. }
  3197. break;
  3198. case IDC_CV_TOGGLERAMPONLY:
  3199. {
  3200. m_bRampOnly = !m_bRampOnly;
  3201. redraw();
  3202. }
  3203. break;
  3204. case IDC_CV_PROCESSSEQUENCES:
  3205. {
  3206. m_bProcessSequences = !m_bProcessSequences;
  3207. }
  3208. break;
  3209. case IDC_CV_CHECKSEQLENGTHS:
  3210. {
  3211. OnCheckSequenceLengths();
  3212. }
  3213. break;
  3214. case IDC_CV_CHANGESCALE:
  3215. {
  3216. OnChangeScale();
  3217. }
  3218. break;
  3219. case IDC_CHOREO_PLAYBACKRATE:
  3220. {
  3221. m_flPlaybackRate = m_pPlaybackRate->getValue();
  3222. redraw();
  3223. }
  3224. break;
  3225. case IDC_COPYEVENTS:
  3226. CopyEvents();
  3227. break;
  3228. case IDC_PASTEEVENTS:
  3229. PasteEvents();
  3230. redraw();
  3231. break;
  3232. case IDC_IMPORTEVENTS:
  3233. ImportEvents();
  3234. redraw();
  3235. break;
  3236. case IDC_EXPORTEVENTS:
  3237. ExportEvents();
  3238. redraw();
  3239. break;
  3240. case IDC_EXPORT_VCD:
  3241. ExportVCD();
  3242. redraw();
  3243. break;
  3244. case IDC_IMPORT_VCD:
  3245. ImportVCD();
  3246. redraw();
  3247. break;
  3248. case IDC_EXPRESSIONTOOL:
  3249. OnExpressionTool();
  3250. break;
  3251. case IDC_GESTURETOOL:
  3252. OnGestureTool();
  3253. break;
  3254. case IDC_ASSOCIATEBSP:
  3255. AssociateBSP();
  3256. break;
  3257. case IDC_ASSOCIATEMODEL:
  3258. AssociateModel();
  3259. break;
  3260. case IDC_CVUNDO:
  3261. Undo();
  3262. break;
  3263. case IDC_CVREDO:
  3264. Redo();
  3265. break;
  3266. case IDC_SELECTALL:
  3267. SelectAll();
  3268. break;
  3269. case IDC_DESELECTALL:
  3270. DeselectAll();
  3271. break;
  3272. case IDC_PLAYSCENE:
  3273. Con_Printf( "Commencing playback\n" );
  3274. PlayScene( true );
  3275. break;
  3276. case IDC_PAUSESCENE:
  3277. Con_Printf( "Pausing playback\n" );
  3278. PauseScene();
  3279. break;
  3280. case IDC_STOPSCENE:
  3281. Con_Printf( "Canceling playback\n" );
  3282. StopScene();
  3283. break;
  3284. case IDC_CHOREOVSCROLL:
  3285. {
  3286. int offset = 0;
  3287. bool processed = true;
  3288. switch ( event->modifiers )
  3289. {
  3290. case SB_THUMBTRACK:
  3291. offset = event->height;
  3292. break;
  3293. case SB_PAGEUP:
  3294. offset = m_pVertScrollBar->getValue();
  3295. offset -= 20;
  3296. offset = max( offset, m_pVertScrollBar->getMinValue() );
  3297. break;
  3298. case SB_PAGEDOWN:
  3299. offset = m_pVertScrollBar->getValue();
  3300. offset += 20;
  3301. offset = min( offset, m_pVertScrollBar->getMaxValue() );
  3302. break;
  3303. case SB_LINEDOWN:
  3304. offset = m_pVertScrollBar->getValue();
  3305. offset += 10;
  3306. offset = min( offset, m_pVertScrollBar->getMaxValue() );
  3307. break;
  3308. case SB_LINEUP:
  3309. offset = m_pVertScrollBar->getValue();
  3310. offset -= 10;
  3311. offset = max( offset, m_pVertScrollBar->getMinValue() );
  3312. break;
  3313. default:
  3314. processed = false;
  3315. break;
  3316. }
  3317. if ( processed )
  3318. {
  3319. m_pVertScrollBar->setValue( offset );
  3320. InvalidateRect( (HWND)m_pVertScrollBar->getHandle(), NULL, TRUE );
  3321. m_nTopOffset = offset;
  3322. InvalidateLayout();
  3323. }
  3324. }
  3325. break;
  3326. case IDC_CHOREOHSCROLL:
  3327. {
  3328. int offset = 0;
  3329. bool processed = true;
  3330. switch ( event->modifiers )
  3331. {
  3332. case SB_THUMBTRACK:
  3333. offset = event->height;
  3334. break;
  3335. case SB_PAGEUP:
  3336. offset = m_pHorzScrollBar->getValue();
  3337. offset -= 20;
  3338. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  3339. break;
  3340. case SB_PAGEDOWN:
  3341. offset = m_pHorzScrollBar->getValue();
  3342. offset += 20;
  3343. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  3344. break;
  3345. case SB_LINEUP:
  3346. offset = m_pHorzScrollBar->getValue();
  3347. offset -= 10;
  3348. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  3349. break;
  3350. case SB_LINEDOWN:
  3351. offset = m_pHorzScrollBar->getValue();
  3352. offset += 10;
  3353. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  3354. break;
  3355. default:
  3356. processed = false;
  3357. break;
  3358. }
  3359. if ( processed )
  3360. {
  3361. MoveTimeSliderToPos( offset );
  3362. }
  3363. }
  3364. break;
  3365. case IDC_ADDACTOR:
  3366. {
  3367. NewActor();
  3368. }
  3369. break;
  3370. case IDC_EDITACTOR:
  3371. {
  3372. CChoreoActorWidget *actor = m_pClickedActor;
  3373. if ( actor )
  3374. {
  3375. EditActor( actor->GetActor() );
  3376. }
  3377. }
  3378. break;
  3379. case IDC_DELETEACTOR:
  3380. {
  3381. CChoreoActorWidget *actor = m_pClickedActor;
  3382. if ( actor )
  3383. {
  3384. DeleteActor( actor->GetActor() );
  3385. }
  3386. }
  3387. break;
  3388. case IDC_MOVEACTORUP:
  3389. {
  3390. CChoreoActorWidget *actor = m_pClickedActor;
  3391. if ( actor )
  3392. {
  3393. MoveActorUp( actor->GetActor() );
  3394. }
  3395. }
  3396. break;
  3397. case IDC_MOVEACTORDOWN:
  3398. {
  3399. CChoreoActorWidget *actor = m_pClickedActor;
  3400. if ( actor )
  3401. {
  3402. MoveActorDown( actor->GetActor() );
  3403. }
  3404. }
  3405. break;
  3406. case IDC_CHANNELOPEN:
  3407. {
  3408. CActorBitmapButton *btn = static_cast< CActorBitmapButton * >( event->widget );
  3409. if ( btn )
  3410. {
  3411. CChoreoActorWidget *a = btn->GetActor();
  3412. if ( a )
  3413. {
  3414. a->ShowChannels( true );
  3415. }
  3416. }
  3417. }
  3418. break;
  3419. case IDC_CHANNELCLOSE:
  3420. {
  3421. CActorBitmapButton *btn = static_cast< CActorBitmapButton * >( event->widget );
  3422. if ( btn )
  3423. {
  3424. CChoreoActorWidget *a = btn->GetActor();
  3425. if ( a )
  3426. {
  3427. a->ShowChannels( false );
  3428. }
  3429. }
  3430. }
  3431. break;
  3432. case IDC_ADDEVENT_INTERRUPT:
  3433. {
  3434. AddEvent( CChoreoEvent::INTERRUPT );
  3435. }
  3436. break;
  3437. case IDC_ADDEVENT_PERMITRESPONSES:
  3438. {
  3439. AddEvent( CChoreoEvent::PERMIT_RESPONSES );
  3440. }
  3441. break;
  3442. case IDC_ADDEVENT_EXPRESSION:
  3443. {
  3444. AddEvent( CChoreoEvent::EXPRESSION );
  3445. }
  3446. break;
  3447. case IDC_ADDEVENT_FLEXANIMATION:
  3448. {
  3449. AddEvent( CChoreoEvent::FLEXANIMATION );
  3450. }
  3451. break;
  3452. case IDC_ADDEVENT_GESTURE:
  3453. {
  3454. AddEvent( CChoreoEvent::GESTURE );
  3455. }
  3456. break;
  3457. case IDC_ADDEVENT_NULLGESTURE:
  3458. {
  3459. AddEvent( CChoreoEvent::GESTURE, 1 );
  3460. }
  3461. break;
  3462. case IDC_ADDEVENT_LOOKAT:
  3463. {
  3464. AddEvent( CChoreoEvent::LOOKAT );
  3465. }
  3466. break;
  3467. case IDC_ADDEVENT_MOVETO:
  3468. {
  3469. AddEvent( CChoreoEvent::MOVETO );
  3470. }
  3471. break;
  3472. case IDC_ADDEVENT_FACE:
  3473. {
  3474. AddEvent( CChoreoEvent::FACE );
  3475. }
  3476. break;
  3477. case IDC_ADDEVENT_SPEAK:
  3478. {
  3479. AddEvent( CChoreoEvent::SPEAK );
  3480. }
  3481. break;
  3482. case IDC_ADDEVENT_FIRETRIGGER:
  3483. {
  3484. AddEvent( CChoreoEvent::FIRETRIGGER );
  3485. }
  3486. break;
  3487. case IDC_ADDEVENT_GENERIC:
  3488. {
  3489. AddEvent( CChoreoEvent::GENERIC );
  3490. }
  3491. break;
  3492. case IDC_ADDEVENT_SUBSCENE:
  3493. {
  3494. AddEvent( CChoreoEvent::SUBSCENE );
  3495. }
  3496. break;
  3497. case IDC_ADDEVENT_SEQUENCE:
  3498. {
  3499. AddEvent( CChoreoEvent::SEQUENCE );
  3500. }
  3501. break;
  3502. case IDC_EDITEVENT:
  3503. {
  3504. CChoreoEventWidget *event = m_pClickedEvent;
  3505. if ( event )
  3506. {
  3507. EditEvent( event->GetEvent() );
  3508. redraw();
  3509. }
  3510. }
  3511. break;
  3512. case IDC_DELETEEVENT:
  3513. {
  3514. DeleteSelectedEvents();
  3515. }
  3516. break;
  3517. case IDC_CV_ENABLEEVENTS:
  3518. {
  3519. EnableSelectedEvents( true );
  3520. }
  3521. break;
  3522. case IDC_CV_DISABLEEVENTS:
  3523. {
  3524. EnableSelectedEvents( false );
  3525. }
  3526. break;
  3527. case IDC_MOVETOBACK:
  3528. {
  3529. CChoreoEventWidget *event = m_pClickedEvent;
  3530. if ( event )
  3531. {
  3532. MoveEventToBack( event->GetEvent() );
  3533. }
  3534. }
  3535. break;
  3536. case IDC_DELETERELATIVETAG:
  3537. {
  3538. CChoreoEventWidget *event = m_pClickedEvent;
  3539. if ( event && m_nClickedTag >= 0 )
  3540. {
  3541. DeleteEventRelativeTag( event->GetEvent(), m_nClickedTag );
  3542. }
  3543. }
  3544. break;
  3545. case IDC_ADDTIMINGTAG:
  3546. {
  3547. AddEventRelativeTag();
  3548. }
  3549. break;
  3550. case IDC_ADDEVENT_PAUSE:
  3551. {
  3552. AddGlobalEvent( CChoreoEvent::SECTION );
  3553. }
  3554. break;
  3555. case IDC_ADDEVENT_LOOP:
  3556. {
  3557. AddGlobalEvent( CChoreoEvent::LOOP );
  3558. }
  3559. break;
  3560. case IDC_ADDEVENT_STOPPOINT:
  3561. {
  3562. AddGlobalEvent( CChoreoEvent::STOPPOINT );
  3563. }
  3564. break;
  3565. case IDC_EDITGLOBALEVENT:
  3566. {
  3567. CChoreoGlobalEventWidget *event = m_pClickedGlobalEvent;
  3568. if ( event )
  3569. {
  3570. EditGlobalEvent( event->GetEvent() );
  3571. redraw();
  3572. }
  3573. }
  3574. break;
  3575. case IDC_DELETEGLOBALEVENT:
  3576. {
  3577. CChoreoGlobalEventWidget *event = m_pClickedGlobalEvent;
  3578. if ( event )
  3579. {
  3580. DeleteGlobalEvent( event->GetEvent() );
  3581. }
  3582. }
  3583. break;
  3584. case IDC_ADDCHANNEL:
  3585. {
  3586. NewChannel();
  3587. }
  3588. break;
  3589. case IDC_EDITCHANNEL:
  3590. {
  3591. CChoreoChannelWidget *channel = m_pClickedChannel;
  3592. if ( channel )
  3593. {
  3594. EditChannel( channel->GetChannel() );
  3595. }
  3596. }
  3597. break;
  3598. case IDC_DELETECHANNEL:
  3599. {
  3600. CChoreoChannelWidget *channel = m_pClickedChannel;
  3601. if ( channel )
  3602. {
  3603. DeleteChannel( channel->GetChannel() );
  3604. }
  3605. }
  3606. break;
  3607. case IDC_MOVECHANNELUP:
  3608. {
  3609. CChoreoChannelWidget *channel = m_pClickedChannel;
  3610. if ( channel )
  3611. {
  3612. MoveChannelUp( channel->GetChannel() );
  3613. }
  3614. }
  3615. break;
  3616. case IDC_MOVECHANNELDOWN:
  3617. {
  3618. CChoreoChannelWidget *channel = m_pClickedChannel;
  3619. if ( channel )
  3620. {
  3621. MoveChannelDown( channel->GetChannel() );
  3622. }
  3623. }
  3624. break;
  3625. case IDC_CV_ALLEVENTS_CHANNEL:
  3626. {
  3627. CChoreoChannelWidget *channel = m_pClickedChannel;
  3628. if ( channel )
  3629. {
  3630. SelectAllEventsInChannel( channel );
  3631. }
  3632. }
  3633. break;
  3634. case IDC_CV_ALLEVENTS_ACTOR:
  3635. {
  3636. CChoreoActorWidget *actor = m_pClickedActor;
  3637. if ( actor )
  3638. {
  3639. SelectAllEventsInActor( actor );
  3640. }
  3641. }
  3642. break;
  3643. case IDC_SELECTEVENTS_ALL_BEFORE:
  3644. {
  3645. SelectionParams_t params;
  3646. Q_memset( &params, 0, sizeof( params ) );
  3647. params.forward = false;
  3648. params.time = GetTimeValueForMouse( m_nClickedX );
  3649. params.type = SelectionParams_t::SP_ALL;
  3650. SelectEvents( params );
  3651. }
  3652. break;
  3653. case IDC_SELECTEVENTS_ALL_AFTER:
  3654. {
  3655. SelectionParams_t params;
  3656. Q_memset( &params, 0, sizeof( params ) );
  3657. params.forward = true;
  3658. params.time = GetTimeValueForMouse( m_nClickedX );
  3659. params.type = SelectionParams_t::SP_ALL;
  3660. SelectEvents( params );
  3661. }
  3662. break;
  3663. case IDC_SELECTEVENTS_ACTIVE_BEFORE:
  3664. {
  3665. SelectionParams_t params;
  3666. Q_memset( &params, 0, sizeof( params ) );
  3667. params.forward = false;
  3668. params.time = GetTimeValueForMouse( m_nClickedX );
  3669. params.type = SelectionParams_t::SP_ACTIVE;
  3670. SelectEvents( params );
  3671. }
  3672. break;
  3673. case IDC_SELECTEVENTS_ACTIVE_AFTER:
  3674. {
  3675. SelectionParams_t params;
  3676. Q_memset( &params, 0, sizeof( params ) );
  3677. params.forward = true;
  3678. params.time = GetTimeValueForMouse( m_nClickedX );
  3679. params.type = SelectionParams_t::SP_ACTIVE;
  3680. SelectEvents( params );
  3681. }
  3682. break;
  3683. case IDC_SELECTEVENTS_CHANNEL_BEFORE:
  3684. {
  3685. SelectionParams_t params;
  3686. Q_memset( &params, 0, sizeof( params ) );
  3687. params.forward = false;
  3688. params.time = GetTimeValueForMouse( m_nClickedX );
  3689. params.type = SelectionParams_t::SP_CHANNEL;
  3690. SelectEvents( params );
  3691. }
  3692. break;
  3693. case IDC_SELECTEVENTS_CHANNEL_AFTER:
  3694. {
  3695. SelectionParams_t params;
  3696. Q_memset( &params, 0, sizeof( params ) );
  3697. params.forward = true;
  3698. params.time = GetTimeValueForMouse( m_nClickedX );
  3699. params.type = SelectionParams_t::SP_CHANNEL;
  3700. SelectEvents( params );
  3701. }
  3702. break;
  3703. case IDC_INSERT_TIME:
  3704. {
  3705. OnInsertTime();
  3706. }
  3707. break;
  3708. case IDC_DELETE_TIME:
  3709. {
  3710. OnDeleteTime();
  3711. }
  3712. break;
  3713. case IDC_CV_ALIGN_LEFT:
  3714. {
  3715. OnAlign( true );
  3716. }
  3717. break;
  3718. case IDC_CV_ALIGN_RIGHT:
  3719. {
  3720. OnAlign( false );
  3721. }
  3722. break;
  3723. case IDC_CV_SAMESIZE_SMALLEST:
  3724. {
  3725. OnMakeSameSize( true );
  3726. }
  3727. break;
  3728. case IDC_CV_SAMESIZE_LARGEST:
  3729. {
  3730. OnMakeSameSize( false );
  3731. }
  3732. break;
  3733. }
  3734. if ( iret == 1 )
  3735. {
  3736. SetActiveTool( this );
  3737. }
  3738. }
  3739. break;
  3740. }
  3741. return iret;
  3742. }
  3743. //-----------------------------------------------------------------------------
  3744. // Purpose:
  3745. //-----------------------------------------------------------------------------
  3746. void CChoreoView::PlayScene( bool forward )
  3747. {
  3748. m_bForward = forward;
  3749. if ( !m_pScene )
  3750. return;
  3751. sound->Flush();
  3752. // Make sure phonemes are loaded
  3753. FacePoser_EnsurePhonemesLoaded();
  3754. // Unpause
  3755. if ( m_bSimulating && m_bPaused )
  3756. {
  3757. m_bPaused = false;
  3758. return;
  3759. }
  3760. m_bSimulating = true;
  3761. m_bPaused = false;
  3762. // float soundlatency = max( sound->GetAmountofTimeAhead(), 0.0f );
  3763. // soundlatency = min( 0.5f, soundlatency );
  3764. float soundlatency = 0.0f;
  3765. float sceneendtime = m_pScene->FindStopTime();
  3766. m_pScene->SetSoundFileStartupLatency( soundlatency );
  3767. if ( m_rgABPoints[ 0 ].active ||
  3768. m_rgABPoints[ 1 ].active )
  3769. {
  3770. if ( m_rgABPoints[ 0 ].active &&
  3771. m_rgABPoints[ 1 ].active )
  3772. {
  3773. float st = m_rgABPoints[ 0 ].time;
  3774. float ed = m_rgABPoints[ 1 ].time;
  3775. m_pScene->ResetSimulation( m_bForward, st, ed );
  3776. SetScrubTime( m_bForward ? st : ed );
  3777. SetScrubTargetTime( m_bForward ? ed : st );
  3778. }
  3779. else
  3780. {
  3781. float startonly = m_rgABPoints[ 0 ].active ? m_rgABPoints[ 0 ].time : m_rgABPoints[ 1 ].time;
  3782. m_pScene->ResetSimulation( m_bForward, startonly );
  3783. SetScrubTime( m_bForward ? startonly : sceneendtime );
  3784. SetScrubTargetTime( m_bForward ? sceneendtime : startonly );
  3785. }
  3786. }
  3787. else
  3788. {
  3789. // NO start end/loop
  3790. m_pScene->ResetSimulation( m_bForward );
  3791. SetScrubTime( m_bForward ? 0 : sceneendtime );
  3792. SetScrubTargetTime( m_bForward ? sceneendtime : 0 );
  3793. }
  3794. if ( g_viewerSettings.speedScale == 0.0f )
  3795. {
  3796. m_flLastSpeedScale = g_viewerSettings.speedScale;
  3797. m_bResetSpeedScale = true;
  3798. g_viewerSettings.speedScale = 1.0f;
  3799. Con_Printf( "Resetting speed scale to 1.0\n" );
  3800. }
  3801. }
  3802. //-----------------------------------------------------------------------------
  3803. // Purpose:
  3804. // Input : x -
  3805. //-----------------------------------------------------------------------------
  3806. void CChoreoView::MoveTimeSliderToPos( int x )
  3807. {
  3808. m_flLeftOffset = (float)x;
  3809. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  3810. InvalidateRect( (HWND)m_pHorzScrollBar->getHandle(), NULL, TRUE );
  3811. InvalidateLayout();
  3812. }
  3813. //-----------------------------------------------------------------------------
  3814. // Purpose:
  3815. //-----------------------------------------------------------------------------
  3816. void CChoreoView::PauseScene( void )
  3817. {
  3818. if ( !m_bSimulating )
  3819. return;
  3820. m_bPaused = true;
  3821. sound->StopAll();
  3822. }
  3823. //-----------------------------------------------------------------------------
  3824. // Purpose: Apply expression to actor's face
  3825. // Input : *event -
  3826. // Output : Returns true on success, false on failure.
  3827. //-----------------------------------------------------------------------------
  3828. void CChoreoView::ProcessExpression( CChoreoScene *scene, CChoreoEvent *event )
  3829. {
  3830. Assert( event->GetType() == CChoreoEvent::EXPRESSION );
  3831. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  3832. if ( !model )
  3833. return;
  3834. CStudioHdr *hdr = model->GetStudioHdr();
  3835. if ( !hdr )
  3836. {
  3837. return;
  3838. }
  3839. CExpClass *p = expressions->FindClass( event->GetParameters(), true );
  3840. if ( !p )
  3841. {
  3842. return;
  3843. }
  3844. CExpression *exp = p->FindExpression( event->GetParameters2() );
  3845. if ( !exp )
  3846. {
  3847. return;
  3848. }
  3849. CChoreoActor *a = event->GetActor();
  3850. if ( !a )
  3851. return;
  3852. CChoreoActorWidget *actor = NULL;
  3853. int i;
  3854. for ( i = 0; i < m_SceneActors.Size(); i++ )
  3855. {
  3856. actor = m_SceneActors[ i ];
  3857. if ( !actor )
  3858. continue;
  3859. if ( actor->GetActor() == a )
  3860. break;
  3861. }
  3862. if ( !actor || i >= m_SceneActors.Size() )
  3863. return;
  3864. float *settings = exp->GetSettings();
  3865. Assert( settings );
  3866. float *weights = exp->GetWeights();
  3867. Assert( weights );
  3868. float *current = actor->GetSettings();
  3869. Assert( current );
  3870. float flIntensity = event->GetIntensity( scene->GetTime() );
  3871. // blend in target values for correct actor
  3872. for ( LocalFlexController_t i = (LocalFlexController_t)0; i < hdr->numflexcontrollers(); i++ )
  3873. {
  3874. mstudioflexcontroller_t *pFlex = hdr->pFlexcontroller( i );
  3875. int j = pFlex->localToGlobal;
  3876. if ( j < 0 )
  3877. continue;
  3878. float s = clamp( weights[j] * flIntensity, 0.0, 1.0 );
  3879. current[ j ] = current[j] * (1.0f - s) + settings[ j ] * s;
  3880. }
  3881. }
  3882. //-----------------------------------------------------------------------------
  3883. // Purpose:
  3884. // Input : *hdr -
  3885. // *event -
  3886. //-----------------------------------------------------------------------------
  3887. void SetupFlexControllerTracks( CStudioHdr *hdr, CChoreoEvent *event )
  3888. {
  3889. Assert( hdr );
  3890. Assert( event );
  3891. if ( !hdr )
  3892. return;
  3893. if ( !event )
  3894. return;
  3895. // Already done
  3896. if ( event->GetTrackLookupSet() )
  3897. return;
  3898. /*
  3899. // FIXME: Brian hooked this stuff up for some took work, but at this point the .mdl files don't look like they've been updated to include the remapping data yet...
  3900. int c = hdr->numflexcontrollerremaps();
  3901. for ( i = 0; i < c; ++i )
  3902. {
  3903. mstudioflexcontrollerremap_t *remap = hdr->pFlexcontrollerRemap( i );
  3904. Msg( "remap %s\n", remap->pszName() );
  3905. Msg( " type %d\n", remap->remaptype );
  3906. Msg( " num remaps %d (stereo %s)\n", remap->numremaps, remap->stereo ? "true" : "false" );
  3907. for ( int j = 0 ; j < remap->numremaps; ++j )
  3908. {
  3909. int index = remap->pRemapControlIndex( j );
  3910. Msg( " %d: maps to %d (%s) with %s\n", j, index, hdr->pFlexcontroller( index )->pszName(), remap->pRemapControl( j ) );
  3911. }
  3912. }
  3913. */
  3914. // Unlink stuff in case it doesn't exist
  3915. int nTrackCount = event->GetNumFlexAnimationTracks();
  3916. for ( int i = 0; i < nTrackCount; ++i )
  3917. {
  3918. CFlexAnimationTrack *pTrack = event->GetFlexAnimationTrack( i );
  3919. pTrack->SetFlexControllerIndex( LocalFlexController_t(-1), -1, 0 );
  3920. pTrack->SetFlexControllerIndex( LocalFlexController_t(-1), -1, 1 );
  3921. }
  3922. for ( LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); ++i )
  3923. {
  3924. int j = hdr->pFlexcontroller( i )->localToGlobal;
  3925. char const *name = hdr->pFlexcontroller( i )->pszName();
  3926. if ( !name )
  3927. continue;
  3928. bool combo = false;
  3929. // Look up or create all necessary tracks
  3930. if ( strncmp( "right_", name, 6 ) == 0 )
  3931. {
  3932. combo = true;
  3933. name = &name[6];
  3934. }
  3935. CFlexAnimationTrack *track = event->FindTrack( name );
  3936. if ( !track )
  3937. {
  3938. track = event->AddTrack( name );
  3939. Assert( track );
  3940. }
  3941. track->SetFlexControllerIndex( i, j, 0 );
  3942. if ( combo )
  3943. {
  3944. track->SetFlexControllerIndex( LocalFlexController_t(i + 1), hdr->pFlexcontroller( LocalFlexController_t(i + 1) )->localToGlobal, 1 );
  3945. track->SetComboType( true );
  3946. }
  3947. float orig_min = track->GetMin( );
  3948. float orig_max = track->GetMax( );
  3949. // set range
  3950. if (hdr->pFlexcontroller( i )->min == 0.0f || hdr->pFlexcontroller( i )->max == 1.0f)
  3951. {
  3952. track->SetInverted( false );
  3953. track->SetMin( hdr->pFlexcontroller( i )->min );
  3954. track->SetMax( hdr->pFlexcontroller( i )->max );
  3955. }
  3956. else
  3957. {
  3958. // invert ranges for wide ranged, makes sense considering flexcontroller names...
  3959. track->SetInverted( true );
  3960. track->SetMin( hdr->pFlexcontroller( i )->max );
  3961. track->SetMax( hdr->pFlexcontroller( i )->min );
  3962. }
  3963. // resample track based on this models dynamic range
  3964. if (track->GetNumSamples( 0 ) > 0)
  3965. {
  3966. float range = track->GetMax( ) - track->GetMin( );
  3967. for (int i = 0; i < track->GetNumSamples( 0 ); i++)
  3968. {
  3969. CExpressionSample *sample = track->GetSample( i, 0 );
  3970. float rangedValue = orig_min * (1 - sample->value) + orig_max * sample->value;
  3971. sample->value = clamp( (rangedValue - track->GetMin( )) / range, 0.0, 1.0 );
  3972. }
  3973. }
  3974. // skip next flex since we've already assigned it
  3975. if ( combo )
  3976. {
  3977. i++;
  3978. }
  3979. }
  3980. event->SetTrackLookupSet( true );
  3981. }
  3982. //-----------------------------------------------------------------------------
  3983. // Purpose: Apply flexanimation to actor's face
  3984. // Input : *event -
  3985. // Output : Returns true on success, false on failure.
  3986. //-----------------------------------------------------------------------------
  3987. void CChoreoView::ProcessFlexAnimation( CChoreoScene *scene, CChoreoEvent *event )
  3988. {
  3989. Assert( event->GetType() == CChoreoEvent::FLEXANIMATION );
  3990. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  3991. if ( !model )
  3992. return;
  3993. CStudioHdr *hdr = model->GetStudioHdr();
  3994. if ( !hdr )
  3995. {
  3996. return;
  3997. }
  3998. CChoreoActor *a = event->GetActor();
  3999. CChoreoActorWidget *actor = NULL;
  4000. int i;
  4001. for ( i = 0; i < m_SceneActors.Size(); i++ )
  4002. {
  4003. actor = m_SceneActors[ i ];
  4004. if ( !actor )
  4005. continue;
  4006. if ( !stricmp( actor->GetActor()->GetName(), a->GetName() ) )
  4007. break;
  4008. }
  4009. if ( !actor || i >= m_SceneActors.Size() )
  4010. return;
  4011. float *current = actor->GetSettings();
  4012. Assert( current );
  4013. if ( !event->GetTrackLookupSet() )
  4014. {
  4015. SetupFlexControllerTracks( hdr, event );
  4016. }
  4017. float weight = event->GetIntensity( scene->GetTime() );
  4018. CChoreoEventWidget *eventwidget = FindWidgetForEvent( event );
  4019. bool bUpdateSliders = (eventwidget && eventwidget->IsSelected() && model == models->GetActiveStudioModel() );
  4020. // Iterate animation tracks
  4021. for ( i = 0; i < event->GetNumFlexAnimationTracks(); i++ )
  4022. {
  4023. CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
  4024. if ( !track )
  4025. continue;
  4026. // Disabled
  4027. if ( !track->IsTrackActive() )
  4028. {
  4029. if ( bUpdateSliders )
  4030. {
  4031. for ( int side = 0; side < 1 + track->IsComboType(); side++ )
  4032. {
  4033. int controller = track->GetFlexControllerIndex( side );
  4034. if ( controller != -1 && !g_pFlexPanel->IsEdited( controller ))
  4035. {
  4036. g_pFlexPanel->SetSlider( controller, 0.0 );
  4037. g_pFlexPanel->SetInfluence( controller, 0.0f );
  4038. }
  4039. }
  4040. }
  4041. continue;
  4042. }
  4043. // Map track flex controller to global name
  4044. if ( track->IsComboType() )
  4045. {
  4046. for ( int side = 0; side < 2; side++ )
  4047. {
  4048. int controller = track->GetFlexControllerIndex( side );
  4049. if ( controller != -1 )
  4050. {
  4051. // Get spline intensity for controller
  4052. float flIntensity = track->GetIntensity( scene->GetTime(), side );
  4053. if (bUpdateSliders && !g_pFlexPanel->IsEdited( controller ) )
  4054. {
  4055. g_pFlexPanel->SetSlider( controller, flIntensity );
  4056. g_pFlexPanel->SetInfluence( controller, 1.0f );
  4057. }
  4058. flIntensity = current[ controller ] * (1 - weight) + flIntensity * weight;
  4059. current[ controller ] = flIntensity;
  4060. }
  4061. }
  4062. }
  4063. else
  4064. {
  4065. int controller = track->GetFlexControllerIndex( 0 );
  4066. if ( controller != -1 )
  4067. {
  4068. // Get spline intensity for controller
  4069. float flIntensity = track->GetIntensity( scene->GetTime(), 0 );
  4070. if (bUpdateSliders && !g_pFlexPanel->IsEdited( controller ) )
  4071. {
  4072. g_pFlexPanel->SetSlider( controller, flIntensity );
  4073. g_pFlexPanel->SetInfluence( controller, 1.0f );
  4074. }
  4075. flIntensity = current[ controller ] * (1 - weight) + flIntensity * weight;
  4076. current[ controller ] = flIntensity;
  4077. }
  4078. }
  4079. }
  4080. }
  4081. #include "mapentities.h"
  4082. //-----------------------------------------------------------------------------
  4083. // Purpose: Apply lookat target
  4084. // Input : *event -
  4085. // Output : Returns true on success, false on failure.
  4086. //-----------------------------------------------------------------------------
  4087. void CChoreoView::ProcessLookat( CChoreoScene *scene, CChoreoEvent *event )
  4088. {
  4089. Assert( event->GetType() == CChoreoEvent::LOOKAT );
  4090. if ( !event->GetActor() )
  4091. return;
  4092. CChoreoActor *a = event->GetActor();
  4093. Assert( a );
  4094. StudioModel *model = FindAssociatedModel( scene, a );
  4095. if ( !model )
  4096. {
  4097. return;
  4098. }
  4099. float flIntensity = event->GetIntensity( scene->GetTime() );
  4100. // clamp in-ramp to 0.3 seconds
  4101. float flDuration = scene->GetTime() - event->GetStartTime();
  4102. float flMaxIntensity = flDuration < 0.3f ? SimpleSpline( flDuration / 0.3f ) : 1.0f;
  4103. flDuration = event->GetEndTime() - scene->GetTime();
  4104. flMaxIntensity = min( flMaxIntensity, flDuration < 0.3f ? SimpleSpline( flDuration / 0.3f ) : 1.0f );
  4105. flIntensity = clamp( flIntensity, 0.0f, flMaxIntensity );
  4106. if (!stricmp( event->GetParameters(), a->GetName() ) || !stricmp( event->GetParameters(), "!self" ))
  4107. {
  4108. model->AddLookTargetSelf( flIntensity );
  4109. }
  4110. else if ( !stricmp( event->GetParameters(), "player" ) ||
  4111. !stricmp( event->GetParameters(), "!player" ) )
  4112. {
  4113. Vector vecTarget = model->m_origin;
  4114. vecTarget.z = 0;
  4115. model->AddLookTarget( vecTarget, flIntensity );
  4116. }
  4117. else
  4118. {
  4119. mapentities->CheckUpdateMap( scene->GetMapname() );
  4120. Vector orgActor;
  4121. Vector orgTarget;
  4122. QAngle anglesActor;
  4123. QAngle anglesDummy;
  4124. if ( event->GetPitch() != 0 ||
  4125. event->GetYaw() != 0 )
  4126. {
  4127. QAngle angles( -(float)event->GetPitch(),
  4128. (float)event->GetYaw(),
  4129. 0 );
  4130. matrix3x4_t matrix;
  4131. AngleMatrix( model->m_angles, matrix );
  4132. Vector vecForward;
  4133. AngleVectors( angles, &vecForward );
  4134. Vector eyeTarget;
  4135. VectorRotate( vecForward, matrix, eyeTarget );
  4136. VectorScale( eyeTarget, 75, eyeTarget );
  4137. model->AddLookTarget( eyeTarget, flIntensity );
  4138. }
  4139. else
  4140. {
  4141. if ( mapentities->LookupOrigin( a->GetName(), orgActor, anglesActor ) )
  4142. {
  4143. if ( mapentities->LookupOrigin( event->GetParameters(), orgTarget, anglesDummy ) )
  4144. {
  4145. Vector delta = orgTarget - orgActor;
  4146. matrix3x4_t matrix;
  4147. Vector lookTarget;
  4148. // Rotate around actor's placed forward direction since we look straight down x in faceposer/hlmv
  4149. AngleMatrix( anglesActor, matrix );
  4150. VectorIRotate( delta, matrix, lookTarget );
  4151. model->AddLookTarget( lookTarget, flIntensity );
  4152. return;
  4153. }
  4154. }
  4155. // hack up something based on the name.
  4156. {
  4157. const char *cp = event->GetParameters();
  4158. float value = 0.0;
  4159. while (*cp)
  4160. {
  4161. value += *cp++;
  4162. }
  4163. value = cos( value );
  4164. value = acos( value );
  4165. QAngle angles( 0.0, value * 45 / M_PI, 0.0 );
  4166. matrix3x4_t matrix;
  4167. AngleMatrix( model->m_angles, matrix );
  4168. Vector vecForward;
  4169. AngleVectors( angles, &vecForward );
  4170. Vector eyeTarget;
  4171. VectorRotate( vecForward, matrix, eyeTarget );
  4172. VectorScale( eyeTarget, 75, eyeTarget );
  4173. model->AddLookTarget( eyeTarget, flIntensity );
  4174. }
  4175. }
  4176. }
  4177. }
  4178. //-----------------------------------------------------------------------------
  4179. // Purpose: Returns a target for Faceing
  4180. // Input : *event -
  4181. // Output : Returns true on success, false on failure.
  4182. //-----------------------------------------------------------------------------
  4183. bool CChoreoView::GetTarget( CChoreoScene *scene, CChoreoEvent *event, Vector &vecTarget, QAngle &vecAngle )
  4184. {
  4185. if ( !event->GetActor() )
  4186. return false;
  4187. CChoreoActor *a = event->GetActor();
  4188. Assert( a );
  4189. StudioModel *model = FindAssociatedModel( scene, a );
  4190. if ( !model )
  4191. {
  4192. return false;
  4193. }
  4194. if (!stricmp( event->GetParameters(), a->GetName() ))
  4195. {
  4196. vecTarget = vec3_origin;
  4197. return true;
  4198. }
  4199. else if ( !stricmp( event->GetParameters(), "player" ) ||
  4200. !stricmp( event->GetParameters(), "!player" ) )
  4201. {
  4202. vecTarget = model->m_origin;
  4203. vecTarget.z = 0;
  4204. vecAngle = model->m_angles;
  4205. return true;
  4206. }
  4207. else
  4208. {
  4209. mapentities->CheckUpdateMap( scene->GetMapname() );
  4210. Vector orgActor;
  4211. Vector orgTarget;
  4212. QAngle anglesActor;
  4213. QAngle anglesDummy;
  4214. if ( event->GetPitch() != 0 ||
  4215. event->GetYaw() != 0 )
  4216. {
  4217. QAngle angles( -(float)event->GetPitch(),
  4218. (float)event->GetYaw(),
  4219. 0 );
  4220. matrix3x4_t matrix;
  4221. AngleMatrix( model->m_angles, matrix );
  4222. QAngle angles2 = angles;
  4223. angles2.x *= 0.6f;
  4224. angles2.y *= 0.8f;
  4225. Vector vecForward, vecForward2;
  4226. AngleVectors( angles, &vecForward );
  4227. AngleVectors( angles2, &vecForward2 );
  4228. VectorNormalize( vecForward );
  4229. VectorNormalize( vecForward2 );
  4230. Vector eyeTarget, headTarget;
  4231. VectorRotate( vecForward, matrix, eyeTarget );
  4232. VectorRotate( vecForward2, matrix, headTarget );
  4233. VectorScale( eyeTarget, 150, eyeTarget );
  4234. VectorScale( headTarget, 150, vecTarget );
  4235. return true;
  4236. }
  4237. else
  4238. {
  4239. if ( mapentities->LookupOrigin( a->GetName(), orgActor, anglesActor ) )
  4240. {
  4241. if ( mapentities->LookupOrigin( event->GetParameters(), orgTarget, anglesDummy ) )
  4242. {
  4243. Vector delta = orgTarget - orgActor;
  4244. matrix3x4_t matrix;
  4245. Vector lookTarget;
  4246. // Rotate around actor's placed forward direction since we look straight down x in faceposer/hlmv
  4247. AngleMatrix( anglesActor, matrix );
  4248. VectorIRotate( delta, matrix, vecTarget );
  4249. return true;
  4250. }
  4251. }
  4252. }
  4253. }
  4254. return false;
  4255. }
  4256. //-----------------------------------------------------------------------------
  4257. // Purpose: Apply lookat target
  4258. // Input : *event -
  4259. // Output : Returns true on success, false on failure.
  4260. //-----------------------------------------------------------------------------
  4261. void CChoreoView::ProcessFace( CChoreoScene *scene, CChoreoEvent *event )
  4262. {
  4263. Assert( event->GetType() == CChoreoEvent::FACE );
  4264. if ( !event->GetActor() )
  4265. return;
  4266. CChoreoActor *a = event->GetActor();
  4267. Assert( a );
  4268. StudioModel *model = FindAssociatedModel( scene, a );
  4269. if ( !model )
  4270. {
  4271. return;
  4272. }
  4273. Vector vecTarget;
  4274. QAngle vecAngle;
  4275. if (!GetTarget( scene, event, vecTarget, vecAngle ))
  4276. {
  4277. return;
  4278. }
  4279. /*
  4280. // FIXME: this is broke
  4281. float goalYaw = -(vecAngle.y > 180 ? 360 - vecAngle.y : vecAngle.y );
  4282. float intensity = event->GetIntensity( scene->GetTime() );
  4283. float diff = goalYaw * intensity;
  4284. float dir = 1.0;
  4285. if (diff < 0)
  4286. {
  4287. diff = -diff;
  4288. dir = -1;
  4289. }
  4290. float spineintensity = 0 * max( 0.0, (intensity - 0.5) / 0.5 );
  4291. float goalSpineYaw = min( diff * (1.0 - spineintensity), 30 );
  4292. //float idealYaw = info->m_flInitialYaw + (diff - m_goalBodyYaw * dir - m_goalSpineYaw * dir) * dir;
  4293. // float idealYaw = UTIL_AngleMod( info->m_flInitialYaw + diff * intensity );
  4294. // FIXME: this is broke
  4295. // model->SetSpineYaw( goalSpineYaw * dir);
  4296. // model->SetBodyYaw( goalBodyYaw * dir );
  4297. // Msg("yaw %.1f : %.1f (%.1f)\n", info->m_flInitialYaw, idealYaw, intensity );
  4298. */
  4299. }
  4300. //-----------------------------------------------------------------------------
  4301. // Purpose:
  4302. // Input : *scene -
  4303. // *event -
  4304. //-----------------------------------------------------------------------------
  4305. void CChoreoView::ProcessLoop( CChoreoScene *scene, CChoreoEvent *event )
  4306. {
  4307. Assert( event->GetType() == CChoreoEvent::LOOP );
  4308. // Don't loop when dragging scrubber!
  4309. if ( IsScrubbing() )
  4310. return;
  4311. float backtime = (float)atof( event->GetParameters() );
  4312. bool process = true;
  4313. int counter = event->GetLoopCount();
  4314. if ( counter != -1 )
  4315. {
  4316. int remaining = event->GetNumLoopsRemaining();
  4317. if ( remaining <= 0 )
  4318. {
  4319. process = false;
  4320. }
  4321. else
  4322. {
  4323. event->SetNumLoopsRemaining( --remaining );
  4324. }
  4325. }
  4326. if ( !process )
  4327. return;
  4328. scene->LoopToTime( backtime );
  4329. SetScrubTime( backtime );
  4330. }
  4331. //-----------------------------------------------------------------------------
  4332. // Purpose: Add a gesture layer
  4333. // Input : *event -
  4334. // Output : Returns true on success, false on failure.
  4335. //-----------------------------------------------------------------------------
  4336. void CChoreoView::ProcessGesture( CChoreoScene *scene, CChoreoEvent *event )
  4337. {
  4338. Assert( event->GetType() == CChoreoEvent::GESTURE );
  4339. // NULL event is just a placeholder
  4340. if ( !Q_stricmp( event->GetName(), "NULL" ) )
  4341. {
  4342. return;
  4343. }
  4344. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  4345. if ( !model )
  4346. return;
  4347. if ( !event->GetActor() )
  4348. return;
  4349. CChoreoActor *a = event->GetActor();
  4350. Assert( a );
  4351. int iSequence = model->LookupSequence( event->GetParameters() );
  4352. if (iSequence < 0)
  4353. return;
  4354. // Get spline intensity for controller
  4355. float eventlocaltime = scene->GetTime() - event->GetStartTime();
  4356. float referencetime = event->GetOriginalPercentageFromPlaybackPercentage( eventlocaltime / event->GetDuration() ) * event->GetDuration();
  4357. float resampledtime = event->GetStartTime() + referencetime;
  4358. float cycle = event->GetCompletion( resampledtime );
  4359. int iLayer = model->GetNewAnimationLayer( a->FindChannelIndex( event->GetChannel() ) );
  4360. model->SetOverlaySequence( iLayer, iSequence, event->GetIntensity( scene->GetTime() ) );
  4361. model->SetOverlayRate( iLayer, cycle, 0.0 );
  4362. }
  4363. //-----------------------------------------------------------------------------
  4364. // Purpose: Apply a sequence
  4365. // Input : *event -
  4366. //-----------------------------------------------------------------------------
  4367. void CChoreoView::ProcessSequence( CChoreoScene *scene, CChoreoEvent *event )
  4368. {
  4369. Assert( event->GetType() == CChoreoEvent::SEQUENCE );
  4370. if ( !m_bProcessSequences )
  4371. {
  4372. return;
  4373. }
  4374. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  4375. if ( !model )
  4376. return;
  4377. if ( !event->GetActor() )
  4378. return;
  4379. CChoreoActor *a = event->GetActor();
  4380. Assert( a );
  4381. int iSequence = model->LookupSequence( event->GetParameters() );
  4382. if (iSequence < 0)
  4383. return;
  4384. float flFrameRate;
  4385. float flGroundSpeed;
  4386. model->GetSequenceInfo( iSequence, &flFrameRate, &flGroundSpeed );
  4387. float cycle;
  4388. bool looping = model->GetSequenceLoops( iSequence );
  4389. if (looping)
  4390. {
  4391. float dt = scene->GetTime() - event->m_flPrevTime;
  4392. event->m_flPrevTime = scene->GetTime();
  4393. dt = clamp( dt, 0.0, 0.1 );
  4394. cycle = event->m_flPrevCycle + flFrameRate * dt;
  4395. cycle = cycle - (int)cycle;
  4396. event->m_flPrevCycle = cycle;
  4397. }
  4398. else
  4399. {
  4400. float dt = scene->GetTime() - event->GetStartTime();
  4401. cycle = flFrameRate * dt;
  4402. cycle = cycle - (int)(cycle);
  4403. }
  4404. // FIXME: shouldn't sequences always be lower priority than gestures?
  4405. int iLayer = model->GetNewAnimationLayer( a->FindChannelIndex( event->GetChannel() ) );
  4406. model->SetOverlaySequence( iLayer, iSequence, event->GetIntensity( scene->GetTime() ) );
  4407. model->SetOverlayRate( iLayer, cycle, 0.0 );
  4408. }
  4409. //-----------------------------------------------------------------------------
  4410. // Purpose: Apply a walking animation
  4411. // Input : *event -
  4412. //-----------------------------------------------------------------------------
  4413. void CChoreoView::ProcessMoveto( CChoreoScene *scene, CChoreoEvent *event )
  4414. {
  4415. Assert( event->GetType() == CChoreoEvent::MOVETO );
  4416. if ( !m_bProcessSequences )
  4417. {
  4418. return;
  4419. }
  4420. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  4421. if ( !model )
  4422. return;
  4423. if ( !event->GetActor() )
  4424. return;
  4425. int iSequence = GetMovetoSequence( scene, event, model );
  4426. if (iSequence < 0)
  4427. return;
  4428. float flFrameRate;
  4429. float flGroundSpeed;
  4430. model->GetSequenceInfo( iSequence, &flFrameRate, &flGroundSpeed );
  4431. float dt = scene->GetTime() - event->GetStartTime();
  4432. float cycle = flFrameRate * dt;
  4433. cycle = cycle - (int)(cycle);
  4434. float idealAccel = 100;
  4435. // accel to ideal
  4436. float t1 = flGroundSpeed / idealAccel;
  4437. float intensity = 1.0;
  4438. if (dt < t1)
  4439. {
  4440. intensity = dt / t1;
  4441. }
  4442. else if (event->GetDuration() - dt < t1)
  4443. {
  4444. intensity = (event->GetDuration() - dt) / t1;
  4445. }
  4446. // movement should always be higher priority than postures, but not gestures....grrr, any way to tell them apart?
  4447. int iLayer = model->GetNewAnimationLayer( 0 /* a->FindChannelIndex( event->GetChannel() ) */ );
  4448. model->SetOverlaySequence( iLayer, iSequence, intensity );
  4449. model->SetOverlayRate( iLayer, cycle, 0.0 );
  4450. }
  4451. int CChoreoView::GetMovetoSequence( CChoreoScene *scene, CChoreoEvent *event, StudioModel *model )
  4452. {
  4453. // FIXME: needs to pull from event (activity or sequence?)
  4454. if ( !event->GetParameters2() || !event->GetParameters2()[0] )
  4455. return model->LookupSequence( "walk_all" );
  4456. // Custom distance styles are appended to param2 with a space as a separator
  4457. const char *pszAct = Q_strstr( event->GetParameters2(), " " );
  4458. if ( pszAct )
  4459. {
  4460. char szActName[256];
  4461. Q_strncpy( szActName, event->GetParameters2(), sizeof(szActName) );
  4462. szActName[ (pszAct-event->GetParameters2()) ] = '\0';
  4463. pszAct = szActName;
  4464. }
  4465. else
  4466. {
  4467. pszAct = event->GetParameters2();
  4468. }
  4469. if ( !Q_strcmp( pszAct, "Walk" ) )
  4470. {
  4471. pszAct = "ACT_WALK";
  4472. }
  4473. else if ( !Q_strcmp( pszAct, "Run" ) )
  4474. {
  4475. pszAct = "ACT_RUN";
  4476. }
  4477. else if ( !Q_strcmp( pszAct, "CrouchWalk" ) )
  4478. {
  4479. pszAct = "ACT_WALK_CROUCH";
  4480. }
  4481. int iSequence = model->LookupActivity( pszAct );
  4482. if (iSequence == -1)
  4483. {
  4484. return model->LookupSequence( "walk_all" );
  4485. }
  4486. return iSequence;
  4487. }
  4488. //-----------------------------------------------------------------------------
  4489. // Purpose: Process a pause event
  4490. // Input : *event -
  4491. //-----------------------------------------------------------------------------
  4492. void CChoreoView::ProcessPause( CChoreoScene *scene, CChoreoEvent *event )
  4493. {
  4494. Assert( event->GetType() == CChoreoEvent::SECTION );
  4495. // Don't pause if scrubbing
  4496. bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
  4497. if ( scrubbing )
  4498. return;
  4499. PauseScene();
  4500. m_bAutomated = false;
  4501. m_nAutomatedAction = SCENE_ACTION_UNKNOWN;
  4502. m_flAutomationDelay = 0.0f;
  4503. m_flAutomationTime = 0.0f;
  4504. // Check for auto resume/cancel
  4505. ParseFromMemory( (char *)event->GetParameters(), strlen( event->GetParameters() ) );
  4506. if ( tokenprocessor->TokenAvailable() )
  4507. {
  4508. tokenprocessor->GetToken( false );
  4509. if ( !stricmp( tokenprocessor->CurrentToken(), "automate" ) )
  4510. {
  4511. if ( tokenprocessor->TokenAvailable() )
  4512. {
  4513. tokenprocessor->GetToken( false );
  4514. if ( !stricmp( tokenprocessor->CurrentToken(), "Cancel" ) )
  4515. {
  4516. m_nAutomatedAction = SCENE_ACTION_CANCEL;
  4517. }
  4518. else if ( !stricmp( tokenprocessor->CurrentToken(), "Resume" ) )
  4519. {
  4520. m_nAutomatedAction = SCENE_ACTION_RESUME;
  4521. }
  4522. if ( tokenprocessor->TokenAvailable() &&
  4523. m_nAutomatedAction != SCENE_ACTION_UNKNOWN )
  4524. {
  4525. tokenprocessor->GetToken( false );
  4526. m_flAutomationDelay = (float)atof( tokenprocessor->CurrentToken() );
  4527. if ( m_flAutomationDelay > 0.0f )
  4528. {
  4529. // Success
  4530. m_bAutomated = true;
  4531. m_flAutomationTime = 0.0f;
  4532. }
  4533. }
  4534. }
  4535. }
  4536. }
  4537. }
  4538. //-----------------------------------------------------------------------------
  4539. // Purpose: Main event processor
  4540. // Input : *event -
  4541. // Output : Returns true on success, false on failure.
  4542. //-----------------------------------------------------------------------------
  4543. void CChoreoView::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  4544. {
  4545. if ( !event || !event->GetActive() )
  4546. return;
  4547. CChoreoActor *actor = event->GetActor();
  4548. if ( actor && !actor->GetActive() )
  4549. {
  4550. return;
  4551. }
  4552. CChoreoChannel *channel = event->GetChannel();
  4553. if ( channel && !channel->GetActive() )
  4554. {
  4555. return;
  4556. }
  4557. switch( event->GetType() )
  4558. {
  4559. case CChoreoEvent::EXPRESSION:
  4560. ProcessExpression( scene, event );
  4561. break;
  4562. case CChoreoEvent::FLEXANIMATION:
  4563. ProcessFlexAnimation( scene, event );
  4564. break;
  4565. case CChoreoEvent::LOOKAT:
  4566. ProcessLookat( scene, event );
  4567. break;
  4568. case CChoreoEvent::FACE:
  4569. ProcessFace( scene, event );
  4570. break;
  4571. case CChoreoEvent::GESTURE:
  4572. ProcessGesture( scene, event );
  4573. break;
  4574. case CChoreoEvent::SEQUENCE:
  4575. ProcessSequence( scene, event );
  4576. break;
  4577. case CChoreoEvent::SUBSCENE:
  4578. ProcessSubscene( scene, event );
  4579. break;
  4580. case CChoreoEvent::SPEAK:
  4581. ProcessSpeak( scene, event );
  4582. break;
  4583. case CChoreoEvent::MOVETO:
  4584. ProcessMoveto( scene, event );
  4585. break;
  4586. case CChoreoEvent::STOPPOINT:
  4587. // Nothing
  4588. break;
  4589. case CChoreoEvent::INTERRUPT:
  4590. ProcessInterrupt( scene, event );
  4591. break;
  4592. case CChoreoEvent::PERMIT_RESPONSES:
  4593. ProcessPermitResponses( scene, event );
  4594. break;
  4595. default:
  4596. break;
  4597. }
  4598. }
  4599. //-----------------------------------------------------------------------------
  4600. // Purpose: Main event completion checker
  4601. // Input : *event -
  4602. // Output : Returns true on success, false on failure.
  4603. //-----------------------------------------------------------------------------
  4604. bool CChoreoView::CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  4605. {
  4606. if ( !event || !event->GetActive() )
  4607. return true;
  4608. CChoreoActor *actor = event->GetActor();
  4609. if ( actor && !actor->GetActive() )
  4610. {
  4611. return true;
  4612. }
  4613. CChoreoChannel *channel = event->GetChannel();
  4614. if ( channel && !channel->GetActive() )
  4615. {
  4616. return true;
  4617. }
  4618. switch( event->GetType() )
  4619. {
  4620. case CChoreoEvent::EXPRESSION:
  4621. break;
  4622. case CChoreoEvent::FLEXANIMATION:
  4623. break;
  4624. case CChoreoEvent::LOOKAT:
  4625. break;
  4626. case CChoreoEvent::GESTURE:
  4627. break;
  4628. case CChoreoEvent::SEQUENCE:
  4629. break;
  4630. case CChoreoEvent::SUBSCENE:
  4631. break;
  4632. case CChoreoEvent::SPEAK:
  4633. break;
  4634. case CChoreoEvent::MOVETO:
  4635. break;
  4636. case CChoreoEvent::INTERRUPT:
  4637. break;
  4638. case CChoreoEvent::PERMIT_RESPONSES:
  4639. break;
  4640. default:
  4641. break;
  4642. }
  4643. return true;
  4644. }
  4645. //-----------------------------------------------------------------------------
  4646. // Purpose:
  4647. //-----------------------------------------------------------------------------
  4648. void CChoreoView::PauseThink( void )
  4649. {
  4650. // FIXME: Game code would check for conditions being met
  4651. if ( !m_bAutomated )
  4652. return;
  4653. m_flAutomationTime += fabs( m_flFrameTime );
  4654. RECT rcPauseRect;
  4655. rcPauseRect.left = 0;
  4656. rcPauseRect.right = w2();
  4657. rcPauseRect.top = GetCaptionHeight() + SCRUBBER_HEIGHT;
  4658. rcPauseRect.bottom = rcPauseRect.top + 10;
  4659. CChoreoWidgetDrawHelper drawHelper( this,
  4660. rcPauseRect,
  4661. COLOR_CHOREO_BACKGROUND );
  4662. DrawSceneABTicks( drawHelper );
  4663. if ( m_flAutomationDelay > 0.0f &&
  4664. m_flAutomationTime < m_flAutomationDelay )
  4665. {
  4666. char sz[ 256 ];
  4667. sprintf( sz, "Pause %.2f/%.2f", m_flAutomationTime, m_flAutomationDelay );
  4668. int textlen = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  4669. RECT rcText;
  4670. GetScrubHandleRect( rcText, true );
  4671. rcText.left = ( rcText.left + rcText.right ) / 2;
  4672. rcText.left -= ( textlen * 0.5f );
  4673. rcText.right = rcText.left + textlen + 1;
  4674. rcText.top = rcPauseRect.top;
  4675. rcText.bottom = rcPauseRect.bottom;
  4676. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, COLOR_CHOREO_PLAYBACKTICKTEXT, rcText, sz );
  4677. return;
  4678. }
  4679. // Time to act
  4680. m_bAutomated = false;
  4681. switch ( m_nAutomatedAction )
  4682. {
  4683. case SCENE_ACTION_RESUME:
  4684. m_bPaused = false;
  4685. sound->StopAll();
  4686. break;
  4687. case SCENE_ACTION_CANCEL:
  4688. FinishSimulation();
  4689. break;
  4690. default:
  4691. break;
  4692. }
  4693. m_nAutomatedAction = SCENE_ACTION_UNKNOWN;
  4694. m_flAutomationTime = 0.0f;
  4695. m_flAutomationDelay = 0.0f;
  4696. }
  4697. //-----------------------------------------------------------------------------
  4698. // Purpose: Conclude simulation
  4699. //-----------------------------------------------------------------------------
  4700. void CChoreoView::FinishSimulation( void )
  4701. {
  4702. if ( !m_bSimulating )
  4703. return;
  4704. // m_pScene->ResetSimulation();
  4705. m_bSimulating = false;
  4706. m_bPaused = false;
  4707. sound->StopAll();
  4708. if ( m_bResetSpeedScale )
  4709. {
  4710. m_bResetSpeedScale = false;
  4711. g_viewerSettings.speedScale = m_flLastSpeedScale;
  4712. m_flLastSpeedScale = 0.0f;
  4713. Con_Printf( "Resetting speed scale to %f\n", m_flLastSpeedScale );
  4714. }
  4715. models->ClearOverlaysSequences();
  4716. // redraw();
  4717. }
  4718. void CChoreoView::SceneThink( float time )
  4719. {
  4720. if ( !m_pScene )
  4721. return;
  4722. if ( m_bSimulating )
  4723. {
  4724. if ( m_bPaused )
  4725. {
  4726. PauseThink();
  4727. }
  4728. else
  4729. {
  4730. m_pScene->SetSoundFileStartupLatency( 0.0f );
  4731. models->CheckResetFlexes();
  4732. ResetTargetSettings();
  4733. models->ClearOverlaysSequences();
  4734. // Tell scene to go
  4735. m_pScene->Think( time );
  4736. // Move flexes toward their targets
  4737. UpdateCurrentSettings();
  4738. }
  4739. }
  4740. else
  4741. {
  4742. FinishSimulation();
  4743. }
  4744. if ( !ShouldProcessSpeak() )
  4745. {
  4746. bool autoprocess = ShouldAutoProcess();
  4747. bool anyscrub = IsAnyToolScrubbing() ;
  4748. bool anyprocessing = IsAnyToolProcessing();
  4749. //Con_Printf( "autoprocess %i anyscrub %i anyprocessing %i\n",
  4750. // autoprocess ? 1 : 0,
  4751. // anyscrub ? 1 : 0,
  4752. // anyprocessing ? 1 : 0 );
  4753. if ( !anyscrub &&
  4754. !anyprocessing &&
  4755. autoprocess &&
  4756. !m_bForceProcess )
  4757. {
  4758. sound->StopAll();
  4759. // why clear lookat?
  4760. //models->ClearModelTargets( false );
  4761. }
  4762. }
  4763. }
  4764. //-----------------------------------------------------------------------------
  4765. // Purpose:
  4766. //-----------------------------------------------------------------------------
  4767. void CChoreoView::LayoutScene( void )
  4768. {
  4769. if ( !m_pScene )
  4770. return;
  4771. if ( m_bLayoutIsValid )
  4772. return;
  4773. m_pScene->ReconcileTags();
  4774. RECT rc;
  4775. GetClientRect( (HWND)getHandle(), &rc );
  4776. RECT rcClient = rc;
  4777. rcClient.top += GetStartRow();
  4778. OffsetRect( &rcClient, 0, -m_nTopOffset );
  4779. m_flStartTime = m_flLeftOffset / GetPixelsPerSecond();
  4780. m_flEndTime = m_flStartTime + (float)( rcClient.right - GetLabelWidth() ) / GetPixelsPerSecond();
  4781. m_rcTimeLine = rcClient;
  4782. m_rcTimeLine.top = GetCaptionHeight() + SCRUBBER_HEIGHT;
  4783. m_rcTimeLine.bottom = m_rcTimeLine.top + 44;
  4784. int currentRow = rcClient.top + 2;
  4785. int itemHeight;
  4786. // Draw actors
  4787. int i;
  4788. for ( i = 0; i < m_SceneActors.Size(); i++ )
  4789. {
  4790. CChoreoActorWidget *a = m_SceneActors[ i ];
  4791. Assert( a );
  4792. if ( !a )
  4793. {
  4794. continue;
  4795. }
  4796. // Figure out rectangle
  4797. itemHeight = a->GetItemHeight();
  4798. RECT rcActor = rcClient;
  4799. rcActor.top = currentRow;
  4800. rcActor.bottom = currentRow + itemHeight;
  4801. a->Layout( rcActor );
  4802. currentRow += itemHeight;
  4803. }
  4804. // Draw section tabs
  4805. for ( i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  4806. {
  4807. CChoreoGlobalEventWidget *e = m_SceneGlobalEvents[ i ];
  4808. if ( !e )
  4809. continue;
  4810. RECT rcEvent;
  4811. rcEvent = m_rcTimeLine;
  4812. float frac = ( e->GetEvent()->GetStartTime() - m_flStartTime ) / ( m_flEndTime - m_flStartTime );
  4813. rcEvent.left = GetLabelWidth() + rcEvent.left + (int)( frac * ( m_rcTimeLine.right - m_rcTimeLine.left - GetLabelWidth() ) );
  4814. rcEvent.left -= 4;
  4815. rcEvent.right = rcEvent.left + 8;
  4816. rcEvent.bottom += 0;
  4817. rcEvent.top = rcEvent.bottom - 8;
  4818. if ( rcEvent.left + 10 < GetLabelWidth() )
  4819. {
  4820. e->setVisible( false );
  4821. }
  4822. else
  4823. {
  4824. e->setVisible( true );
  4825. }
  4826. // OffsetRect( &rcEvent, GetLabelWidth(), 0 );
  4827. e->Layout( rcEvent );
  4828. }
  4829. m_bLayoutIsValid = true;
  4830. }
  4831. //-----------------------------------------------------------------------------
  4832. // Purpose:
  4833. //-----------------------------------------------------------------------------
  4834. void CChoreoView::DeleteSceneWidgets( void )
  4835. {
  4836. bool oldcandraw = m_bCanDraw;
  4837. m_bCanDraw = false;
  4838. int i;
  4839. CChoreoWidget *w;
  4840. ClearStatusArea();
  4841. for( i = 0 ; i < m_SceneActors.Size(); i++ )
  4842. {
  4843. w = m_SceneActors[ i ];
  4844. m_ActorExpanded[ i ].expanded = ((CChoreoActorWidget *)w)->GetShowChannels();
  4845. delete w;
  4846. }
  4847. m_SceneActors.RemoveAll();
  4848. for( i = 0 ; i < m_SceneGlobalEvents.Size(); i++ )
  4849. {
  4850. w = m_SceneGlobalEvents[ i ];
  4851. delete w;
  4852. }
  4853. m_SceneGlobalEvents.RemoveAll();
  4854. m_bCanDraw = oldcandraw;
  4855. // Make sure nobody is still pointing at us
  4856. m_pClickedActor = NULL;
  4857. m_pClickedChannel = NULL;
  4858. m_pClickedEvent = NULL;
  4859. m_pClickedGlobalEvent = NULL;
  4860. }
  4861. //-----------------------------------------------------------------------------
  4862. // Purpose:
  4863. //-----------------------------------------------------------------------------
  4864. void CChoreoView::InvalidateLayout( void )
  4865. {
  4866. if ( m_bSuppressLayout )
  4867. return;
  4868. if ( ComputeHPixelsNeeded() != m_nLastHPixelsNeeded )
  4869. {
  4870. RepositionHSlider();
  4871. }
  4872. if ( ComputeVPixelsNeeded() != m_nLastVPixelsNeeded )
  4873. {
  4874. RepositionVSlider();
  4875. }
  4876. // Recheck gesture start/end times
  4877. if ( m_pScene )
  4878. {
  4879. m_pScene->ReconcileGestureTimes();
  4880. m_pScene->ReconcileCloseCaption();
  4881. }
  4882. m_bLayoutIsValid = false;
  4883. redraw();
  4884. }
  4885. //-----------------------------------------------------------------------------
  4886. // Purpose:
  4887. //-----------------------------------------------------------------------------
  4888. void CChoreoView::CreateSceneWidgets( void )
  4889. {
  4890. DeleteSceneWidgets();
  4891. m_bSuppressLayout = true;
  4892. int i;
  4893. for ( i = 0; i < m_pScene->GetNumActors(); i++ )
  4894. {
  4895. CChoreoActor *a = m_pScene->GetActor( i );
  4896. Assert( a );
  4897. if ( !a )
  4898. continue;
  4899. CChoreoActorWidget *actorWidget = new CChoreoActorWidget( NULL );
  4900. Assert( actorWidget );
  4901. actorWidget->SetActor( a );
  4902. actorWidget->Create();
  4903. m_SceneActors.AddToTail( actorWidget );
  4904. actorWidget->ShowChannels( m_ActorExpanded[ i ].expanded );
  4905. }
  4906. // Find global events
  4907. for ( i = 0; i < m_pScene->GetNumEvents(); i++ )
  4908. {
  4909. CChoreoEvent *e = m_pScene->GetEvent( i );
  4910. if ( !e || e->GetActor() )
  4911. continue;
  4912. CChoreoGlobalEventWidget *eventWidget = new CChoreoGlobalEventWidget( NULL );
  4913. Assert( eventWidget );
  4914. eventWidget->SetEvent( e );
  4915. eventWidget->Create();
  4916. m_SceneGlobalEvents.AddToTail( eventWidget );
  4917. }
  4918. m_bSuppressLayout = false;
  4919. }
  4920. //-----------------------------------------------------------------------------
  4921. // Purpose:
  4922. // Output : int
  4923. //-----------------------------------------------------------------------------
  4924. int CChoreoView::GetLabelWidth( void )
  4925. {
  4926. return m_nLabelWidth;
  4927. }
  4928. //-----------------------------------------------------------------------------
  4929. // Purpose:
  4930. // Output : int
  4931. //-----------------------------------------------------------------------------
  4932. int CChoreoView::GetStartRow( void )
  4933. {
  4934. return m_nStartRow + GetCaptionHeight() + SCRUBBER_HEIGHT;
  4935. }
  4936. //-----------------------------------------------------------------------------
  4937. // Purpose:
  4938. // Output : int
  4939. //-----------------------------------------------------------------------------
  4940. int CChoreoView::GetRowHeight( void )
  4941. {
  4942. return m_nRowHeight;
  4943. }
  4944. //-----------------------------------------------------------------------------
  4945. // Purpose:
  4946. // Output : int
  4947. //-----------------------------------------------------------------------------
  4948. int CChoreoView::GetFontSize( void )
  4949. {
  4950. return m_nFontSize;
  4951. }
  4952. //-----------------------------------------------------------------------------
  4953. // Purpose:
  4954. // Output : int
  4955. //-----------------------------------------------------------------------------
  4956. int CChoreoView::ComputeVPixelsNeeded( void )
  4957. {
  4958. int pixels = 0;
  4959. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  4960. {
  4961. CChoreoActorWidget *actor = m_SceneActors[ i ];
  4962. if ( !actor )
  4963. continue;
  4964. pixels += actor->GetItemHeight() + 2;
  4965. }
  4966. pixels += GetStartRow() + 15;
  4967. // pixels += m_nInfoHeight;
  4968. //pixels += 30;
  4969. return pixels;
  4970. }
  4971. //-----------------------------------------------------------------------------
  4972. // Purpose:
  4973. // Output : int
  4974. //-----------------------------------------------------------------------------
  4975. int CChoreoView::ComputeHPixelsNeeded( void )
  4976. {
  4977. if ( !m_pScene )
  4978. {
  4979. return 0;
  4980. }
  4981. int pixels = 0;
  4982. float maxtime = m_pScene->FindStopTime();
  4983. if ( maxtime < 5.0 )
  4984. {
  4985. maxtime = 5.0f;
  4986. }
  4987. pixels = (int)( ( maxtime + 5.0 ) * GetPixelsPerSecond() );
  4988. return pixels;
  4989. }
  4990. //-----------------------------------------------------------------------------
  4991. // Purpose:
  4992. //-----------------------------------------------------------------------------
  4993. void CChoreoView::RepositionVSlider( void )
  4994. {
  4995. int pixelsneeded = ComputeVPixelsNeeded();
  4996. if ( pixelsneeded <= ( h2() - GetStartRow() ))
  4997. {
  4998. m_pVertScrollBar->setVisible( false );
  4999. m_nTopOffset = 0;
  5000. }
  5001. else
  5002. {
  5003. m_pVertScrollBar->setVisible( true );
  5004. }
  5005. m_pVertScrollBar->setBounds( w2() - m_nScrollbarHeight, GetStartRow(), m_nScrollbarHeight, h2() - m_nScrollbarHeight - GetStartRow() );
  5006. //int visiblepixels = h2() - m_nScrollbarHeight - GetStartRow();
  5007. //m_nTopOffset = min( pixelsneeded - visiblepixels, m_nTopOffset );
  5008. m_nTopOffset = max( 0, m_nTopOffset );
  5009. m_nTopOffset = min( pixelsneeded, m_nTopOffset );
  5010. m_pVertScrollBar->setRange( 0, pixelsneeded );
  5011. m_pVertScrollBar->setValue( m_nTopOffset );
  5012. m_pVertScrollBar->setPagesize( h2() - GetStartRow() );
  5013. m_nLastVPixelsNeeded = pixelsneeded;
  5014. }
  5015. //-----------------------------------------------------------------------------
  5016. // Purpose:
  5017. //-----------------------------------------------------------------------------
  5018. void CChoreoView::RepositionHSlider( void )
  5019. {
  5020. int pixelsneeded = ComputeHPixelsNeeded();
  5021. int w = w2();
  5022. int lw = GetLabelWidth();
  5023. if ( pixelsneeded <= ( w - lw ) )
  5024. {
  5025. m_pHorzScrollBar->setVisible( false );
  5026. }
  5027. else
  5028. {
  5029. m_pHorzScrollBar->setVisible( true );
  5030. }
  5031. m_pHorzScrollBar->setBounds( 0, h2() - m_nScrollbarHeight, w - m_nScrollbarHeight, m_nScrollbarHeight );
  5032. m_flLeftOffset = max( 0.f, m_flLeftOffset );
  5033. m_flLeftOffset = min( (float)pixelsneeded, m_flLeftOffset );
  5034. m_pHorzScrollBar->setRange( 0, pixelsneeded );
  5035. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  5036. m_pHorzScrollBar->setPagesize(w - lw );
  5037. m_nLastHPixelsNeeded = pixelsneeded;
  5038. }
  5039. //-----------------------------------------------------------------------------
  5040. // Purpose:
  5041. // Input : dirty -
  5042. //-----------------------------------------------------------------------------
  5043. void CChoreoView::SetDirty( bool dirty, bool clearundo /*=true*/ )
  5044. {
  5045. bool changed = dirty != m_bDirty;
  5046. m_bDirty = dirty;
  5047. if ( !dirty && clearundo )
  5048. {
  5049. WipeUndo();
  5050. redraw();
  5051. }
  5052. if ( changed )
  5053. {
  5054. SetPrefix( m_bDirty ? "* " : "" );
  5055. }
  5056. }
  5057. //-----------------------------------------------------------------------------
  5058. // Purpose:
  5059. //-----------------------------------------------------------------------------
  5060. void CChoreoView::New( void )
  5061. {
  5062. if ( m_pScene )
  5063. {
  5064. Close( );
  5065. if ( m_pScene )
  5066. {
  5067. return;
  5068. }
  5069. }
  5070. char scenefile[ 512 ];
  5071. if ( FacePoser_ShowSaveFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  5072. {
  5073. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  5074. m_pScene = new CChoreoScene( this );
  5075. g_MDLViewer->InitGridSettings();
  5076. SetChoreoFile( scenefile );
  5077. m_pScene->SetPrintFunc( Con_Printf );
  5078. ShowButtons( true );
  5079. SetDirty( false );
  5080. }
  5081. if ( !m_pScene )
  5082. return;
  5083. // Get first actor name
  5084. CActorParams params;
  5085. memset( &params, 0, sizeof( params ) );
  5086. strcpy( params.m_szDialogTitle, "Create Actor" );
  5087. strcpy( params.m_szName, "" );
  5088. if ( !ActorProperties( &params ) )
  5089. return;
  5090. if ( strlen( params.m_szName ) <= 0 )
  5091. return;
  5092. SetDirty( true );
  5093. PushUndo( "Create Actor" );
  5094. Con_Printf( "Creating scene %s with actor '%s'\n", GetChoreoFile(), params.m_szName );
  5095. CChoreoActor *actor = m_pScene->AllocActor();
  5096. if ( actor )
  5097. {
  5098. actor->SetName( params.m_szName );
  5099. }
  5100. PushRedo( "Create Actor" );
  5101. CreateSceneWidgets();
  5102. // Redraw
  5103. InvalidateLayout();
  5104. }
  5105. //-----------------------------------------------------------------------------
  5106. // Purpose:
  5107. //-----------------------------------------------------------------------------
  5108. void CChoreoView::Save( void )
  5109. {
  5110. if ( !m_pScene )
  5111. return;
  5112. if ( !MakeFileWriteablePrompt( GetChoreoFile(), "VCD File" ) )
  5113. {
  5114. Con_Printf( "Not saving changes to %s\n", GetChoreoFile() );
  5115. return;
  5116. }
  5117. Con_Printf( "Saving changes to %s\n", GetChoreoFile() );
  5118. CP4AutoEditAddFile checkout( GetChoreoFile() );
  5119. if ( !m_pScene->SaveToFile( GetChoreoFile() ) )
  5120. {
  5121. mxMessageBox( this, va( "Unable to write \"%s\"", GetChoreoFile() ),
  5122. "SaveToFile", MX_MB_OK | MX_MB_ERROR );
  5123. }
  5124. g_MDLViewer->OnVCDSaved();
  5125. // Refresh the suffix
  5126. SetChoreoFile( GetChoreoFile() );
  5127. SetDirty( false, false );
  5128. redraw();
  5129. }
  5130. //-----------------------------------------------------------------------------
  5131. // Purpose:
  5132. //-----------------------------------------------------------------------------
  5133. void CChoreoView::SaveAs( void )
  5134. {
  5135. if ( !m_pScene )
  5136. return;
  5137. char scenefile[ 512 ];
  5138. if ( !FacePoser_ShowSaveFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  5139. return;
  5140. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  5141. Con_Printf( "Saving %s\n", scenefile );
  5142. MakeFileWriteable( scenefile );
  5143. // Change filename
  5144. SetChoreoFile( scenefile );
  5145. // Write it out baby
  5146. CP4AutoEditAddFile checkout( scenefile );
  5147. if (!m_pScene->SaveToFile( GetChoreoFile() ))
  5148. {
  5149. mxMessageBox( this, va( "Unable to write \"%s\"", GetChoreoFile() ),
  5150. "SaveToFile", MX_MB_OK | MX_MB_ERROR );
  5151. }
  5152. g_MDLViewer->OnVCDSaved();
  5153. SetDirty( false, false );
  5154. }
  5155. //-----------------------------------------------------------------------------
  5156. // Purpose:
  5157. //-----------------------------------------------------------------------------
  5158. void CChoreoView::Load( void )
  5159. {
  5160. char scenefile[ 512 ];
  5161. if ( !FacePoser_ShowOpenFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  5162. {
  5163. return;
  5164. }
  5165. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  5166. LoadSceneFromFile( scenefile );
  5167. m_nextFileList.RemoveAll();
  5168. }
  5169. void CChoreoView::LoadNext( void )
  5170. {
  5171. if (GetChoreoFile() == NULL)
  5172. return;
  5173. char fixedupFile[ 512 ];
  5174. V_FixupPathName( fixedupFile, sizeof( fixedupFile ), GetChoreoFile() );
  5175. char relativeFile[ 512 ];
  5176. filesystem->FullPathToRelativePath( fixedupFile, relativeFile, sizeof( relativeFile ) );
  5177. char relativePath[ 512 ];
  5178. Q_ExtractFilePath( relativeFile, relativePath, sizeof( relativePath ) );
  5179. if (m_nextFileList.Count() == 0)
  5180. {
  5181. // iterate files in the local directory
  5182. char path[ 512 ];
  5183. strcpy( path, relativePath );
  5184. strcat( path, "/*.vcd" );
  5185. FileFindHandle_t hFindFile;
  5186. char const *fn = filesystem->FindFirstEx( path, "MOD", &hFindFile );
  5187. if ( fn )
  5188. {
  5189. while ( fn )
  5190. {
  5191. // Don't do anything with directories
  5192. if ( !filesystem->FindIsDirectory( hFindFile ) )
  5193. {
  5194. CUtlString s = fn;
  5195. m_nextFileList.AddToTail( s );
  5196. }
  5197. fn = filesystem->FindNext( hFindFile );
  5198. }
  5199. filesystem->FindClose( hFindFile );
  5200. }
  5201. }
  5202. // look for a match, then pick the next in the list
  5203. const char *fileBase;
  5204. fileBase = V_UnqualifiedFileName( fixedupFile );
  5205. for (int i = 0; i < m_nextFileList.Count(); i++)
  5206. {
  5207. if (!stricmp( fileBase, m_nextFileList[i] ))
  5208. {
  5209. char fileName[512];
  5210. strcpy( fileName, relativePath );
  5211. if (i < m_nextFileList.Count() - 1)
  5212. {
  5213. strcat( fileName, m_nextFileList[i+1] );
  5214. }
  5215. else
  5216. {
  5217. strcat( fileName, m_nextFileList[0] );
  5218. }
  5219. LoadSceneFromFile( fileName );
  5220. break;
  5221. }
  5222. }
  5223. }
  5224. //-----------------------------------------------------------------------------
  5225. // Purpose:
  5226. // Input : *filename -
  5227. //-----------------------------------------------------------------------------
  5228. void CChoreoView::LoadSceneFromFile( const char *filename )
  5229. {
  5230. if ( filename[ 0 ] == '/' ||
  5231. filename[ 0 ] == '\\' )
  5232. {
  5233. ++filename;
  5234. }
  5235. char fn[ 512 ];
  5236. Q_strncpy( fn, filename, sizeof( fn ) );
  5237. if ( m_pScene )
  5238. {
  5239. Close();
  5240. if ( m_pScene )
  5241. {
  5242. return;
  5243. }
  5244. }
  5245. m_pScene = LoadScene( fn );
  5246. g_MDLViewer->InitGridSettings();
  5247. if ( !m_pScene )
  5248. return;
  5249. g_MDLViewer->OnFileLoaded( fn );
  5250. ShowButtons( true );
  5251. CChoreoWidget::m_pScene = m_pScene;
  5252. SetChoreoFile( fn );
  5253. bool cleaned = FixupSequenceDurations( m_pScene, false );
  5254. SetDirty( cleaned );
  5255. DeleteSceneWidgets();
  5256. CreateSceneWidgets();
  5257. // Force scroll bars to recompute
  5258. ForceScrollBarsToRecompute( false );
  5259. InvalidateLayout();
  5260. }
  5261. //-----------------------------------------------------------------------------
  5262. // Purpose:
  5263. // Input : closing -
  5264. //-----------------------------------------------------------------------------
  5265. void CChoreoView::UnloadScene( void )
  5266. {
  5267. InvalidateLayout();
  5268. ReportSceneClearToTools();
  5269. ClearStatusArea();
  5270. delete m_pScene;
  5271. m_pScene = NULL;
  5272. SetDirty( false );
  5273. SetChoreoFile( "" );
  5274. g_MDLViewer->InitGridSettings();
  5275. CChoreoWidget::m_pScene = NULL;
  5276. DeleteSceneWidgets();
  5277. m_pVertScrollBar->setVisible( false );
  5278. m_pHorzScrollBar->setVisible( false );
  5279. ShowButtons( false );
  5280. }
  5281. //-----------------------------------------------------------------------------
  5282. // Purpose:
  5283. // Input : *channel -
  5284. //-----------------------------------------------------------------------------
  5285. void CChoreoView::DeleteChannel( CChoreoChannel *channel )
  5286. {
  5287. if ( !channel || !m_pScene )
  5288. return;
  5289. SetDirty( true );
  5290. PushUndo( "Delete Channel" );
  5291. DeleteSceneWidgets();
  5292. // Delete channel and it's children
  5293. // Find the appropriate actor
  5294. for ( int i = 0; i < m_pScene->GetNumActors(); i++ )
  5295. {
  5296. CChoreoActor *a = m_pScene->GetActor( i );
  5297. if ( !a )
  5298. continue;
  5299. if ( a->FindChannelIndex( channel ) == -1 )
  5300. continue;
  5301. Con_Printf( "Deleting %s\n", channel->GetName() );
  5302. a->RemoveChannel( channel );
  5303. m_pScene->DeleteReferencedObjects( channel );
  5304. break;
  5305. }
  5306. ReportSceneClearToTools();
  5307. CreateSceneWidgets();
  5308. PushRedo( "Delete Channel" );
  5309. // Redraw
  5310. InvalidateLayout();
  5311. }
  5312. //-----------------------------------------------------------------------------
  5313. // Purpose:
  5314. //-----------------------------------------------------------------------------
  5315. void CChoreoView::NewChannel( void )
  5316. {
  5317. if ( !m_pScene )
  5318. return;
  5319. if ( !m_pScene->GetNumActors() )
  5320. {
  5321. Con_Printf( "You must create an actor before you can add a channel\n" );
  5322. return;
  5323. }
  5324. CChannelParams params;
  5325. memset( &params, 0, sizeof( params ) );
  5326. strcpy( params.m_szDialogTitle, "Create Channel" );
  5327. strcpy( params.m_szName, "" );
  5328. params.m_bShowActors = true;
  5329. strcpy( params.m_szSelectedActor, "" );
  5330. params.m_pScene = m_pScene;
  5331. if ( !ChannelProperties( &params ) )
  5332. {
  5333. return;
  5334. }
  5335. if ( strlen( params.m_szName ) <= 0 )
  5336. {
  5337. return;
  5338. }
  5339. CChoreoActor *actor = m_pScene->FindActor( params.m_szSelectedActor );
  5340. if ( !actor )
  5341. {
  5342. Con_Printf( "Can't add channel %s, actor %s doesn't exist\n", params.m_szName, params.m_szSelectedActor );
  5343. return;
  5344. }
  5345. SetDirty( true );
  5346. PushUndo( "Add Channel" );
  5347. DeleteSceneWidgets();
  5348. CChoreoChannel *channel = m_pScene->AllocChannel();
  5349. if ( !channel )
  5350. {
  5351. Con_Printf( "Unable to allocate channel %s!\n", params.m_szName );
  5352. }
  5353. else
  5354. {
  5355. channel->SetName( params.m_szName );
  5356. channel->SetActor( actor );
  5357. actor->AddChannel( channel );
  5358. }
  5359. CreateSceneWidgets();
  5360. PushRedo( "Add Channel" );
  5361. // Redraw
  5362. InvalidateLayout();
  5363. }
  5364. //-----------------------------------------------------------------------------
  5365. // Purpose:
  5366. // Input : *channel -
  5367. //-----------------------------------------------------------------------------
  5368. void CChoreoView::MoveChannelUp( CChoreoChannel *channel )
  5369. {
  5370. SetDirty( true );
  5371. PushUndo( "Move Channel Up" );
  5372. DeleteSceneWidgets();
  5373. // Find the appropriate actor
  5374. for ( int i = 0; i < m_pScene->GetNumActors(); i++ )
  5375. {
  5376. CChoreoActor *a = m_pScene->GetActor( i );
  5377. if ( !a )
  5378. continue;
  5379. int index = a->FindChannelIndex( channel );
  5380. if ( index == -1 )
  5381. continue;
  5382. if ( index != 0 )
  5383. {
  5384. Con_Printf( "Moving %s up\n", channel->GetName() );
  5385. a->SwapChannels( index, index - 1 );
  5386. }
  5387. break;
  5388. }
  5389. CreateSceneWidgets();
  5390. PushRedo( "Move Channel Up" );
  5391. // Redraw
  5392. InvalidateLayout();
  5393. }
  5394. //-----------------------------------------------------------------------------
  5395. // Purpose:
  5396. // Input : *channel -
  5397. //-----------------------------------------------------------------------------
  5398. void CChoreoView::MoveChannelDown( CChoreoChannel *channel )
  5399. {
  5400. SetDirty( true );
  5401. PushUndo( "Move Channel Down" );
  5402. DeleteSceneWidgets();
  5403. // Find the appropriate actor
  5404. for ( int i = 0; i < m_pScene->GetNumActors(); i++ )
  5405. {
  5406. CChoreoActor *a = m_pScene->GetActor( i );
  5407. if ( !a )
  5408. continue;
  5409. int index = a->FindChannelIndex( channel );
  5410. if ( index == -1 )
  5411. continue;
  5412. if ( index < a->GetNumChannels() - 1 )
  5413. {
  5414. Con_Printf( "Moving %s down\n", channel->GetName() );
  5415. a->SwapChannels( index, index + 1 );
  5416. }
  5417. break;
  5418. }
  5419. CreateSceneWidgets();
  5420. PushRedo( "Move Channel Down" );
  5421. // Redraw
  5422. InvalidateLayout();
  5423. }
  5424. //-----------------------------------------------------------------------------
  5425. // Purpose:
  5426. // Input : *channel -
  5427. //-----------------------------------------------------------------------------
  5428. void CChoreoView::EditChannel( CChoreoChannel *channel )
  5429. {
  5430. if ( !channel )
  5431. return;
  5432. CChannelParams params;
  5433. memset( &params, 0, sizeof( params ) );
  5434. strcpy( params.m_szDialogTitle, "Edit Channel" );
  5435. V_strcpy_safe( params.m_szName, channel->GetName() );
  5436. if ( !ChannelProperties( &params ) )
  5437. return;
  5438. if ( strlen( params.m_szName ) <= 0 )
  5439. return;
  5440. SetDirty( true );
  5441. PushUndo( "Edit Channel" );
  5442. channel->SetName( params.m_szName );
  5443. PushRedo( "Edit Channel" );
  5444. // Redraw
  5445. InvalidateLayout();
  5446. }
  5447. //-----------------------------------------------------------------------------
  5448. // Purpose:
  5449. // Input : *actor -
  5450. //-----------------------------------------------------------------------------
  5451. void CChoreoView::DeleteActor( CChoreoActor *actor )
  5452. {
  5453. if ( !actor || !m_pScene )
  5454. return;
  5455. SetDirty( true );
  5456. PushUndo( "Delete Actor" );
  5457. DeleteSceneWidgets();
  5458. // Delete channel and it's children
  5459. // Find the appropriate actor
  5460. Con_Printf( "Deleting %s\n", actor->GetName() );
  5461. m_pScene->RemoveActor( actor );
  5462. m_pScene->DeleteReferencedObjects( actor );
  5463. ReportSceneClearToTools();
  5464. CreateSceneWidgets();
  5465. PushRedo( "Delete Actor" );
  5466. // Redraw
  5467. InvalidateLayout();
  5468. }
  5469. //-----------------------------------------------------------------------------
  5470. // Purpose:
  5471. //-----------------------------------------------------------------------------
  5472. void CChoreoView::NewActor( void )
  5473. {
  5474. if ( !m_pScene )
  5475. {
  5476. Con_ErrorPrintf( "You must load or create a scene file first\n" );
  5477. return;
  5478. }
  5479. CActorParams params;
  5480. memset( &params, 0, sizeof( params ) );
  5481. strcpy( params.m_szDialogTitle, "Create Actor" );
  5482. strcpy( params.m_szName, "" );
  5483. if ( !ActorProperties( &params ) )
  5484. return;
  5485. if ( strlen( params.m_szName ) <= 0 )
  5486. return;
  5487. SetDirty( true );
  5488. PushUndo( "Add Actor" );
  5489. DeleteSceneWidgets();
  5490. Con_Printf( "Adding new actor '%s'\n", params.m_szName );
  5491. CChoreoActor *actor = m_pScene->AllocActor();
  5492. if ( actor )
  5493. {
  5494. actor->SetName( params.m_szName );
  5495. }
  5496. CreateSceneWidgets();
  5497. PushRedo( "Add Actor" );
  5498. // Redraw
  5499. InvalidateLayout();
  5500. }
  5501. //-----------------------------------------------------------------------------
  5502. // Purpose:
  5503. // Input : *actor -
  5504. //-----------------------------------------------------------------------------
  5505. void CChoreoView::MoveActorUp( CChoreoActor *actor )
  5506. {
  5507. DeleteSceneWidgets();
  5508. int index = m_pScene->FindActorIndex( actor );
  5509. // found it and it's not first
  5510. if ( index != -1 && index != 0 )
  5511. {
  5512. Con_Printf( "Moving %s up\n", actor->GetName() );
  5513. SetDirty( true );
  5514. PushUndo( "Move Actor Up" );
  5515. m_pScene->SwapActors( index, index - 1 );
  5516. PushRedo( "Move Actor Up" );
  5517. }
  5518. CreateSceneWidgets();
  5519. // Redraw
  5520. InvalidateLayout();
  5521. }
  5522. //-----------------------------------------------------------------------------
  5523. // Purpose:
  5524. // Input : *actor -
  5525. //-----------------------------------------------------------------------------
  5526. void CChoreoView::MoveActorDown( CChoreoActor *actor )
  5527. {
  5528. DeleteSceneWidgets();
  5529. int index = m_pScene->FindActorIndex( actor );
  5530. // found it and it's not first
  5531. if ( index != -1 && ( index < m_pScene->GetNumActors() - 1 ) )
  5532. {
  5533. Con_Printf( "Moving %s down\n", actor->GetName() );
  5534. SetDirty( true );
  5535. PushUndo( "Move Actor Down" );
  5536. m_pScene->SwapActors( index, index + 1 );
  5537. PushRedo( "Move Actor Down" );
  5538. }
  5539. CreateSceneWidgets();
  5540. // Redraw
  5541. InvalidateLayout();
  5542. }
  5543. //-----------------------------------------------------------------------------
  5544. // Purpose:
  5545. // Input : *actor -
  5546. //-----------------------------------------------------------------------------
  5547. void CChoreoView::EditActor( CChoreoActor *actor )
  5548. {
  5549. if ( !actor )
  5550. return;
  5551. CActorParams params;
  5552. memset( &params, 0, sizeof( params ) );
  5553. strcpy( params.m_szDialogTitle, "Edit Actor" );
  5554. V_strcpy_safe( params.m_szName, actor->GetName() );
  5555. if ( !ActorProperties( &params ) )
  5556. return;
  5557. if ( strlen( params.m_szName ) <= 0 )
  5558. return;
  5559. SetDirty( true );
  5560. PushUndo( "Edit Actor" );
  5561. actor->SetName( params.m_szName );
  5562. PushRedo( "Edit Actor" );
  5563. // Redraw
  5564. InvalidateLayout();
  5565. }
  5566. //-----------------------------------------------------------------------------
  5567. // Purpose:
  5568. // Input : type -
  5569. //-----------------------------------------------------------------------------
  5570. void CChoreoView::AddEvent( int type, int subtype /*= 0*/, char const *defaultparameters /*= NULL*/ )
  5571. {
  5572. int mx, my;
  5573. mx = m_nClickedX;
  5574. my = m_nClickedY;
  5575. CChoreoChannelWidget *channel = m_pClickedChannel;
  5576. if ( !channel || !channel->GetChannel() )
  5577. {
  5578. CChoreoActorWidget *actor = m_pClickedActor;
  5579. if ( actor )
  5580. {
  5581. if ( actor->GetNumChannels() <= 0 )
  5582. return;
  5583. channel = actor->GetChannel( 0 );
  5584. if ( !channel || !channel->GetChannel() )
  5585. return;
  5586. }
  5587. else
  5588. {
  5589. return;
  5590. }
  5591. }
  5592. // Convert click position local to this window
  5593. POINT pt;
  5594. pt.x = mx;
  5595. pt.y = my;
  5596. CEventParams params;
  5597. memset( &params, 0, sizeof( params ) );
  5598. if ( defaultparameters )
  5599. {
  5600. Q_strncpy( params.m_szParameters, defaultparameters, sizeof( params.m_szParameters ) );
  5601. }
  5602. strcpy( params.m_szDialogTitle, "Create Event" );
  5603. params.m_nType = type;
  5604. params.m_pScene = m_pScene;
  5605. params.m_bFixedLength = false;
  5606. params.m_bResumeCondition = false;
  5607. params.m_flStartTime = GetTimeValueForMouse( pt.x );
  5608. params.m_bCloseCaptionNoAttenuate = false;
  5609. params.m_bForceShortMovement = false;
  5610. params.m_bSyncToFollowingGesture = false;
  5611. params.m_bDisabled = false;
  5612. params.m_bPlayOverScript = false;
  5613. switch ( type )
  5614. {
  5615. case CChoreoEvent::EXPRESSION:
  5616. case CChoreoEvent::FLEXANIMATION:
  5617. case CChoreoEvent::GESTURE:
  5618. case CChoreoEvent::SEQUENCE:
  5619. case CChoreoEvent::LOOKAT:
  5620. case CChoreoEvent::MOVETO:
  5621. case CChoreoEvent::FACE:
  5622. case CChoreoEvent::SUBSCENE:
  5623. case CChoreoEvent::INTERRUPT:
  5624. case CChoreoEvent::GENERIC:
  5625. case CChoreoEvent::PERMIT_RESPONSES:
  5626. params.m_bHasEndTime = true;
  5627. params.m_flEndTime = params.m_flStartTime + 0.5f;
  5628. if ( type == CChoreoEvent::GESTURE && subtype == 1 )
  5629. {
  5630. strcpy( params.m_szDialogTitle, "Create <NULL> Gesture" );
  5631. strcpy( params.m_szName, "NULL" );
  5632. }
  5633. break;
  5634. case CChoreoEvent::SPEAK:
  5635. params.m_bFixedLength = true;
  5636. params.m_bHasEndTime = false;
  5637. params.m_flEndTime = -1.0f;
  5638. break;
  5639. default:
  5640. params.m_bHasEndTime = false;
  5641. params.m_flEndTime = -1.0f;
  5642. break;
  5643. }
  5644. params.m_bUsesTag = false;
  5645. while (1)
  5646. {
  5647. SetScrubTargetTime( m_flScrub );
  5648. FinishSimulation();
  5649. sound->Flush();
  5650. m_bForceProcess = true;
  5651. if (!EventProperties( &params ))
  5652. {
  5653. m_bForceProcess = false;
  5654. return;
  5655. }
  5656. m_bForceProcess = false;
  5657. if ( Q_strlen( params.m_szName ) <= 0 )
  5658. {
  5659. mxMessageBox( this, va( "Event must have a valid name" ),
  5660. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  5661. continue;
  5662. }
  5663. if ( Q_strlen( params.m_szParameters ) <= 0 )
  5664. {
  5665. bool shouldBreak = false;
  5666. switch ( params.m_nType )
  5667. {
  5668. case CChoreoEvent::FLEXANIMATION:
  5669. case CChoreoEvent::INTERRUPT:
  5670. case CChoreoEvent::PERMIT_RESPONSES:
  5671. shouldBreak = true;
  5672. break;
  5673. case CChoreoEvent::GESTURE:
  5674. if ( subtype == 1 )
  5675. {
  5676. shouldBreak = true;
  5677. }
  5678. break;
  5679. default:
  5680. // Have to have a non-null parameters block
  5681. break;
  5682. }
  5683. if ( !shouldBreak )
  5684. {
  5685. mxMessageBox( this, va( "No parameters specified for %s\n", params.m_szName ),
  5686. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  5687. continue;
  5688. }
  5689. }
  5690. break;
  5691. }
  5692. SetDirty( true );
  5693. PushUndo( "Add Event" );
  5694. CChoreoEvent *event = m_pScene->AllocEvent();
  5695. if ( event )
  5696. {
  5697. event->SetType( (CChoreoEvent::EVENTTYPE)type );
  5698. event->SetName( params.m_szName );
  5699. event->SetParameters( params.m_szParameters );
  5700. event->SetParameters2( params.m_szParameters2 );
  5701. event->SetParameters3( params.m_szParameters3 );
  5702. event->SetStartTime( params.m_flStartTime );
  5703. event->SetResumeCondition( params.m_bResumeCondition );
  5704. event->SetLockBodyFacing( params.m_bLockBodyFacing );
  5705. event->SetDistanceToTarget( params.m_flDistanceToTarget );
  5706. event->SetForceShortMovement( params.m_bForceShortMovement );
  5707. event->SetSyncToFollowingGesture( params.m_bSyncToFollowingGesture );
  5708. event->SetActive( !params.m_bDisabled );
  5709. event->SetPlayOverScript( params.m_bPlayOverScript );
  5710. if ( params.m_bUsesTag )
  5711. {
  5712. event->SetUsingRelativeTag( true, params.m_szTagName, params.m_szTagWav );
  5713. }
  5714. else
  5715. {
  5716. event->SetUsingRelativeTag( false );
  5717. }
  5718. CChoreoChannel *pchannel = channel->GetChannel();
  5719. event->SetChannel( pchannel );
  5720. event->SetActor( pchannel->GetActor() );
  5721. if ( params.m_bHasEndTime &&
  5722. params.m_flEndTime != -1.0 &&
  5723. params.m_flEndTime > params.m_flStartTime )
  5724. {
  5725. event->SetEndTime( params.m_flEndTime );
  5726. }
  5727. else
  5728. {
  5729. event->SetEndTime( -1.0f );
  5730. }
  5731. switch ( event->GetType() )
  5732. {
  5733. default:
  5734. break;
  5735. case CChoreoEvent::SUBSCENE:
  5736. {
  5737. // Just grab end time
  5738. CChoreoScene *scene = LoadScene( event->GetParameters() );
  5739. if ( scene )
  5740. {
  5741. event->SetEndTime( params.m_flStartTime + scene->FindStopTime() );
  5742. }
  5743. delete scene;
  5744. }
  5745. break;
  5746. case CChoreoEvent::SEQUENCE:
  5747. {
  5748. CheckSequenceLength( event, false );
  5749. // AutoaddSequenceKeys( event);
  5750. }
  5751. break;
  5752. case CChoreoEvent::GESTURE:
  5753. {
  5754. DefaultGestureLength( event, false );
  5755. AutoaddGestureKeys( event, false );
  5756. }
  5757. break;
  5758. case CChoreoEvent::LOOKAT:
  5759. case CChoreoEvent::FACE:
  5760. {
  5761. if ( params.usepitchyaw )
  5762. {
  5763. event->SetPitch( params.pitch );
  5764. event->SetYaw( params.yaw );
  5765. }
  5766. else
  5767. {
  5768. event->SetPitch( 0 );
  5769. event->SetYaw( 0 );
  5770. }
  5771. }
  5772. break;
  5773. case CChoreoEvent::SPEAK:
  5774. {
  5775. // Try and load wav to get length
  5776. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  5777. if ( wave )
  5778. {
  5779. event->SetEndTime( params.m_flStartTime + wave->GetRunningLength() );
  5780. delete wave;
  5781. }
  5782. event->SetSuppressingCaptionAttenuation( params.m_bCloseCaptionNoAttenuate );
  5783. }
  5784. break;
  5785. }
  5786. event->SnapTimes();
  5787. DeleteSceneWidgets();
  5788. // Add to appropriate channel
  5789. pchannel->AddEvent( event );
  5790. CreateSceneWidgets();
  5791. // Redraw
  5792. InvalidateLayout();
  5793. }
  5794. PushRedo( "Add Event" );
  5795. }
  5796. //-----------------------------------------------------------------------------
  5797. // Purpose: Adds a scene "pause" event
  5798. //-----------------------------------------------------------------------------
  5799. void CChoreoView::AddGlobalEvent( CChoreoEvent::EVENTTYPE type )
  5800. {
  5801. int mx, my;
  5802. mx = m_nClickedX;
  5803. my = m_nClickedY;
  5804. // Convert click position local to this window
  5805. POINT pt;
  5806. pt.x = mx;
  5807. pt.y = my;
  5808. CGlobalEventParams params;
  5809. memset( &params, 0, sizeof( params ) );
  5810. params.m_nType = type;
  5811. switch ( type )
  5812. {
  5813. default:
  5814. Assert( 0 );
  5815. strcpy( params.m_szDialogTitle, "???" );
  5816. break;
  5817. case CChoreoEvent::SECTION:
  5818. {
  5819. strcpy( params.m_szDialogTitle, "Add Pause Point" );
  5820. }
  5821. break;
  5822. case CChoreoEvent::LOOP:
  5823. {
  5824. strcpy( params.m_szDialogTitle, "Add Loop Point" );
  5825. }
  5826. break;
  5827. case CChoreoEvent::STOPPOINT:
  5828. {
  5829. strcpy( params.m_szDialogTitle, "Add Fire Completion" );
  5830. }
  5831. break;
  5832. }
  5833. strcpy( params.m_szName, "" );
  5834. strcpy( params.m_szAction, "" );
  5835. params.m_flStartTime = GetTimeValueForMouse( pt.x );
  5836. if ( !GlobalEventProperties( &params ) )
  5837. return;
  5838. if ( strlen( params.m_szName ) <= 0 )
  5839. {
  5840. Con_Printf( "Pause section event must have a valid name\n" );
  5841. return;
  5842. }
  5843. if ( strlen( params.m_szAction ) <= 0 )
  5844. {
  5845. Con_Printf( "No action specified for section pause\n" );
  5846. return;
  5847. }
  5848. char undotext[ 256 ];
  5849. undotext[0]=0;
  5850. switch( type )
  5851. {
  5852. default:
  5853. Assert( 0 );
  5854. break;
  5855. case CChoreoEvent::SECTION:
  5856. {
  5857. Q_strcpy( undotext, "Add Section Pause" );
  5858. }
  5859. break;
  5860. case CChoreoEvent::LOOP:
  5861. {
  5862. Q_strcpy( undotext, "Add Loop Point" );
  5863. }
  5864. break;
  5865. case CChoreoEvent::STOPPOINT:
  5866. {
  5867. Q_strcpy( undotext, "Add Fire Completion" );
  5868. }
  5869. break;
  5870. }
  5871. SetDirty( true );
  5872. PushUndo( undotext );
  5873. CChoreoEvent *event = m_pScene->AllocEvent();
  5874. if ( event )
  5875. {
  5876. event->SetType( type );
  5877. event->SetName( params.m_szName );
  5878. event->SetParameters( params.m_szAction );
  5879. event->SetStartTime( params.m_flStartTime );
  5880. event->SetEndTime( -1.0f );
  5881. switch ( type )
  5882. {
  5883. default:
  5884. break;
  5885. case CChoreoEvent::LOOP:
  5886. {
  5887. event->SetLoopCount( params.m_nLoopCount );
  5888. event->SetParameters( va( "%f", params.m_flLoopTime ) );
  5889. }
  5890. break;
  5891. }
  5892. event->SnapTimes();
  5893. DeleteSceneWidgets();
  5894. CreateSceneWidgets();
  5895. // Redraw
  5896. InvalidateLayout();
  5897. }
  5898. PushRedo( undotext );
  5899. }
  5900. //-----------------------------------------------------------------------------
  5901. // Purpose:
  5902. // Input : *event -
  5903. //-----------------------------------------------------------------------------
  5904. void CChoreoView::EditGlobalEvent( CChoreoEvent *event )
  5905. {
  5906. if ( !event )
  5907. return;
  5908. CGlobalEventParams params;
  5909. memset( &params, 0, sizeof( params ) );
  5910. params.m_nType = event->GetType();
  5911. switch ( event->GetType() )
  5912. {
  5913. default:
  5914. Assert( 0 );
  5915. strcpy( params.m_szDialogTitle, "???" );
  5916. break;
  5917. case CChoreoEvent::SECTION:
  5918. {
  5919. strcpy( params.m_szDialogTitle, "Edit Pause Point" );
  5920. V_strcpy_safe( params.m_szAction, event->GetParameters() );
  5921. }
  5922. break;
  5923. case CChoreoEvent::LOOP:
  5924. {
  5925. strcpy( params.m_szDialogTitle, "Edit Loop Point" );
  5926. strcpy( params.m_szAction, "" );
  5927. params.m_flLoopTime = (float)atof( event->GetParameters() );
  5928. params.m_nLoopCount = event->GetLoopCount();
  5929. }
  5930. break;
  5931. case CChoreoEvent::STOPPOINT:
  5932. {
  5933. strcpy( params.m_szDialogTitle, "Edit Fire Completion" );
  5934. strcpy( params.m_szAction, "" );
  5935. }
  5936. break;
  5937. }
  5938. strcpy( params.m_szName, event->GetName() );
  5939. params.m_flStartTime = event->GetStartTime();
  5940. if ( !GlobalEventProperties( &params ) )
  5941. return;
  5942. if ( strlen( params.m_szName ) <= 0 )
  5943. {
  5944. Con_Printf( "Event %s must have a valid name\n", event->GetName() );
  5945. return;
  5946. }
  5947. if ( strlen( params.m_szAction ) <= 0 )
  5948. {
  5949. Con_Printf( "No action specified for %s\n", event->GetName() );
  5950. return;
  5951. }
  5952. SetDirty( true );
  5953. char undotext[ 256 ];
  5954. undotext[0]=0;
  5955. switch( event->GetType() )
  5956. {
  5957. default:
  5958. Assert( 0 );
  5959. break;
  5960. case CChoreoEvent::SECTION:
  5961. {
  5962. Q_strcpy( undotext, "Edit Section Pause" );
  5963. }
  5964. break;
  5965. case CChoreoEvent::LOOP:
  5966. {
  5967. Q_strcpy( undotext, "Edit Loop Point" );
  5968. }
  5969. break;
  5970. case CChoreoEvent::STOPPOINT:
  5971. {
  5972. Q_strcpy( undotext, "Edit Fire Completion" );
  5973. }
  5974. break;
  5975. }
  5976. PushUndo( undotext );
  5977. event->SetName( params.m_szName );
  5978. event->SetStartTime( params.m_flStartTime );
  5979. event->SetEndTime( -1.0f );
  5980. switch ( event->GetType() )
  5981. {
  5982. default:
  5983. {
  5984. event->SetParameters( params.m_szAction );
  5985. }
  5986. break;
  5987. case CChoreoEvent::LOOP:
  5988. {
  5989. event->SetLoopCount( params.m_nLoopCount );
  5990. event->SetParameters( va( "%f", params.m_flLoopTime ) );
  5991. }
  5992. break;
  5993. }
  5994. event->SnapTimes();
  5995. PushRedo( undotext );
  5996. // Redraw
  5997. InvalidateLayout();
  5998. }
  5999. //-----------------------------------------------------------------------------
  6000. // Purpose:
  6001. // Input : *event -
  6002. //-----------------------------------------------------------------------------
  6003. void CChoreoView::DeleteGlobalEvent( CChoreoEvent *event )
  6004. {
  6005. if ( !event || !m_pScene )
  6006. return;
  6007. SetDirty( true );
  6008. char undotext[ 256 ];
  6009. undotext[0]=0;
  6010. switch( event->GetType() )
  6011. {
  6012. default:
  6013. Assert( 0 );
  6014. break;
  6015. case CChoreoEvent::SECTION:
  6016. {
  6017. Q_strcpy( undotext, "Delete Section Pause" );
  6018. }
  6019. break;
  6020. case CChoreoEvent::LOOP:
  6021. {
  6022. Q_strcpy( undotext, "Delete Loop Point" );
  6023. }
  6024. break;
  6025. case CChoreoEvent::STOPPOINT:
  6026. {
  6027. Q_strcpy( undotext, "Delete Fire Completion" );
  6028. }
  6029. break;
  6030. }
  6031. PushUndo( undotext );
  6032. DeleteSceneWidgets();
  6033. Con_Printf( "Deleting %s\n", event->GetName() );
  6034. m_pScene->DeleteReferencedObjects( event );
  6035. CreateSceneWidgets();
  6036. PushRedo( undotext );
  6037. // Redraw
  6038. InvalidateLayout();
  6039. }
  6040. //-----------------------------------------------------------------------------
  6041. // Purpose:
  6042. // Input : *event -
  6043. //-----------------------------------------------------------------------------
  6044. void CChoreoView::EditEvent( CChoreoEvent *event )
  6045. {
  6046. if ( !event )
  6047. return;
  6048. CEventParams params;
  6049. memset( &params, 0, sizeof( params ) );
  6050. strcpy( params.m_szDialogTitle, "Edit Event" );
  6051. // Copy in current even properties
  6052. params.m_nType = event->GetType();
  6053. params.m_bDisabled = !event->GetActive();
  6054. switch ( params.m_nType )
  6055. {
  6056. case CChoreoEvent::EXPRESSION:
  6057. case CChoreoEvent::SEQUENCE:
  6058. case CChoreoEvent::MOVETO:
  6059. case CChoreoEvent::SPEAK:
  6060. case CChoreoEvent::GESTURE:
  6061. case CChoreoEvent::INTERRUPT:
  6062. case CChoreoEvent::PERMIT_RESPONSES:
  6063. case CChoreoEvent::GENERIC:
  6064. V_strcpy_safe( params.m_szParameters3, event->GetParameters3() );
  6065. V_strcpy_safe( params.m_szParameters2, event->GetParameters2() );
  6066. V_strcpy_safe( params.m_szParameters, event->GetParameters() );
  6067. V_strcpy_safe( params.m_szName, event->GetName() );
  6068. break;
  6069. case CChoreoEvent::FACE:
  6070. case CChoreoEvent::LOOKAT:
  6071. case CChoreoEvent::FIRETRIGGER:
  6072. case CChoreoEvent::FLEXANIMATION:
  6073. case CChoreoEvent::SUBSCENE:
  6074. V_strcpy_safe( params.m_szParameters, event->GetParameters() );
  6075. V_strcpy_safe( params.m_szName, event->GetName() );
  6076. if ( params.m_nType == CChoreoEvent::LOOKAT || params.m_nType == CChoreoEvent::FACE )
  6077. {
  6078. if ( event->GetPitch() != 0 ||
  6079. event->GetYaw() != 0 )
  6080. {
  6081. params.usepitchyaw = true;
  6082. params.pitch = event->GetPitch();
  6083. params.yaw = event->GetYaw();
  6084. }
  6085. }
  6086. break;
  6087. default:
  6088. Con_Printf( "Don't know how to edit event type %s\n",
  6089. CChoreoEvent::NameForType( (CChoreoEvent::EVENTTYPE)params.m_nType ) );
  6090. return;
  6091. }
  6092. params.m_pScene = m_pScene;
  6093. params.m_pEvent = event;
  6094. params.m_flStartTime = event->GetStartTime();
  6095. params.m_flEndTime = event->GetEndTime();
  6096. params.m_bHasEndTime = event->HasEndTime();
  6097. params.m_bFixedLength = event->IsFixedLength();
  6098. params.m_bResumeCondition = event->IsResumeCondition();
  6099. params.m_bLockBodyFacing = event->IsLockBodyFacing();
  6100. params.m_flDistanceToTarget = event->GetDistanceToTarget();
  6101. params.m_bForceShortMovement = event->GetForceShortMovement();
  6102. params.m_bSyncToFollowingGesture = event->GetSyncToFollowingGesture();
  6103. params.m_bPlayOverScript = event->GetPlayOverScript();
  6104. params.m_bUsesTag = event->IsUsingRelativeTag();
  6105. params.m_bCloseCaptionNoAttenuate = event->IsSuppressingCaptionAttenuation();
  6106. if ( params.m_bUsesTag )
  6107. {
  6108. V_strcpy_safe( params.m_szTagName, event->GetRelativeTagName() );
  6109. V_strcpy_safe( params.m_szTagWav, event->GetRelativeWavName() );
  6110. }
  6111. while (1)
  6112. {
  6113. SetScrubTargetTime( m_flScrub );
  6114. FinishSimulation();
  6115. sound->Flush();
  6116. m_bForceProcess = true;
  6117. if (!EventProperties( &params ))
  6118. {
  6119. m_bForceProcess = false;
  6120. return;
  6121. }
  6122. m_bForceProcess = false;
  6123. if ( Q_strlen( params.m_szName ) <= 0 )
  6124. {
  6125. mxMessageBox( this, va( "Event %s must have a valid name", event->GetName() ),
  6126. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  6127. continue;
  6128. }
  6129. if ( Q_strlen( params.m_szParameters ) <= 0 )
  6130. {
  6131. bool shouldBreak = false;
  6132. switch ( params.m_nType )
  6133. {
  6134. case CChoreoEvent::FLEXANIMATION:
  6135. case CChoreoEvent::INTERRUPT:
  6136. case CChoreoEvent::PERMIT_RESPONSES:
  6137. shouldBreak = true;
  6138. break;
  6139. case CChoreoEvent::GESTURE:
  6140. if ( !Q_stricmp( params.m_szName, "NULL" ) )
  6141. {
  6142. shouldBreak = true;
  6143. }
  6144. break;
  6145. default:
  6146. // Have to have a non-null parameters block
  6147. break;
  6148. }
  6149. if ( !shouldBreak )
  6150. {
  6151. mxMessageBox( this, va( "No parameters specified for %s\n", params.m_szName ),
  6152. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  6153. continue;
  6154. }
  6155. }
  6156. break;
  6157. }
  6158. SetDirty( true );
  6159. PushUndo( "Edit Event" );
  6160. event->SetName( params.m_szName );
  6161. event->SetParameters( params.m_szParameters );
  6162. event->SetParameters2( params.m_szParameters2 );
  6163. event->SetParameters3( params.m_szParameters3 );
  6164. event->SetStartTime( params.m_flStartTime );
  6165. event->SetResumeCondition( params.m_bResumeCondition );
  6166. event->SetLockBodyFacing( params.m_bLockBodyFacing );
  6167. event->SetDistanceToTarget( params.m_flDistanceToTarget );
  6168. event->SetForceShortMovement( params.m_bForceShortMovement );
  6169. event->SetSyncToFollowingGesture( params.m_bSyncToFollowingGesture );
  6170. event->SetActive( !params.m_bDisabled );
  6171. event->SetPlayOverScript( params.m_bPlayOverScript );
  6172. if ( params.m_bUsesTag )
  6173. {
  6174. event->SetUsingRelativeTag( true, params.m_szTagName, params.m_szTagWav );
  6175. }
  6176. else
  6177. {
  6178. event->SetUsingRelativeTag( false );
  6179. }
  6180. if ( params.m_bHasEndTime &&
  6181. params.m_flEndTime != -1.0 &&
  6182. params.m_flEndTime > params.m_flStartTime )
  6183. {
  6184. float dt = params.m_flEndTime - event->GetEndTime();
  6185. float newduration = event->GetDuration() + dt;
  6186. RescaleRamp( event, newduration );
  6187. switch ( event->GetType() )
  6188. {
  6189. default:
  6190. break;
  6191. case CChoreoEvent::GESTURE:
  6192. {
  6193. event->RescaleGestureTimes( event->GetStartTime(), event->GetEndTime() + dt, true );
  6194. }
  6195. break;
  6196. case CChoreoEvent::FLEXANIMATION:
  6197. {
  6198. RescaleExpressionTimes( event, event->GetStartTime(), event->GetEndTime() + dt );
  6199. }
  6200. break;
  6201. }
  6202. event->SetEndTime( params.m_flEndTime );
  6203. event->SnapTimes();
  6204. event->ResortRamp();
  6205. }
  6206. else
  6207. {
  6208. event->SetEndTime( -1.0f );
  6209. }
  6210. switch ( event->GetType() )
  6211. {
  6212. default:
  6213. break;
  6214. case CChoreoEvent::SPEAK:
  6215. {
  6216. // Try and load wav to get length
  6217. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  6218. if ( wave )
  6219. {
  6220. event->SetEndTime( params.m_flStartTime + wave->GetRunningLength() );
  6221. delete wave;
  6222. }
  6223. event->SetSuppressingCaptionAttenuation( params.m_bCloseCaptionNoAttenuate );
  6224. }
  6225. break;
  6226. case CChoreoEvent::SUBSCENE:
  6227. {
  6228. // Just grab end time
  6229. CChoreoScene *scene = LoadScene( event->GetParameters() );
  6230. if ( scene )
  6231. {
  6232. event->SetEndTime( params.m_flStartTime + scene->FindStopTime() );
  6233. }
  6234. delete scene;
  6235. }
  6236. break;
  6237. case CChoreoEvent::SEQUENCE:
  6238. {
  6239. CheckSequenceLength( event, false );
  6240. }
  6241. break;
  6242. case CChoreoEvent::GESTURE:
  6243. {
  6244. CheckGestureLength( event, false );
  6245. AutoaddGestureKeys( event, false );
  6246. g_pGestureTool->redraw();
  6247. }
  6248. break;
  6249. case CChoreoEvent::LOOKAT:
  6250. case CChoreoEvent::FACE:
  6251. {
  6252. if ( params.usepitchyaw )
  6253. {
  6254. event->SetPitch( params.pitch );
  6255. event->SetYaw( params.yaw );
  6256. }
  6257. else
  6258. {
  6259. event->SetPitch( 0 );
  6260. event->SetYaw( 0 );
  6261. }
  6262. }
  6263. break;
  6264. }
  6265. event->SnapTimes();
  6266. PushRedo( "Edit Event" );
  6267. // Redraw
  6268. InvalidateLayout();
  6269. }
  6270. void CChoreoView::EnableSelectedEvents( bool state )
  6271. {
  6272. if ( !m_pScene )
  6273. return;
  6274. SetDirty( true );
  6275. // If we right clicked on an unseleced event, then select it for the user.
  6276. if ( CountSelectedEvents() == 0 )
  6277. {
  6278. CChoreoEventWidget *event = m_pClickedEvent;
  6279. if ( event )
  6280. {
  6281. event->SetSelected( true );
  6282. }
  6283. }
  6284. char const *desc = state ? "Enable Events" : "Disable Events";
  6285. PushUndo( desc );
  6286. // Find the appropriate event by iterating across all actors and channels
  6287. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  6288. {
  6289. CChoreoActorWidget *a = m_SceneActors[ i ];
  6290. if ( !a )
  6291. continue;
  6292. for ( int j = 0; j < a->GetNumChannels(); j++ )
  6293. {
  6294. CChoreoChannelWidget *channel = a->GetChannel( j );
  6295. if ( !channel )
  6296. continue;
  6297. for ( int k = channel->GetNumEvents() - 1; k >= 0; k-- )
  6298. {
  6299. CChoreoEventWidget *event = channel->GetEvent( k );
  6300. if ( !event->IsSelected() )
  6301. continue;
  6302. event->GetEvent()->SetActive( state );
  6303. }
  6304. }
  6305. }
  6306. for ( int i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  6307. {
  6308. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  6309. if ( !event || !event->IsSelected() )
  6310. continue;
  6311. event->GetEvent()->SetActive( state );
  6312. }
  6313. PushRedo( desc );
  6314. // Redraw
  6315. InvalidateLayout();
  6316. }
  6317. //-----------------------------------------------------------------------------
  6318. // Purpose:
  6319. // Input : *event -
  6320. //-----------------------------------------------------------------------------
  6321. void CChoreoView::DeleteSelectedEvents( void )
  6322. {
  6323. if ( !m_pScene )
  6324. return;
  6325. SetDirty( true );
  6326. PushUndo( "Delete Events" );
  6327. int deleteCount = 0;
  6328. float oldstoptime = m_pScene->FindStopTime();
  6329. // Find the appropriate event by iterating across all actors and channels
  6330. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  6331. {
  6332. CChoreoActorWidget *a = m_SceneActors[ i ];
  6333. if ( !a )
  6334. continue;
  6335. for ( int j = 0; j < a->GetNumChannels(); j++ )
  6336. {
  6337. CChoreoChannelWidget *channel = a->GetChannel( j );
  6338. if ( !channel )
  6339. continue;
  6340. for ( int k = channel->GetNumEvents() - 1; k >= 0; k-- )
  6341. {
  6342. CChoreoEventWidget *event = channel->GetEvent( k );
  6343. if ( !event->IsSelected() )
  6344. continue;
  6345. channel->GetChannel()->RemoveEvent( event->GetEvent() );
  6346. m_pScene->DeleteReferencedObjects( event->GetEvent() );
  6347. deleteCount++;
  6348. }
  6349. }
  6350. }
  6351. for ( int i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  6352. {
  6353. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  6354. if ( !event || !event->IsSelected() )
  6355. continue;
  6356. m_pScene->DeleteReferencedObjects( event->GetEvent() );
  6357. deleteCount++;
  6358. }
  6359. DeleteSceneWidgets();
  6360. ReportSceneClearToTools();
  6361. CreateSceneWidgets();
  6362. PushRedo( "Delete Events" );
  6363. Con_Printf( "Deleted <%i> events\n", deleteCount );
  6364. if ( m_pScene->FindStopTime() != oldstoptime )
  6365. {
  6366. // Force scroll bars to recompute
  6367. ForceScrollBarsToRecompute( false );
  6368. }
  6369. // Redraw
  6370. InvalidateLayout();
  6371. }
  6372. //-----------------------------------------------------------------------------
  6373. // Purpose:
  6374. // Input : resetthumb -
  6375. //-----------------------------------------------------------------------------
  6376. void CChoreoView::ForceScrollBarsToRecompute( bool resetthumb )
  6377. {
  6378. if ( resetthumb )
  6379. {
  6380. m_flLeftOffset = 0.0f;
  6381. }
  6382. m_nLastHPixelsNeeded = -1;
  6383. m_nLastVPixelsNeeded = -1;
  6384. }
  6385. //-----------------------------------------------------------------------------
  6386. // Purpose:
  6387. // Input : *filename -
  6388. // Output : CChoreoScene
  6389. //-----------------------------------------------------------------------------
  6390. CChoreoScene *CChoreoView::LoadScene( char const *filename )
  6391. {
  6392. // If relative path, then make a full path
  6393. char pFullPathBuf[ MAX_PATH ];
  6394. if ( !Q_IsAbsolutePath( filename ) )
  6395. {
  6396. filesystem->RelativePathToFullPath( filename, "GAME", pFullPathBuf, sizeof( pFullPathBuf ) );
  6397. filename = pFullPathBuf;
  6398. }
  6399. if ( !filesystem->FileExists( filename ) )
  6400. return NULL;
  6401. LoadScriptFile( const_cast<char*>( filename ) );
  6402. CChoreoScene *scene = ChoreoLoadScene( filename, this, tokenprocessor, Con_Printf );
  6403. return scene;
  6404. }
  6405. //-----------------------------------------------------------------------------
  6406. // Purpose:
  6407. //-----------------------------------------------------------------------------
  6408. bool CChoreoView::FixupSequenceDurations( CChoreoScene *scene, bool checkonly )
  6409. {
  6410. bool bret = false;
  6411. if ( !scene )
  6412. return bret;
  6413. int c = scene->GetNumEvents();
  6414. for ( int i = 0; i < c; i++ )
  6415. {
  6416. CChoreoEvent *event = scene->GetEvent( i );
  6417. if ( !event )
  6418. continue;
  6419. switch ( event->GetType() )
  6420. {
  6421. default:
  6422. break;
  6423. case CChoreoEvent::SPEAK:
  6424. {
  6425. // Try and load wav to get length
  6426. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  6427. if ( wave )
  6428. {
  6429. float endtime = event->GetStartTime() + wave->GetRunningLength();
  6430. if ( event->GetEndTime() != endtime )
  6431. {
  6432. event->SetEndTime( event->GetStartTime() + wave->GetRunningLength() );
  6433. bret = true;
  6434. }
  6435. delete wave;
  6436. }
  6437. }
  6438. break;
  6439. case CChoreoEvent::SEQUENCE:
  6440. {
  6441. if ( CheckSequenceLength( event, checkonly ) )
  6442. {
  6443. bret = true;
  6444. }
  6445. }
  6446. break;
  6447. case CChoreoEvent::GESTURE:
  6448. {
  6449. if ( CheckGestureLength( event, checkonly ) )
  6450. {
  6451. bret = true;
  6452. }
  6453. if ( AutoaddGestureKeys( event, checkonly ) )
  6454. {
  6455. bret = true;
  6456. }
  6457. }
  6458. break;
  6459. }
  6460. }
  6461. return bret;
  6462. }
  6463. //-----------------------------------------------------------------------------
  6464. // Purpose: IChoreoEventCallback
  6465. // Input : currenttime -
  6466. // *event -
  6467. //-----------------------------------------------------------------------------
  6468. void CChoreoView::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  6469. {
  6470. if ( !event || !event->GetActive() )
  6471. return;
  6472. CChoreoActor *actor = event->GetActor();
  6473. if ( actor && !actor->GetActive() )
  6474. {
  6475. return;
  6476. }
  6477. CChoreoChannel *channel = event->GetChannel();
  6478. if ( channel && !channel->GetActive() )
  6479. {
  6480. return;
  6481. }
  6482. // Con_Printf( "%8.4f: start %s\n", currenttime, event->GetDescription() );
  6483. switch ( event->GetType() )
  6484. {
  6485. case CChoreoEvent::SEQUENCE:
  6486. {
  6487. ProcessSequence( scene, event );
  6488. }
  6489. break;
  6490. case CChoreoEvent::SUBSCENE:
  6491. {
  6492. if ( !scene->IsSubScene() )
  6493. {
  6494. CChoreoScene *subscene = event->GetSubScene();
  6495. if ( !subscene )
  6496. {
  6497. subscene = LoadScene( event->GetParameters() );
  6498. subscene->SetSubScene( true );
  6499. event->SetSubScene( subscene );
  6500. }
  6501. if ( subscene )
  6502. {
  6503. subscene->ResetSimulation( m_bForward );
  6504. }
  6505. }
  6506. }
  6507. break;
  6508. case CChoreoEvent::SECTION:
  6509. {
  6510. ProcessPause( scene, event );
  6511. }
  6512. break;
  6513. case CChoreoEvent::SPEAK:
  6514. {
  6515. if ( ShouldProcessSpeak() )
  6516. {
  6517. // See if we should trigger CC
  6518. char soundname[ 512 ];
  6519. Q_strncpy( soundname, event->GetParameters(), sizeof( soundname ) );
  6520. float actualEndTime = event->GetEndTime();
  6521. if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
  6522. {
  6523. char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  6524. if ( event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
  6525. {
  6526. float duration = max( event->GetDuration(), event->GetLastSlaveEndTime() - event->GetStartTime() );
  6527. closecaptionmanager->Process( tok, duration, GetCloseCaptionLanguageId() );
  6528. // Use the token as the sound name lookup, too.
  6529. if ( event->IsUsingCombinedFile() &&
  6530. ( event->GetNumSlaves() > 0 ) )
  6531. {
  6532. Q_strncpy( soundname, tok, sizeof( soundname ) );
  6533. actualEndTime = max( actualEndTime, event->GetLastSlaveEndTime() );
  6534. }
  6535. }
  6536. }
  6537. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  6538. CAudioMixer *mixer = event->GetMixer();
  6539. if ( !mixer || !sound->IsSoundPlaying( mixer ) )
  6540. {
  6541. CSoundParameters params;
  6542. float volume = VOL_NORM;
  6543. gender_t gender = GENDER_NONE;
  6544. if (model)
  6545. {
  6546. gender = soundemitter->GetActorGender( model->GetFileName() );
  6547. }
  6548. if ( !Q_stristr( soundname, ".wav" ) &&
  6549. soundemitter->GetParametersForSound( soundname, params, gender ) )
  6550. {
  6551. volume = params.volume;
  6552. }
  6553. sound->PlaySound(
  6554. model,
  6555. volume,
  6556. va( "sound/%s", FacePoser_TranslateSoundName( soundname, model ) ),
  6557. &mixer );
  6558. event->SetMixer( mixer );
  6559. }
  6560. if ( mixer )
  6561. {
  6562. mixer->SetDirection( m_flFrameTime >= 0.0f );
  6563. float starttime, endtime;
  6564. starttime = event->GetStartTime();
  6565. endtime = actualEndTime;
  6566. float soundtime = endtime - starttime;
  6567. if ( soundtime > 0.0f )
  6568. {
  6569. float f = ( currenttime - starttime ) / soundtime;
  6570. f = clamp( f, 0.0f, 1.0f );
  6571. // Compute sample
  6572. float numsamples = (float)mixer->GetSource()->SampleCount();
  6573. int cursample = f * numsamples;
  6574. cursample = clamp( cursample, 0, numsamples - 1 );
  6575. mixer->SetSamplePosition( cursample );
  6576. mixer->SetActive( true );
  6577. }
  6578. }
  6579. }
  6580. }
  6581. break;
  6582. case CChoreoEvent::EXPRESSION:
  6583. {
  6584. }
  6585. break;
  6586. case CChoreoEvent::LOOP:
  6587. {
  6588. ProcessLoop( scene, event );
  6589. }
  6590. break;
  6591. case CChoreoEvent::STOPPOINT:
  6592. {
  6593. // Nothing, this is a symbolic event for keeping the vcd alive for ramping out after the last true event
  6594. }
  6595. break;
  6596. default:
  6597. break;
  6598. }
  6599. }
  6600. //-----------------------------------------------------------------------------
  6601. // Purpose:
  6602. // Input : currenttime -
  6603. // *event -
  6604. //-----------------------------------------------------------------------------
  6605. void CChoreoView::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  6606. {
  6607. if ( !event || !event->GetActive() )
  6608. return;
  6609. CChoreoActor *actor = event->GetActor();
  6610. if ( actor && !actor->GetActive() )
  6611. {
  6612. return;
  6613. }
  6614. CChoreoChannel *channel = event->GetChannel();
  6615. if ( channel && !channel->GetActive() )
  6616. {
  6617. return;
  6618. }
  6619. switch ( event->GetType() )
  6620. {
  6621. case CChoreoEvent::SUBSCENE:
  6622. {
  6623. CChoreoScene *subscene = event->GetSubScene();
  6624. if ( subscene )
  6625. {
  6626. subscene->ResetSimulation();
  6627. }
  6628. }
  6629. break;
  6630. case CChoreoEvent::SPEAK:
  6631. {
  6632. CAudioMixer *mixer = event->GetMixer();
  6633. if ( mixer && sound->IsSoundPlaying( mixer ) )
  6634. {
  6635. sound->StopSound( mixer );
  6636. }
  6637. event->SetMixer( NULL );
  6638. }
  6639. break;
  6640. default:
  6641. break;
  6642. }
  6643. // Con_Printf( "%8.4f: finish %s\n", currenttime, event->GetDescription() );
  6644. }
  6645. //-----------------------------------------------------------------------------
  6646. // Purpose:
  6647. // Input : *event -
  6648. // mx -
  6649. // my -
  6650. //-----------------------------------------------------------------------------
  6651. int CChoreoView::GetTagUnderCursorPos( CChoreoEventWidget *event, int mx, int my )
  6652. {
  6653. if ( !event )
  6654. {
  6655. return -1;
  6656. }
  6657. for ( int i = 0; i < event->GetEvent()->GetNumRelativeTags(); i++ )
  6658. {
  6659. CEventRelativeTag *tag = event->GetEvent()->GetRelativeTag( i );
  6660. if ( !tag )
  6661. continue;
  6662. // Determine left edcge
  6663. RECT bounds;
  6664. bounds = event->getBounds();
  6665. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  6666. int tolerance = 3;
  6667. if ( abs( mx - left ) < tolerance )
  6668. {
  6669. if ( abs( my - bounds.top ) < tolerance )
  6670. {
  6671. return i;
  6672. }
  6673. }
  6674. }
  6675. return -1;
  6676. }
  6677. //-----------------------------------------------------------------------------
  6678. // Purpose:
  6679. // Input : *event -
  6680. // mx -
  6681. // my -
  6682. //-----------------------------------------------------------------------------
  6683. CEventAbsoluteTag *CChoreoView::GetAbsoluteTagUnderCursorPos( CChoreoEventWidget *event, int mx, int my )
  6684. {
  6685. if ( !event )
  6686. {
  6687. return NULL;
  6688. }
  6689. for ( int i = 0; i < event->GetEvent()->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ); i++ )
  6690. {
  6691. CEventAbsoluteTag *tag = event->GetEvent()->GetAbsoluteTag( CChoreoEvent::PLAYBACK, i );
  6692. if ( !tag )
  6693. continue;
  6694. // Determine left edcge
  6695. RECT bounds;
  6696. bounds = event->getBounds();
  6697. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  6698. int tolerance = 3;
  6699. if ( abs( mx - left ) < tolerance )
  6700. {
  6701. if ( abs( my - bounds.top ) < tolerance )
  6702. {
  6703. return tag;
  6704. }
  6705. }
  6706. }
  6707. return NULL;
  6708. }
  6709. //-----------------------------------------------------------------------------
  6710. // Purpose:
  6711. // Input : mx -
  6712. // my -
  6713. // **actor -
  6714. // **channel -
  6715. // **event -
  6716. //-----------------------------------------------------------------------------
  6717. void CChoreoView::GetObjectsUnderMouse( int mx, int my, CChoreoActorWidget **actor,
  6718. CChoreoChannelWidget **channel, CChoreoEventWidget **event, CChoreoGlobalEventWidget **globalevent,
  6719. int *clickedTag,
  6720. CEventAbsoluteTag **absolutetag, int *clickedCCArea )
  6721. {
  6722. if ( actor )
  6723. {
  6724. *actor = GetActorUnderCursorPos( mx, my );
  6725. }
  6726. if ( channel )
  6727. {
  6728. *channel = GetChannelUnderCursorPos( mx, my );
  6729. if ( *channel && clickedCCArea )
  6730. {
  6731. *clickedCCArea = (*channel)->GetChannelItemUnderMouse( mx, my );
  6732. }
  6733. }
  6734. if ( event )
  6735. {
  6736. *event = GetEventUnderCursorPos( mx, my );
  6737. }
  6738. if ( globalevent )
  6739. {
  6740. *globalevent = GetGlobalEventUnderCursorPos( mx, my );
  6741. }
  6742. if ( clickedTag )
  6743. {
  6744. if ( event && *event )
  6745. {
  6746. *clickedTag = GetTagUnderCursorPos( *event, mx, my );
  6747. }
  6748. else
  6749. {
  6750. *clickedTag = -1;
  6751. }
  6752. }
  6753. if ( absolutetag )
  6754. {
  6755. if ( event && *event )
  6756. {
  6757. *absolutetag = GetAbsoluteTagUnderCursorPos( *event, mx, my );
  6758. }
  6759. else
  6760. {
  6761. *absolutetag = NULL;
  6762. }
  6763. }
  6764. m_nSelectedEvents = CountSelectedEvents();
  6765. }
  6766. //-----------------------------------------------------------------------------
  6767. // Purpose:
  6768. // Input : mx -
  6769. // my -
  6770. // Output : CChoreoGlobalEventWidget
  6771. //-----------------------------------------------------------------------------
  6772. CChoreoGlobalEventWidget *CChoreoView::GetGlobalEventUnderCursorPos( int mx, int my )
  6773. {
  6774. POINT check;
  6775. check.x = mx;
  6776. check.y = my;
  6777. CChoreoGlobalEventWidget *event;
  6778. for ( int i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  6779. {
  6780. event = m_SceneGlobalEvents[ i ];
  6781. if ( !event )
  6782. continue;
  6783. RECT bounds;
  6784. event->getBounds( bounds );
  6785. if ( PtInRect( &bounds, check ) )
  6786. {
  6787. return event;
  6788. }
  6789. }
  6790. return NULL;
  6791. }
  6792. //-----------------------------------------------------------------------------
  6793. // Purpose: Caller must first translate mouse into screen coordinates
  6794. // Input : mx -
  6795. // my -
  6796. //-----------------------------------------------------------------------------
  6797. CChoreoActorWidget *CChoreoView::GetActorUnderCursorPos( int mx, int my )
  6798. {
  6799. POINT check;
  6800. check.x = mx;
  6801. check.y = my;
  6802. CChoreoActorWidget *actor;
  6803. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  6804. {
  6805. actor = m_SceneActors[ i ];
  6806. if ( !actor )
  6807. continue;
  6808. RECT bounds;
  6809. actor->getBounds( bounds );
  6810. if ( PtInRect( &bounds, check ) )
  6811. {
  6812. return actor;
  6813. }
  6814. }
  6815. return NULL;
  6816. }
  6817. //-----------------------------------------------------------------------------
  6818. // Purpose: Caller must first translate mouse into screen coordinates
  6819. // Input : mx -
  6820. // my -
  6821. // Output : CChoreoChannelWidget
  6822. //-----------------------------------------------------------------------------
  6823. CChoreoChannelWidget *CChoreoView::GetChannelUnderCursorPos( int mx, int my )
  6824. {
  6825. CChoreoActorWidget *actor = GetActorUnderCursorPos( mx, my );
  6826. if ( !actor )
  6827. {
  6828. return NULL;
  6829. }
  6830. POINT check;
  6831. check.x = mx;
  6832. check.y = my;
  6833. CChoreoChannelWidget *channel;
  6834. for ( int i = 0; i < actor->GetNumChannels(); i++ )
  6835. {
  6836. channel = actor->GetChannel( i );
  6837. if ( !channel )
  6838. continue;
  6839. RECT bounds;
  6840. channel->getBounds( bounds );
  6841. if ( PtInRect( &bounds, check ) )
  6842. {
  6843. return channel;
  6844. }
  6845. }
  6846. return NULL;
  6847. }
  6848. //-----------------------------------------------------------------------------
  6849. // Purpose: Caller must first translate mouse into screen coordinates
  6850. // Input : mx -
  6851. // my -
  6852. //-----------------------------------------------------------------------------
  6853. CChoreoEventWidget *CChoreoView::GetEventUnderCursorPos( int mx, int my )
  6854. {
  6855. CChoreoChannelWidget *channel = GetChannelUnderCursorPos( mx, my );
  6856. if ( !channel )
  6857. {
  6858. return NULL;
  6859. }
  6860. POINT check;
  6861. check.x = mx;
  6862. check.y = my;
  6863. if ( mx < GetLabelWidth() )
  6864. return NULL;
  6865. if ( my < GetStartRow() )
  6866. return NULL;
  6867. if ( my >= h2() - ( m_nInfoHeight + m_nScrollbarHeight ) )
  6868. return NULL;
  6869. CChoreoEventWidget *event;
  6870. for ( int i = 0; i < channel->GetNumEvents(); i++ )
  6871. {
  6872. event = channel->GetEvent( i );
  6873. if ( !event )
  6874. continue;
  6875. RECT bounds;
  6876. event->getBounds( bounds );
  6877. // Events get an expanded border
  6878. InflateRect( &bounds, 8, 4 );
  6879. if ( PtInRect( &bounds, check ) )
  6880. {
  6881. return event;
  6882. }
  6883. }
  6884. return NULL;
  6885. }
  6886. //-----------------------------------------------------------------------------
  6887. // Purpose: Select wave file for phoneme editing
  6888. // Input : *filename -
  6889. //-----------------------------------------------------------------------------
  6890. void CChoreoView::SetCurrentWaveFile( const char *filename, CChoreoEvent *event )
  6891. {
  6892. g_pPhonemeEditor->SetCurrentWaveFile( filename, false, event );
  6893. }
  6894. //-----------------------------------------------------------------------------
  6895. // Purpose:
  6896. // Input : pfn -
  6897. // *param1 -
  6898. //-----------------------------------------------------------------------------
  6899. void CChoreoView::TraverseWidgets( CVMEMBERFUNC pfn, CChoreoWidget *param1 )
  6900. {
  6901. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  6902. {
  6903. CChoreoActorWidget *actor = m_SceneActors[ i ];
  6904. if ( !actor )
  6905. continue;
  6906. (this->*pfn)( actor, param1 );
  6907. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  6908. {
  6909. CChoreoChannelWidget *channel = actor->GetChannel( j );
  6910. if ( !channel )
  6911. continue;
  6912. (this->*pfn)( channel, param1 );
  6913. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  6914. {
  6915. CChoreoEventWidget *event = channel->GetEvent( k );
  6916. if ( !event )
  6917. continue;
  6918. (this->*pfn)( event, param1 );
  6919. }
  6920. }
  6921. }
  6922. for ( int i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  6923. {
  6924. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  6925. if ( !event )
  6926. continue;
  6927. (this->*pfn)( event, param1 );
  6928. }
  6929. }
  6930. //-----------------------------------------------------------------------------
  6931. // Purpose:
  6932. // Input : *widget -
  6933. // *param1 -
  6934. //-----------------------------------------------------------------------------
  6935. void CChoreoView::Deselect( CChoreoWidget *widget, CChoreoWidget *param1 )
  6936. {
  6937. if ( widget->IsSelected() )
  6938. {
  6939. widget->SetSelected( false );
  6940. }
  6941. }
  6942. //-----------------------------------------------------------------------------
  6943. // Purpose:
  6944. // Input : *widget -
  6945. // *param1 -
  6946. //-----------------------------------------------------------------------------
  6947. void CChoreoView::Select( CChoreoWidget *widget, CChoreoWidget *param1 )
  6948. {
  6949. if ( widget != param1 )
  6950. return;
  6951. if ( widget->IsSelected() )
  6952. return;
  6953. widget->SetSelected( true );
  6954. }
  6955. //-----------------------------------------------------------------------------
  6956. // Purpose:
  6957. // Input : *widget -
  6958. // *param1 -
  6959. //-----------------------------------------------------------------------------
  6960. void CChoreoView::SelectAllEvents( CChoreoWidget *widget, CChoreoWidget *param1 )
  6961. {
  6962. CChoreoEventWidget *ew = dynamic_cast< CChoreoEventWidget * >( widget );
  6963. CChoreoGlobalEventWidget *gew = dynamic_cast< CChoreoGlobalEventWidget * >( widget );
  6964. if ( ew || gew )
  6965. {
  6966. if ( widget->IsSelected() )
  6967. return;
  6968. widget->SetSelected( true );
  6969. }
  6970. }
  6971. bool CChoreoView::CreateAnimationEvent( int mx, int my, char const *animationname )
  6972. {
  6973. if ( !animationname || !animationname[0] )
  6974. return false;
  6975. // Convert screen to client
  6976. POINT pt;
  6977. pt.x = mx;
  6978. pt.y = my;
  6979. ScreenToClient( (HWND)getHandle(), &pt );
  6980. if ( pt.x < 0 || pt.y < 0 )
  6981. return false;
  6982. if ( pt.x > w2() || pt.y > h2() )
  6983. return false;
  6984. pt.x -= GetLabelWidth();
  6985. m_nClickedX = pt.x;
  6986. GetObjectsUnderMouse( pt.x, pt.y, &m_pClickedActor, &m_pClickedChannel, &m_pClickedEvent, &m_pClickedGlobalEvent, &m_nClickedTag, &m_pClickedAbsoluteTag, &m_nClickedChannelCloseCaptionButton );
  6987. // Find channel actor and time ( uses screen space coordinates )
  6988. //
  6989. CChoreoChannelWidget *channel = GetChannelUnderCursorPos( pt.x, pt.y );
  6990. if ( !channel )
  6991. {
  6992. CChoreoActorWidget *actor = GetActorUnderCursorPos( pt.x, pt.y );
  6993. if ( !actor )
  6994. return false;
  6995. // Grab first channel
  6996. if ( !actor->GetNumChannels() )
  6997. return false;
  6998. channel = actor->GetChannel( 0 );
  6999. }
  7000. if ( !channel )
  7001. return false;
  7002. CChoreoChannel *pchannel = channel->GetChannel();
  7003. if ( !pchannel )
  7004. {
  7005. Assert( 0 );
  7006. return false;
  7007. }
  7008. // At this point we need to ask the user what type of even to create (gesture or sequence) and just show the approprite dialog
  7009. CChoiceParams params;
  7010. strcpy( params.m_szDialogTitle, "Create Animation Event" );
  7011. params.m_bPositionDialog = false;
  7012. params.m_nLeft = 0;
  7013. params.m_nTop = 0;
  7014. strcpy( params.m_szPrompt, "Type of event:" );
  7015. params.m_Choices.RemoveAll();
  7016. params.m_nSelected = 0;
  7017. ChoiceText text;
  7018. strcpy( text.choice, "gesture" );
  7019. params.m_Choices.AddToTail( text );
  7020. strcpy( text.choice, "sequence" );
  7021. params.m_Choices.AddToTail( text );
  7022. if ( !ChoiceProperties( &params ) )
  7023. return false;
  7024. if ( params.m_nSelected < 0 )
  7025. return false;
  7026. switch ( params.m_nSelected )
  7027. {
  7028. default:
  7029. case 0:
  7030. AddEvent( CChoreoEvent::GESTURE, 0, animationname );
  7031. break;
  7032. case 1:
  7033. AddEvent( CChoreoEvent::SEQUENCE, 0, animationname );
  7034. break;
  7035. }
  7036. return true;
  7037. }
  7038. //-----------------------------------------------------------------------------
  7039. // Purpose:
  7040. // Input : mx -
  7041. // my -
  7042. // *cl -
  7043. // *exp -
  7044. // Output : Returns true on success, false on failure.
  7045. //-----------------------------------------------------------------------------
  7046. bool CChoreoView::CreateExpressionEvent( int mx, int my, CExpClass *cl, CExpression *exp )
  7047. {
  7048. if ( !m_pScene )
  7049. return false;
  7050. if ( !exp )
  7051. return false;
  7052. // Convert screen to client
  7053. POINT pt;
  7054. pt.x = mx;
  7055. pt.y = my;
  7056. ScreenToClient( (HWND)getHandle(), &pt );
  7057. if ( pt.x < 0 || pt.y < 0 )
  7058. return false;
  7059. if ( pt.x > w2() || pt.y > h2() )
  7060. return false;
  7061. // Find channel actor and time ( uses screen space coordinates )
  7062. //
  7063. CChoreoChannelWidget *channel = GetChannelUnderCursorPos( pt.x, pt.y );
  7064. if ( !channel )
  7065. {
  7066. CChoreoActorWidget *actor = GetActorUnderCursorPos( pt.x, pt.y );
  7067. if ( !actor )
  7068. return false;
  7069. // Grab first channel
  7070. if ( !actor->GetNumChannels() )
  7071. return false;
  7072. channel = actor->GetChannel( 0 );
  7073. }
  7074. if ( !channel )
  7075. return false;
  7076. CChoreoChannel *pchannel = channel->GetChannel();
  7077. if ( !pchannel )
  7078. {
  7079. Assert( 0 );
  7080. return false;
  7081. }
  7082. CChoreoEvent *event = m_pScene->AllocEvent();
  7083. if ( !event )
  7084. {
  7085. Assert( 0 );
  7086. return false;
  7087. }
  7088. float starttime = GetTimeValueForMouse( pt.x, false );
  7089. SetDirty( true );
  7090. PushUndo( "Create Expression" );
  7091. event->SetType( CChoreoEvent::EXPRESSION );
  7092. event->SetName( exp->name );
  7093. event->SetParameters( cl->GetName() );
  7094. event->SetParameters2( exp->name );
  7095. event->SetStartTime( starttime );
  7096. event->SetChannel( pchannel );
  7097. event->SetActor( pchannel->GetActor() );
  7098. event->SetEndTime( starttime + 1.0f );
  7099. event->SnapTimes();
  7100. DeleteSceneWidgets();
  7101. // Add to appropriate channel
  7102. pchannel->AddEvent( event );
  7103. CreateSceneWidgets();
  7104. PushRedo( "Create Expression" );
  7105. // Redraw
  7106. InvalidateLayout();
  7107. return true;
  7108. }
  7109. //-----------------------------------------------------------------------------
  7110. // Purpose:
  7111. // Output : Returns true on success, false on failure.
  7112. //-----------------------------------------------------------------------------
  7113. bool CChoreoView::IsPlayingScene( void )
  7114. {
  7115. return m_bSimulating;
  7116. }
  7117. //-----------------------------------------------------------------------------
  7118. // Purpose:
  7119. //-----------------------------------------------------------------------------
  7120. void CChoreoView::ResetTargetSettings( void )
  7121. {
  7122. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  7123. {
  7124. CChoreoActorWidget *w = m_SceneActors[ i ];
  7125. if ( w )
  7126. {
  7127. w->ResetSettings();
  7128. }
  7129. }
  7130. models->ClearModelTargets( true );
  7131. }
  7132. //-----------------------------------------------------------------------------
  7133. // Purpose: copies the actors "settings" into the models FlexControllers
  7134. // Input : dt -
  7135. //-----------------------------------------------------------------------------
  7136. void CChoreoView::UpdateCurrentSettings( void )
  7137. {
  7138. StudioModel *defaultModel = models->GetActiveStudioModel();
  7139. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  7140. {
  7141. CChoreoActorWidget *w = m_SceneActors[ i ];
  7142. if ( !w )
  7143. continue;
  7144. if ( !w->GetActor()->GetActive() )
  7145. continue;
  7146. StudioModel *model = FindAssociatedModel( m_pScene, w->GetActor() );
  7147. if ( !model )
  7148. continue;
  7149. CStudioHdr *hdr = model->GetStudioHdr();
  7150. if ( !hdr )
  7151. continue;
  7152. float *current = w->GetSettings();
  7153. for ( LocalFlexController_t j = LocalFlexController_t(0); j < hdr->numflexcontrollers(); j++ )
  7154. {
  7155. int k = hdr->pFlexcontroller( j )->localToGlobal;
  7156. if (k != -1)
  7157. {
  7158. if ( defaultModel == model && g_pFlexPanel->IsEdited( k ) )
  7159. {
  7160. model->SetFlexController( j, g_pFlexPanel->GetSlider( k ) );
  7161. }
  7162. else
  7163. {
  7164. model->SetFlexController( j, current[ k ] );
  7165. }
  7166. }
  7167. }
  7168. }
  7169. }
  7170. //-----------------------------------------------------------------------------
  7171. // Purpose:
  7172. // Input : *event -
  7173. // tagnum -
  7174. //-----------------------------------------------------------------------------
  7175. void CChoreoView::DeleteEventRelativeTag( CChoreoEvent *event, int tagnum )
  7176. {
  7177. if ( !event )
  7178. return;
  7179. CEventRelativeTag *tag = event->GetRelativeTag( tagnum );
  7180. if ( !tag )
  7181. return;
  7182. SetDirty( true );
  7183. PushUndo( "Delete Event Tag" );
  7184. event->RemoveRelativeTag( tag->GetName() );
  7185. m_pScene->ReconcileTags();
  7186. PushRedo( "Delete Event Tag" );
  7187. g_pPhonemeEditor->redraw();
  7188. InvalidateLayout();
  7189. }
  7190. //-----------------------------------------------------------------------------
  7191. // Purpose:
  7192. // Input : *event -
  7193. //-----------------------------------------------------------------------------
  7194. void CChoreoView::AddEventRelativeTag( void )
  7195. {
  7196. CChoreoEventWidget *ew = m_pClickedEvent;
  7197. if ( !ew )
  7198. return;
  7199. CChoreoEvent *event = ew->GetEvent();
  7200. if ( !event->GetEndTime() )
  7201. {
  7202. Con_ErrorPrintf( "Event Tag: Can only tag events with an end time\n" );
  7203. return;
  7204. }
  7205. CInputParams params;
  7206. memset( &params, 0, sizeof( params ) );
  7207. strcpy( params.m_szDialogTitle, "Event Tag Name" );
  7208. strcpy( params.m_szPrompt, "Name:" );
  7209. strcpy( params.m_szInputText, "" );
  7210. if ( !InputProperties( &params ) )
  7211. return;
  7212. if ( strlen( params.m_szInputText ) <= 0 )
  7213. {
  7214. Con_ErrorPrintf( "Event Tag Name: No name entered!\n" );
  7215. return;
  7216. }
  7217. RECT bounds = ew->getBounds();
  7218. // Convert click to frac
  7219. float frac = 0.0f;
  7220. if ( bounds.right - bounds.left > 0 )
  7221. {
  7222. frac = (float)( m_nClickedX - bounds.left ) / (float)( bounds.right - bounds.left );
  7223. frac = min( 1.0f, frac );
  7224. frac = max( 0.0f, frac );
  7225. }
  7226. SetDirty( true );
  7227. PushUndo( "Add Event Tag" );
  7228. event->AddRelativeTag( params.m_szInputText, frac );
  7229. PushRedo( "Add Event Tag" );
  7230. InvalidateLayout();
  7231. g_pPhonemeEditor->redraw();
  7232. g_pExpressionTool->redraw();
  7233. g_pGestureTool->redraw();
  7234. g_pRampTool->redraw();
  7235. g_pSceneRampTool->redraw();
  7236. }
  7237. CChoreoChannelWidget *CChoreoView::FindChannelForEvent( CChoreoEvent *event )
  7238. {
  7239. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  7240. {
  7241. CChoreoActorWidget *a = m_SceneActors[ i ];
  7242. if ( !a )
  7243. continue;
  7244. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7245. {
  7246. CChoreoChannelWidget *c = a->GetChannel( j );
  7247. if ( !c )
  7248. continue;
  7249. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7250. {
  7251. CChoreoEventWidget *e = c->GetEvent( k );
  7252. if ( !e )
  7253. continue;
  7254. if ( e->GetEvent() != event )
  7255. continue;
  7256. return c;
  7257. }
  7258. }
  7259. }
  7260. return NULL;
  7261. }
  7262. //-----------------------------------------------------------------------------
  7263. // Purpose:
  7264. // Input : *event -
  7265. // Output : CChoreoEventWidget
  7266. //-----------------------------------------------------------------------------
  7267. CChoreoEventWidget *CChoreoView::FindWidgetForEvent( CChoreoEvent *event )
  7268. {
  7269. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  7270. {
  7271. CChoreoActorWidget *a = m_SceneActors[ i ];
  7272. if ( !a )
  7273. continue;
  7274. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7275. {
  7276. CChoreoChannelWidget *c = a->GetChannel( j );
  7277. if ( !c )
  7278. continue;
  7279. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7280. {
  7281. CChoreoEventWidget *e = c->GetEvent( k );
  7282. if ( !e )
  7283. continue;
  7284. if ( e->GetEvent() != event )
  7285. continue;
  7286. return e;
  7287. }
  7288. }
  7289. }
  7290. return NULL;
  7291. }
  7292. //-----------------------------------------------------------------------------
  7293. // Purpose:
  7294. //-----------------------------------------------------------------------------
  7295. void CChoreoView::SelectAll( void )
  7296. {
  7297. TraverseWidgets( &CChoreoView::SelectAllEvents, NULL );
  7298. redraw();
  7299. }
  7300. //-----------------------------------------------------------------------------
  7301. // Purpose:
  7302. //-----------------------------------------------------------------------------
  7303. void CChoreoView::DeselectAll( void )
  7304. {
  7305. TraverseWidgets( &CChoreoView::Deselect, NULL );
  7306. redraw();
  7307. }
  7308. //-----------------------------------------------------------------------------
  7309. // Purpose:
  7310. // Input : mx -
  7311. // my -
  7312. //-----------------------------------------------------------------------------
  7313. void CChoreoView::UpdateStatusArea( int mx, int my )
  7314. {
  7315. FLYOVER fo;
  7316. GetObjectsUnderMouse( mx, my, &fo.a, &fo.c,
  7317. &fo.e, &fo.ge, &fo.tag, &fo.at, &fo.ccbutton );
  7318. if ( fo.a )
  7319. {
  7320. m_Flyover.a = fo.a;
  7321. }
  7322. if ( fo.e )
  7323. {
  7324. m_Flyover.e = fo.e;
  7325. }
  7326. if ( fo.c )
  7327. {
  7328. m_Flyover.c = fo.c;
  7329. }
  7330. if ( fo.ge )
  7331. {
  7332. m_Flyover.ge = fo.ge;
  7333. }
  7334. if ( fo.tag != -1 )
  7335. {
  7336. m_Flyover.tag = fo.tag;
  7337. }
  7338. if ( fo.ccbutton != -1 )
  7339. {
  7340. m_Flyover.ccbutton = fo.ccbutton;
  7341. // m_Flyover.e = NULL;
  7342. }
  7343. RECT rcClip;
  7344. GetClientRect( (HWND)getHandle(), &rcClip );
  7345. rcClip.bottom -= m_nScrollbarHeight;
  7346. rcClip.top = rcClip.bottom - m_nInfoHeight;
  7347. rcClip.right -= m_nScrollbarHeight;
  7348. CChoreoWidgetDrawHelper drawHelper( this, rcClip, COLOR_CHOREO_BACKGROUND );
  7349. drawHelper.StartClipping( rcClip );
  7350. RedrawStatusArea( drawHelper, rcClip );
  7351. drawHelper.StopClipping();
  7352. ValidateRect( (HWND)getHandle(), &rcClip );
  7353. }
  7354. //-----------------------------------------------------------------------------
  7355. // Purpose:
  7356. //-----------------------------------------------------------------------------
  7357. void CChoreoView::ClearStatusArea( void )
  7358. {
  7359. memset( &m_Flyover, 0, sizeof( m_Flyover ) );
  7360. }
  7361. //-----------------------------------------------------------------------------
  7362. // Purpose:
  7363. // Input : drawHelper -
  7364. // rcStatus -
  7365. //-----------------------------------------------------------------------------
  7366. void CChoreoView::RedrawStatusArea( CChoreoWidgetDrawHelper& drawHelper, RECT& rcStatus )
  7367. {
  7368. drawHelper.DrawFilledRect( COLOR_CHOREO_BACKGROUND, rcStatus );
  7369. drawHelper.DrawColoredLine( COLOR_INFO_BORDER, PS_SOLID, 1, rcStatus.left, rcStatus.top,
  7370. rcStatus.right, rcStatus.top );
  7371. RECT rcInfo = rcStatus;
  7372. rcInfo.top += 2;
  7373. if ( m_Flyover.e )
  7374. {
  7375. m_Flyover.e->redrawStatus( drawHelper, rcInfo );
  7376. }
  7377. if ( m_Flyover.c &&
  7378. m_Flyover.ccbutton != -1 )
  7379. {
  7380. m_Flyover.c->redrawStatus( drawHelper, rcInfo, m_Flyover.ccbutton );
  7381. }
  7382. if ( m_pScene )
  7383. {
  7384. char sz[ 512 ];
  7385. int fontsize = 9;
  7386. int fontweight = FW_NORMAL;
  7387. RECT rcText;
  7388. rcText = rcInfo;
  7389. rcText.bottom = rcText.top + fontsize + 2;
  7390. char const *mapname = m_pScene->GetMapname();
  7391. if ( mapname )
  7392. {
  7393. sprintf( sz, "Associated .bsp: %s", mapname[ 0 ] ? mapname : "none" );
  7394. int len = drawHelper.CalcTextWidth( "Arial", fontsize, fontweight, sz );
  7395. rcText.left = rcText.right - len - 10;
  7396. drawHelper.DrawColoredText( "Arial", fontsize, fontweight, COLOR_INFO_TEXT, rcText, sz );
  7397. OffsetRect( &rcText, 0, fontsize + 2 );
  7398. }
  7399. sprintf( sz, "Scene: %s", GetChoreoFile() );
  7400. int len = drawHelper.CalcTextWidth( "Arial", fontsize, fontweight, sz );
  7401. rcText.left = rcText.right - len - 10;
  7402. drawHelper.DrawColoredText( "Arial", fontsize, fontweight, COLOR_INFO_TEXT, rcText, sz );
  7403. }
  7404. // drawHelper.DrawColoredText( "Arial", 12, 500, RGB( 0, 0, 0 ), rcInfo, m_Flyover.e ? m_Flyover.e->GetEvent()->GetName() : "" );
  7405. }
  7406. //-----------------------------------------------------------------------------
  7407. // Purpose:
  7408. // Input : *event -
  7409. //-----------------------------------------------------------------------------
  7410. void CChoreoView::MoveEventToBack( CChoreoEvent *event )
  7411. {
  7412. // Now find channel widget
  7413. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  7414. {
  7415. CChoreoActorWidget *a = m_SceneActors[ i ];
  7416. if ( !a )
  7417. continue;
  7418. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7419. {
  7420. CChoreoChannelWidget *c = a->GetChannel( j );
  7421. if ( !c )
  7422. continue;
  7423. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7424. {
  7425. CChoreoEventWidget *e = c->GetEvent( k );
  7426. if ( !e )
  7427. continue;
  7428. if ( event == e->GetEvent() )
  7429. {
  7430. // Move it to back of channel's list
  7431. c->MoveEventToTail( e );
  7432. InvalidateLayout();
  7433. return;
  7434. }
  7435. }
  7436. }
  7437. }
  7438. }
  7439. //-----------------------------------------------------------------------------
  7440. // Purpose:
  7441. // Output : int
  7442. //-----------------------------------------------------------------------------
  7443. int CChoreoView::GetEndRow( void )
  7444. {
  7445. RECT rcClient;
  7446. GetClientRect( (HWND)getHandle(), &rcClient );
  7447. return rcClient.bottom - ( m_nInfoHeight + m_nScrollbarHeight );
  7448. }
  7449. // Undo/Redo
  7450. void CChoreoView::Undo( void )
  7451. {
  7452. if ( m_UndoStack.Size() > 0 && m_nUndoLevel > 0 )
  7453. {
  7454. m_nUndoLevel--;
  7455. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7456. Assert( u->undo );
  7457. DeleteSceneWidgets();
  7458. *m_pScene = *(u->undo);
  7459. g_MDLViewer->InitGridSettings();
  7460. CreateSceneWidgets();
  7461. ReportSceneClearToTools();
  7462. ClearStatusArea();
  7463. m_pClickedActor = NULL;
  7464. m_pClickedChannel = NULL;
  7465. m_pClickedEvent = NULL;
  7466. m_pClickedGlobalEvent = NULL;
  7467. }
  7468. InvalidateLayout();
  7469. }
  7470. void CChoreoView::Redo( void )
  7471. {
  7472. if ( m_UndoStack.Size() > 0 && m_nUndoLevel <= m_UndoStack.Size() - 1 )
  7473. {
  7474. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7475. Assert( u->redo );
  7476. DeleteSceneWidgets();
  7477. *m_pScene = *(u->redo);
  7478. g_MDLViewer->InitGridSettings();
  7479. CreateSceneWidgets();
  7480. ReportSceneClearToTools();
  7481. ClearStatusArea();
  7482. m_pClickedActor = NULL;
  7483. m_pClickedChannel = NULL;
  7484. m_pClickedEvent = NULL;
  7485. m_pClickedGlobalEvent = NULL;
  7486. m_nUndoLevel++;
  7487. }
  7488. InvalidateLayout();
  7489. }
  7490. static char *CopyString( const char *in )
  7491. {
  7492. int len = strlen( in );
  7493. char *n = new char[ len + 1 ];
  7494. strcpy( n, in );
  7495. return n;
  7496. }
  7497. void CChoreoView::PushUndo( const char *description )
  7498. {
  7499. Assert( !m_bRedoPending );
  7500. m_bRedoPending = true;
  7501. WipeRedo();
  7502. // Copy current data
  7503. CChoreoScene *u = new CChoreoScene( this );
  7504. *u = *m_pScene;
  7505. CVUndo *undo = new CVUndo;
  7506. undo->undo = u;
  7507. undo->redo = NULL;
  7508. undo->udescription = CopyString( description );
  7509. undo->rdescription = NULL;
  7510. m_UndoStack.AddToTail( undo );
  7511. m_nUndoLevel++;
  7512. }
  7513. void CChoreoView::PushRedo( const char *description )
  7514. {
  7515. Assert( m_bRedoPending );
  7516. m_bRedoPending = false;
  7517. // Copy current data
  7518. CChoreoScene *r = new CChoreoScene( this );
  7519. *r = *m_pScene;
  7520. CVUndo *undo = m_UndoStack[ m_nUndoLevel - 1 ];
  7521. undo->redo = r;
  7522. undo->rdescription = CopyString( description );
  7523. // Always redo here to reflect that someone has made a change
  7524. redraw();
  7525. }
  7526. void CChoreoView::WipeUndo( void )
  7527. {
  7528. while ( m_UndoStack.Size() > 0 )
  7529. {
  7530. CVUndo *u = m_UndoStack[ 0 ];
  7531. delete u->undo;
  7532. delete u->redo;
  7533. delete[] u->udescription;
  7534. delete[] u->rdescription;
  7535. delete u;
  7536. m_UndoStack.Remove( 0 );
  7537. }
  7538. m_nUndoLevel = 0;
  7539. }
  7540. void CChoreoView::WipeRedo( void )
  7541. {
  7542. // Wipe everything above level
  7543. while ( m_UndoStack.Size() > m_nUndoLevel )
  7544. {
  7545. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7546. delete u->undo;
  7547. delete u->redo;
  7548. delete[] u->udescription;
  7549. delete[] u->rdescription;
  7550. delete u;
  7551. m_UndoStack.Remove( m_nUndoLevel );
  7552. }
  7553. }
  7554. //-----------------------------------------------------------------------------
  7555. // Purpose:
  7556. // Output : const char
  7557. //-----------------------------------------------------------------------------
  7558. const char *CChoreoView::GetUndoDescription( void )
  7559. {
  7560. if ( CanUndo() )
  7561. {
  7562. CVUndo *u = m_UndoStack[ m_nUndoLevel - 1 ];
  7563. return u->udescription;
  7564. }
  7565. return "???undo";
  7566. }
  7567. //-----------------------------------------------------------------------------
  7568. // Purpose:
  7569. // Output : const char
  7570. //-----------------------------------------------------------------------------
  7571. const char *CChoreoView::GetRedoDescription( void )
  7572. {
  7573. if ( CanRedo() )
  7574. {
  7575. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7576. return u->rdescription;
  7577. }
  7578. return "???redo";
  7579. }
  7580. //-----------------------------------------------------------------------------
  7581. // Purpose:
  7582. // Output : Returns true on success, false on failure.
  7583. //-----------------------------------------------------------------------------
  7584. bool CChoreoView::CanUndo()
  7585. {
  7586. return m_nUndoLevel != 0;
  7587. }
  7588. //-----------------------------------------------------------------------------
  7589. // Purpose:
  7590. // Output : Returns true on success, false on failure.
  7591. //-----------------------------------------------------------------------------
  7592. bool CChoreoView::CanRedo()
  7593. {
  7594. return m_nUndoLevel != m_UndoStack.Size();
  7595. }
  7596. //-----------------------------------------------------------------------------
  7597. // Purpose:
  7598. //-----------------------------------------------------------------------------
  7599. void CChoreoView::OnGestureTool( void )
  7600. {
  7601. if ( m_pClickedEvent->GetEvent()->GetType() != CChoreoEvent::GESTURE )
  7602. return;
  7603. g_pGestureTool->SetEvent( m_pClickedEvent->GetEvent() );
  7604. }
  7605. //-----------------------------------------------------------------------------
  7606. // Purpose:
  7607. //-----------------------------------------------------------------------------
  7608. void CChoreoView::OnExpressionTool( void )
  7609. {
  7610. if ( m_pClickedEvent->GetEvent()->GetType() != CChoreoEvent::FLEXANIMATION )
  7611. return;
  7612. g_pExpressionTool->SetEvent( m_pClickedEvent->GetEvent() );
  7613. }
  7614. //-----------------------------------------------------------------------------
  7615. // Purpose:
  7616. // Output : CChoreoScene
  7617. //-----------------------------------------------------------------------------
  7618. CChoreoScene *CChoreoView::GetScene( void )
  7619. {
  7620. return m_pScene;
  7621. }
  7622. bool CChoreoView::CanPaste( void )
  7623. {
  7624. char const *copyfile = COPYPASTE_FILENAME;
  7625. if ( !filesystem->FileExists( copyfile ) )
  7626. {
  7627. return false;
  7628. }
  7629. return true;
  7630. }
  7631. void CChoreoView::CopyEvents( void )
  7632. {
  7633. if ( !m_pScene )
  7634. return;
  7635. char const *copyfile = COPYPASTE_FILENAME;
  7636. MakeFileWriteable( copyfile );
  7637. ExportVCDFile( copyfile );
  7638. }
  7639. void CChoreoView::PasteEvents( void )
  7640. {
  7641. if ( !m_pScene )
  7642. return;
  7643. if ( !CanPaste() )
  7644. return;
  7645. char const *copyfile = COPYPASTE_FILENAME;
  7646. ImportVCDFile( copyfile );
  7647. }
  7648. void CChoreoView::ImportEvents( void )
  7649. {
  7650. if ( !m_pScene )
  7651. return;
  7652. if ( !m_pClickedActor || !m_pClickedChannel )
  7653. return;
  7654. char eventfile[ 512 ];
  7655. if ( !FacePoser_ShowOpenFileNameDialog( eventfile, sizeof( eventfile ), "scenes", "*.vce" ) )
  7656. return;
  7657. char fullpathbuf[ 512 ];
  7658. char *fullpath = eventfile;
  7659. if ( !Q_IsAbsolutePath( eventfile ) )
  7660. {
  7661. filesystem->RelativePathToFullPath( eventfile, "GAME", fullpathbuf, sizeof( fullpathbuf ) );
  7662. fullpath = fullpathbuf;
  7663. }
  7664. if ( !filesystem->FileExists( fullpath ) )
  7665. return;
  7666. LoadScriptFile( fullpath );
  7667. DeselectAll();
  7668. SetDirty( true );
  7669. PushUndo( "Import Events" );
  7670. m_pScene->ImportEvents( tokenprocessor, m_pClickedActor->GetActor(), m_pClickedChannel->GetChannel() );
  7671. PushRedo( "Import Events" );
  7672. CreateSceneWidgets();
  7673. // Redraw
  7674. InvalidateLayout();
  7675. Con_Printf( "Imported events from %s\n", fullpath );
  7676. }
  7677. void CChoreoView::ExportEvents( void )
  7678. {
  7679. char eventfilename[ 512 ];
  7680. if ( !FacePoser_ShowSaveFileNameDialog( eventfilename, sizeof( eventfilename ), "scenes", "*.vce" ) )
  7681. return;
  7682. Q_DefaultExtension( eventfilename, ".vce", sizeof( eventfilename ) );
  7683. Con_Printf( "Exporting events to %s\n", eventfilename );
  7684. // Write to file
  7685. CUtlVector< CChoreoEvent * > events;
  7686. // Find selected eventss
  7687. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  7688. {
  7689. CChoreoActorWidget *a = m_SceneActors[ i ];
  7690. if ( !a )
  7691. continue;
  7692. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7693. {
  7694. CChoreoChannelWidget *c = a->GetChannel( j );
  7695. if ( !c )
  7696. continue;
  7697. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7698. {
  7699. CChoreoEventWidget *e = c->GetEvent( k );
  7700. if ( !e )
  7701. continue;
  7702. if ( !e->IsSelected() )
  7703. continue;
  7704. CChoreoEvent *event = e->GetEvent();
  7705. if ( !event )
  7706. continue;
  7707. events.AddToTail( event );
  7708. }
  7709. }
  7710. }
  7711. if ( events.Size() > 0 )
  7712. {
  7713. m_pScene->ExportEvents( eventfilename, events );
  7714. }
  7715. else
  7716. {
  7717. Con_Printf( "No events selected\n" );
  7718. }
  7719. }
  7720. void CChoreoView::ExportVCDFile( char const *filename )
  7721. {
  7722. Con_Printf( "Exporting to %s\n", filename );
  7723. // Unmark everything
  7724. m_pScene->MarkForSaveAll( false );
  7725. // Mark everything related to selected events
  7726. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  7727. {
  7728. CChoreoActorWidget *a = m_SceneActors[ i ];
  7729. if ( !a )
  7730. continue;
  7731. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7732. {
  7733. CChoreoChannelWidget *c = a->GetChannel( j );
  7734. if ( !c )
  7735. continue;
  7736. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7737. {
  7738. CChoreoEventWidget *e = c->GetEvent( k );
  7739. if ( !e )
  7740. continue;
  7741. if ( !e->IsSelected() )
  7742. continue;
  7743. CChoreoEvent *event = e->GetEvent();
  7744. if ( !event )
  7745. continue;
  7746. event->SetMarkedForSave( true );
  7747. if ( event->GetChannel() )
  7748. {
  7749. event->GetChannel()->SetMarkedForSave( true );
  7750. }
  7751. if ( event->GetActor() )
  7752. {
  7753. event->GetActor()->SetMarkedForSave( true );
  7754. }
  7755. }
  7756. }
  7757. }
  7758. m_pScene->ExportMarkedToFile( filename );
  7759. }
  7760. void CChoreoView::ImportVCDFile( char const *filename )
  7761. {
  7762. CChoreoScene *merge = LoadScene( filename );
  7763. if ( !merge )
  7764. {
  7765. Con_Printf( "Couldn't load from .vcd %s\n", filename );
  7766. return;
  7767. }
  7768. DeselectAll();
  7769. CUtlRBTree< CChoreoEvent *, int > oldEvents( 0, 0, DefLessFunc( CChoreoEvent * ) );
  7770. int i;
  7771. for ( i = 0; i < m_SceneActors.Count(); ++i )
  7772. {
  7773. CChoreoActorWidget *actor = m_SceneActors[ i ];
  7774. if ( !actor )
  7775. continue;
  7776. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  7777. {
  7778. CChoreoChannelWidget *channel = actor->GetChannel( j );
  7779. if ( !channel )
  7780. continue;
  7781. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  7782. {
  7783. CChoreoEventWidget *event = channel->GetEvent( k );
  7784. if ( !event )
  7785. continue;
  7786. oldEvents.Insert( event->GetEvent() );
  7787. }
  7788. }
  7789. }
  7790. SetDirty( true );
  7791. PushUndo( "Merge/Import VCD" );
  7792. m_pScene->Merge( merge );
  7793. PushRedo( "Merge/Import VCD" );
  7794. DeleteSceneWidgets();
  7795. CreateSceneWidgets();
  7796. // Force scroll bars to recompute
  7797. ForceScrollBarsToRecompute( false );
  7798. // Now walk through the "new" events and select everything that wasn't already there (all of the stuff that was "added" during the merge)
  7799. for ( i = 0; i < m_SceneActors.Count(); ++i )
  7800. {
  7801. CChoreoActorWidget *actor = m_SceneActors[ i ];
  7802. if ( !actor )
  7803. continue;
  7804. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  7805. {
  7806. CChoreoChannelWidget *channel = actor->GetChannel( j );
  7807. if ( !channel )
  7808. continue;
  7809. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  7810. {
  7811. CChoreoEventWidget *event = channel->GetEvent( k );
  7812. if ( !event )
  7813. continue;
  7814. if ( oldEvents.Find( event->GetEvent() ) == oldEvents.InvalidIndex() )
  7815. {
  7816. event->SetSelected( true );
  7817. }
  7818. }
  7819. }
  7820. }
  7821. // Redraw
  7822. InvalidateLayout();
  7823. Con_Printf( "Imported vcd '%s'\n", filename );
  7824. delete merge;
  7825. redraw();
  7826. }
  7827. void CChoreoView::ExportVCD()
  7828. {
  7829. char scenefile[ 512 ];
  7830. if ( !FacePoser_ShowSaveFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  7831. {
  7832. return;
  7833. }
  7834. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  7835. ExportVCDFile( scenefile );
  7836. }
  7837. void CChoreoView::ImportVCD()
  7838. {
  7839. if ( !m_pScene )
  7840. return;
  7841. if ( !m_pClickedActor || !m_pClickedChannel )
  7842. return;
  7843. char scenefile[ 512 ];
  7844. if ( !FacePoser_ShowOpenFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  7845. {
  7846. return;
  7847. }
  7848. ImportVCDFile( scenefile );
  7849. }
  7850. //-----------------------------------------------------------------------------
  7851. // Purpose:
  7852. // Output : Returns true on success, false on failure.
  7853. //-----------------------------------------------------------------------------
  7854. bool CChoreoView::IsProcessing( void )
  7855. {
  7856. if ( !m_pScene )
  7857. return false;
  7858. if ( m_flScrub != m_flScrubTarget )
  7859. return true;
  7860. return false;
  7861. }
  7862. //-----------------------------------------------------------------------------
  7863. // Purpose:
  7864. // Output : Returns true on success, false on failure.
  7865. //-----------------------------------------------------------------------------
  7866. bool CChoreoView::ShouldProcessSpeak( void )
  7867. {
  7868. if ( !g_pControlPanel->AllToolsDriveSpeech() )
  7869. {
  7870. if ( !IsActiveTool() )
  7871. return false;
  7872. }
  7873. if ( IFacePoserToolWindow::IsAnyToolScrubbing() )
  7874. return true;
  7875. if ( IFacePoserToolWindow::IsAnyToolProcessing() )
  7876. return true;
  7877. return false;
  7878. }
  7879. //-----------------------------------------------------------------------------
  7880. // Purpose:
  7881. // Input : *scene -
  7882. // *event -
  7883. //-----------------------------------------------------------------------------
  7884. void CChoreoView::ProcessSpeak( CChoreoScene *scene, CChoreoEvent *event )
  7885. {
  7886. if ( !ShouldProcessSpeak() )
  7887. return;
  7888. Assert( event->GetType() == CChoreoEvent::SPEAK );
  7889. Assert( scene );
  7890. float t = scene->GetTime();
  7891. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  7892. // See if we should trigger CC
  7893. char soundname[ 512 ];
  7894. Q_strncpy( soundname, event->GetParameters(), sizeof( soundname ) );
  7895. float actualEndTime = event->GetEndTime();
  7896. if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
  7897. {
  7898. char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  7899. if ( event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
  7900. {
  7901. // Use the token as the sound name lookup, too.
  7902. if ( event->IsUsingCombinedFile() &&
  7903. ( event->GetNumSlaves() > 0 ) )
  7904. {
  7905. Q_strncpy( soundname, tok, sizeof( soundname ) );
  7906. actualEndTime = max( actualEndTime, event->GetLastSlaveEndTime() );
  7907. }
  7908. }
  7909. }
  7910. CAudioMixer *mixer = event->GetMixer();
  7911. if ( !mixer || !sound->IsSoundPlaying( mixer ) )
  7912. {
  7913. CSoundParameters params;
  7914. float volume = VOL_NORM;
  7915. gender_t gender = GENDER_NONE;
  7916. if (model)
  7917. {
  7918. gender = soundemitter->GetActorGender( model->GetFileName() );
  7919. }
  7920. if ( !Q_stristr( soundname, ".wav" ) &&
  7921. soundemitter->GetParametersForSound( soundname, params, gender ) )
  7922. {
  7923. volume = params.volume;
  7924. }
  7925. sound->PlaySound(
  7926. model,
  7927. volume,
  7928. va( "sound/%s", FacePoser_TranslateSoundName( soundname, model ) ),
  7929. &mixer );
  7930. event->SetMixer( mixer );
  7931. }
  7932. mixer = event->GetMixer();
  7933. if ( !mixer )
  7934. return;
  7935. mixer->SetDirection( m_flFrameTime >= 0.0f );
  7936. float starttime, endtime;
  7937. starttime = event->GetStartTime();
  7938. endtime = actualEndTime;
  7939. float soundtime = endtime - starttime;
  7940. if ( soundtime <= 0.0f )
  7941. return;
  7942. float f = ( t - starttime ) / soundtime;
  7943. f = clamp( f, 0.0f, 1.0f );
  7944. // Compute sample
  7945. float numsamples = (float)mixer->GetSource()->SampleCount();
  7946. int cursample = f * numsamples;
  7947. cursample = clamp( cursample, 0, numsamples - 1 );
  7948. int realsample = mixer->GetSamplePosition();
  7949. int dsample = cursample - realsample;
  7950. int samplelimit = mixer->GetSource()->SampleRate() * 0.02f; // don't shift until samples are off by this much
  7951. if (IsScrubbing())
  7952. {
  7953. samplelimit = mixer->GetSource()->SampleRate() * 0.01f; // make it shorter tolerance when scrubbing
  7954. }
  7955. if ( abs( dsample ) > samplelimit )
  7956. {
  7957. mixer->SetSamplePosition( cursample, IsScrubbing() );
  7958. }
  7959. mixer->SetActive( true );
  7960. }
  7961. //-----------------------------------------------------------------------------
  7962. // Purpose:
  7963. // Input : *event -
  7964. // Output : Returns true on success, false on failure.
  7965. //-----------------------------------------------------------------------------
  7966. void CChoreoView::ProcessSubscene( CChoreoScene *scene, CChoreoEvent *event )
  7967. {
  7968. Assert( event->GetType() == CChoreoEvent::SUBSCENE );
  7969. CChoreoScene *subscene = event->GetSubScene();
  7970. if ( !subscene )
  7971. return;
  7972. if ( subscene->SimulationFinished() )
  7973. return;
  7974. // Have subscenes think for appropriate time
  7975. subscene->Think( m_flScrub );
  7976. }
  7977. void CChoreoView::PositionControls()
  7978. {
  7979. int topx = GetCaptionHeight() + SCRUBBER_HEIGHT;
  7980. int bx = 2;
  7981. int bw = 16;
  7982. m_btnPlay->setBounds( bx, topx + 4, 16, 16 );
  7983. bx += bw + 2;
  7984. m_btnPause->setBounds( bx, topx + 4, 16, 16 );
  7985. bx += bw + 2;
  7986. m_btnStop->setBounds( bx, topx + 4, 16, 16 );
  7987. bx += bw + 2;
  7988. m_pPlaybackRate->setBounds( bx, topx + 4, 100, 16 );
  7989. }
  7990. void CChoreoView::SetChoreoFile( char const *filename )
  7991. {
  7992. strcpy( m_szChoreoFile, filename );
  7993. if ( m_szChoreoFile[ 0 ] )
  7994. {
  7995. char sz[ 256 ];
  7996. if ( IsFileWriteable( m_szChoreoFile ) )
  7997. {
  7998. Q_snprintf( sz, sizeof( sz ), " - %s", m_szChoreoFile );
  7999. }
  8000. else
  8001. {
  8002. Q_snprintf( sz, sizeof( sz ), " - %s [Read-Only]", m_szChoreoFile );
  8003. }
  8004. SetSuffix( sz );
  8005. }
  8006. else
  8007. {
  8008. SetSuffix( "" );
  8009. }
  8010. }
  8011. char const *CChoreoView::GetChoreoFile( void ) const
  8012. {
  8013. return m_szChoreoFile;
  8014. }
  8015. //-----------------------------------------------------------------------------
  8016. // Purpose:
  8017. // Input : rcHandle -
  8018. //-----------------------------------------------------------------------------
  8019. void CChoreoView::GetScrubHandleRect( RECT& rcHandle, bool clipped )
  8020. {
  8021. float pixel = 0.0f;
  8022. if ( m_pScene )
  8023. {
  8024. float currenttime = m_flScrub;
  8025. float starttime = m_flStartTime;
  8026. float endtime = m_flEndTime;
  8027. float screenfrac = ( currenttime - starttime ) / ( endtime - starttime );
  8028. pixel = GetLabelWidth() + screenfrac * ( w2() - GetLabelWidth() );
  8029. if ( clipped )
  8030. {
  8031. pixel = clamp( pixel, SCRUBBER_HANDLE_WIDTH/2, w2() - SCRUBBER_HANDLE_WIDTH/2 );
  8032. }
  8033. }
  8034. rcHandle.left = pixel-SCRUBBER_HANDLE_WIDTH/2;
  8035. rcHandle.right = pixel + SCRUBBER_HANDLE_WIDTH/2;
  8036. rcHandle.top = 2 + GetCaptionHeight();
  8037. rcHandle.bottom = rcHandle.top + SCRUBBER_HANDLE_HEIGHT;
  8038. }
  8039. //-----------------------------------------------------------------------------
  8040. // Purpose:
  8041. // Input : rcArea -
  8042. //-----------------------------------------------------------------------------
  8043. void CChoreoView::GetScrubAreaRect( RECT& rcArea )
  8044. {
  8045. rcArea.left = 0;
  8046. rcArea.right = w2();
  8047. rcArea.top = 2 + GetCaptionHeight();
  8048. rcArea.bottom = rcArea.top + SCRUBBER_HEIGHT - 4;
  8049. }
  8050. //-----------------------------------------------------------------------------
  8051. // Purpose:
  8052. // Input : drawHelper -
  8053. // rcHandle -
  8054. //-----------------------------------------------------------------------------
  8055. void CChoreoView::DrawScrubHandle( CChoreoWidgetDrawHelper& drawHelper )
  8056. {
  8057. RECT rcHandle;
  8058. GetScrubHandleRect( rcHandle, true );
  8059. HBRUSH br = CreateSolidBrush( RGB( 0, 150, 100 ) );
  8060. drawHelper.DrawFilledRect( br, rcHandle );
  8061. //
  8062. char sz[ 32 ];
  8063. sprintf( sz, "%.3f", m_flScrub );
  8064. int len = drawHelper.CalcTextWidth( "Arial", 9, 500, sz );
  8065. RECT rcText = rcHandle;
  8066. int textw = rcText.right - rcText.left;
  8067. rcText.left += ( textw - len ) / 2;
  8068. drawHelper.DrawColoredText( "Arial", 9, 500, RGB( 255, 255, 255 ), rcText, sz );
  8069. DeleteObject( br );
  8070. }
  8071. //-----------------------------------------------------------------------------
  8072. // Purpose:
  8073. // Input : *event -
  8074. // Output : Returns true on success, false on failure.
  8075. //-----------------------------------------------------------------------------
  8076. bool CChoreoView::IsMouseOverScrubHandle( mxEvent *event )
  8077. {
  8078. RECT rcHandle;
  8079. GetScrubHandleRect( rcHandle, true );
  8080. InflateRect( &rcHandle, 2, 2 );
  8081. POINT pt;
  8082. pt.x = (short)event->x;
  8083. pt.y = (short)event->y;
  8084. if ( PtInRect( &rcHandle, pt ) )
  8085. {
  8086. return true;
  8087. }
  8088. return false;
  8089. }
  8090. bool CChoreoView::IsMouseOverScrubArea( mxEvent *event )
  8091. {
  8092. RECT rcArea;
  8093. GetScrubAreaRect( rcArea );
  8094. InflateRect( &rcArea, 2, 2 );
  8095. POINT pt;
  8096. pt.x = (short)event->x;
  8097. pt.y = (short)event->y;
  8098. if ( PtInRect( &rcArea, pt ) )
  8099. {
  8100. return true;
  8101. }
  8102. return false;
  8103. }
  8104. bool CChoreoView::IsScrubbing( void ) const
  8105. {
  8106. bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
  8107. return scrubbing;
  8108. }
  8109. //-----------------------------------------------------------------------------
  8110. // Purpose:
  8111. // Input : dt -
  8112. //-----------------------------------------------------------------------------
  8113. void CChoreoView::Think( float dt )
  8114. {
  8115. bool scrubbing = IFacePoserToolWindow::IsAnyToolScrubbing();
  8116. ScrubThink( dt, scrubbing, this );
  8117. }
  8118. static int lastthinkframe = -1;
  8119. void CChoreoView::ScrubThink( float dt, bool scrubbing, IFacePoserToolWindow *invoker )
  8120. {
  8121. // Make sure we don't get called more than once per frame
  8122. int thisframe = g_MDLViewer->GetCurrentFrame();
  8123. if ( thisframe == lastthinkframe )
  8124. return;
  8125. lastthinkframe = thisframe;
  8126. if ( !m_pScene )
  8127. return;
  8128. if ( m_flScrubTarget == m_flScrub && !scrubbing )
  8129. {
  8130. // Act like it's paused
  8131. if ( IFacePoserToolWindow::ShouldAutoProcess() )
  8132. {
  8133. m_bSimulating = true;
  8134. SceneThink( m_flScrub );
  8135. }
  8136. if ( m_bSimulating && !m_bPaused )
  8137. {
  8138. //FinishSimulation();
  8139. }
  8140. return;
  8141. }
  8142. // Make sure we're solving head turns during playback
  8143. models->SetSolveHeadTurn( 1 );
  8144. if ( m_bPaused )
  8145. {
  8146. SceneThink( m_flScrub );
  8147. return;
  8148. }
  8149. // Make sure phonemes are loaded
  8150. FacePoser_EnsurePhonemesLoaded();
  8151. if ( !m_bSimulating )
  8152. {
  8153. m_bSimulating = true;
  8154. }
  8155. float d = m_flScrubTarget - m_flScrub;
  8156. int sign = d > 0.0f ? 1 : -1;
  8157. float maxmove = dt * m_flPlaybackRate;
  8158. float prevScrub = m_flScrub;
  8159. if ( sign > 0 )
  8160. {
  8161. if ( d < maxmove )
  8162. {
  8163. m_flScrub = m_flScrubTarget;
  8164. }
  8165. else
  8166. {
  8167. m_flScrub += maxmove;
  8168. }
  8169. }
  8170. else
  8171. {
  8172. if ( -d < maxmove )
  8173. {
  8174. m_flScrub = m_flScrubTarget;
  8175. }
  8176. else
  8177. {
  8178. m_flScrub -= maxmove;
  8179. }
  8180. }
  8181. m_flFrameTime = ( m_flScrub - prevScrub );
  8182. SceneThink( m_flScrub );
  8183. DrawScrubHandle();
  8184. if ( scrubbing )
  8185. {
  8186. g_pMatSysWindow->Frame();
  8187. }
  8188. if ( invoker != g_pExpressionTool )
  8189. {
  8190. g_pExpressionTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8191. }
  8192. if ( invoker != g_pGestureTool )
  8193. {
  8194. g_pGestureTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8195. }
  8196. if ( invoker != g_pRampTool )
  8197. {
  8198. g_pRampTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8199. }
  8200. if ( invoker != g_pSceneRampTool )
  8201. {
  8202. g_pSceneRampTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8203. }
  8204. }
  8205. void CChoreoView::DrawScrubHandle( void )
  8206. {
  8207. if ( !m_bCanDraw )
  8208. return;
  8209. // Handle new time and
  8210. RECT rcArea;
  8211. GetScrubAreaRect( rcArea );
  8212. CChoreoWidgetDrawHelper drawHelper( this, rcArea, COLOR_CHOREO_BACKGROUND );
  8213. DrawScrubHandle( drawHelper );
  8214. }
  8215. void CChoreoView::SetScrubTime( float t )
  8216. {
  8217. m_flScrub = t;
  8218. m_bPaused = false;
  8219. }
  8220. void CChoreoView::SetScrubTargetTime( float t )
  8221. {
  8222. m_flScrubTarget = t;
  8223. m_bPaused = false;
  8224. }
  8225. void CChoreoView::ClampTimeToSelectionInterval( float& timeval )
  8226. {
  8227. // FIXME hook this up later
  8228. return;
  8229. }
  8230. //-----------------------------------------------------------------------------
  8231. // Purpose:
  8232. // Input : show -
  8233. //-----------------------------------------------------------------------------
  8234. void CChoreoView::ShowButtons( bool show )
  8235. {
  8236. m_btnPlay->setVisible( show );
  8237. m_btnPause->setVisible( show );
  8238. m_btnStop->setVisible( show );
  8239. m_pPlaybackRate->setVisible( show );
  8240. }
  8241. void CChoreoView::RememberSelectedEvents( CUtlVector< CChoreoEvent * >& list )
  8242. {
  8243. GetSelectedEvents( list );
  8244. }
  8245. void CChoreoView::ReselectEvents( CUtlVector< CChoreoEvent * >& list )
  8246. {
  8247. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  8248. {
  8249. CChoreoActorWidget *actor = m_SceneActors[ i ];
  8250. if ( !actor )
  8251. continue;
  8252. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  8253. {
  8254. CChoreoChannelWidget *channel = actor->GetChannel( j );
  8255. if ( !channel )
  8256. continue;
  8257. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  8258. {
  8259. CChoreoEventWidget *event = channel->GetEvent( k );
  8260. if ( !event )
  8261. continue;
  8262. CChoreoEvent *check = event->GetEvent();
  8263. if ( list.Find( check ) != list.InvalidIndex() )
  8264. {
  8265. event->SetSelected( true );
  8266. }
  8267. }
  8268. }
  8269. }
  8270. }
  8271. void CChoreoView::OnChangeScale( void )
  8272. {
  8273. CChoreoScene *scene = m_pScene;
  8274. if ( !scene )
  8275. {
  8276. return;
  8277. }
  8278. // Zoom time in / out
  8279. CInputParams params;
  8280. memset( &params, 0, sizeof( params ) );
  8281. strcpy( params.m_szDialogTitle, "Change Zoom" );
  8282. strcpy( params.m_szPrompt, "New scale (e.g., 2.5x):" );
  8283. Q_snprintf( params.m_szInputText, sizeof( params.m_szInputText ), "%.2f", (float)GetTimeZoom( GetToolName() ) / 100.0f );
  8284. if ( !InputProperties( &params ) )
  8285. return;
  8286. SetTimeZoom( GetToolName(), clamp( (int)( 100.0f * atof( params.m_szInputText ) ), 1, MAX_TIME_ZOOM ), false );
  8287. // Force scroll bars to recompute
  8288. ForceScrollBarsToRecompute( false );
  8289. CUtlVector< CChoreoEvent * > selected;
  8290. RememberSelectedEvents( selected );
  8291. DeleteSceneWidgets();
  8292. CreateSceneWidgets();
  8293. ReselectEvents( selected );
  8294. InvalidateLayout();
  8295. Con_Printf( "Zoom factor %i %%\n", GetTimeZoom( GetToolName() ) );
  8296. }
  8297. void CChoreoView::OnCheckSequenceLengths( void )
  8298. {
  8299. if ( !m_pScene )
  8300. return;
  8301. Con_Printf( "Checking sequence durations...\n" );
  8302. bool changed = FixupSequenceDurations( m_pScene, true );
  8303. if ( !changed )
  8304. {
  8305. Con_Printf( " no changes...\n" );
  8306. return;
  8307. }
  8308. SetDirty( true );
  8309. PushUndo( "Check sequence lengths" );
  8310. FixupSequenceDurations( m_pScene, false );
  8311. PushRedo( "Check sequence lengths" );
  8312. InvalidateLayout();
  8313. }
  8314. //-----------------------------------------------------------------------------
  8315. // Purpose:
  8316. // Input : *scene -
  8317. //-----------------------------------------------------------------------------
  8318. void CChoreoView::InvalidateTrackLookup_R( CChoreoScene *scene )
  8319. {
  8320. // No need to undo since this data doesn't matter
  8321. int c = scene->GetNumEvents();
  8322. for ( int i = 0; i < c; i++ )
  8323. {
  8324. CChoreoEvent *event = scene->GetEvent( i );
  8325. if ( !event )
  8326. continue;
  8327. switch ( event->GetType() )
  8328. {
  8329. default:
  8330. break;
  8331. case CChoreoEvent::FLEXANIMATION:
  8332. {
  8333. event->SetTrackLookupSet( false );
  8334. }
  8335. break;
  8336. case CChoreoEvent::SUBSCENE:
  8337. {
  8338. CChoreoScene *sub = event->GetSubScene();
  8339. // NOTE: Don't bother loading it now if it's not on hand
  8340. if ( sub )
  8341. {
  8342. InvalidateTrackLookup_R( sub );
  8343. }
  8344. }
  8345. break;
  8346. }
  8347. }
  8348. }
  8349. //-----------------------------------------------------------------------------
  8350. // Purpose: Model changed so we'll have to re-index flex anim tracks
  8351. //-----------------------------------------------------------------------------
  8352. void CChoreoView::InvalidateTrackLookup( void )
  8353. {
  8354. if ( !m_pScene )
  8355. return;
  8356. InvalidateTrackLookup_R( m_pScene );
  8357. }
  8358. bool CChoreoView::IsRampOnly( void ) const
  8359. {
  8360. return m_bRampOnly;
  8361. }
  8362. //-----------------------------------------------------------------------------
  8363. // Purpose:
  8364. // Input : *scene -
  8365. // *event -
  8366. //-----------------------------------------------------------------------------
  8367. void CChoreoView::ProcessInterrupt( CChoreoScene *scene, CChoreoEvent *event )
  8368. {
  8369. }
  8370. //-----------------------------------------------------------------------------
  8371. // Purpose:
  8372. // Input : *scene -
  8373. // *event -
  8374. //-----------------------------------------------------------------------------
  8375. void CChoreoView::ProcessPermitResponses( CChoreoScene *scene, CChoreoEvent *event )
  8376. {
  8377. }
  8378. void CChoreoView::ApplyBounds( int& mx, int& my )
  8379. {
  8380. if ( !m_bUseBounds )
  8381. return;
  8382. mx = clamp( mx, m_nMinX, m_nMaxX );
  8383. }
  8384. //-----------------------------------------------------------------------------
  8385. // Purpose: Returns -1 if no event found
  8386. // Input : *channel -
  8387. // *e -
  8388. // forward -
  8389. // Output : float
  8390. //-----------------------------------------------------------------------------
  8391. float CChoreoView::FindNextEventTime( CChoreoEvent::EVENTTYPE type, CChoreoChannel *channel, CChoreoEvent *e, bool forward )
  8392. {
  8393. bool foundone = false;
  8394. float bestTime = -1.0f;
  8395. float bestGap = 999999.0f;
  8396. int c = channel->GetNumEvents();
  8397. for ( int i = 0; i < c; i++ )
  8398. {
  8399. CChoreoEvent *test = channel->GetEvent( i );
  8400. if ( test->GetType() != type )
  8401. continue;
  8402. if ( forward )
  8403. {
  8404. float dt = test->GetStartTime() - e->GetEndTime();
  8405. if ( dt <= 0.0f )
  8406. continue;
  8407. if ( dt < bestGap )
  8408. {
  8409. foundone = true;
  8410. bestGap = dt;
  8411. bestTime = test->GetStartTime();
  8412. }
  8413. }
  8414. else
  8415. {
  8416. float dt = e->GetStartTime() - test->GetEndTime();
  8417. if ( dt <= 0.0f )
  8418. continue;
  8419. if ( dt < bestGap )
  8420. {
  8421. foundone = true;
  8422. bestGap = dt;
  8423. bestTime = test->GetEndTime();
  8424. }
  8425. }
  8426. }
  8427. return bestTime;
  8428. }
  8429. void CChoreoView::CalcBounds( int movetype )
  8430. {
  8431. m_bUseBounds = false;
  8432. m_nMinX = 0;
  8433. m_nMaxX = 0;
  8434. if ( !m_pClickedEvent )
  8435. return;
  8436. switch ( movetype )
  8437. {
  8438. default:
  8439. break;
  8440. case DRAGTYPE_EVENT_MOVE:
  8441. case DRAGTYPE_EVENT_STARTTIME:
  8442. case DRAGTYPE_EVENT_ENDTIME:
  8443. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  8444. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  8445. {
  8446. m_nMinX = GetPixelForTimeValue( 0 );
  8447. m_nMaxX = GetPixelForTimeValue( m_pScene->FindStopTime() );
  8448. CChoreoEvent *e = m_pClickedEvent->GetEvent();
  8449. m_bUseBounds = false; // e && e->GetType() == CChoreoEvent::GESTURE;
  8450. // FIXME: use this for finding adjacent gesture edges (kenb)
  8451. if ( m_bUseBounds )
  8452. {
  8453. CChoreoChannel *channel = e->GetChannel();
  8454. Assert( channel );
  8455. float forwardTime = FindNextEventTime( e->GetType(), channel, e, true );
  8456. float reverseTime = FindNextEventTime( e->GetType(), channel, e, false );
  8457. // Compute pixel for time
  8458. int nextPixel = forwardTime != -1 ? GetPixelForTimeValue( forwardTime ) : m_nMaxX;
  8459. int prevPixel = reverseTime != -1 ? GetPixelForTimeValue( reverseTime ) : m_nMinX;
  8460. int startPixel = GetPixelForTimeValue( e->GetStartTime() );
  8461. int endPixel = GetPixelForTimeValue( e->GetEndTime() );
  8462. switch ( movetype )
  8463. {
  8464. case DRAGTYPE_EVENT_MOVE:
  8465. {
  8466. m_nMinX = prevPixel + ( m_xStart - startPixel ) + 1;
  8467. m_nMaxX = nextPixel - ( endPixel - m_xStart ) - 1;
  8468. }
  8469. break;
  8470. case DRAGTYPE_EVENT_STARTTIME:
  8471. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  8472. {
  8473. m_nMinX = prevPixel + ( m_xStart - startPixel ) + 1;
  8474. }
  8475. break;
  8476. case DRAGTYPE_EVENT_ENDTIME:
  8477. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  8478. {
  8479. m_nMaxX = nextPixel - ( endPixel - m_xStart ) - 1;
  8480. }
  8481. break;
  8482. }
  8483. }
  8484. }
  8485. break;
  8486. }
  8487. }
  8488. bool CChoreoView::ShouldSelectEvent( SelectionParams_t &params, CChoreoEvent *event )
  8489. {
  8490. if ( params.forward )
  8491. {
  8492. if ( event->GetStartTime() >= params.time )
  8493. return true;
  8494. }
  8495. else
  8496. {
  8497. float endtime = event->HasEndTime() ? event->GetEndTime() : event->GetStartTime();
  8498. if ( endtime <= params.time )
  8499. return true;
  8500. }
  8501. return false;
  8502. }
  8503. void CChoreoView::SelectEvents( SelectionParams_t& params )
  8504. {
  8505. if ( !m_pScene )
  8506. return;
  8507. if ( !m_pClickedActor )
  8508. return;
  8509. if ( params.type == SelectionParams_t::SP_CHANNEL && !m_pClickedChannel )
  8510. return;
  8511. //CChoreoActor *actor = m_pClickedActor->GetActor();
  8512. CChoreoChannel *channel = m_pClickedChannel ? m_pClickedChannel->GetChannel() : NULL;
  8513. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  8514. {
  8515. CChoreoActorWidget *a = m_SceneActors[ i ];
  8516. if ( !a )
  8517. continue;
  8518. //if ( a->GetActor() != actor )
  8519. // continue;
  8520. for ( int j = 0; j < a->GetNumChannels(); j++ )
  8521. {
  8522. CChoreoChannelWidget *c = a->GetChannel( j );
  8523. if ( !c )
  8524. continue;
  8525. if ( params.type == SelectionParams_t::SP_CHANNEL &&
  8526. c->GetChannel() != channel )
  8527. continue;
  8528. if ( params.type == SelectionParams_t::SP_ACTIVE &&
  8529. !c->GetChannel()->GetActive() )
  8530. continue;
  8531. for ( int k = 0; k < c->GetNumEvents(); k++ )
  8532. {
  8533. CChoreoEventWidget *e = c->GetEvent( k );
  8534. if ( !e )
  8535. continue;
  8536. CChoreoEvent *event = e->GetEvent();
  8537. if ( !event )
  8538. continue;
  8539. if ( !ShouldSelectEvent( params, event ) )
  8540. continue;
  8541. e->SetSelected( true );
  8542. }
  8543. }
  8544. }
  8545. // Now handle global events, too
  8546. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  8547. {
  8548. CChoreoGlobalEventWidget *e = m_SceneGlobalEvents[ i ];
  8549. if ( !e )
  8550. continue;
  8551. CChoreoEvent *event = e->GetEvent();
  8552. if ( !event )
  8553. continue;
  8554. if ( !ShouldSelectEvent( params, event ) )
  8555. continue;
  8556. e->SetSelected( true );
  8557. }
  8558. redraw();
  8559. }
  8560. void CChoreoView::SetTimeZoom( char const *tool, int tz, bool preserveFocus )
  8561. {
  8562. if ( !m_pScene )
  8563. return;
  8564. // No change
  8565. int oldZoom = GetTimeZoom( tool );
  8566. if ( tz == oldZoom )
  8567. return;
  8568. SetDirty( true );
  8569. POINT pt;
  8570. ::GetCursorPos( &pt );
  8571. ::ScreenToClient( (HWND)getHandle(), &pt );
  8572. // Now figure out time under cursor at old zoom scale
  8573. float t = GetTimeValueForMouse( pt.x, true );
  8574. m_pScene->SetTimeZoom( tool, tz );
  8575. if ( preserveFocus )
  8576. {
  8577. RECT rc;
  8578. GetClientRect( (HWND)getHandle(), &rc );
  8579. RECT rcClient = rc;
  8580. rcClient.top += GetStartRow();
  8581. OffsetRect( &rcClient, 0, -m_nTopOffset );
  8582. m_flStartTime = m_flLeftOffset / GetPixelsPerSecond();
  8583. m_flEndTime = m_flStartTime + (float)( rcClient.right - GetLabelWidth() ) / GetPixelsPerSecond();
  8584. // Now figure out tie under pt.x
  8585. float newT = GetTimeValueForMouse( pt.x, true );
  8586. if ( newT != t )
  8587. {
  8588. // We need to scroll over a bit
  8589. float pps = GetPixelsPerSecond();
  8590. float movePixels = pps * ( newT - t );
  8591. m_flLeftOffset -= movePixels;
  8592. if ( m_flLeftOffset < 0.0f )
  8593. {
  8594. //float fixup = - m_flLeftOffset;
  8595. m_flLeftOffset = 0;
  8596. }
  8597. // float maxtime = m_pScene->FindStopTime();
  8598. float flApparentEndTime = max( m_pScene->FindStopTime(), 5.0f ) + 5.0f;
  8599. if ( m_flEndTime > flApparentEndTime )
  8600. {
  8601. movePixels = pps * ( m_flEndTime - flApparentEndTime );
  8602. m_flLeftOffset = max( 0.0f, m_flLeftOffset - movePixels );
  8603. }
  8604. }
  8605. }
  8606. // Deal with the slider
  8607. RepositionHSlider();
  8608. redraw();
  8609. }
  8610. int CChoreoView::GetTimeZoom( char const *tool )
  8611. {
  8612. if ( !m_pScene )
  8613. return 100;
  8614. return m_pScene->GetTimeZoom( tool );
  8615. }
  8616. void CChoreoView::CheckInsertTime( CChoreoEvent *e, float dt, float starttime, float endtime )
  8617. {
  8618. // Not influenced
  8619. float eventend = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime();
  8620. if ( eventend < starttime )
  8621. return;
  8622. if ( e->GetStartTime() > starttime )
  8623. {
  8624. e->OffsetTime( dt );
  8625. e->SnapTimes();
  8626. }
  8627. else if ( !e->IsFixedLength() && e->HasEndTime() ) // the event starts before start, but ends after start time, need to insert space into the event, act like user dragged end time
  8628. {
  8629. float newduration = e->GetDuration() + dt;
  8630. RescaleRamp( e, newduration );
  8631. switch ( e->GetType() )
  8632. {
  8633. default:
  8634. break;
  8635. case CChoreoEvent::GESTURE:
  8636. {
  8637. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() + dt, true );
  8638. }
  8639. break;
  8640. case CChoreoEvent::FLEXANIMATION:
  8641. {
  8642. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() + dt );
  8643. }
  8644. break;
  8645. }
  8646. e->OffsetEndTime( dt );
  8647. e->SnapTimes();
  8648. e->ResortRamp();
  8649. }
  8650. switch ( e->GetType() )
  8651. {
  8652. default:
  8653. break;
  8654. case CChoreoEvent::SPEAK:
  8655. {
  8656. // Try and load wav to get length
  8657. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  8658. if ( wave )
  8659. {
  8660. e->SetEndTime( e->GetStartTime() + wave->GetRunningLength() );
  8661. delete wave;
  8662. }
  8663. }
  8664. break;
  8665. case CChoreoEvent::SEQUENCE:
  8666. {
  8667. CheckSequenceLength( e, false );
  8668. }
  8669. break;
  8670. case CChoreoEvent::GESTURE:
  8671. {
  8672. CheckGestureLength( e, false );
  8673. }
  8674. break;
  8675. }
  8676. }
  8677. void CChoreoView::OnInsertTime()
  8678. {
  8679. if ( !m_rgABPoints[ 0 ].active &&
  8680. !m_rgABPoints[ 1 ].active )
  8681. {
  8682. return;
  8683. }
  8684. Con_Printf( "OnInsertTime()\n" );
  8685. float starttime = m_rgABPoints[ 0 ].time;
  8686. float endtime = m_rgABPoints[ 1 ].time;
  8687. // Sort samples correctly
  8688. if ( starttime > endtime )
  8689. {
  8690. float temp = starttime;
  8691. starttime = endtime;
  8692. endtime = temp;
  8693. }
  8694. float dt = endtime - starttime;
  8695. if ( dt == 0.0f )
  8696. {
  8697. // Nothing to do...
  8698. return;
  8699. }
  8700. SetDirty( true );
  8701. PushUndo( "Insert Time" );
  8702. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  8703. {
  8704. CChoreoActorWidget *actor = m_SceneActors[ i ];
  8705. if ( !actor )
  8706. continue;
  8707. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  8708. {
  8709. CChoreoChannelWidget *channel = actor->GetChannel( j );
  8710. if ( !channel )
  8711. continue;
  8712. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  8713. {
  8714. CChoreoEventWidget *event = channel->GetEvent( k );
  8715. if ( !event )
  8716. continue;
  8717. CChoreoEvent *e = event->GetEvent();
  8718. if ( !e )
  8719. continue;
  8720. CheckInsertTime( e, dt, starttime, endtime );
  8721. }
  8722. }
  8723. }
  8724. // Now handle global events, too
  8725. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  8726. {
  8727. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  8728. if ( !event )
  8729. continue;
  8730. CChoreoEvent *e = event->GetEvent();
  8731. if ( !e )
  8732. continue;
  8733. CheckInsertTime( e, dt, starttime, endtime );
  8734. }
  8735. PushRedo( "Insert Time" );
  8736. InvalidateLayout();
  8737. g_pExpressionTool->LayoutItems( true );
  8738. g_pExpressionTool->redraw();
  8739. g_pGestureTool->redraw();
  8740. g_pRampTool->redraw();
  8741. g_pSceneRampTool->redraw();
  8742. }
  8743. void CChoreoView::CheckDeleteTime( CChoreoEvent *e, float dt, float starttime, float endtime, bool& deleteEvent )
  8744. {
  8745. deleteEvent = false;
  8746. // Not influenced
  8747. float eventend = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime();
  8748. if ( eventend < starttime )
  8749. {
  8750. return;
  8751. }
  8752. // On right side of start mark, just shift left
  8753. if ( e->GetStartTime() > starttime )
  8754. {
  8755. // If it has no duration and it's in the bounds then kill it.
  8756. if ( !e->HasEndTime() && e->GetStartTime() < endtime )
  8757. {
  8758. deleteEvent = true;
  8759. return;
  8760. }
  8761. else
  8762. {
  8763. float shift = e->GetStartTime() - starttime;
  8764. float maxoffset = min( dt, shift );
  8765. e->OffsetTime( -maxoffset );
  8766. e->SnapTimes();
  8767. }
  8768. }
  8769. else if ( !e->IsFixedLength() && e->HasEndTime() ) // the event starts before start, but ends after start time, need to insert space into the event, act like user dragged end time
  8770. {
  8771. float shiftend = e->GetEndTime() - starttime;
  8772. float maxoffset = min( dt, shiftend );
  8773. float newduration = e->GetDuration() - maxoffset;
  8774. if ( newduration <= 0.0f )
  8775. {
  8776. deleteEvent = true;
  8777. return;
  8778. }
  8779. else
  8780. {
  8781. RescaleRamp( e, newduration );
  8782. switch ( e->GetType() )
  8783. {
  8784. default:
  8785. break;
  8786. case CChoreoEvent::GESTURE:
  8787. {
  8788. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() - maxoffset, true );
  8789. }
  8790. break;
  8791. case CChoreoEvent::FLEXANIMATION:
  8792. {
  8793. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() - maxoffset );
  8794. }
  8795. break;
  8796. }
  8797. e->OffsetEndTime( -maxoffset );
  8798. e->SnapTimes();
  8799. e->ResortRamp();
  8800. }
  8801. }
  8802. switch ( e->GetType() )
  8803. {
  8804. default:
  8805. break;
  8806. case CChoreoEvent::SPEAK:
  8807. {
  8808. // Try and load wav to get length
  8809. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  8810. if ( wave )
  8811. {
  8812. e->SetEndTime( e->GetStartTime() + wave->GetRunningLength() );
  8813. delete wave;
  8814. }
  8815. }
  8816. break;
  8817. case CChoreoEvent::SEQUENCE:
  8818. {
  8819. CheckSequenceLength( e, false );
  8820. }
  8821. break;
  8822. case CChoreoEvent::GESTURE:
  8823. {
  8824. CheckGestureLength( e, false );
  8825. }
  8826. break;
  8827. }
  8828. }
  8829. void CChoreoView::OnDeleteTime()
  8830. {
  8831. if ( !m_rgABPoints[ 0 ].active &&
  8832. !m_rgABPoints[ 1 ].active )
  8833. {
  8834. return;
  8835. }
  8836. Con_Printf( "OnDeleteTime()\n" );
  8837. float starttime = m_rgABPoints[ 0 ].time;
  8838. float endtime = m_rgABPoints[ 1 ].time;
  8839. // Sort samples correctly
  8840. if ( starttime > endtime )
  8841. {
  8842. float temp = starttime;
  8843. starttime = endtime;
  8844. endtime = temp;
  8845. }
  8846. float dt = endtime - starttime;
  8847. if ( dt == 0.0f )
  8848. {
  8849. // Nothing to do...
  8850. return;
  8851. }
  8852. SetDirty( true );
  8853. PushUndo( "Delete Time" );
  8854. CUtlVector< CChoreoEventWidget * > deletions;
  8855. CUtlVector< CChoreoGlobalEventWidget * > global_deletions;
  8856. for ( int i = 0; i < m_SceneActors.Size(); i++ )
  8857. {
  8858. CChoreoActorWidget *actor = m_SceneActors[ i ];
  8859. if ( !actor )
  8860. continue;
  8861. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  8862. {
  8863. CChoreoChannelWidget *channel = actor->GetChannel( j );
  8864. if ( !channel )
  8865. continue;
  8866. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  8867. {
  8868. CChoreoEventWidget *event = channel->GetEvent( k );
  8869. if ( !event )
  8870. continue;
  8871. CChoreoEvent *e = event->GetEvent();
  8872. if ( !e )
  8873. continue;
  8874. bool deleteEvent = false;
  8875. CheckDeleteTime( e, dt, starttime, endtime, deleteEvent );
  8876. if ( deleteEvent )
  8877. {
  8878. deletions.AddToTail( event );
  8879. }
  8880. }
  8881. }
  8882. }
  8883. // Now handle global events, too
  8884. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  8885. {
  8886. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  8887. if ( !event )
  8888. continue;
  8889. CChoreoEvent *e = event->GetEvent();
  8890. if ( !e )
  8891. continue;
  8892. bool deleteEvent = false;
  8893. CheckDeleteTime( e, dt, starttime, endtime, deleteEvent );
  8894. if ( deleteEvent )
  8895. {
  8896. global_deletions.AddToTail( event );
  8897. }
  8898. }
  8899. for ( int i = 0; i < deletions.Count(); i++ )
  8900. {
  8901. CChoreoEventWidget *w = deletions[ i ];
  8902. CChoreoEvent *e = w->GetEvent();
  8903. CChoreoChannel *channel = e->GetChannel();
  8904. if ( channel )
  8905. {
  8906. channel->RemoveEvent( e );
  8907. }
  8908. m_pScene->DeleteReferencedObjects( e );
  8909. }
  8910. for ( int i = 0; i < global_deletions.Count(); i++ )
  8911. {
  8912. CChoreoGlobalEventWidget *w = global_deletions[ i ];
  8913. CChoreoEvent *e = w->GetEvent();
  8914. m_pScene->DeleteReferencedObjects( e );
  8915. }
  8916. // Force scroll bars to recompute
  8917. ForceScrollBarsToRecompute( false );
  8918. if ( deletions.Count() > 0 || global_deletions.Count() > 0 )
  8919. {
  8920. DeleteSceneWidgets();
  8921. CreateSceneWidgets();
  8922. }
  8923. PushRedo( "Delete Time" );
  8924. InvalidateLayout();
  8925. g_pExpressionTool->LayoutItems( true );
  8926. g_pExpressionTool->redraw();
  8927. g_pGestureTool->redraw();
  8928. g_pRampTool->redraw();
  8929. g_pSceneRampTool->redraw();
  8930. }
  8931. void CChoreoView::OnModelChanged()
  8932. {
  8933. InvalidateTrackLookup();
  8934. // OnCheckSequenceLengths();
  8935. }
  8936. void CChoreoView::SetShowCloseCaptionData( bool show )
  8937. {
  8938. m_bShowCloseCaptionData = show;
  8939. }
  8940. bool CChoreoView::GetShowCloseCaptionData( void ) const
  8941. {
  8942. return m_bShowCloseCaptionData;
  8943. }
  8944. void CChoreoView::OnToggleCloseCaptionTags()
  8945. {
  8946. m_bShowCloseCaptionData = !m_bShowCloseCaptionData;
  8947. InvalidateLayout();
  8948. }
  8949. static bool EventStartTimeLessFunc( CChoreoEvent * const &p1, CChoreoEvent * const &p2 )
  8950. {
  8951. CChoreoEvent *w1;
  8952. CChoreoEvent *w2;
  8953. w1 = const_cast< CChoreoEvent * >( p1 );
  8954. w2 = const_cast< CChoreoEvent * >( p2 );
  8955. return w1->GetStartTime() < w2->GetStartTime();
  8956. }
  8957. bool CChoreoView::GenerateCombinedFile( char const *outfilename, char const *cctoken, gender_t gender, CUtlRBTree< CChoreoEvent * >& sorted )
  8958. {
  8959. CUtlVector< CombinerEntry > work;
  8960. char actualfile[ 512 ];
  8961. soundemitter->GenderExpandString( gender, outfilename, actualfile, sizeof( actualfile ) );
  8962. if ( Q_strlen( actualfile ) <= 0 )
  8963. {
  8964. return false;
  8965. }
  8966. int i = sorted.FirstInorder();
  8967. if ( i != sorted.InvalidIndex() )
  8968. {
  8969. CChoreoEvent *e = sorted[ i ];
  8970. float startoffset = e->GetStartTime();
  8971. do
  8972. {
  8973. e = sorted[ i ];
  8974. float curoffset = e->GetStartTime();
  8975. CombinerEntry ce;
  8976. Q_snprintf( ce.wavefile, sizeof( ce.wavefile ), "sound/%s", FacePoser_TranslateSoundNameGender( e->GetParameters(), gender ) );
  8977. ce.startoffset = curoffset - startoffset;
  8978. work.AddToTail( ce );
  8979. i = sorted.NextInorder( i );
  8980. }
  8981. while ( i != sorted.InvalidIndex() );
  8982. }
  8983. bool ok = soundcombiner->CombineSoundFiles( filesystem, actualfile, work );
  8984. if ( !ok )
  8985. {
  8986. Con_ErrorPrintf( "Failed to create combined sound '%s':'%s'\n", cctoken, actualfile );
  8987. return false;
  8988. }
  8989. Con_Printf( "Created combined sound '%s':'%s'\n", cctoken, actualfile );
  8990. return true;
  8991. }
  8992. bool CChoreoView::ValidateCombinedFileCheckSum( char const *outfilename, char const *cctoken, gender_t gender, CUtlRBTree< CChoreoEvent * >& sorted )
  8993. {
  8994. CUtlVector< CombinerEntry > work;
  8995. char actualfile[ 512 ];
  8996. soundemitter->GenderExpandString( gender, outfilename, actualfile, sizeof( actualfile ) );
  8997. if ( Q_strlen( actualfile ) <= 0 )
  8998. {
  8999. return false;
  9000. }
  9001. int i = sorted.FirstInorder();
  9002. if ( i != sorted.InvalidIndex() )
  9003. {
  9004. CChoreoEvent *e = sorted[ i ];
  9005. float startoffset = e->GetStartTime();
  9006. do
  9007. {
  9008. e = sorted[ i ];
  9009. float curoffset = e->GetStartTime();
  9010. CombinerEntry ce;
  9011. Q_snprintf( ce.wavefile, sizeof( ce.wavefile ), "sound/%s", FacePoser_TranslateSoundNameGender( e->GetParameters(), gender ) );
  9012. ce.startoffset = curoffset - startoffset;
  9013. work.AddToTail( ce );
  9014. i = sorted.NextInorder( i );
  9015. }
  9016. while ( i != sorted.InvalidIndex() );
  9017. }
  9018. return soundcombiner->IsCombinedFileChecksumValid( filesystem, actualfile, work );
  9019. }
  9020. void SuggestCaption( char *dest, int destlen, CUtlVector< CChoreoEvent * >& events )
  9021. {
  9022. // Walk through events and concatenate current captions, or raw wav data if have any
  9023. dest[ 0 ] = 0;
  9024. int c = events.Count();
  9025. for ( int i = 0 ; i < c; ++i )
  9026. {
  9027. CChoreoEvent *e = events[ i ];
  9028. bool found = false;
  9029. char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  9030. if ( e->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
  9031. {
  9032. wchar_t *localized = g_pLocalize->Find( tok );
  9033. if ( localized )
  9034. {
  9035. found = true;
  9036. char ansi[ 1024 ];
  9037. g_pLocalize->ConvertUnicodeToANSI( localized, ansi, sizeof( ansi ) );
  9038. Q_strncat( dest, ansi, destlen, COPY_ALL_CHARACTERS );
  9039. }
  9040. }
  9041. if ( !found )
  9042. {
  9043. // See if the wav file has data...
  9044. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  9045. if ( wave )
  9046. {
  9047. CSentence *sentence = wave->GetSentence();
  9048. if ( sentence )
  9049. {
  9050. Q_strncat( dest, sentence->GetText(), destlen, COPY_ALL_CHARACTERS );
  9051. found = true;
  9052. }
  9053. }
  9054. }
  9055. if ( found && Q_strlen( dest ) > 0 && i != c - 1 )
  9056. {
  9057. Q_strncat( dest, " ", destlen, COPY_ALL_CHARACTERS );
  9058. }
  9059. }
  9060. }
  9061. void CChoreoView::OnCombineSpeakEvents()
  9062. {
  9063. if ( !m_pScene )
  9064. return;
  9065. CChoreoChannel *firstChannel = NULL;
  9066. CUtlVector< CChoreoEvent * > selected;
  9067. GetSelectedEvents( selected );
  9068. int c = selected.Count();
  9069. // Find the appropriate event by iterating across all actors and channels
  9070. for ( int i = c - 1; i >= 0; --i )
  9071. {
  9072. CChoreoEvent *e = selected[ i ];
  9073. if ( e->GetType() != CChoreoEvent::SPEAK )
  9074. {
  9075. Con_ErrorPrintf( "Can't combine events, all events must be SPEAK events.\n" );
  9076. return;
  9077. }
  9078. if ( !firstChannel )
  9079. {
  9080. firstChannel = e->GetChannel();
  9081. }
  9082. else if ( e->GetChannel() != firstChannel )
  9083. {
  9084. Con_ErrorPrintf( "Can't combine events, all events must reside in the same channel.\n" );
  9085. return;
  9086. }
  9087. }
  9088. if ( selected.Count() < 2 )
  9089. {
  9090. Con_ErrorPrintf( "Can't combine events, must have at least two events selected.\n" );
  9091. return;
  9092. }
  9093. // Let the user pick a CC phrase
  9094. CCloseCaptionLookupParams params;
  9095. Q_strncpy( params.m_szDialogTitle, "Choose Close Caption Token", sizeof( params.m_szDialogTitle ) );
  9096. params.m_bPositionDialog = false;
  9097. params.m_nLeft = 0;
  9098. params.m_nTop = 0;
  9099. char playbacktoken[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  9100. if ( !selected[0]->GetPlaybackCloseCaptionToken( playbacktoken, sizeof( playbacktoken ) ) )
  9101. {
  9102. return;
  9103. }
  9104. if ( !Q_stristr( playbacktoken, "_cc" ) )
  9105. {
  9106. Q_strncpy( params.m_szCCToken, va( "%s_cc", playbacktoken ), sizeof( params.m_szCCToken ) );
  9107. }
  9108. else
  9109. {
  9110. Q_strncpy( params.m_szCCToken, va( "%s", playbacktoken ), sizeof( params.m_szCCToken ) );
  9111. }
  9112. // User hit okay and value actually changed?
  9113. if ( !CloseCaptionLookup( &params ) &&
  9114. params.m_szCCToken[0] != 0 )
  9115. {
  9116. return;
  9117. }
  9118. // See if the token exists?
  9119. StringIndex_t stringIndex = g_pLocalize->FindIndex( params.m_szCCToken );
  9120. if ( INVALID_LOCALIZE_STRING_INDEX == stringIndex )
  9121. {
  9122. // Add token to closecaption_english file.
  9123. // Guess at string and ask user to confirm.
  9124. CInputParams ip;
  9125. memset( &ip, 0, sizeof( ip ) );
  9126. Q_strncpy( ip.m_szDialogTitle, "Add Close Caption", sizeof( ip.m_szDialogTitle ) );
  9127. Q_snprintf( ip.m_szPrompt, sizeof( ip.m_szPrompt ), "Token (%s):", params.m_szCCToken );
  9128. char suggested[ 2048 ];
  9129. SuggestCaption( suggested, sizeof( suggested ), selected );
  9130. Q_snprintf( ip.m_szInputText, sizeof( ip.m_szInputText ), "%s", suggested );
  9131. if ( !InputProperties( &ip ) )
  9132. {
  9133. Con_Printf( "Combining of sound events cancelled\n" );
  9134. return;
  9135. }
  9136. if ( Q_strlen( ip.m_szInputText ) == 0 )
  9137. {
  9138. Q_snprintf( ip.m_szInputText, sizeof( ip.m_szInputText ), "!!!%s", params.m_szCCToken );
  9139. }
  9140. char const *captionFile = "resource/closecaption_english.txt";
  9141. if ( !filesystem->IsFileWritable( captionFile, "GAME" ) )
  9142. {
  9143. Warning( "Forcing %s to be writable!!!\n", captionFile );
  9144. MakeFileWriteable( captionFile );
  9145. }
  9146. wchar_t unicode[ 2048 ];
  9147. g_pLocalize->ConvertANSIToUnicode( ip.m_szInputText, unicode, sizeof( unicode ) );
  9148. g_pLocalize->AddString( params.m_szCCToken, unicode, captionFile );
  9149. g_pLocalize->SaveToFile( captionFile );
  9150. }
  9151. SetDirty( true );
  9152. PushUndo( "Combine Sound Events" );
  9153. c = selected.Count();
  9154. for ( int i = 0 ; i < c; ++i )
  9155. {
  9156. selected[ i ]->SetCloseCaptionToken( params.m_szCCToken );
  9157. }
  9158. PushRedo( "Combine Sound Events" );
  9159. // Redraw
  9160. InvalidateLayout();
  9161. Con_Printf( "Changed %i events to use close caption token '%s'\n", c, params.m_szCCToken );
  9162. // Sort the sounds by start time
  9163. CUtlRBTree< CChoreoEvent * > sorted( 0, 0, EventStartTimeLessFunc );
  9164. // Sort items
  9165. c = selected.Count();
  9166. bool genderwildcard = false;
  9167. for ( int i = 0; i < c; i++ )
  9168. {
  9169. CChoreoEvent *e = selected[ i ];
  9170. sorted.Insert( e );
  9171. // Get the sound entry name and use it to look up the gender info
  9172. // Look up the sound level from the soundemitter system
  9173. if ( !genderwildcard )
  9174. {
  9175. genderwildcard = soundemitter->IsUsingGenderToken( e->GetParameters() );
  9176. }
  9177. }
  9178. char outfilename[ 512 ];
  9179. Q_memset( outfilename, 0, sizeof( outfilename ) );
  9180. CChoreoEvent *e = sorted[ sorted.FirstInorder() ];
  9181. // Update whether we use the $gender token
  9182. e->SetCombinedUsingGenderToken( genderwildcard );
  9183. if ( !e->ComputeCombinedBaseFileName( outfilename, sizeof( outfilename ), genderwildcard ) )
  9184. {
  9185. Con_ErrorPrintf( "Unable to regenerate wav file name for combined sound\n" );
  9186. return;
  9187. }
  9188. int soundindex = soundemitter->GetSoundIndex( e->GetParameters() );
  9189. char const *scriptfile = soundemitter->GetSourceFileForSound( soundindex );
  9190. if ( !scriptfile || !scriptfile[0] )
  9191. {
  9192. Con_ErrorPrintf( "Unable to find existing script to use for new combined sound entry.\n" );
  9193. return;
  9194. }
  9195. // Create a new sound entry for this sound
  9196. CAddSoundParams asp;
  9197. Q_memset( &asp, 0, sizeof( asp ) );
  9198. Q_strncpy( asp.m_szDialogTitle, "Add Combined Sound Entry", sizeof( asp.m_szDialogTitle ) );
  9199. Q_strncpy( asp.m_szWaveFile, outfilename + Q_strlen( "sound/"), sizeof( asp.m_szWaveFile ) );
  9200. Q_strncpy( asp.m_szScriptName, scriptfile, sizeof( asp.m_szScriptName ) );
  9201. Q_strncpy( asp.m_szSoundName, params.m_szCCToken, sizeof( asp.m_szSoundName ) );
  9202. asp.m_bAllowExistingSound = true;
  9203. asp.m_bReadOnlySoundName = true;
  9204. if ( !AddSound( &asp, (HWND)g_MDLViewer->getHandle() ) )
  9205. {
  9206. return;
  9207. }
  9208. if ( genderwildcard )
  9209. {
  9210. GenerateCombinedFile( outfilename, params.m_szCCToken, GENDER_MALE, sorted );
  9211. GenerateCombinedFile( outfilename, params.m_szCCToken, GENDER_FEMALE, sorted );
  9212. }
  9213. else
  9214. {
  9215. GenerateCombinedFile( outfilename, params.m_szCCToken, GENDER_NONE, sorted );
  9216. }
  9217. }
  9218. bool CChoreoView::ValidateCombinedSoundCheckSum( CChoreoEvent *e )
  9219. {
  9220. if ( !e || e->GetType() != CChoreoEvent::SPEAK )
  9221. return false;
  9222. bool genderwildcard = e->IsCombinedUsingGenderToken();
  9223. char outfilename[ 512 ];
  9224. Q_memset( outfilename, 0, sizeof( outfilename ) );
  9225. if ( !e->ComputeCombinedBaseFileName( outfilename, sizeof( outfilename ), genderwildcard ) )
  9226. {
  9227. Con_ErrorPrintf( "Unable to regenerate wav file name for combined sound (%s)\n", e->GetCloseCaptionToken() );
  9228. return false;
  9229. }
  9230. bool checksumvalid = false;
  9231. CUtlRBTree< CChoreoEvent * > eventList( 0, 0, EventStartTimeLessFunc );
  9232. if ( !e->GetChannel()->GetSortedCombinedEventList( e->GetCloseCaptionToken(), eventList ) )
  9233. {
  9234. Con_ErrorPrintf( "Unable to generated combined event list (%s)\n", e->GetCloseCaptionToken() );
  9235. return false;
  9236. }
  9237. if ( genderwildcard )
  9238. {
  9239. checksumvalid = ValidateCombinedFileCheckSum( outfilename, e->GetCloseCaptionToken(), GENDER_MALE, eventList );
  9240. checksumvalid &= ValidateCombinedFileCheckSum( outfilename, e->GetCloseCaptionToken(), GENDER_FEMALE, eventList );
  9241. }
  9242. else
  9243. {
  9244. checksumvalid = ValidateCombinedFileCheckSum( outfilename, e->GetCloseCaptionToken(), GENDER_NONE, eventList );
  9245. }
  9246. return checksumvalid;
  9247. }
  9248. void CChoreoView::OnRemoveSpeakEventFromGroup()
  9249. {
  9250. if ( !m_pScene )
  9251. return;
  9252. int i, c;
  9253. CUtlVector< CChoreoEvent * > selected;
  9254. CUtlVector< CChoreoEvent * > processlist;
  9255. if ( GetSelectedEvents( selected ) > 0 )
  9256. {
  9257. int c = selected.Count();
  9258. // Find the appropriate event by iterating across all actors and channels
  9259. for ( i = c - 1; i >= 0; --i )
  9260. {
  9261. CChoreoEvent *e = selected[ i ];
  9262. if ( e->GetType() != CChoreoEvent::SPEAK )
  9263. {
  9264. selected.Remove( i );
  9265. continue;
  9266. }
  9267. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED )
  9268. {
  9269. selected.Remove( i );
  9270. continue;
  9271. }
  9272. m_pClickedChannel->GetMasterAndSlaves( e, processlist );
  9273. }
  9274. }
  9275. else
  9276. {
  9277. m_pClickedChannel->GetMasterAndSlaves( m_pClickedChannel->GetCaptionClickedEvent(), processlist );
  9278. }
  9279. if ( selected.Count() < 1 )
  9280. {
  9281. Con_ErrorPrintf( "No eligible SPEAK event selected.\n" );
  9282. return;
  9283. }
  9284. SetDirty( true );
  9285. PushUndo( "Remove speak event(s)" );
  9286. c = processlist.Count();
  9287. for ( i = 0 ; i < c; ++i )
  9288. {
  9289. processlist[ i ]->SetCloseCaptionToken( "" );
  9290. processlist[ i ]->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
  9291. processlist[ i ]->SetUsingCombinedFile( false );
  9292. processlist[ i ]->SetRequiredCombinedChecksum( 0 );
  9293. processlist[ i ]->SetNumSlaves( 0 );
  9294. processlist[ i ]->SetLastSlaveEndTime( 0.0f );
  9295. }
  9296. PushRedo( "Remove speak event(s)" );
  9297. // Redraw
  9298. InvalidateLayout();
  9299. Con_Printf( "Reverted %i events to use default close caption token\n", c );
  9300. }
  9301. bool CChoreoView::AreSelectedEventsCombinable()
  9302. {
  9303. CUtlVector< CChoreoEvent * > events;
  9304. if ( GetSelectedEvents( events ) <= 0 )
  9305. return false;
  9306. CChoreoChannel *firstChannel = NULL;
  9307. CUtlVector< CChoreoEvent * > selected;
  9308. GetSelectedEvents( selected );
  9309. int c = selected.Count();
  9310. // Find the appropriate event by iterating across all actors and channels
  9311. for ( int i = c - 1; i >= 0; --i )
  9312. {
  9313. CChoreoEvent *e = selected[ i ];
  9314. if ( e->GetType() != CChoreoEvent::SPEAK )
  9315. {
  9316. return false;
  9317. }
  9318. if ( !firstChannel )
  9319. {
  9320. firstChannel = e->GetChannel();
  9321. }
  9322. else if ( e->GetChannel() != firstChannel )
  9323. {
  9324. return false;
  9325. }
  9326. }
  9327. return selected.Count() >= 2 ? true : false;
  9328. }
  9329. bool CChoreoView::AreSelectedEventsInSpeakGroup()
  9330. {
  9331. CUtlVector< CChoreoEvent * > selected;
  9332. if ( GetSelectedEvents( selected ) <= 0 )
  9333. {
  9334. if ( m_pClickedChannel )
  9335. {
  9336. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  9337. if ( e && e->GetCloseCaptionType() == CChoreoEvent::CC_MASTER &&
  9338. e->GetNumSlaves() >= 1 )
  9339. {
  9340. return true;
  9341. }
  9342. }
  9343. return false;
  9344. }
  9345. int c = selected.Count();
  9346. // Find the appropriate event by iterating across all actors and channels
  9347. for ( int i = c - 1; i >= 0; --i )
  9348. {
  9349. CChoreoEvent *e = selected[ i ];
  9350. if ( e->GetType() != CChoreoEvent::SPEAK )
  9351. {
  9352. selected.Remove( i );
  9353. continue;
  9354. }
  9355. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED )
  9356. {
  9357. selected.Remove( i );
  9358. continue;
  9359. }
  9360. }
  9361. return selected.Count() >= 1 ? true : false;
  9362. }
  9363. void CChoreoView::OnChangeCloseCaptionToken( CChoreoEvent *e )
  9364. {
  9365. CCloseCaptionLookupParams params;
  9366. Q_strncpy( params.m_szDialogTitle, "Close Caption Token Lookup", sizeof( params.m_szDialogTitle ) );
  9367. params.m_bPositionDialog = false;
  9368. params.m_nLeft = 0;
  9369. params.m_nTop = 0;
  9370. // strcpy( params.m_szPrompt, "Choose model:" );
  9371. Q_strncpy( params.m_szCCToken, e->GetCloseCaptionToken(), sizeof( params.m_szCCToken ) );
  9372. // User hit okay and value actually changed?
  9373. if ( CloseCaptionLookup( &params ) &&
  9374. Q_stricmp( e->GetCloseCaptionToken(), params.m_szCCToken ) )
  9375. {
  9376. char oldToken[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  9377. Q_strncpy( oldToken, e->GetCloseCaptionToken(), sizeof( oldToken ) );
  9378. CUtlVector< CChoreoEvent * > events;
  9379. m_pClickedChannel->GetMasterAndSlaves( e, events );
  9380. if ( events.Count() < 2 )
  9381. {
  9382. Con_ErrorPrintf( "Can't combine events, must have at least two events selected.\n" );
  9383. }
  9384. SetDirty( true );
  9385. PushUndo( "Change closecaption token" );
  9386. // Make the change...
  9387. int c = events.Count();
  9388. for ( int i = 0 ; i < c; ++i )
  9389. {
  9390. events[i]->SetCloseCaptionToken( params.m_szCCToken );
  9391. }
  9392. PushRedo( "Change closecaption token" );
  9393. InvalidateLayout();
  9394. Con_Printf( "Close Caption token for '%s' changed to '%s'\n", e->GetName(), params.m_szCCToken );
  9395. }
  9396. }
  9397. void CChoreoView::OnToggleCloseCaptionsForEvent()
  9398. {
  9399. if ( !m_pClickedChannel )
  9400. {
  9401. return;
  9402. }
  9403. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  9404. if ( !e )
  9405. {
  9406. return;
  9407. }
  9408. CChoreoEvent::CLOSECAPTION newType = CChoreoEvent::CC_MASTER;
  9409. // Can't mess with slave
  9410. switch ( e->GetCloseCaptionType() )
  9411. {
  9412. default:
  9413. case CChoreoEvent::CC_SLAVE:
  9414. return;
  9415. case CChoreoEvent::CC_MASTER:
  9416. newType = CChoreoEvent::CC_DISABLED;
  9417. break;
  9418. case CChoreoEvent::CC_DISABLED:
  9419. newType = CChoreoEvent::CC_MASTER;
  9420. break;
  9421. }
  9422. SetDirty( true );
  9423. PushUndo( "Enable/disable captions" );
  9424. // Make the change...
  9425. e->SetCloseCaptionType( newType );
  9426. PushRedo( "Enable/disable captions" );
  9427. InvalidateLayout();
  9428. Con_Printf( "Close Caption type for '%s' changed to '%s'\n", e->GetName(), CChoreoEvent::NameForCCType( newType ) );
  9429. }
  9430. void CChoreoView::StopScene()
  9431. {
  9432. SetScrubTargetTime( m_flScrub );
  9433. FinishSimulation();
  9434. sound->Flush();
  9435. }
  9436. //-----------------------------------------------------------------------------
  9437. // Purpose:
  9438. // Input : -
  9439. //-----------------------------------------------------------------------------
  9440. template <class T>
  9441. void DeleteAllAndPurge( T &tree )
  9442. {
  9443. T::IndexType_t i;
  9444. for ( i = tree.FirstInorder(); i != T::InvalidIndex(); i = tree.NextInorder( i ) )
  9445. {
  9446. delete tree[i];
  9447. }
  9448. tree.Purge();
  9449. }
  9450. void CChoreoView::OnPlaceNextSpeakEvent()
  9451. {
  9452. CUtlVector< CChoreoEvent * > list;
  9453. GetSelectedEvents( list );
  9454. if ( list.Count() != 1 )
  9455. {
  9456. Warning( "Can't place sound event, nothing selected\n" );
  9457. return;
  9458. }
  9459. CChoreoEvent *ev = list[ 0 ];
  9460. if ( ev->GetType() != CChoreoEvent::SPEAK )
  9461. {
  9462. Warning( "Can't place sound event, no previous sound event selected\n" );
  9463. return;
  9464. }
  9465. CChoreoChannelWidget *widget = FindChannelForEvent( ev );
  9466. if ( !widget )
  9467. {
  9468. Warning( "Can't place sound event, can't find channel widget for event\n" );
  9469. return;
  9470. }
  9471. CChoreoChannel *channel = widget->GetChannel();
  9472. if ( !channel )
  9473. {
  9474. Warning( "Can't place sound event, can't find channel for new event\n" );
  9475. return;
  9476. }
  9477. CUtlRBTree< char const *, int > m_SortedNames( 0, 0, NameLessFunc );
  9478. int c = soundemitter->GetSoundCount();
  9479. for ( int i = 0; i < c; i++ )
  9480. {
  9481. char const *name = soundemitter->GetSoundName( i );
  9482. if ( name && name[ 0 ] )
  9483. {
  9484. m_SortedNames.Insert( strdup( name ) );
  9485. }
  9486. }
  9487. int idx = m_SortedNames.Find( ev->GetParameters() );
  9488. if ( idx == m_SortedNames.InvalidIndex() )
  9489. {
  9490. Warning( "Can't place sound event, can't find '%s' in sound list\n", ev->GetParameters() );
  9491. DeleteAllAndPurge( m_SortedNames );
  9492. return;
  9493. }
  9494. int nextIdx = m_SortedNames.NextInorder( idx );
  9495. if ( nextIdx == m_SortedNames.InvalidIndex() )
  9496. {
  9497. Warning( "Can't place sound event, can't next sound after '%s' in sound list\n", ev->GetParameters() );
  9498. DeleteAllAndPurge( m_SortedNames );
  9499. return;
  9500. }
  9501. DeselectAll();
  9502. SetDirty( true );
  9503. PushUndo( "Place Next Speak Event" );
  9504. CChoreoEvent *event = m_pScene->AllocEvent();
  9505. Assert( event );
  9506. if ( event )
  9507. {
  9508. // Copy everything for source event
  9509. *event = *ev;
  9510. event->SetParameters( m_SortedNames[ nextIdx ] );
  9511. // Start it at the end time...
  9512. event->SetStartTime( event->GetEndTime() );
  9513. event->SetResumeCondition( false );
  9514. event->ClearAllRelativeTags();
  9515. event->ClearAllTimingTags();
  9516. event->ClearAllAbsoluteTags( CChoreoEvent::PLAYBACK );
  9517. event->ClearAllAbsoluteTags( CChoreoEvent::ORIGINAL );
  9518. event->SetChannel( channel );
  9519. event->SetActor( channel->GetActor() );
  9520. // Try and load wav to get length
  9521. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  9522. if ( wave )
  9523. {
  9524. event->SetEndTime( event->GetStartTime() + wave->GetRunningLength() );
  9525. delete wave;
  9526. }
  9527. DeleteSceneWidgets();
  9528. // Add to appropriate channel
  9529. channel->AddEvent( event );
  9530. CreateSceneWidgets();
  9531. CChoreoEventWidget *eventWidget = FindWidgetForEvent( event );
  9532. if ( eventWidget )
  9533. {
  9534. eventWidget->SetSelected( true );
  9535. }
  9536. // Redraw
  9537. InvalidateLayout();
  9538. }
  9539. PushRedo( "Place Next Speak Event" );
  9540. DeleteAllAndPurge( m_SortedNames );
  9541. }
  9542. enum
  9543. {
  9544. FM_LEFT = 0,
  9545. FM_RIGHT,
  9546. FM_SMALLESTWIDE,
  9547. FM_LARGESTWIDE
  9548. };
  9549. static int FindMetric( int type, CUtlVector< CChoreoEvent * > &list, float& value )
  9550. {
  9551. float bestVal = 999999.0f;
  9552. int bestIndex = -1;
  9553. bool greater = true;
  9554. switch ( type )
  9555. {
  9556. default:
  9557. case FM_LEFT:
  9558. case FM_SMALLESTWIDE:
  9559. greater = false;
  9560. break;
  9561. case FM_RIGHT:
  9562. case FM_LARGESTWIDE:
  9563. bestVal = -bestVal;
  9564. greater = true;
  9565. break;
  9566. }
  9567. int c = list.Count();
  9568. for ( int i = 0; i < c; ++i )
  9569. {
  9570. CChoreoEvent *e = list[ i ];
  9571. if ( type != FM_LEFT &&
  9572. !e->HasEndTime() )
  9573. continue;
  9574. float val;
  9575. switch ( type )
  9576. {
  9577. default:
  9578. case FM_LEFT:
  9579. val = e->GetStartTime();
  9580. break;
  9581. case FM_RIGHT:
  9582. val = e->GetEndTime();
  9583. break;
  9584. case FM_SMALLESTWIDE:
  9585. case FM_LARGESTWIDE:
  9586. val = e->GetDuration();
  9587. break;
  9588. }
  9589. if ( greater )
  9590. {
  9591. if ( val <= bestVal )
  9592. continue;
  9593. }
  9594. else
  9595. {
  9596. if ( val >= bestVal )
  9597. continue;
  9598. }
  9599. bestVal = val;
  9600. bestIndex = i;
  9601. }
  9602. value = bestVal;
  9603. return bestIndex;
  9604. }
  9605. void CChoreoView::OnAlign( bool left )
  9606. {
  9607. CUtlVector< CChoreoEvent * > list;
  9608. GetSelectedEvents( list );
  9609. if ( left )
  9610. {
  9611. for ( int i = 0; i < m_SceneGlobalEvents.Size(); i++ )
  9612. {
  9613. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  9614. if ( !event || !event->IsSelected() )
  9615. continue;
  9616. list.AddToTail( event->GetEvent() );
  9617. }
  9618. }
  9619. int numSel = list.Count();
  9620. if ( numSel < 2 )
  9621. {
  9622. Warning( "Can't align, must have at least two events selected\n" );
  9623. return;
  9624. }
  9625. float value;
  9626. int idx = FindMetric( left ? FM_LEFT : FM_RIGHT, list, value );
  9627. if ( idx == -1 )
  9628. {
  9629. return;
  9630. }
  9631. SetDirty( true );
  9632. char undotext[ 128 ];
  9633. Q_snprintf( undotext, sizeof( undotext ), "Align %s", left ? "Left" : "Right" );
  9634. PushUndo( undotext );
  9635. for ( int i = 0; i < numSel; ++i )
  9636. {
  9637. if ( i == idx )
  9638. continue;
  9639. CChoreoEvent *e = list[ i ];
  9640. float newStartTime = left ? value : ( value - e->GetDuration() );
  9641. float offset = newStartTime - e->GetStartTime();
  9642. e->OffsetTime( offset );
  9643. }
  9644. PushRedo( undotext );
  9645. InvalidateLayout();
  9646. }
  9647. void CChoreoView::OnMakeSameSize( bool smallest )
  9648. {
  9649. CUtlVector< CChoreoEvent * > list;
  9650. int numSel = GetSelectedEvents( list );
  9651. if ( numSel < 2 )
  9652. {
  9653. Warning( "Can't align, must have at least two events selected\n" );
  9654. return;
  9655. }
  9656. float value;
  9657. int idx = FindMetric( smallest ? FM_SMALLESTWIDE : FM_LARGESTWIDE, list, value );
  9658. if ( idx == -1 )
  9659. {
  9660. return;
  9661. }
  9662. SetDirty( true );
  9663. char undotext[ 128 ];
  9664. Q_snprintf( undotext, sizeof( undotext ), "Size to %s", smallest ? "Smallest" : "Largest" );
  9665. PushUndo( undotext );
  9666. for ( int i = 0; i < numSel; ++i )
  9667. {
  9668. if ( i == idx )
  9669. continue;
  9670. list[ i ]->SetEndTime( list[ i ]->GetStartTime() + value );
  9671. }
  9672. PushRedo( undotext );
  9673. InvalidateLayout();
  9674. }
  9675. void CChoreoView::SelectAllEventsInActor( CChoreoActorWidget *actor )
  9676. {
  9677. TraverseWidgets( &CChoreoView::SelectInActor, actor );
  9678. redraw();
  9679. }
  9680. void CChoreoView::SelectAllEventsInChannel( CChoreoChannelWidget *channel )
  9681. {
  9682. TraverseWidgets( &CChoreoView::SelectInChannel, channel );
  9683. redraw();
  9684. }
  9685. void CChoreoView::SelectInActor( CChoreoWidget *widget, CChoreoWidget *param1 )
  9686. {
  9687. CChoreoEventWidget *ev = dynamic_cast< CChoreoEventWidget * >( widget );
  9688. if ( !ev )
  9689. return;
  9690. if ( ev->IsSelected() )
  9691. return;
  9692. CChoreoChannel *ch = ev->GetEvent()->GetChannel();
  9693. if ( !ch )
  9694. return;
  9695. CChoreoActor *actor = ch->GetActor();
  9696. if ( !actor )
  9697. return;
  9698. CChoreoActorWidget *actorw = dynamic_cast< CChoreoActorWidget * >( param1 );
  9699. if ( !actorw )
  9700. return;
  9701. if ( actorw->GetActor() != actor )
  9702. return;
  9703. widget->SetSelected( true );
  9704. }
  9705. void CChoreoView::SelectInChannel( CChoreoWidget *widget, CChoreoWidget *param1 )
  9706. {
  9707. CChoreoEventWidget *ev = dynamic_cast< CChoreoEventWidget * >( widget );
  9708. if ( !ev )
  9709. return;
  9710. if ( ev->IsSelected() )
  9711. return;
  9712. CChoreoChannel *ch = ev->GetEvent()->GetChannel();
  9713. if ( !ch )
  9714. return;
  9715. CChoreoChannelWidget *chw = dynamic_cast< CChoreoChannelWidget * >( param1 );
  9716. if ( !chw )
  9717. return;
  9718. if ( chw->GetChannel() != ch )
  9719. return;
  9720. widget->SetSelected( true );
  9721. }