Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

11719 lines
264 KiB

  1. //===== Copyright � 1996-2005, 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. // 10x magnification
  65. #define MAX_TIME_ZOOM 1000
  66. #define TIME_ZOOM_STEP 4
  67. #define PHONEME_FILTER 0.08f
  68. #define PHONEME_DELAY 0.0f
  69. #define SCRUBBER_HEIGHT 15
  70. #define TIMELINE_NUMBERS_HEIGHT 11
  71. #define COPYPASTE_FILENAME "scenes/copydatavcd.txt"
  72. extern double realtime;
  73. extern bool NameLessFunc( const char *const& name1, const char *const& name2 );
  74. // Try to keep shifted times at same absolute time
  75. static void RescaleExpressionTimes( CChoreoEvent *event, float newstart, float newend )
  76. {
  77. if ( !event || event->GetType() != CChoreoEvent::FLEXANIMATION )
  78. return;
  79. // Did it actually change
  80. if ( newstart == event->GetStartTime() &&
  81. newend == event->GetEndTime() )
  82. {
  83. return;
  84. }
  85. float newduration = newend - newstart;
  86. float dt = 0.0f;
  87. //If the end is moving, leave tags stay where they are (dt == 0.0f)
  88. if ( newstart != event->GetStartTime() )
  89. {
  90. // Otherwise, if the new start is later, then tags need to be shifted backwards
  91. dt -= ( newstart - event->GetStartTime() );
  92. }
  93. int count = event->GetNumFlexAnimationTracks();
  94. int i;
  95. for ( i = 0; i < count; i++ )
  96. {
  97. CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
  98. if ( !track )
  99. continue;
  100. for ( int type = 0; type < 2; type++ )
  101. {
  102. int sampleCount = track->GetNumSamples( type );
  103. for ( int sample = sampleCount - 1; sample >= 0 ; sample-- )
  104. {
  105. CExpressionSample *s = track->GetSample( sample, type );
  106. if ( !s )
  107. continue;
  108. s->time += dt;
  109. if ( s->time > newduration || s->time < 0.0f )
  110. {
  111. track->RemoveSample( sample, type );
  112. }
  113. }
  114. }
  115. }
  116. }
  117. static void RescaleRamp( CChoreoEvent *event, float newduration )
  118. {
  119. float oldduration = event->GetDuration();
  120. if ( fabs( oldduration - newduration ) < 0.000001f )
  121. return;
  122. if ( newduration <= 0.0f )
  123. return;
  124. float midpointtime = oldduration * 0.5f;
  125. float newmidpointtime = newduration * 0.5f;
  126. int count = event->GetRampCount();
  127. int i;
  128. for ( i = 0; i < count; i++ )
  129. {
  130. CExpressionSample *sample = event->GetRamp( i );
  131. if ( !sample )
  132. continue;
  133. float t = sample->time;
  134. if ( t < midpointtime )
  135. continue;
  136. float timefromend = oldduration - t;
  137. // There's room to just shift it
  138. if ( timefromend <= newmidpointtime )
  139. {
  140. t = newduration - timefromend;
  141. }
  142. else
  143. {
  144. // No room, rescale them instead
  145. float frac = ( t - midpointtime ) / midpointtime;
  146. t = newmidpointtime + frac * newmidpointtime;
  147. }
  148. sample->time = t;
  149. }
  150. }
  151. bool DoesAnyActorHaveAssociatedModelLoaded( CChoreoScene *scene )
  152. {
  153. if ( !scene )
  154. return false;
  155. int c = scene->GetNumActors();
  156. int i;
  157. for ( i = 0; i < c; i++ )
  158. {
  159. CChoreoActor *a = scene->GetActor( i );
  160. if ( !a )
  161. continue;
  162. char const *modelname = a->GetFacePoserModelName();
  163. if ( !modelname )
  164. continue;
  165. if ( !modelname[ 0 ] )
  166. continue;
  167. char mdlname[ 256 ];
  168. Q_strncpy( mdlname, modelname, sizeof( mdlname ) );
  169. Q_FixSlashes( mdlname );
  170. int idx = models->FindModelByFilename( mdlname );
  171. if ( idx >= 0 )
  172. {
  173. return true;
  174. }
  175. }
  176. return false;
  177. }
  178. //-----------------------------------------------------------------------------
  179. // Purpose:
  180. // Input : *a -
  181. // Output : StudioModel
  182. //-----------------------------------------------------------------------------
  183. StudioModel *FindAssociatedModel( CChoreoScene *scene, CChoreoActor *a )
  184. {
  185. if ( !a || !scene )
  186. return NULL;
  187. Assert( models->GetActiveStudioModel() );
  188. StudioModel *model = NULL;
  189. if ( a->GetFacePoserModelName()[ 0 ] )
  190. {
  191. int idx = models->FindModelByFilename( a->GetFacePoserModelName() );
  192. if ( idx >= 0 )
  193. {
  194. model = models->GetStudioModel( idx );
  195. return model;
  196. }
  197. }
  198. // Is there any loaded model with the actorname in it?
  199. int c = models->Count();
  200. for ( int i = 0; i < c; i++ )
  201. {
  202. char const *modelname = models->GetModelName( i );
  203. if ( !Q_stricmp( modelname, a->GetName() ) )
  204. {
  205. return models->GetStudioModel( i );
  206. }
  207. }
  208. // Does any actor have an associated model which is loaded
  209. if ( DoesAnyActorHaveAssociatedModelLoaded( scene ) )
  210. {
  211. // Then return NULL here so we don't override with the default an actor who has a valid model going
  212. return NULL;
  213. }
  214. // Couldn't find it and nobody else has a loaded associated model, so just use the default model
  215. if ( !model )
  216. {
  217. model = models->GetActiveStudioModel();
  218. }
  219. return model;
  220. }
  221. CChoreoView *g_pChoreoView = 0;
  222. //-----------------------------------------------------------------------------
  223. // Purpose:
  224. // Input : *parent -
  225. // x -
  226. // y -
  227. // w -
  228. // h -
  229. // id -
  230. //-----------------------------------------------------------------------------
  231. CChoreoView::CChoreoView( mxWindow *parent, int x, int y, int w, int h, int id )
  232. : IFacePoserToolWindow( "CChoreoView", "Choreography" ), mxWindow( parent, x, y, w, h )
  233. {
  234. m_bRampOnly = false;
  235. m_bForceProcess = false;
  236. m_bSuppressLayout = true;
  237. SetAutoProcess( true );
  238. m_flLastMouseClickTime = -1.0f;
  239. m_bProcessSequences = true;
  240. m_flPlaybackRate = 1.0f;
  241. m_pScene = NULL;
  242. m_flScrub = 0.0f;
  243. m_flScrubTarget = 0.0f;
  244. m_bCanDraw = false;
  245. m_bRedoPending = false;
  246. m_nUndoLevel = 0;
  247. CChoreoEventWidget::LoadImages();
  248. CChoreoWidget::m_pView = this;
  249. setId( id );
  250. m_flLastSpeedScale = 0.0f;
  251. m_bResetSpeedScale = false;
  252. m_nTopOffset = 0;
  253. m_flLeftOffset = 0.0f;
  254. m_nLastHPixelsNeeded = -1;
  255. m_nLastVPixelsNeeded = -1;
  256. m_nStartRow = 45;
  257. m_nLabelWidth = 140;
  258. m_nRowHeight = 35;
  259. m_bSimulating = false;
  260. m_bPaused = false;
  261. m_bForward = true;
  262. m_flStartTime = 0.0f;
  263. m_flEndTime = 0.0f;
  264. m_flFrameTime = 0.0f;
  265. m_bAutomated = false;
  266. m_nAutomatedAction = SCENE_ACTION_UNKNOWN;
  267. m_flAutomationDelay = 0.0f;
  268. m_flAutomationTime = 0.0f;
  269. m_pVertScrollBar = new mxScrollbar( this, 0, 0, 18, 100, IDC_CHOREOVSCROLL, mxScrollbar::Vertical );
  270. m_pHorzScrollBar = new mxScrollbar( this, 0, 0, 18, 100, IDC_CHOREOHSCROLL, mxScrollbar::Horizontal );
  271. m_bLayoutIsValid = false;
  272. m_flPixelsPerSecond = 150.0f;
  273. m_btnPlay = new mxBitmapButton( this, 2, 4, 16, 16, IDC_PLAYSCENE, "gfx/hlfaceposer/play.bmp" );
  274. m_btnPause = new mxBitmapButton( this, 18, 4, 16, 16, IDC_PAUSESCENE, "gfx/hlfaceposer/pause.bmp" );
  275. m_btnStop = new mxBitmapButton( this, 34, 4, 16, 16, IDC_STOPSCENE, "gfx/hlfaceposer/stop.bmp" );
  276. m_pPlaybackRate = new mxSlider( this, 0, 0, 16, 16, IDC_CHOREO_PLAYBACKRATE );
  277. m_pPlaybackRate->setRange( 0.0, 2.0, 40 );
  278. m_pPlaybackRate->setValue( m_flPlaybackRate );
  279. ShowButtons( false );
  280. m_nFontSize = 12;
  281. for ( int i = 0; i < MAX_ACTORS; i++ )
  282. {
  283. m_ActorExpanded[ i ].expanded = true;
  284. }
  285. SetChoreoFile( "" );
  286. if ( workspacefiles->GetNumStoredFiles( IWorkspaceFiles::CHOREODATA ) >= 1 )
  287. {
  288. LoadSceneFromFile( workspacefiles->GetStoredFile( IWorkspaceFiles::CHOREODATA, 0 ) );
  289. }
  290. ClearABPoints();
  291. m_pClickedActor = NULL;
  292. m_pClickedChannel = NULL;
  293. m_pClickedEvent = NULL;
  294. m_pClickedGlobalEvent = NULL;
  295. m_nClickedX = 0;
  296. m_nClickedY = 0;
  297. m_nSelectedEvents = 0;
  298. m_nClickedTag = -1;
  299. m_nClickedChannelCloseCaptionButton = CChoreoChannelWidget::CLOSECAPTION_NONE;
  300. // Mouse dragging
  301. m_bDragging = false;
  302. m_xStart = 0;
  303. m_yStart = 0;
  304. m_nDragType = DRAGTYPE_NONE;
  305. m_hPrevCursor = 0;
  306. m_nMinX = 0;
  307. m_nMaxX = 0;
  308. m_bUseBounds = false;
  309. m_nScrollbarHeight = 12;
  310. m_nInfoHeight = 30;
  311. ClearStatusArea();
  312. SetDirty( false );
  313. m_bCanDraw = true;
  314. m_bSuppressLayout = false;
  315. m_flScrubberTimeOffset = 0.0f;
  316. m_bShowCloseCaptionData = true;
  317. m_bScrubSeconds = false;
  318. }
  319. //-----------------------------------------------------------------------------
  320. // Purpose:
  321. // Input : closing -
  322. //-----------------------------------------------------------------------------
  323. bool CChoreoView::Close( void )
  324. {
  325. if ( m_pScene && m_bDirty )
  326. {
  327. int retval = mxMessageBox( NULL, va( "Save changes to scene '%s'?", GetChoreoFile() ), g_appTitle, MX_MB_YESNOCANCEL );
  328. if ( retval == 2 )
  329. {
  330. return false;
  331. }
  332. if ( retval == 0 )
  333. {
  334. Save();
  335. }
  336. }
  337. if ( m_pScene )
  338. {
  339. UnloadScene();
  340. }
  341. return true;
  342. }
  343. bool CChoreoView::CanClose()
  344. {
  345. if ( m_pScene )
  346. {
  347. workspacefiles->StartStoringFiles( IWorkspaceFiles::CHOREODATA );
  348. workspacefiles->StoreFile( IWorkspaceFiles::CHOREODATA, GetChoreoFile() );
  349. workspacefiles->FinishStoringFiles( IWorkspaceFiles::CHOREODATA );
  350. }
  351. if ( m_pScene && m_bDirty && !Close() )
  352. {
  353. return false;
  354. }
  355. return true;
  356. }
  357. //-----------------------------------------------------------------------------
  358. // Purpose: Called just before window is destroyed
  359. //-----------------------------------------------------------------------------
  360. void CChoreoView::OnDelete()
  361. {
  362. if ( m_pScene )
  363. {
  364. UnloadScene();
  365. }
  366. CChoreoWidget::m_pView = NULL;
  367. CChoreoEventWidget::DestroyImages();
  368. }
  369. //-----------------------------------------------------------------------------
  370. // Purpose:
  371. //-----------------------------------------------------------------------------
  372. CChoreoView::~CChoreoView()
  373. {
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Purpose:
  377. //-----------------------------------------------------------------------------
  378. void CChoreoView::ReportSceneClearToTools( void )
  379. {
  380. if ( m_pScene )
  381. {
  382. m_pScene->ResetSimulation();
  383. }
  384. g_pPhonemeEditor->ClearEvent();
  385. g_pExpressionTool->LayoutItems( true );
  386. g_pExpressionTool->redraw();
  387. g_pGestureTool->redraw();
  388. g_pRampTool->redraw();
  389. g_pSceneRampTool->redraw();
  390. }
  391. //-----------------------------------------------------------------------------
  392. // Purpose: Find a time that's less than input on the granularity:
  393. // e.g., 3.01 granularity 0.05 will be 3.00, 3.05 will be 3.05
  394. // Input : input -
  395. // granularity -
  396. // Output : float
  397. //-----------------------------------------------------------------------------
  398. float SnapTime( float input, float granularity )
  399. {
  400. float base = (float)(int)input;
  401. float multiplier = (float)(int)( 1.0f / granularity );
  402. float fracpart = input - (int)input;
  403. fracpart *= multiplier;
  404. fracpart = (float)(int)fracpart;
  405. fracpart *= granularity;
  406. return base + fracpart;
  407. }
  408. //-----------------------------------------------------------------------------
  409. // Purpose:
  410. // Input : drawHelper -
  411. // rc -
  412. // left -
  413. // right -
  414. //-----------------------------------------------------------------------------
  415. void CChoreoView::DrawTimeLine( CChoreoWidgetDrawHelper& drawHelper, RECT& rc, float left, float right )
  416. {
  417. RECT rcFill = m_rcTimeLine;
  418. rcFill.bottom -= TIMELINE_NUMBERS_HEIGHT;
  419. drawHelper.DrawFilledRect( COLOR_CHOREO_DARKBACKGROUND, rcFill );
  420. RECT rcLabel;
  421. float granularity = 0.25f / ((float)GetTimeZoom( GetToolName() ) / 100.0f);
  422. drawHelper.DrawColoredLine( COLOR_CHOREO_TIMELINE, PS_SOLID, 1, rc.left, GetStartRow() - 1, rc.right, GetStartRow() - 1 );
  423. float f = SnapTime( left, granularity );
  424. while ( f < right )
  425. {
  426. float frac = ( f - left ) / ( right - left );
  427. if ( frac >= 0.0f && frac <= 1.0f )
  428. {
  429. rcLabel.left = GetLabelWidth() + (int)( frac * ( rc.right - GetLabelWidth() ) );
  430. rcLabel.bottom = GetStartRow() - 1;
  431. rcLabel.top = rcLabel.bottom - 10;
  432. if ( f != left )
  433. {
  434. drawHelper.DrawColoredLine( Color( 220, 220, 240 ), PS_DOT, 1,
  435. rcLabel.left, GetStartRow(), rcLabel.left, h2() );
  436. }
  437. char sz[ 32 ];
  438. sprintf( sz, "%.2f", f );
  439. int textWidth = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  440. rcLabel.right = rcLabel.left + textWidth;
  441. OffsetRect( &rcLabel, -textWidth / 2, 0 );
  442. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, COLOR_CHOREO_TEXT, rcLabel, sz );
  443. }
  444. f += granularity;
  445. }
  446. }
  447. //-----------------------------------------------------------------------------
  448. // Purpose:
  449. // Output : Returns true on success, false on failure.
  450. //-----------------------------------------------------------------------------
  451. bool CChoreoView::PaintBackground( void )
  452. {
  453. redraw();
  454. return false;
  455. }
  456. //-----------------------------------------------------------------------------
  457. // Purpose:
  458. // Input : drawHelper -
  459. //-----------------------------------------------------------------------------
  460. void CChoreoView::DrawSceneABTicks( CChoreoWidgetDrawHelper& drawHelper )
  461. {
  462. RECT rcThumb;
  463. float scenestart = m_rgABPoints[ 0 ].active ? m_rgABPoints[ 0 ].time : 0.0f;
  464. float sceneend = m_rgABPoints[ 1 ].active ? m_rgABPoints[ 1 ].time : 0.0f;
  465. if ( scenestart )
  466. {
  467. int markerstart = GetPixelForTimeValue( scenestart );
  468. rcThumb.left = markerstart - 4;
  469. rcThumb.right = markerstart + 4;
  470. rcThumb.top = 2 + GetCaptionHeight() + SCRUBBER_HEIGHT;
  471. rcThumb.bottom = rcThumb.top + 8;
  472. drawHelper.DrawTriangleMarker( rcThumb, COLOR_CHOREO_TICKAB );
  473. // Draw the frame number next to the time tick
  474. char sz[48];
  475. const int fontsize = 9;
  476. sprintf( sz, "Frame: %i", (int)(GetScene()->GetSceneFPS() * (float)scenestart) );
  477. const int length = drawHelper.CalcTextWidth( "Arial", fontsize, FW_NORMAL, sz);
  478. rcThumb.left = markerstart - length - 10;
  479. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL, Color( 50, 50, 50 ), rcThumb, sz );
  480. }
  481. if ( sceneend )
  482. {
  483. int markerend = GetPixelForTimeValue( sceneend );
  484. rcThumb.left = markerend - 4;
  485. rcThumb.right = markerend + 4;
  486. rcThumb.top = 2 + GetCaptionHeight() + SCRUBBER_HEIGHT;
  487. rcThumb.bottom = rcThumb.top + 8;
  488. drawHelper.DrawTriangleMarker( rcThumb, COLOR_CHOREO_TICKAB );
  489. // Draw the frame number next to the time tick
  490. char sz[48];
  491. const int fontsize = 9;
  492. sprintf( sz, "Frame: %i", (int)(GetScene()->GetSceneFPS() * (float)sceneend) );
  493. const int length = drawHelper.CalcTextWidth( "Arial", fontsize, FW_NORMAL, sz);
  494. rcThumb.left = markerend + 10;
  495. rcThumb.right = rcThumb.left + length;
  496. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL, Color( 50, 50, 50 ), rcThumb, sz );
  497. }
  498. }
  499. //-----------------------------------------------------------------------------
  500. // Purpose:
  501. // Input : drawHelper -
  502. // rc -
  503. //-----------------------------------------------------------------------------
  504. void CChoreoView::DrawRelativeTagLines( CChoreoWidgetDrawHelper& drawHelper, RECT& rc )
  505. {
  506. if ( !m_pScene )
  507. return;
  508. RECT rcClip;
  509. GetClientRect( (HWND)getHandle(), &rcClip );
  510. rcClip.top = GetStartRow();
  511. rcClip.bottom -= ( m_nInfoHeight + m_nScrollbarHeight );
  512. rcClip.right -= m_nScrollbarHeight;
  513. drawHelper.StartClipping( rcClip );
  514. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  515. {
  516. CChoreoActorWidget *a = m_SceneActors[ i ];
  517. if ( !a )
  518. continue;
  519. for ( int j = 0; j < a->GetNumChannels(); j++ )
  520. {
  521. CChoreoChannelWidget *c = a->GetChannel( j );
  522. if ( !c )
  523. continue;
  524. for ( int k = 0; k < c->GetNumEvents(); k++ )
  525. {
  526. CChoreoEventWidget *e = c->GetEvent( k );
  527. if ( !e )
  528. continue;
  529. CChoreoEvent *event = e->GetEvent();
  530. if ( !event )
  531. continue;
  532. if ( !event->IsUsingRelativeTag() )
  533. continue;
  534. // Using it, find the tag and figure out the time for it
  535. CEventRelativeTag *tag = m_pScene->FindTagByName(
  536. event->GetRelativeWavName(),
  537. event->GetRelativeTagName() );
  538. if ( !tag )
  539. continue;
  540. // Found it, draw a vertical line
  541. //
  542. float tagtime = tag->GetStartTime();
  543. // Convert to pixel value
  544. bool clipped = false;
  545. int pixel = GetPixelForTimeValue( tagtime, &clipped );
  546. if ( clipped )
  547. continue;
  548. drawHelper.DrawColoredLine( Color( 180, 180, 220 ), PS_SOLID, 1,
  549. pixel, rcClip.top, pixel, rcClip.bottom );
  550. }
  551. }
  552. }
  553. drawHelper.StopClipping();
  554. }
  555. //-----------------------------------------------------------------------------
  556. // Purpose: Draw the background markings (actor names, etc)
  557. // Input : drawHelper -
  558. // rc -
  559. //-----------------------------------------------------------------------------
  560. void CChoreoView::DrawBackground( CChoreoWidgetDrawHelper& drawHelper, RECT& rc )
  561. {
  562. RECT rcClip;
  563. GetClientRect( (HWND)getHandle(), &rcClip );
  564. rcClip.top = GetStartRow();
  565. rcClip.bottom -= ( m_nInfoHeight + m_nScrollbarHeight );
  566. rcClip.right -= m_nScrollbarHeight;
  567. int i;
  568. for ( i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  569. {
  570. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  571. if ( event )
  572. {
  573. event->redraw( drawHelper );
  574. }
  575. }
  576. drawHelper.StartClipping( rcClip );
  577. for ( i = 0; i < m_SceneActors.Count(); i++ )
  578. {
  579. CChoreoActorWidget *actorW = m_SceneActors[ i ];
  580. if ( !actorW )
  581. continue;
  582. actorW->redraw( drawHelper );
  583. }
  584. drawHelper.StopClipping();
  585. }
  586. //-----------------------------------------------------------------------------
  587. // Purpose:
  588. //-----------------------------------------------------------------------------
  589. void CChoreoView::redraw()
  590. {
  591. if ( !ToolCanDraw() )
  592. return;
  593. if ( m_bSuppressLayout )
  594. return;
  595. LayoutScene();
  596. CChoreoWidgetDrawHelper drawHelper( this, COLOR_CHOREO_BACKGROUND );
  597. HandleToolRedraw( drawHelper );
  598. if ( !m_bCanDraw )
  599. return;
  600. RECT rc;
  601. rc.left = 0;
  602. rc.top = GetCaptionHeight();
  603. rc.right = drawHelper.GetWidth();
  604. rc.bottom = drawHelper.GetHeight();
  605. RECT rcInfo;
  606. rcInfo.left = rc.left;
  607. rcInfo.right = rc.right - m_nScrollbarHeight;
  608. rcInfo.bottom = rc.bottom - m_nScrollbarHeight;
  609. rcInfo.top = rcInfo.bottom - m_nInfoHeight;
  610. drawHelper.StartClipping( rcInfo );
  611. RedrawStatusArea( drawHelper, rcInfo );
  612. drawHelper.StopClipping();
  613. RECT rcClip = rc;
  614. rcClip.bottom -= ( m_nInfoHeight + m_nScrollbarHeight );
  615. drawHelper.StartClipping( rcClip );
  616. if ( !m_pScene )
  617. {
  618. char sz[ 256 ];
  619. sprintf( sz, "No choreography scene file (.vcd) loaded" );
  620. int pointsize = 18;
  621. int textlen = drawHelper.CalcTextWidth( "Arial", pointsize, FW_NORMAL, sz );
  622. RECT rcText;
  623. rcText.top = ( rc.bottom - rc.top ) / 2 - pointsize / 2;
  624. rcText.bottom = rcText.top + pointsize + 10;
  625. rcText.left = rc.right / 2 - textlen / 2;
  626. rcText.right = rcText.left + textlen;
  627. drawHelper.DrawColoredText( "Arial", pointsize, FW_NORMAL, COLOR_CHOREO_LIGHTTEXT, rcText, sz );
  628. drawHelper.StopClipping();
  629. return;
  630. }
  631. DrawTimeLine( drawHelper, rc, m_flStartTime, m_flEndTime );
  632. bool clipped = false;
  633. int finishx = GetPixelForTimeValue( m_pScene->FindStopTime(), &clipped );
  634. if ( !clipped )
  635. {
  636. drawHelper.DrawColoredLine( COLOR_CHOREO_ENDTIME, PS_DOT, 1, finishx, rc.top + GetStartRow(), finishx, rc.bottom );
  637. }
  638. DrawRelativeTagLines( drawHelper, rc );
  639. DrawBackground( drawHelper, rc );
  640. DrawSceneABTicks( drawHelper );
  641. drawHelper.StopClipping();
  642. if ( m_UndoStack.Count() > 0 )
  643. {
  644. int length = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL,
  645. "undo %i/%i", m_nUndoLevel, m_UndoStack.Count() );
  646. RECT rcText = rc;
  647. rcText.top = rc.top + 48;
  648. rcText.bottom = rcText.top + 10;
  649. rcText.left = GetLabelWidth() - length - 20;
  650. rcText.right = rcText.left + length;
  651. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, Color( 100, 180, 100 ), rcText,
  652. "undo %i/%i", m_nUndoLevel, m_UndoStack.Count() );
  653. }
  654. DrawScrubHandle( drawHelper );
  655. char sz[ 48 ];
  656. sprintf( sz, "Speed: %.2fx", m_flPlaybackRate );
  657. int fontsize = 9;
  658. int length = drawHelper.CalcTextWidth( "Arial", fontsize, FW_NORMAL, sz);
  659. RECT rcText = rc;
  660. rcText.top = rc.top + 35;
  661. rcText.bottom = rcText.top + 10;
  662. rcText.left = GetLabelWidth() + 20;
  663. rcText.right = rcText.left + length;
  664. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL,
  665. Color( 50, 50, 50 ), rcText, sz );
  666. sprintf( sz, "Zoom: %.2fx", (float)GetTimeZoom( GetToolName() ) / 100.0f );
  667. length = drawHelper.CalcTextWidth( "Arial", fontsize, FW_NORMAL, sz);
  668. rcText = rc;
  669. rcText.left = 5;
  670. rcText.top = rc.top + 48;
  671. rcText.bottom = rcText.top + 10;
  672. rcText.right = rcText.left + length;
  673. drawHelper.DrawColoredText( "Arial", fontsize, FW_NORMAL,
  674. Color( 50, 50, 50 ), rcText, sz );
  675. }
  676. //-----------------------------------------------------------------------------
  677. // Purpose:
  678. // Input : current -
  679. // number -
  680. // Output : int
  681. //-----------------------------------------------------------------------------
  682. void CChoreoView::GetUndoLevels( int& current, int& number )
  683. {
  684. current = m_nUndoLevel;
  685. number = m_UndoStack.Count();
  686. }
  687. //-----------------------------------------------------------------------------
  688. // Purpose:
  689. // Input : time -
  690. // *clipped -
  691. // Output : int
  692. //-----------------------------------------------------------------------------
  693. int CChoreoView::GetPixelForTimeValue( float time, bool *clipped /*=NULL*/ )
  694. {
  695. if ( clipped )
  696. {
  697. *clipped = false;
  698. }
  699. float frac = ( time - m_flStartTime ) / ( m_flEndTime - m_flStartTime );
  700. if ( frac < 0.0 || frac > 1.0 )
  701. {
  702. if ( clipped )
  703. {
  704. *clipped = true;
  705. }
  706. }
  707. int pixel = GetLabelWidth() + (int)( frac * ( w2() - GetLabelWidth() ) );
  708. return pixel;
  709. }
  710. //-----------------------------------------------------------------------------
  711. // Purpose:
  712. // Input : mx -
  713. // clip -
  714. // Output : float
  715. //-----------------------------------------------------------------------------
  716. float CChoreoView::GetTimeValueForMouse( int mx, bool clip /*=false*/)
  717. {
  718. RECT rc = m_rcTimeLine;
  719. rc.left = GetLabelWidth();
  720. if ( clip )
  721. {
  722. if ( mx < rc.left )
  723. {
  724. return m_flStartTime;
  725. }
  726. if ( mx > rc.right )
  727. {
  728. return m_flEndTime;
  729. }
  730. }
  731. float frac = (float)( mx - rc.left ) / (float)( rc.right - rc.left );
  732. return m_flStartTime + frac * ( m_flEndTime - m_flStartTime );
  733. }
  734. //-----------------------------------------------------------------------------
  735. // Purpose:
  736. // Input : time -
  737. //-----------------------------------------------------------------------------
  738. void CChoreoView::SetStartTime( float time )
  739. {
  740. m_flStartTime = time;
  741. InvalidateLayout();
  742. }
  743. //-----------------------------------------------------------------------------
  744. // Purpose:
  745. // Output : float
  746. //-----------------------------------------------------------------------------
  747. float CChoreoView::GetStartTime( void )
  748. {
  749. return m_flStartTime;
  750. }
  751. //-----------------------------------------------------------------------------
  752. // Purpose:
  753. // Output : float
  754. //-----------------------------------------------------------------------------
  755. float CChoreoView::GetEndTime( void )
  756. {
  757. return m_flEndTime;
  758. }
  759. //-----------------------------------------------------------------------------
  760. // Purpose:
  761. // Output : float
  762. //-----------------------------------------------------------------------------
  763. float CChoreoView::GetPixelsPerSecond( void )
  764. {
  765. return m_flPixelsPerSecond * (float)GetTimeZoom( GetToolName() ) / 100.0f;
  766. }
  767. //-----------------------------------------------------------------------------
  768. // Purpose:
  769. // Input : mx -
  770. // origmx -
  771. // Output : float
  772. //-----------------------------------------------------------------------------
  773. float CChoreoView::GetTimeDeltaForMouseDelta( int mx, int origmx )
  774. {
  775. float t1, t2;
  776. t2 = GetTimeValueForMouse( mx );
  777. t1 = GetTimeValueForMouse( origmx );
  778. return t2 - t1;
  779. }
  780. //-----------------------------------------------------------------------------
  781. // Purpose:
  782. // Input : mx -
  783. //-----------------------------------------------------------------------------
  784. void CChoreoView::PlaceABPoint( int mx )
  785. {
  786. m_rgABPoints[ ( m_nCurrentABPoint) & 0x01 ].time = GetTimeValueForMouse( mx );
  787. m_rgABPoints[ ( m_nCurrentABPoint) & 0x01 ].active = true;
  788. m_nCurrentABPoint++;
  789. if ( m_rgABPoints[ 0 ].active && m_rgABPoints [ 1 ].active &&
  790. m_rgABPoints[ 0 ].time > m_rgABPoints[ 1 ].time )
  791. {
  792. float temp = m_rgABPoints[ 0 ].time;
  793. m_rgABPoints[ 0 ].time = m_rgABPoints[ 1 ].time;
  794. m_rgABPoints[ 1 ].time = temp;
  795. }
  796. }
  797. //-----------------------------------------------------------------------------
  798. // Purpose:
  799. //-----------------------------------------------------------------------------
  800. void CChoreoView::ClearABPoints( void )
  801. {
  802. memset( m_rgABPoints, 0, sizeof( m_rgABPoints ) );
  803. m_nCurrentABPoint = 0;
  804. }
  805. //-----------------------------------------------------------------------------
  806. // Purpose:
  807. // Input : mx -
  808. // my -
  809. // Output : Returns true on success, false on failure.
  810. //-----------------------------------------------------------------------------
  811. bool CChoreoView::IsMouseOverTimeline( int mx, int my )
  812. {
  813. POINT pt;
  814. pt.x = mx;
  815. pt.y = my;
  816. RECT rcCheck = m_rcTimeLine;
  817. rcCheck.bottom -= TIMELINE_NUMBERS_HEIGHT;
  818. if ( PtInRect( &rcCheck, pt ) )
  819. return true;
  820. return false;
  821. }
  822. //-----------------------------------------------------------------------------
  823. // Purpose:
  824. // Input : mx -
  825. // my -
  826. //-----------------------------------------------------------------------------
  827. void CChoreoView::ShowContextMenu( int mx, int my )
  828. {
  829. CChoreoActorWidget *a = NULL;
  830. CChoreoChannelWidget *c = NULL;
  831. CChoreoEventWidget *e = NULL;
  832. CChoreoGlobalEventWidget *ge = NULL;
  833. int ct = -1;
  834. CEventAbsoluteTag *at = NULL;
  835. int clickedCloseCaptionButton = CChoreoChannelWidget::CLOSECAPTION_NONE;
  836. GetObjectsUnderMouse( mx, my, &a, &c, &e, &ge, &ct, &at, &clickedCloseCaptionButton );
  837. m_pClickedActor = a;
  838. m_pClickedChannel = c;
  839. m_pClickedEvent = e;
  840. m_pClickedGlobalEvent = ge;
  841. m_nClickedX = mx;
  842. m_nClickedY = my;
  843. m_nClickedTag = ct;
  844. m_pClickedAbsoluteTag = at;
  845. m_nClickedChannelCloseCaptionButton = clickedCloseCaptionButton;
  846. // Construct main
  847. mxPopupMenu *pop = new mxPopupMenu();
  848. if ( a && c )
  849. {
  850. if (!e)
  851. {
  852. pop->add( "Expression...", IDC_ADDEVENT_EXPRESSION );
  853. pop->add( "WAV File...", IDC_ADDEVENT_SPEAK );
  854. pop->add( "Gesture...", IDC_ADDEVENT_GESTURE );
  855. pop->add( "NULL Gesture...", IDC_ADDEVENT_NULLGESTURE );
  856. pop->add( "Look at actor...", IDC_ADDEVENT_LOOKAT );
  857. pop->add( "Move to actor...", IDC_ADDEVENT_MOVETO );
  858. pop->add( "Face actor...", IDC_ADDEVENT_FACE );
  859. pop->add( "Fire Trigger...", IDC_ADDEVENT_FIRETRIGGER );
  860. pop->add( "Generic(AI)...", IDC_ADDEVENT_GENERIC );
  861. pop->add( "Sequence...", IDC_ADDEVENT_SEQUENCE );
  862. pop->add( "Flex animation...", IDC_ADDEVENT_FLEXANIMATION );
  863. pop->add( "Sub-scene...", IDC_ADDEVENT_SUBSCENE );
  864. pop->add( "Interrupt...", IDC_ADDEVENT_INTERRUPT );
  865. pop->add( "Permit Responses...", IDC_ADDEVENT_PERMITRESPONSES );
  866. pop->add( "Camera...", IDC_ADDEVENT_CAMERA );
  867. pop->addSeparator();
  868. }
  869. else
  870. {
  871. pop->add( va( "Edit Event '%s'...", e->GetEvent()->GetName() ), IDC_EDITEVENT );
  872. switch ( e->GetEvent()->GetType() )
  873. {
  874. default:
  875. break;
  876. case CChoreoEvent::FLEXANIMATION:
  877. {
  878. pop->add( va( "Edit Event '%s' in expression tool", e->GetEvent()->GetName() ), IDC_EXPRESSIONTOOL );
  879. }
  880. break;
  881. case CChoreoEvent::GESTURE:
  882. {
  883. pop->add( va( "Edit Event '%s' in gesture tool", e->GetEvent()->GetName() ), IDC_GESTURETOOL );
  884. }
  885. break;
  886. }
  887. if ( e->GetEvent()->HasEndTime() )
  888. {
  889. pop->add( "Timing Tag...", IDC_ADDTIMINGTAG );
  890. }
  891. pop->addSeparator();
  892. }
  893. }
  894. // Construct "New..."
  895. mxPopupMenu *newMenu = new mxPopupMenu();
  896. {
  897. newMenu->add( "Actor...", IDC_ADDACTOR );
  898. if ( a )
  899. {
  900. newMenu->add( "Channel...", IDC_ADDCHANNEL );
  901. }
  902. newMenu->add( "Section Pause...", IDC_ADDEVENT_PAUSE );
  903. newMenu->add( "Loop...", IDC_ADDEVENT_LOOP );
  904. newMenu->add( "Fire Completion...", IDC_ADDEVENT_STOPPOINT );
  905. }
  906. pop->addMenu( "New", newMenu );
  907. // Now construct "Edit..."
  908. if ( a || c || e || ge )
  909. {
  910. mxPopupMenu *editMenu = new mxPopupMenu();
  911. {
  912. if ( a )
  913. {
  914. editMenu->add( va( "Actor '%s'...", a->GetActor()->GetName() ), IDC_EDITACTOR );
  915. }
  916. if ( c )
  917. {
  918. editMenu->add( va( "Channel '%s'...", c->GetChannel()->GetName() ), IDC_EDITCHANNEL );
  919. }
  920. if ( ge )
  921. {
  922. switch ( ge->GetEvent()->GetType() )
  923. {
  924. default:
  925. break;
  926. case CChoreoEvent::SECTION:
  927. {
  928. editMenu->add( va( "Section Pause '%s'...", ge->GetEvent()->GetName() ), IDC_EDITGLOBALEVENT );
  929. }
  930. break;
  931. case CChoreoEvent::LOOP:
  932. {
  933. editMenu->add( va( "Loop Point '%s'...", ge->GetEvent()->GetName() ), IDC_EDITGLOBALEVENT );
  934. }
  935. break;
  936. case CChoreoEvent::STOPPOINT:
  937. {
  938. editMenu->add( va( "Fire Completion '%s'...", ge->GetEvent()->GetName() ), IDC_EDITGLOBALEVENT );
  939. }
  940. break;
  941. }
  942. }
  943. }
  944. pop->addMenu( "Edit", editMenu );
  945. }
  946. // Move up/down
  947. if ( a || c )
  948. {
  949. mxPopupMenu *moveUpMenu = new mxPopupMenu();
  950. mxPopupMenu *moveDownMenu = new mxPopupMenu();
  951. if ( a )
  952. {
  953. moveUpMenu->add( va( "Move '%s' up", a->GetActor()->GetName() ), IDC_MOVEACTORUP );
  954. moveDownMenu->add( va( "Move '%s' down", a->GetActor()->GetName() ), IDC_MOVEACTORDOWN );
  955. }
  956. if ( c )
  957. {
  958. moveUpMenu->add( va( "Move '%s' up", c->GetChannel()->GetName() ), IDC_MOVECHANNELUP );
  959. moveDownMenu->add( va( "Move '%s' down", c->GetChannel()->GetName() ), IDC_MOVECHANNELDOWN );
  960. }
  961. pop->addMenu( "Move Up", moveUpMenu );
  962. pop->addMenu( "Move Down", moveDownMenu );
  963. }
  964. // Delete
  965. if ( a || c || e || ge || (ct != -1) )
  966. {
  967. mxPopupMenu *deleteMenu = new mxPopupMenu();
  968. if ( a )
  969. {
  970. deleteMenu->add( va( "Actor '%s'", a->GetActor()->GetName() ), IDC_DELETEACTOR );
  971. }
  972. if ( c )
  973. {
  974. deleteMenu->add( va( "Channel '%s'", c->GetChannel()->GetName() ), IDC_DELETECHANNEL );
  975. }
  976. if ( e )
  977. {
  978. deleteMenu->add( va( "Event '%s'", e->GetEvent()->GetName() ), IDC_DELETEEVENT );
  979. }
  980. if ( ge )
  981. {
  982. switch ( ge->GetEvent()->GetType() )
  983. {
  984. default:
  985. break;
  986. case CChoreoEvent::SECTION:
  987. {
  988. deleteMenu->add( va( "Section Pause '%s'...", ge->GetEvent()->GetName() ), IDC_DELETEGLOBALEVENT );
  989. }
  990. break;
  991. case CChoreoEvent::LOOP:
  992. {
  993. deleteMenu->add( va( "Loop Point '%s'...", ge->GetEvent()->GetName() ), IDC_DELETEGLOBALEVENT );
  994. }
  995. break;
  996. case CChoreoEvent::STOPPOINT:
  997. {
  998. deleteMenu->add( va( "Fire Completion '%s'...", ge->GetEvent()->GetName() ), IDC_DELETEGLOBALEVENT );
  999. }
  1000. break;
  1001. }
  1002. }
  1003. if ( e && ct != -1 )
  1004. {
  1005. CEventRelativeTag *tag = e->GetEvent()->GetRelativeTag( ct );
  1006. if ( tag )
  1007. {
  1008. deleteMenu->add( va( "Relative Tag '%s'...", tag->GetName() ), IDC_DELETERELATIVETAG );
  1009. }
  1010. }
  1011. pop->addMenu( "Delete", deleteMenu );
  1012. }
  1013. // Select
  1014. {
  1015. mxPopupMenu *selectMenu = new mxPopupMenu();
  1016. selectMenu->add( "Select All", IDC_SELECTALL );
  1017. selectMenu->add( "Deselect All", IDC_DESELECTALL );
  1018. selectMenu->addSeparator();
  1019. selectMenu->add( "All events before", IDC_SELECTEVENTS_ALL_BEFORE );
  1020. selectMenu->add( "All events after", IDC_SELECTEVENTS_ALL_AFTER );
  1021. selectMenu->add( "Active events before", IDC_SELECTEVENTS_ACTIVE_BEFORE );
  1022. selectMenu->add( "Active events after", IDC_SELECTEVENTS_ACTIVE_AFTER );
  1023. selectMenu->add( "Channel events before", IDC_SELECTEVENTS_CHANNEL_BEFORE );
  1024. selectMenu->add( "Channel events after", IDC_SELECTEVENTS_CHANNEL_AFTER );
  1025. if ( a || c )
  1026. {
  1027. selectMenu->addSeparator();
  1028. if ( a )
  1029. {
  1030. selectMenu->add( va( "All events in actor '%s'", a->GetActor()->GetName() ), IDC_CV_ALLEVENTS_ACTOR );
  1031. }
  1032. if ( c )
  1033. {
  1034. selectMenu->add( va( "All events in channel '%s'", c->GetChannel()->GetName() ), IDC_CV_ALLEVENTS_CHANNEL );
  1035. }
  1036. }
  1037. pop->addMenu( "Select/Deselect", selectMenu );
  1038. }
  1039. // Quick delete for events
  1040. if ( e )
  1041. {
  1042. pop->addSeparator();
  1043. switch ( e->GetEvent()->GetType() )
  1044. {
  1045. default:
  1046. break;
  1047. case CChoreoEvent::FLEXANIMATION:
  1048. {
  1049. pop->add( va( "Edit event '%s' in expression tool", e->GetEvent()->GetName() ), IDC_EXPRESSIONTOOL );
  1050. }
  1051. break;
  1052. case CChoreoEvent::GESTURE:
  1053. {
  1054. pop->add( va( "Edit event '%s' in gesture tool", e->GetEvent()->GetName() ), IDC_GESTURETOOL );
  1055. }
  1056. break;
  1057. }
  1058. pop->add( va( "Move event '%s' to back", e->GetEvent()->GetName() ), IDC_MOVETOBACK );
  1059. if ( CountSelectedEvents() > 1 )
  1060. {
  1061. pop->add( va( "Delete events" ), IDC_DELETEEVENT );
  1062. pop->addSeparator();
  1063. pop->add( "Enable events", IDC_CV_ENABLEEVENTS );
  1064. pop->add( "Disable events", IDC_CV_DISABLEEVENTS );
  1065. }
  1066. else
  1067. {
  1068. pop->add( va( "Delete event '%s'", e->GetEvent()->GetName() ), IDC_DELETEEVENT );
  1069. pop->addSeparator();
  1070. if ( e->GetEvent()->GetActive() )
  1071. {
  1072. pop->add( va( "Disable event '%s'", e->GetEvent()->GetName() ), IDC_CV_DISABLEEVENTS );
  1073. }
  1074. else
  1075. {
  1076. pop->add( va( "Enable event '%s'", e->GetEvent()->GetName() ), IDC_CV_ENABLEEVENTS );
  1077. }
  1078. }
  1079. }
  1080. if ( m_rgABPoints[ 0 ].active && m_rgABPoints[ 1 ].active )
  1081. {
  1082. pop->addSeparator();
  1083. mxPopupMenu *timeMenu = new mxPopupMenu();
  1084. timeMenu->add( "Insert empty space between marks (shifts events right)", IDC_INSERT_TIME );
  1085. timeMenu->add( "Delete events between marks (shifts remaining events left)", IDC_DELETE_TIME );
  1086. pop->addMenu( "Time Marks", timeMenu );
  1087. }
  1088. // Copy/paste
  1089. if ( CanPaste() || e )
  1090. {
  1091. pop->addSeparator();
  1092. if ( CountSelectedEvents() > 1 )
  1093. {
  1094. pop->add( va( "Copy events to clipboard" ), IDC_COPYEVENTS );
  1095. }
  1096. else if ( e )
  1097. {
  1098. pop->add( va( "Copy event '%s' to clipboard", e->GetEvent()->GetName() ), IDC_COPYEVENTS );
  1099. }
  1100. if ( CanPaste() )
  1101. {
  1102. pop->add( va( "Paste events" ), IDC_PASTEEVENTS );
  1103. }
  1104. }
  1105. // Export / import
  1106. pop->addSeparator();
  1107. if ( e )
  1108. {
  1109. mxPopupMenu *exportMenu = new mxPopupMenu();
  1110. if ( CountSelectedEvents() > 1 )
  1111. {
  1112. exportMenu->add( va( "Export events to .vce..." ), IDC_EXPORTEVENTS );
  1113. }
  1114. else if ( e )
  1115. {
  1116. exportMenu->add( va( "Export event '%s' to .vce...", e->GetEvent()->GetName() ), IDC_EXPORTEVENTS );
  1117. }
  1118. exportMenu->add( va( "Export as .vcd..." ), IDC_EXPORT_VCD );
  1119. pop->addMenu( "Export", exportMenu );
  1120. }
  1121. mxPopupMenu *importMenu = new mxPopupMenu();
  1122. importMenu->add( va( "Import events from .vce..." ), IDC_IMPORTEVENTS );
  1123. importMenu->add( va( "Merge from .vcd..." ), IDC_IMPORT_VCD );
  1124. pop->addMenu( "Import", importMenu );
  1125. bool bShowAlignLeft = ( CountSelectedEvents() + CountSelectedGlobalEvents() ) > 1 ? true : false;
  1126. if ( e && ( ( CountSelectedEvents() > 1 ) || bShowAlignLeft ) )
  1127. {
  1128. pop->addSeparator();
  1129. mxPopupMenu *alignMenu = new mxPopupMenu();
  1130. alignMenu->add( "Align Left", IDC_CV_ALIGN_LEFT );
  1131. if ( CountSelectedEvents() > 1 )
  1132. {
  1133. alignMenu->add( "Align Right", IDC_CV_ALIGN_RIGHT );
  1134. alignMenu->add( "Size to Smallest", IDC_CV_SAMESIZE_SMALLEST );
  1135. alignMenu->add( "Size to Largest", IDC_CV_SAMESIZE_LARGEST );
  1136. }
  1137. pop->addMenu( "Align", alignMenu );
  1138. }
  1139. // Misc.
  1140. pop->addSeparator();
  1141. pop->add( va( "Change scale..." ), IDC_CV_CHANGESCALE );
  1142. pop->add( va( "Check sequences" ), IDC_CV_CHECKSEQLENGTHS );
  1143. pop->add( va( "Process sequences" ), IDC_CV_PROCESSSEQUENCES );
  1144. pop->add( va( m_bRampOnly ? "Ramp normal" : "Ramp only" ), IDC_CV_TOGGLERAMPONLY );
  1145. pop->setChecked( IDC_CV_PROCESSSEQUENCES, m_bProcessSequences );
  1146. bool onmaster= ( m_pClickedChannel &&
  1147. m_pClickedChannel->GetCaptionClickedEvent() &&
  1148. m_pClickedChannel->GetCaptionClickedEvent()->GetCloseCaptionType() == CChoreoEvent::CC_MASTER ) ? true : false;
  1149. bool ondisabled = ( m_pClickedChannel &&
  1150. m_pClickedChannel->GetCaptionClickedEvent() &&
  1151. m_pClickedChannel->GetCaptionClickedEvent()->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED ) ? true : false;
  1152. // The close captioning menu
  1153. if ( m_bShowCloseCaptionData && ( AreSelectedEventsCombinable() || AreSelectedEventsInSpeakGroup() || onmaster || ondisabled ) )
  1154. {
  1155. pop->addSeparator();
  1156. if ( AreSelectedEventsCombinable() )
  1157. {
  1158. pop->add( "Combine Speak Events", IDC_CV_COMBINESPEAKEVENTS );
  1159. }
  1160. if ( AreSelectedEventsInSpeakGroup() )
  1161. {
  1162. pop->add( "Uncombine Speak Events", IDC_CV_REMOVESPEAKEVENTFROMGROUP );
  1163. }
  1164. if ( onmaster )
  1165. {
  1166. // Can only change tokens for "combined" files
  1167. if ( m_pClickedChannel->GetCaptionClickedEvent()->GetNumSlaves() >= 1 )
  1168. {
  1169. pop->add( "Change Token", IDC_CV_CHANGECLOSECAPTIONTOKEN );
  1170. }
  1171. pop->add( "Disable captions", IDC_CV_TOGGLECLOSECAPTIONS );
  1172. }
  1173. if ( ondisabled )
  1174. {
  1175. pop->add( "Enable captions", IDC_CV_TOGGLECLOSECAPTIONS );
  1176. }
  1177. }
  1178. // Undo/redo
  1179. if ( CanUndo() || CanRedo() )
  1180. {
  1181. pop->addSeparator();
  1182. if ( CanUndo() )
  1183. {
  1184. pop->add( va( "Undo %s", GetUndoDescription() ), IDC_CVUNDO );
  1185. }
  1186. if ( CanRedo() )
  1187. {
  1188. pop->add( va( "Redo %s", GetRedoDescription() ), IDC_CVREDO );
  1189. }
  1190. }
  1191. if ( m_pScene )
  1192. {
  1193. // Associate map file
  1194. pop->addSeparator();
  1195. pop->add( va( "Associate .bsp (%s)", m_pScene->GetMapname() ), IDC_ASSOCIATEBSP );
  1196. if ( a )
  1197. {
  1198. if ( a->GetActor() && a->GetActor()->GetFacePoserModelName()[0] )
  1199. {
  1200. pop->add( va( "Change .mdl for %s", a->GetActor()->GetName() ), IDC_ASSOCIATEMODEL );
  1201. }
  1202. else
  1203. {
  1204. pop->add( va( "Associate .mdl with %s", a->GetActor()->GetName() ), IDC_ASSOCIATEMODEL );
  1205. }
  1206. }
  1207. }
  1208. pop->popup( this, mx, my );
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // Purpose:
  1212. //-----------------------------------------------------------------------------
  1213. void CChoreoView::AssociateModel( void )
  1214. {
  1215. if ( !m_pScene )
  1216. return;
  1217. CChoreoActorWidget *actor = m_pClickedActor;
  1218. if ( !actor )
  1219. return;
  1220. CChoreoActor *a = actor->GetActor();
  1221. if ( !a )
  1222. return;
  1223. CChoiceParams params;
  1224. strcpy( params.m_szDialogTitle, "Associate Model" );
  1225. params.m_bPositionDialog = false;
  1226. params.m_nLeft = 0;
  1227. params.m_nTop = 0;
  1228. strcpy( params.m_szPrompt, "Choose model:" );
  1229. params.m_Choices.RemoveAll();
  1230. params.m_nSelected = -1;
  1231. int oldsel = -1;
  1232. int c = models->Count();
  1233. ChoiceText text;
  1234. for ( int i = 0; i < c; i++ )
  1235. {
  1236. char const *modelname = models->GetModelName( i );
  1237. strcpy( text.choice, modelname );
  1238. if ( !stricmp( a->GetName(), modelname ) )
  1239. {
  1240. params.m_nSelected = i;
  1241. oldsel = -1;
  1242. }
  1243. params.m_Choices.AddToTail( text );
  1244. }
  1245. // Add an extra entry which is "No association"
  1246. strcpy( text.choice, "No Associated Model" );
  1247. params.m_Choices.AddToTail( text );
  1248. if ( !ChoiceProperties( &params ) )
  1249. return;
  1250. if ( params.m_nSelected == oldsel )
  1251. return;
  1252. // Chose something new...
  1253. if ( params.m_nSelected >= 0 &&
  1254. params.m_nSelected < params.m_Choices.Count() )
  1255. {
  1256. AssociateModelToActor( a, params.m_nSelected );
  1257. }
  1258. else
  1259. {
  1260. // Chose "No association"
  1261. AssociateModelToActor( a, -1 );
  1262. }
  1263. }
  1264. //-----------------------------------------------------------------------------
  1265. // Purpose:
  1266. // Input : *actor -
  1267. // modelindex -
  1268. //-----------------------------------------------------------------------------
  1269. void CChoreoView::AssociateModelToActor( CChoreoActor *actor, int modelindex )
  1270. {
  1271. Assert( actor );
  1272. SetDirty( true );
  1273. PushUndo( "Associate model" );
  1274. // Chose something new...
  1275. if ( modelindex >= 0 &&
  1276. modelindex < models->Count() )
  1277. {
  1278. actor->SetFacePoserModelName( models->GetModelFileName( modelindex ) );
  1279. }
  1280. else
  1281. {
  1282. // Chose "No Associated Model"
  1283. actor->SetFacePoserModelName( "" );
  1284. }
  1285. RecomputeWaves();
  1286. PushRedo( "Associate model" );
  1287. }
  1288. void CChoreoView::AssociateBSP( void )
  1289. {
  1290. if ( !m_pScene )
  1291. return;
  1292. // Strip game directory and slash
  1293. char mapname[ 512 ];
  1294. if ( !FacePoser_ShowOpenFileNameDialog( mapname, sizeof( mapname ), "maps", "*.bsp" ) )
  1295. {
  1296. return;
  1297. }
  1298. m_pScene->SetMapname( mapname );
  1299. redraw();
  1300. }
  1301. //-----------------------------------------------------------------------------
  1302. // Purpose:
  1303. //-----------------------------------------------------------------------------
  1304. void CChoreoView::DrawFocusRect( void )
  1305. {
  1306. HDC dc = GetDC( NULL );
  1307. for ( int i = 0; i < m_FocusRects.Count(); i++ )
  1308. {
  1309. RECT rc = m_FocusRects[ i ].m_rcFocus;
  1310. ::DrawFocusRect( dc, &rc );
  1311. }
  1312. ReleaseDC( NULL, dc );
  1313. }
  1314. int CChoreoView::GetSelectedEventWidgets( CUtlVector< CChoreoEventWidget * >& events )
  1315. {
  1316. events.RemoveAll();
  1317. int c = 0;
  1318. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  1319. {
  1320. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1321. if ( !actor )
  1322. continue;
  1323. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1324. {
  1325. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1326. if ( !channel )
  1327. continue;
  1328. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1329. {
  1330. CChoreoEventWidget *event = channel->GetEvent( k );
  1331. if ( !event )
  1332. continue;
  1333. if ( event->IsSelected() )
  1334. {
  1335. events.AddToTail( event );
  1336. c++;
  1337. }
  1338. }
  1339. }
  1340. }
  1341. return c;
  1342. }
  1343. //-----------------------------------------------------------------------------
  1344. // Purpose:
  1345. // Input : events -
  1346. // Output : int
  1347. //-----------------------------------------------------------------------------
  1348. int CChoreoView::GetSelectedEvents( CUtlVector< CChoreoEvent * >& events )
  1349. {
  1350. events.RemoveAll();
  1351. int c = 0;
  1352. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  1353. {
  1354. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1355. if ( !actor )
  1356. continue;
  1357. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1358. {
  1359. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1360. if ( !channel )
  1361. continue;
  1362. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1363. {
  1364. CChoreoEventWidget *event = channel->GetEvent( k );
  1365. if ( !event )
  1366. continue;
  1367. if ( event->IsSelected() )
  1368. {
  1369. events.AddToTail( event->GetEvent() );
  1370. c++;
  1371. }
  1372. }
  1373. }
  1374. }
  1375. return c;
  1376. }
  1377. int CChoreoView::CountSelectedGlobalEvents( void )
  1378. {
  1379. int c = 0;
  1380. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  1381. {
  1382. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  1383. if ( !event || !event->IsSelected() )
  1384. continue;
  1385. ++c;
  1386. }
  1387. return c;
  1388. }
  1389. //-----------------------------------------------------------------------------
  1390. // Purpose:
  1391. // Output : int
  1392. //-----------------------------------------------------------------------------
  1393. int CChoreoView::CountSelectedEvents( void )
  1394. {
  1395. int c = 0;
  1396. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  1397. {
  1398. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1399. if ( !actor )
  1400. continue;
  1401. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1402. {
  1403. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1404. if ( !channel )
  1405. continue;
  1406. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1407. {
  1408. CChoreoEventWidget *event = channel->GetEvent( k );
  1409. if ( !event )
  1410. continue;
  1411. if ( event->IsSelected() )
  1412. c++;
  1413. }
  1414. }
  1415. }
  1416. return c;
  1417. }
  1418. bool CChoreoView::IsMouseOverEvent( CChoreoEventWidget *ew, int mx, int my )
  1419. {
  1420. int tolerance = DRAG_EVENT_EDGE_TOLERANCE;
  1421. RECT bounds = ew->getBounds();
  1422. mx -= bounds.left;
  1423. my -= bounds.top;
  1424. if ( mx <= -tolerance )
  1425. {
  1426. return false;
  1427. }
  1428. CChoreoEvent *event = ew->GetEvent();
  1429. if ( event )
  1430. {
  1431. if ( event->HasEndTime() )
  1432. {
  1433. int rightside = ew->GetDurationRightEdge() ? ew->GetDurationRightEdge() : ew->w();
  1434. if ( mx > rightside + tolerance )
  1435. {
  1436. return false;
  1437. }
  1438. }
  1439. }
  1440. return true;
  1441. }
  1442. bool CChoreoView::IsMouseOverEventEdge( CChoreoEventWidget *ew, bool bLeftEdge, int mx, int my )
  1443. {
  1444. int tolerance = DRAG_EVENT_EDGE_TOLERANCE;
  1445. RECT bounds = ew->getBounds();
  1446. mx -= bounds.left;
  1447. my -= bounds.top;
  1448. CChoreoEvent *event = ew->GetEvent();
  1449. if ( event && event->HasEndTime() )
  1450. {
  1451. if ( mx > -tolerance && mx <= tolerance )
  1452. {
  1453. return bLeftEdge;
  1454. }
  1455. int rightside = ew->GetDurationRightEdge() ? ew->GetDurationRightEdge() : ew->w();
  1456. if ( mx >= rightside - tolerance )
  1457. {
  1458. if ( mx > rightside + tolerance )
  1459. {
  1460. return false;
  1461. }
  1462. else
  1463. {
  1464. return !bLeftEdge;
  1465. }
  1466. }
  1467. }
  1468. return false;
  1469. }
  1470. int CChoreoView::GetEarliestEventIndex( CUtlVector< CChoreoEventWidget * >& events )
  1471. {
  1472. int best = -1;
  1473. float minTime = FLT_MAX;
  1474. int c = events.Count();
  1475. for ( int i = 0; i < c; ++i )
  1476. {
  1477. CChoreoEvent *e = events[ i ]->GetEvent();
  1478. float t = e->GetStartTime();
  1479. if ( t < minTime )
  1480. {
  1481. minTime = t;
  1482. best = i;
  1483. }
  1484. }
  1485. return best;
  1486. }
  1487. int CChoreoView::GetLatestEventIndex( CUtlVector< CChoreoEventWidget * >& events )
  1488. {
  1489. int best = -1;
  1490. float maxTime = FLT_MIN;
  1491. int c = events.Count();
  1492. for ( int i = 0; i < c; ++i )
  1493. {
  1494. CChoreoEvent *e = events[ i ]->GetEvent();
  1495. float t = e->GetEndTime();
  1496. if ( t > maxTime )
  1497. {
  1498. maxTime = t;
  1499. best = i;
  1500. }
  1501. }
  1502. return best;
  1503. }
  1504. //-----------------------------------------------------------------------------
  1505. // Purpose:
  1506. // Input : mx -
  1507. // Output : int
  1508. //-----------------------------------------------------------------------------
  1509. int CChoreoView::ComputeEventDragType( int mx, int my )
  1510. {
  1511. int tolerance = DRAG_EVENT_EDGE_TOLERANCE;
  1512. // Iterate the events and see who's closest
  1513. CChoreoEventWidget *ew = GetEventUnderCursorPos( mx, my );
  1514. if ( !ew )
  1515. {
  1516. return DRAGTYPE_NONE;
  1517. }
  1518. // Deal with small windows by lowering tolerance
  1519. if ( ew->w() < 4 * tolerance )
  1520. {
  1521. tolerance = 2;
  1522. }
  1523. int tagnum = GetTagUnderCursorPos( ew, mx, my );
  1524. if ( tagnum != -1 && CountSelectedEvents() <= 1 )
  1525. {
  1526. return DRAGTYPE_EVENTTAG_MOVE;
  1527. }
  1528. CEventAbsoluteTag *tag = GetAbsoluteTagUnderCursorPos( ew, mx, my );
  1529. if ( tag != NULL && CountSelectedEvents() <= 1 )
  1530. {
  1531. return DRAGTYPE_EVENTABSTAG_MOVE;
  1532. }
  1533. if ( CountSelectedEvents() > 1 )
  1534. {
  1535. CUtlVector< CChoreoEventWidget * > events;
  1536. GetSelectedEventWidgets( events );
  1537. int iStart, iEnd;
  1538. iStart = GetEarliestEventIndex( events );
  1539. iEnd = GetLatestEventIndex( events );
  1540. if ( events.IsValidIndex( iStart ) )
  1541. {
  1542. // See if mouse is over left edge of starting event
  1543. if ( IsMouseOverEventEdge( events[ iStart ], true, mx, my ) )
  1544. {
  1545. return DRAGTYPE_RESCALELEFT;
  1546. }
  1547. }
  1548. if ( events.IsValidIndex( iEnd ) )
  1549. {
  1550. if ( IsMouseOverEventEdge( events[ iEnd ], false, mx, my ) )
  1551. {
  1552. return DRAGTYPE_RESCALERIGHT;
  1553. }
  1554. }
  1555. return DRAGTYPE_EVENT_MOVE;
  1556. }
  1557. CChoreoEvent *event = ew->GetEvent();
  1558. if ( event )
  1559. {
  1560. if ( event->IsFixedLength() || !event->HasEndTime() )
  1561. {
  1562. return DRAGTYPE_EVENT_MOVE;
  1563. }
  1564. }
  1565. if ( IsMouseOverEventEdge( ew, true, mx, my ) )
  1566. {
  1567. if ( GetAsyncKeyState( VK_SHIFT ) )
  1568. return DRAGTYPE_EVENT_STARTTIME_RESCALE;
  1569. return DRAGTYPE_EVENT_STARTTIME;
  1570. }
  1571. if ( IsMouseOverEventEdge( ew, false, mx, my ) )
  1572. {
  1573. if ( GetAsyncKeyState( VK_SHIFT ) )
  1574. return DRAGTYPE_EVENT_ENDTIME_RESCALE;
  1575. return DRAGTYPE_EVENT_ENDTIME;
  1576. }
  1577. if ( IsMouseOverEvent( ew, mx, my ) )
  1578. {
  1579. return DRAGTYPE_EVENT_MOVE;
  1580. }
  1581. return DRAGTYPE_NONE;
  1582. }
  1583. void CChoreoView::StartDraggingSceneEndTime( int mx, int my )
  1584. {
  1585. m_nDragType = DRAGTYPE_SCENE_ENDTIME;
  1586. m_FocusRects.Purge();
  1587. RECT rcFocus;
  1588. rcFocus.left = mx;
  1589. rcFocus.top = 0;
  1590. rcFocus.bottom = h2();
  1591. rcFocus.right = rcFocus.left + 2;
  1592. POINT offset;
  1593. offset.x = 0;
  1594. offset.y = 0;
  1595. ClientToScreen( (HWND)getHandle(), &offset );
  1596. OffsetRect( &rcFocus, offset.x, offset.y );
  1597. CFocusRect fr;
  1598. fr.m_rcFocus = rcFocus;
  1599. fr.m_rcOrig = rcFocus;
  1600. // Relative tag events don't move
  1601. m_FocusRects.AddToTail( fr );
  1602. m_xStart = mx;
  1603. m_yStart = my;
  1604. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1605. DrawFocusRect();
  1606. m_bDragging = true;
  1607. }
  1608. //-----------------------------------------------------------------------------
  1609. // Purpose:
  1610. //-----------------------------------------------------------------------------
  1611. void CChoreoView::StartDraggingEvent( int mx, int my )
  1612. {
  1613. m_nDragType = ComputeEventDragType( mx, my );
  1614. if ( m_nDragType == DRAGTYPE_NONE )
  1615. {
  1616. if( m_pClickedGlobalEvent )
  1617. {
  1618. m_nDragType = DRAGTYPE_EVENT_MOVE;
  1619. }
  1620. else
  1621. {
  1622. return;
  1623. }
  1624. }
  1625. m_FocusRects.Purge();
  1626. // Go through all selected events
  1627. RECT rcFocus;
  1628. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  1629. {
  1630. CChoreoActorWidget *actor = m_SceneActors[ i ];
  1631. if ( !actor )
  1632. continue;
  1633. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  1634. {
  1635. CChoreoChannelWidget *channel = actor->GetChannel( j );
  1636. if ( !channel )
  1637. continue;
  1638. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  1639. {
  1640. CChoreoEventWidget *event = channel->GetEvent( k );
  1641. if ( !event )
  1642. continue;
  1643. if ( !event->IsSelected() )
  1644. continue;
  1645. if ( event == m_pClickedEvent &&
  1646. ( m_nClickedTag != -1 || m_pClickedAbsoluteTag ) )
  1647. {
  1648. int leftEdge = 0;
  1649. int tagWidth = 1;
  1650. if ( !m_pClickedAbsoluteTag )
  1651. {
  1652. CEventRelativeTag *tag = event->GetEvent()->GetRelativeTag( m_nClickedTag );
  1653. if ( tag )
  1654. {
  1655. // Determine left edcge
  1656. RECT bounds;
  1657. bounds = event->getBounds();
  1658. if ( bounds.right - bounds.left > 0 )
  1659. {
  1660. leftEdge = (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  1661. }
  1662. }
  1663. }
  1664. else
  1665. {
  1666. // Determine left edcge
  1667. RECT bounds;
  1668. bounds = event->getBounds();
  1669. if ( bounds.right - bounds.left > 0 )
  1670. {
  1671. leftEdge = (int)( m_pClickedAbsoluteTag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  1672. }
  1673. }
  1674. rcFocus.left = event->x() + leftEdge - tagWidth;
  1675. rcFocus.top = event->y() - tagWidth;
  1676. rcFocus.right = rcFocus.left + 2 * tagWidth;
  1677. rcFocus.bottom = event->y() + event->h();
  1678. }
  1679. else
  1680. {
  1681. rcFocus.left = event->x();
  1682. rcFocus.top = event->y();
  1683. if ( event->GetDurationRightEdge() )
  1684. {
  1685. rcFocus.right = event->x() + event->GetDurationRightEdge();
  1686. }
  1687. else
  1688. {
  1689. rcFocus.right = rcFocus.left + event->w();
  1690. }
  1691. rcFocus.bottom = rcFocus.top + event->h();
  1692. }
  1693. POINT offset;
  1694. offset.x = 0;
  1695. offset.y = 0;
  1696. ClientToScreen( (HWND)getHandle(), &offset );
  1697. OffsetRect( &rcFocus, offset.x, offset.y );
  1698. CFocusRect fr;
  1699. fr.m_rcFocus = rcFocus;
  1700. fr.m_rcOrig = rcFocus;
  1701. // Relative tag events don't move
  1702. m_FocusRects.AddToTail( fr );
  1703. }
  1704. }
  1705. }
  1706. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  1707. {
  1708. CChoreoGlobalEventWidget *gew = m_SceneGlobalEvents[ i ];
  1709. if ( !gew )
  1710. continue;
  1711. if ( !gew->IsSelected() )
  1712. continue;
  1713. rcFocus.left = gew->x() + gew->w() / 2;
  1714. rcFocus.top = 0;
  1715. rcFocus.right = rcFocus.left + 2;
  1716. rcFocus.bottom = h2();
  1717. POINT offset;
  1718. offset.x = 0;
  1719. offset.y = 0;
  1720. ClientToScreen( (HWND)getHandle(), &offset );
  1721. OffsetRect( &rcFocus, offset.x, offset.y );
  1722. CFocusRect fr;
  1723. fr.m_rcFocus = rcFocus;
  1724. fr.m_rcOrig = rcFocus;
  1725. m_FocusRects.AddToTail( fr );
  1726. }
  1727. m_xStart = mx;
  1728. m_yStart = my;
  1729. m_hPrevCursor = NULL;
  1730. switch ( m_nDragType )
  1731. {
  1732. default:
  1733. break;
  1734. case DRAGTYPE_EVENTTAG_MOVE:
  1735. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1736. break;
  1737. case DRAGTYPE_EVENTABSTAG_MOVE:
  1738. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_IBEAM ) );
  1739. break;
  1740. case DRAGTYPE_EVENT_MOVE:
  1741. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
  1742. break;
  1743. case DRAGTYPE_EVENT_STARTTIME:
  1744. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  1745. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1746. break;
  1747. case DRAGTYPE_EVENT_ENDTIME:
  1748. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  1749. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1750. break;
  1751. case DRAGTYPE_RESCALELEFT:
  1752. case DRAGTYPE_RESCALERIGHT:
  1753. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1754. break;
  1755. }
  1756. DrawFocusRect();
  1757. m_bDragging = true;
  1758. }
  1759. bool CChoreoView::IsMouseOverSceneEndTime( int mx )
  1760. {
  1761. // See if mouse if over scene end time instead
  1762. if ( m_pScene )
  1763. {
  1764. float endtime = m_pScene->FindStopTime();
  1765. bool clip = false;
  1766. int lastpixel = GetPixelForTimeValue( endtime, &clip );
  1767. if ( !clip )
  1768. {
  1769. if ( abs( mx - lastpixel ) < DRAG_EVENT_EDGE_TOLERANCE )
  1770. {
  1771. return true;
  1772. }
  1773. }
  1774. }
  1775. return false;
  1776. }
  1777. //-----------------------------------------------------------------------------
  1778. // Purpose:
  1779. // Input : mx -
  1780. // my -
  1781. //-----------------------------------------------------------------------------
  1782. void CChoreoView::MouseStartDrag( mxEvent *event, int mx, int my )
  1783. {
  1784. bool isrightbutton = event->buttons & mxEvent::MouseRightButton ? true : false;
  1785. if ( m_bDragging )
  1786. {
  1787. return;
  1788. }
  1789. GetObjectsUnderMouse( mx, my, &m_pClickedActor, &m_pClickedChannel, &m_pClickedEvent, &m_pClickedGlobalEvent, &m_nClickedTag, &m_pClickedAbsoluteTag, &m_nClickedChannelCloseCaptionButton );
  1790. if ( m_pClickedEvent )
  1791. {
  1792. CChoreoEvent *e = m_pClickedEvent->GetEvent();
  1793. Assert( e );
  1794. int dtPreview = ComputeEventDragType( mx, my );
  1795. // Shift clicking on exact edge shouldn't toggle selection state
  1796. bool bIsEdgeRescale = ( dtPreview == DRAGTYPE_EVENT_ENDTIME_RESCALE || dtPreview == DRAGTYPE_EVENT_STARTTIME_RESCALE );
  1797. if ( !( event->modifiers & ( mxEvent::KeyCtrl | mxEvent::KeyShift ) ) )
  1798. {
  1799. if ( !m_pClickedEvent->IsSelected() )
  1800. {
  1801. DeselectAll();
  1802. }
  1803. TraverseWidgets( &CChoreoView::Select, m_pClickedEvent );
  1804. }
  1805. else if ( !bIsEdgeRescale )
  1806. {
  1807. m_pClickedEvent->SetSelected( !m_pClickedEvent->IsSelected() );
  1808. }
  1809. switch ( m_pClickedEvent->GetEvent()->GetType() )
  1810. {
  1811. default:
  1812. break;
  1813. case CChoreoEvent::FLEXANIMATION:
  1814. {
  1815. g_pExpressionTool->SetEvent( e );
  1816. g_pFlexPanel->SetEvent( e );
  1817. }
  1818. break;
  1819. case CChoreoEvent::GESTURE:
  1820. {
  1821. g_pGestureTool->SetEvent( e );
  1822. }
  1823. break;
  1824. case CChoreoEvent::SPEAK:
  1825. {
  1826. g_pWaveBrowser->SetEvent( e );
  1827. }
  1828. break;
  1829. }
  1830. if ( e->HasEndTime() )
  1831. {
  1832. g_pRampTool->SetEvent( e );
  1833. }
  1834. redraw();
  1835. StartDraggingEvent( mx, my );
  1836. }
  1837. else if ( m_pClickedGlobalEvent )
  1838. {
  1839. if ( !( event->modifiers & ( mxEvent::KeyCtrl | mxEvent::KeyShift ) ) )
  1840. {
  1841. if ( !m_pClickedGlobalEvent->IsSelected() )
  1842. {
  1843. DeselectAll();
  1844. }
  1845. TraverseWidgets( &CChoreoView::Select, m_pClickedGlobalEvent );
  1846. }
  1847. else
  1848. {
  1849. m_pClickedGlobalEvent->SetSelected( !m_pClickedGlobalEvent->IsSelected() );
  1850. }
  1851. redraw();
  1852. StartDraggingEvent( mx, my );
  1853. }
  1854. else if ( IsMouseOverScrubArea( event ) )
  1855. {
  1856. if ( IsMouseOverScrubHandle( event ) )
  1857. {
  1858. m_nDragType = DRAGTYPE_SCRUBBER;
  1859. m_bDragging = true;
  1860. float t = GetTimeValueForMouse( (short)event->x );
  1861. m_flScrubberTimeOffset = m_flScrub - t;
  1862. float maxoffset = 0.5f * (float)SCRUBBER_HANDLE_WIDTH / GetPixelsPerSecond();
  1863. m_flScrubberTimeOffset = clamp( m_flScrubberTimeOffset, -maxoffset, maxoffset );
  1864. t += m_flScrubberTimeOffset;
  1865. ClampTimeToSelectionInterval( t );
  1866. SetScrubTime( t );
  1867. SetScrubTargetTime( t );
  1868. redraw();
  1869. RECT rcScrub;
  1870. GetScrubHandleRect( rcScrub, true );
  1871. m_FocusRects.Purge();
  1872. // Go through all selected events
  1873. RECT rcFocus;
  1874. rcFocus.top = GetStartRow();
  1875. rcFocus.bottom = h2() - m_nScrollbarHeight - m_nInfoHeight;
  1876. rcFocus.left = ( rcScrub.left + rcScrub.right ) / 2;
  1877. rcFocus.right = rcFocus.left;
  1878. POINT pt;
  1879. pt.x = pt.y = 0;
  1880. ClientToScreen( (HWND)getHandle(), &pt );
  1881. OffsetRect( &rcFocus, pt.x, pt.y );
  1882. CFocusRect fr;
  1883. fr.m_rcFocus = rcFocus;
  1884. fr.m_rcOrig = rcFocus;
  1885. m_FocusRects.AddToTail( fr );
  1886. m_xStart = mx;
  1887. m_yStart = my;
  1888. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  1889. DrawFocusRect();
  1890. }
  1891. else
  1892. {
  1893. float t = GetTimeValueForMouse( mx );
  1894. ClampTimeToSelectionInterval( t );
  1895. SetScrubTargetTime( t );
  1896. // Unpause the scene
  1897. m_bPaused = false;
  1898. redraw();
  1899. }
  1900. }
  1901. else if ( IsMouseOverSceneEndTime( mx ) )
  1902. {
  1903. redraw();
  1904. StartDraggingSceneEndTime( mx, my );
  1905. }
  1906. else if ( m_pClickedChannel &&
  1907. m_nClickedChannelCloseCaptionButton != CChoreoChannelWidget::CLOSECAPTION_NONE &&
  1908. m_nClickedChannelCloseCaptionButton != CChoreoChannelWidget::CLOSECAPTION_CAPTION )
  1909. {
  1910. switch ( m_nClickedChannelCloseCaptionButton )
  1911. {
  1912. default:
  1913. case CChoreoChannelWidget::CLOSECAPTION_EXPANDCOLLAPSE:
  1914. {
  1915. OnToggleCloseCaptionTags();
  1916. }
  1917. break;
  1918. case CChoreoChannelWidget::CLOSECAPTION_PREVLANGUAGE:
  1919. {
  1920. // Change language
  1921. int id = GetCloseCaptionLanguageId();
  1922. --id;
  1923. if ( id < 0 )
  1924. {
  1925. id = CC_NUM_LANGUAGES - 1;
  1926. Assert( id >= 0 );
  1927. }
  1928. SetCloseCaptionLanguageId( id );
  1929. redraw();
  1930. }
  1931. break;
  1932. case CChoreoChannelWidget::CLOSECAPTION_NEXTLANGUAGE:
  1933. {
  1934. int id = GetCloseCaptionLanguageId();
  1935. ++id;
  1936. if ( id >= CC_NUM_LANGUAGES )
  1937. {
  1938. id = 0;
  1939. }
  1940. SetCloseCaptionLanguageId( id );
  1941. redraw();
  1942. }
  1943. break;
  1944. case CChoreoChannelWidget::CLOSECAPTION_SELECTOR:
  1945. {
  1946. SetDirty( true );
  1947. PushUndo( "Change selector" );
  1948. m_pClickedChannel->HandleSelectorClicked();
  1949. PushRedo( "Change selector" );
  1950. redraw();
  1951. }
  1952. break;
  1953. }
  1954. }
  1955. else
  1956. {
  1957. if ( !( event->modifiers & ( mxEvent::KeyCtrl | mxEvent::KeyShift ) ) )
  1958. {
  1959. DeselectAll();
  1960. if ( !isrightbutton )
  1961. {
  1962. if ( realtime - m_flLastMouseClickTime < 0.3f )
  1963. {
  1964. OnDoubleClicked();
  1965. m_flLastMouseClickTime = -1.0f;
  1966. }
  1967. else
  1968. {
  1969. m_flLastMouseClickTime = realtime;
  1970. }
  1971. }
  1972. redraw();
  1973. }
  1974. }
  1975. CalcBounds( m_nDragType );
  1976. }
  1977. void CChoreoView::OnDoubleClicked()
  1978. {
  1979. if ( m_pClickedChannel )
  1980. {
  1981. switch (m_nClickedChannelCloseCaptionButton )
  1982. {
  1983. default:
  1984. break;
  1985. case CChoreoChannelWidget::CLOSECAPTION_NONE:
  1986. {
  1987. SetDirty( true );
  1988. PushUndo( "Enable/disable Channel" );
  1989. m_pClickedChannel->GetChannel()->SetActive( !m_pClickedChannel->GetChannel()->GetActive() );
  1990. PushRedo( "Enable/disable Channel" );
  1991. }
  1992. break;
  1993. case CChoreoChannelWidget::CLOSECAPTION_CAPTION:
  1994. {
  1995. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  1996. if ( e && e->GetNumSlaves() >= 1 )
  1997. {
  1998. OnChangeCloseCaptionToken( e );
  1999. }
  2000. }
  2001. break;
  2002. }
  2003. return;
  2004. }
  2005. if ( m_pClickedActor )
  2006. {
  2007. SetDirty( true );
  2008. PushUndo( "Enable/disable Actor" );
  2009. m_pClickedActor->GetActor()->SetActive( !m_pClickedActor->GetActor()->GetActive() );
  2010. PushRedo( "Enable/disable Actor" );
  2011. return;
  2012. }
  2013. }
  2014. //-----------------------------------------------------------------------------
  2015. // Purpose:
  2016. // Input : mx -
  2017. // my -
  2018. //-----------------------------------------------------------------------------
  2019. void CChoreoView::MouseContinueDrag( mxEvent *event, int mx, int my )
  2020. {
  2021. if ( !m_bDragging )
  2022. return;
  2023. DrawFocusRect();
  2024. ApplyBounds( mx, my );
  2025. for ( int i = 0; i < m_FocusRects.Count(); i++ )
  2026. {
  2027. CFocusRect *f = &m_FocusRects[ i ];
  2028. f->m_rcFocus = f->m_rcOrig;
  2029. switch ( m_nDragType )
  2030. {
  2031. default:
  2032. case DRAGTYPE_SCRUBBER:
  2033. {
  2034. float t = GetTimeValueForMouse( mx );
  2035. t += m_flScrubberTimeOffset;
  2036. ClampTimeToSelectionInterval( t );
  2037. float dt = t - m_flScrub;
  2038. SetScrubTargetTime( t );
  2039. m_bSimulating = true;
  2040. ScrubThink( dt, true, this );
  2041. SetScrubTime( t );
  2042. OffsetRect( &f->m_rcFocus, ( mx - m_xStart ), 0 );
  2043. }
  2044. break;
  2045. case DRAGTYPE_EVENT_MOVE:
  2046. case DRAGTYPE_EVENTTAG_MOVE:
  2047. case DRAGTYPE_EVENTABSTAG_MOVE:
  2048. {
  2049. int dx = mx - m_xStart;
  2050. int dy = my - m_yStart;
  2051. if ( m_pClickedEvent )
  2052. {
  2053. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  2054. // Only allow jumping channels if shift is down
  2055. if ( !shiftdown )
  2056. {
  2057. dy = 0;
  2058. }
  2059. if ( abs( dy ) < m_pClickedEvent->GetItemHeight() )
  2060. {
  2061. dy = 0;
  2062. }
  2063. if ( m_nSelectedEvents > 1 )
  2064. {
  2065. dy = 0;
  2066. }
  2067. if ( m_nDragType == DRAGTYPE_EVENTTAG_MOVE || m_nDragType == DRAGTYPE_EVENTABSTAG_MOVE )
  2068. {
  2069. dy = 0;
  2070. }
  2071. if ( m_pClickedEvent->GetEvent()->IsUsingRelativeTag() )
  2072. {
  2073. dx = 0;
  2074. }
  2075. }
  2076. else
  2077. {
  2078. dy = 0;
  2079. }
  2080. OffsetRect( &f->m_rcFocus, dx, dy );
  2081. }
  2082. break;
  2083. case DRAGTYPE_EVENT_STARTTIME:
  2084. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2085. f->m_rcFocus.left += ( mx - m_xStart );
  2086. break;
  2087. case DRAGTYPE_EVENT_ENDTIME:
  2088. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2089. f->m_rcFocus.right += ( mx - m_xStart );
  2090. break;
  2091. case DRAGTYPE_SCENE_ENDTIME:
  2092. OffsetRect( &f->m_rcFocus, ( mx - m_xStart ), 0 );
  2093. break;
  2094. case DRAGTYPE_RESCALELEFT:
  2095. case DRAGTYPE_RESCALERIGHT:
  2096. //f->m_rcFocus.right += ( mx - m_xStart );
  2097. break;
  2098. }
  2099. }
  2100. if ( m_nDragType == DRAGTYPE_RESCALELEFT ||
  2101. m_nDragType == DRAGTYPE_RESCALERIGHT )
  2102. {
  2103. int c = m_FocusRects.Count();
  2104. int m_nStart = INT_MAX;
  2105. int m_nEnd = INT_MIN;
  2106. for ( int i = 0; i < c; ++i )
  2107. {
  2108. CFocusRect *f = &m_FocusRects[ i ];
  2109. if ( f->m_rcFocus.left < m_nStart )
  2110. {
  2111. m_nStart = f->m_rcFocus.left;
  2112. }
  2113. if ( f->m_rcFocus.right > m_nEnd )
  2114. {
  2115. m_nEnd = f->m_rcFocus.right;
  2116. }
  2117. }
  2118. // Now figure out rescaling logic
  2119. int dxPixels = mx - m_xStart;
  2120. int oldSize = m_nEnd - m_nStart;
  2121. if ( oldSize > 0 )
  2122. {
  2123. float rescale = 1.0f;
  2124. if ( m_nDragType == DRAGTYPE_RESCALERIGHT )
  2125. {
  2126. rescale = (float)( oldSize + dxPixels )/(float)oldSize;
  2127. }
  2128. else
  2129. {
  2130. rescale = (float)( oldSize - dxPixels )/(float)oldSize;
  2131. }
  2132. for ( int i = 0; i < c; ++i )
  2133. {
  2134. CFocusRect *f = &m_FocusRects[ i ];
  2135. int w = f->m_rcFocus.right - f->m_rcFocus.left;
  2136. if ( m_nDragType == DRAGTYPE_RESCALERIGHT )
  2137. {
  2138. f->m_rcFocus.left = m_nStart + ( int )( rescale * (float)( f->m_rcFocus.left - m_nStart ) + 0.5f );
  2139. f->m_rcFocus.right = f->m_rcFocus.left + ( int )( rescale * (float)w + 0.5f );
  2140. }
  2141. else
  2142. {
  2143. f->m_rcFocus.right = m_nEnd - ( int )( rescale * (float)( m_nEnd - f->m_rcFocus.right ) + 0.5f );
  2144. f->m_rcFocus.left = f->m_rcFocus.right - ( int )( rescale * (float)w + 0.5f );
  2145. }
  2146. }
  2147. }
  2148. }
  2149. DrawFocusRect();
  2150. }
  2151. //-----------------------------------------------------------------------------
  2152. // Purpose:
  2153. // Input : mx -
  2154. // my -
  2155. //-----------------------------------------------------------------------------
  2156. void CChoreoView::MouseMove( int mx, int my )
  2157. {
  2158. if ( m_bDragging )
  2159. return;
  2160. int dragtype = ComputeEventDragType( mx, my );
  2161. if ( dragtype == DRAGTYPE_NONE )
  2162. {
  2163. CChoreoGlobalEventWidget *ge = NULL;
  2164. GetObjectsUnderMouse( mx, my, NULL, NULL, NULL, &ge, NULL, NULL, NULL );
  2165. if ( ge )
  2166. {
  2167. dragtype = DRAGTYPE_EVENT_MOVE;
  2168. }
  2169. if ( dragtype == DRAGTYPE_NONE )
  2170. {
  2171. if ( IsMouseOverSceneEndTime( mx ) )
  2172. {
  2173. dragtype = DRAGTYPE_SCENE_ENDTIME;
  2174. }
  2175. }
  2176. }
  2177. if ( m_hPrevCursor )
  2178. {
  2179. SetCursor( m_hPrevCursor );
  2180. m_hPrevCursor = NULL;
  2181. }
  2182. switch ( dragtype )
  2183. {
  2184. default:
  2185. break;
  2186. case DRAGTYPE_EVENTTAG_MOVE:
  2187. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  2188. break;
  2189. case DRAGTYPE_EVENTABSTAG_MOVE:
  2190. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_IBEAM ) );
  2191. break;
  2192. case DRAGTYPE_EVENT_MOVE:
  2193. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEALL ) );
  2194. break;
  2195. case DRAGTYPE_EVENT_STARTTIME:
  2196. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2197. case DRAGTYPE_EVENT_ENDTIME:
  2198. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2199. case DRAGTYPE_SCENE_ENDTIME:
  2200. case DRAGTYPE_RESCALELEFT:
  2201. case DRAGTYPE_RESCALERIGHT:
  2202. m_hPrevCursor = SetCursor( LoadCursor( NULL, IDC_SIZEWE ) );
  2203. break;
  2204. }
  2205. }
  2206. //-----------------------------------------------------------------------------
  2207. // Purpose:
  2208. // Input : *e -
  2209. // Output : Returns true on success, false on failure.
  2210. //-----------------------------------------------------------------------------
  2211. bool CChoreoView::CheckGestureLength( CChoreoEvent *e, bool bCheckOnly )
  2212. {
  2213. Assert( e );
  2214. if ( !e )
  2215. return false;
  2216. if ( e->GetType() != CChoreoEvent::GESTURE )
  2217. {
  2218. Con_Printf( "CheckGestureLength: called on non-GESTURE event %s\n", e->GetName() );
  2219. return false;
  2220. }
  2221. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2222. if ( !model )
  2223. return false;
  2224. CStudioHdr *pStudioHdr = model->GetStudioHdr();
  2225. if ( !pStudioHdr )
  2226. return false;
  2227. return UpdateGestureLength( e, pStudioHdr, model->GetPoseParameters(), bCheckOnly );
  2228. }
  2229. //-----------------------------------------------------------------------------
  2230. // Purpose:
  2231. // Input : *e -
  2232. // Output : Returns true on success, false on failure.
  2233. //-----------------------------------------------------------------------------
  2234. bool CChoreoView::DefaultGestureLength( CChoreoEvent *e, bool bCheckOnly )
  2235. {
  2236. Assert( e );
  2237. if ( !e )
  2238. return false;
  2239. if ( e->GetType() != CChoreoEvent::GESTURE )
  2240. {
  2241. Con_Printf( "DefaultGestureLength: called on non-GESTURE event %s\n", e->GetName() );
  2242. return false;
  2243. }
  2244. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2245. if ( !model )
  2246. return false;
  2247. if ( !model->GetStudioHdr() )
  2248. return false;
  2249. int iSequence = model->LookupSequence( e->GetParameters() );
  2250. if ( iSequence < 0 )
  2251. return false;
  2252. bool bret = false;
  2253. float seqduration = model->GetDuration( iSequence );
  2254. if ( seqduration != 0.0f )
  2255. {
  2256. bret = true;
  2257. if ( !bCheckOnly )
  2258. {
  2259. e->SetEndTime( e->GetStartTime() + seqduration );
  2260. }
  2261. }
  2262. return bret;
  2263. }
  2264. //-----------------------------------------------------------------------------
  2265. // Purpose:
  2266. // Input : *e -
  2267. // Output : Returns true on success, false on failure.
  2268. //-----------------------------------------------------------------------------
  2269. bool CChoreoView::AutoaddGestureKeys( CChoreoEvent *e, bool bCheckOnly )
  2270. {
  2271. if ( !e )
  2272. return false;
  2273. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2274. if ( !model )
  2275. return false;
  2276. CStudioHdr *pStudioHdr = model->GetStudioHdr();
  2277. if ( !pStudioHdr )
  2278. return false;
  2279. return AutoAddGestureKeys( e, pStudioHdr, model->GetPoseParameters(), bCheckOnly );
  2280. }
  2281. //-----------------------------------------------------------------------------
  2282. // Purpose:
  2283. //-----------------------------------------------------------------------------
  2284. bool CChoreoView::CheckSequenceLength( CChoreoEvent *e, bool bCheckOnly )
  2285. {
  2286. Assert( e );
  2287. if ( !e )
  2288. return false;
  2289. if ( e->GetType() != CChoreoEvent::SEQUENCE )
  2290. {
  2291. Con_Printf( "CheckSequenceLength: called on non-SEQUENCE event %s\n", e->GetName() );
  2292. return false;
  2293. }
  2294. StudioModel *model = FindAssociatedModel( e->GetScene(), e->GetActor() );
  2295. if ( !model )
  2296. return false;
  2297. CStudioHdr *pStudioHdr = model->GetStudioHdr();
  2298. if ( !pStudioHdr )
  2299. return false;
  2300. return UpdateSequenceLength( e, pStudioHdr, model->GetPoseParameters(), bCheckOnly, true );
  2301. }
  2302. void CChoreoView::FinishDraggingSceneEndTime( mxEvent *event, int mx, int my )
  2303. {
  2304. DrawFocusRect();
  2305. m_FocusRects.Purge();
  2306. m_bDragging = false;
  2307. float mouse_dt = GetTimeDeltaForMouseDelta( mx, m_xStart );
  2308. if ( !mouse_dt )
  2309. {
  2310. return;
  2311. }
  2312. SetDirty( true );
  2313. const char *desc = "Change Scene Duration";
  2314. PushUndo( desc );
  2315. float newendtime = GetTimeValueForMouse( mx );
  2316. float oldendtime = m_pScene->FindStopTime();
  2317. float scene_dt = newendtime - oldendtime;
  2318. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  2319. {
  2320. CChoreoActorWidget *a = m_SceneActors[ i ];
  2321. if ( !a )
  2322. continue;
  2323. for ( int j = 0; j < a->GetNumChannels(); j++ )
  2324. {
  2325. CChoreoChannelWidget *channel = a->GetChannel( j );
  2326. if ( !channel )
  2327. continue;
  2328. int k;
  2329. CChoreoEvent *finalGesture = NULL;
  2330. for ( k = channel->GetNumEvents() - 1; k >= 0; k-- )
  2331. {
  2332. CChoreoEventWidget *event = channel->GetEvent( k );
  2333. CChoreoEvent *e = event->GetEvent();
  2334. if ( e->GetType() != CChoreoEvent::GESTURE )
  2335. continue;
  2336. if ( !finalGesture )
  2337. {
  2338. finalGesture = e;
  2339. }
  2340. else
  2341. {
  2342. if ( e->GetStartTime() > finalGesture->GetStartTime() )
  2343. {
  2344. finalGesture = e;
  2345. }
  2346. }
  2347. }
  2348. for ( k = channel->GetNumEvents() - 1; k >= 0; k-- )
  2349. {
  2350. CChoreoEventWidget *event = channel->GetEvent( k );
  2351. CChoreoEvent *e = event->GetEvent();
  2352. // Event starts after new end time, kill it
  2353. if ( e->GetStartTime() > newendtime )
  2354. {
  2355. channel->GetChannel()->RemoveEvent( e );
  2356. m_pScene->DeleteReferencedObjects( e );
  2357. continue;
  2358. }
  2359. // No change to normal events that end earlier than new time (but do change gestures)
  2360. if ( e->GetEndTime() < newendtime &&
  2361. e != finalGesture )
  2362. {
  2363. continue;
  2364. }
  2365. float dt = scene_dt;
  2366. if ( e->GetType() == CChoreoEvent::GESTURE )
  2367. {
  2368. if ( e->GetEndTime() < newendtime )
  2369. {
  2370. dt = newendtime - e->GetEndTime();
  2371. }
  2372. }
  2373. float newduration = e->GetDuration() + dt;
  2374. RescaleRamp( e, newduration );
  2375. switch ( e->GetType() )
  2376. {
  2377. default:
  2378. break;
  2379. case CChoreoEvent::GESTURE:
  2380. {
  2381. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() + dt, true );
  2382. }
  2383. break;
  2384. case CChoreoEvent::FLEXANIMATION:
  2385. {
  2386. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() + dt );
  2387. }
  2388. break;
  2389. }
  2390. e->OffsetEndTime( dt );
  2391. e->SnapTimes();
  2392. e->ResortRamp();
  2393. }
  2394. }
  2395. }
  2396. // Remove event and move to new object
  2397. DeleteSceneWidgets();
  2398. m_nDragType = DRAGTYPE_NONE;
  2399. if ( m_hPrevCursor )
  2400. {
  2401. SetCursor( m_hPrevCursor );
  2402. m_hPrevCursor = 0;
  2403. }
  2404. PushRedo( desc );
  2405. CreateSceneWidgets();
  2406. InvalidateLayout();
  2407. g_pExpressionTool->LayoutItems( true );
  2408. g_pExpressionTool->redraw();
  2409. g_pGestureTool->redraw();
  2410. g_pRampTool->redraw();
  2411. g_pSceneRampTool->redraw();
  2412. }
  2413. //-----------------------------------------------------------------------------
  2414. // Purpose: Called after association changes to reset .wav file images
  2415. // Input : -
  2416. //-----------------------------------------------------------------------------
  2417. void CChoreoView::RecomputeWaves()
  2418. {
  2419. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  2420. {
  2421. CChoreoActorWidget *a = m_SceneActors[ i ];
  2422. if ( !a )
  2423. continue;
  2424. for ( int j = 0; j < a->GetNumChannels(); j++ )
  2425. {
  2426. CChoreoChannelWidget *c = a->GetChannel( j );
  2427. if ( !c )
  2428. continue;
  2429. for ( int k = 0; k < c->GetNumEvents(); k++ )
  2430. {
  2431. CChoreoEventWidget *e = c->GetEvent( k );
  2432. if ( !e )
  2433. continue;
  2434. e->RecomputeWave();
  2435. }
  2436. }
  2437. }
  2438. }
  2439. //-----------------------------------------------------------------------------
  2440. // Purpose:
  2441. // Input : mx -
  2442. // my -
  2443. //-----------------------------------------------------------------------------
  2444. void CChoreoView::FinishDraggingEvent( mxEvent *event, int mx, int my )
  2445. {
  2446. DrawFocusRect();
  2447. m_FocusRects.Purge();
  2448. m_bDragging = false;
  2449. float dt = GetTimeDeltaForMouseDelta( mx, m_xStart );
  2450. if ( !dt )
  2451. {
  2452. if ( m_pScene && m_pClickedEvent && m_pClickedEvent->GetEvent()->GetType() == CChoreoEvent::SPEAK )
  2453. {
  2454. // Show phone wav in wav viewer
  2455. char sndname[ 512 ];
  2456. Q_strncpy( sndname, FacePoser_TranslateSoundName( m_pClickedEvent->GetEvent() ), sizeof( sndname ) );
  2457. if ( sndname[ 0 ] )
  2458. {
  2459. SetCurrentWaveFile( va( "sound/%s", sndname ), m_pClickedEvent->GetEvent() );
  2460. }
  2461. else
  2462. {
  2463. Warning( "Unable to resolve sound name for '%s', check actor associations\n", m_pClickedEvent->GetEvent()->GetName() );
  2464. }
  2465. }
  2466. return;
  2467. }
  2468. SetDirty( true );
  2469. char const *desc = "";
  2470. switch ( m_nDragType )
  2471. {
  2472. default:
  2473. case DRAGTYPE_EVENT_MOVE:
  2474. desc = "Event Move";
  2475. break;
  2476. case DRAGTYPE_EVENT_STARTTIME:
  2477. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2478. desc = "Change Start Time";
  2479. break;
  2480. case DRAGTYPE_EVENT_ENDTIME:
  2481. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2482. desc = "Change End Time";
  2483. break;
  2484. case DRAGTYPE_EVENTTAG_MOVE:
  2485. desc = "Move Event Tag";
  2486. break;
  2487. case DRAGTYPE_EVENTABSTAG_MOVE:
  2488. desc = "Move Abs Event Tag";
  2489. break;
  2490. case DRAGTYPE_RESCALELEFT:
  2491. case DRAGTYPE_RESCALERIGHT:
  2492. desc = "Rescale Time";
  2493. break;
  2494. }
  2495. PushUndo( desc );
  2496. CUtlVector< CChoreoEvent * > rescaleHelper;
  2497. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  2498. {
  2499. CChoreoActorWidget *actor = m_SceneActors[ i ];
  2500. if ( !actor )
  2501. continue;
  2502. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  2503. {
  2504. CChoreoChannelWidget *channel = actor->GetChannel( j );
  2505. if ( !channel )
  2506. continue;
  2507. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  2508. {
  2509. CChoreoEventWidget *event = channel->GetEvent( k );
  2510. if ( !event )
  2511. continue;
  2512. if ( !event->IsSelected() )
  2513. continue;
  2514. // Figure out true dt
  2515. CChoreoEvent *e = event->GetEvent();
  2516. if ( e )
  2517. {
  2518. switch ( m_nDragType )
  2519. {
  2520. default:
  2521. case DRAGTYPE_EVENT_MOVE:
  2522. e->OffsetTime( dt );
  2523. e->SnapTimes();
  2524. break;
  2525. case DRAGTYPE_EVENT_STARTTIME:
  2526. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2527. {
  2528. float newduration = e->GetDuration() - dt;
  2529. RescaleRamp( e, newduration );
  2530. switch ( e->GetType() )
  2531. {
  2532. default:
  2533. break;
  2534. case CChoreoEvent::GESTURE:
  2535. {
  2536. e->RescaleGestureTimes( e->GetStartTime() + dt, e->GetEndTime(), m_nDragType == DRAGTYPE_EVENT_STARTTIME );
  2537. }
  2538. break;
  2539. case CChoreoEvent::FLEXANIMATION:
  2540. {
  2541. RescaleExpressionTimes( e, e->GetStartTime() + dt, e->GetEndTime() );
  2542. }
  2543. break;
  2544. }
  2545. e->OffsetStartTime( dt );
  2546. e->SnapTimes();
  2547. e->ResortRamp();
  2548. }
  2549. break;
  2550. case DRAGTYPE_EVENT_ENDTIME:
  2551. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2552. {
  2553. float newduration = e->GetDuration() + dt;
  2554. RescaleRamp( e, newduration );
  2555. switch ( e->GetType() )
  2556. {
  2557. default:
  2558. break;
  2559. case CChoreoEvent::GESTURE:
  2560. {
  2561. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() + dt, m_nDragType == DRAGTYPE_EVENT_ENDTIME );
  2562. }
  2563. break;
  2564. case CChoreoEvent::FLEXANIMATION:
  2565. {
  2566. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() + dt );
  2567. }
  2568. break;
  2569. }
  2570. e->OffsetEndTime( dt );
  2571. e->SnapTimes();
  2572. e->ResortRamp();
  2573. }
  2574. break;
  2575. case DRAGTYPE_RESCALELEFT:
  2576. case DRAGTYPE_RESCALERIGHT:
  2577. {
  2578. rescaleHelper.AddToTail( e );
  2579. }
  2580. break;
  2581. case DRAGTYPE_EVENTTAG_MOVE:
  2582. {
  2583. // Get current x position
  2584. if ( m_nClickedTag != -1 )
  2585. {
  2586. CEventRelativeTag *tag = e->GetRelativeTag( m_nClickedTag );
  2587. if ( tag )
  2588. {
  2589. float dx = mx - m_xStart;
  2590. // Determine left edcge
  2591. RECT bounds;
  2592. bounds = event->getBounds();
  2593. if ( bounds.right - bounds.left > 0 )
  2594. {
  2595. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  2596. left += dx;
  2597. if ( left < bounds.left )
  2598. {
  2599. left = bounds.left;
  2600. }
  2601. else if ( left >= bounds.right )
  2602. {
  2603. left = bounds.right - 1;
  2604. }
  2605. // Now convert back to a percentage
  2606. float frac = (float)( left - bounds.left ) / (float)( bounds.right - bounds.left );
  2607. tag->SetPercentage( frac );
  2608. }
  2609. }
  2610. }
  2611. }
  2612. break;
  2613. case DRAGTYPE_EVENTABSTAG_MOVE:
  2614. {
  2615. // Get current x position
  2616. if ( m_pClickedAbsoluteTag != NULL )
  2617. {
  2618. CEventAbsoluteTag *tag = m_pClickedAbsoluteTag;
  2619. if ( tag )
  2620. {
  2621. float dx = mx - m_xStart;
  2622. // Determine left edcge
  2623. RECT bounds;
  2624. bounds = event->getBounds();
  2625. if ( bounds.right - bounds.left > 0 )
  2626. {
  2627. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  2628. left += dx;
  2629. if ( left < bounds.left )
  2630. {
  2631. left = bounds.left;
  2632. }
  2633. else if ( left >= bounds.right )
  2634. {
  2635. left = bounds.right - 1;
  2636. }
  2637. // Now convert back to a percentage
  2638. float frac = (float)( left - bounds.left ) / (float)( bounds.right - bounds.left );
  2639. tag->SetPercentage( frac );
  2640. }
  2641. }
  2642. }
  2643. }
  2644. break;
  2645. }
  2646. }
  2647. switch ( e->GetType() )
  2648. {
  2649. default:
  2650. break;
  2651. case CChoreoEvent::SPEAK:
  2652. {
  2653. // Try and load wav to get length
  2654. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  2655. if ( wave )
  2656. {
  2657. e->SetEndTime( e->GetStartTime() + wave->GetRunningLength() );
  2658. delete wave;
  2659. }
  2660. }
  2661. break;
  2662. case CChoreoEvent::SEQUENCE:
  2663. {
  2664. CheckSequenceLength( e, false );
  2665. }
  2666. break;
  2667. case CChoreoEvent::GESTURE:
  2668. {
  2669. CheckGestureLength( e, false );
  2670. }
  2671. break;
  2672. }
  2673. }
  2674. }
  2675. }
  2676. if ( rescaleHelper.Count() > 0 )
  2677. {
  2678. int i;
  2679. // Determine start and end times for existing "selection"
  2680. float flStart = FLT_MAX;
  2681. float flEnd = FLT_MIN;
  2682. for ( i = 0; i < rescaleHelper.Count(); ++i )
  2683. {
  2684. CChoreoEvent *e = rescaleHelper[ i ];
  2685. float st = e->GetStartTime();
  2686. float ed = e->GetEndTime();
  2687. if ( st < flStart )
  2688. {
  2689. flStart = st;
  2690. }
  2691. if ( ed > flEnd )
  2692. {
  2693. flEnd = ed;
  2694. }
  2695. }
  2696. float flSelectionDuration = flEnd - flStart;
  2697. if ( flSelectionDuration > 0.0f )
  2698. {
  2699. float flNewDuration = 0.0f;
  2700. if ( m_nDragType == DRAGTYPE_RESCALELEFT )
  2701. {
  2702. flNewDuration = max( 0.1f, flSelectionDuration - dt );
  2703. }
  2704. else
  2705. {
  2706. flNewDuration = max( 0.1f, flSelectionDuration + dt );
  2707. }
  2708. float flScale = flNewDuration / flSelectionDuration;
  2709. for ( i = 0; i < rescaleHelper.Count(); ++i )
  2710. {
  2711. CChoreoEvent *e = rescaleHelper[ i ];
  2712. float st = e->GetStartTime();
  2713. float et = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime();
  2714. float flTimeFromStart = st - flStart;
  2715. float flTimeFromEnd = flEnd - et;
  2716. float flDuration = e->GetDuration();
  2717. float flNewStartTime = 0.0f;
  2718. float flNewDuration = 0.0f;
  2719. if ( m_nDragType == DRAGTYPE_RESCALELEFT )
  2720. {
  2721. float flNewEndTime = flEnd - flTimeFromEnd * flScale;
  2722. if ( !e->HasEndTime() || e->IsFixedLength() )
  2723. {
  2724. e->OffsetTime( flNewEndTime - flDuration - st );
  2725. continue;
  2726. }
  2727. flNewDuration = flDuration * flScale;
  2728. flNewStartTime = flNewEndTime - flNewDuration;
  2729. }
  2730. else
  2731. {
  2732. flNewStartTime = flTimeFromStart * flScale + flStart;
  2733. if ( !e->HasEndTime() || e->IsFixedLength() )
  2734. {
  2735. e->OffsetTime( flNewStartTime - st );
  2736. continue;
  2737. }
  2738. flNewDuration = flDuration * flScale;
  2739. }
  2740. RescaleRamp( e, flNewDuration );
  2741. switch ( e->GetType() )
  2742. {
  2743. default:
  2744. break;
  2745. case CChoreoEvent::GESTURE:
  2746. {
  2747. e->RescaleGestureTimes( flNewStartTime, flNewStartTime + flNewDuration, m_nDragType == DRAGTYPE_EVENT_STARTTIME || m_nDragType == DRAGTYPE_EVENT_ENDTIME );
  2748. }
  2749. break;
  2750. case CChoreoEvent::FLEXANIMATION:
  2751. {
  2752. RescaleExpressionTimes( e, flNewStartTime, flNewStartTime + flNewDuration );
  2753. }
  2754. break;
  2755. }
  2756. e->SetStartTime( flNewStartTime );
  2757. Assert( e->HasEndTime() );
  2758. e->SetEndTime( flNewStartTime + flNewDuration );
  2759. }
  2760. }
  2761. }
  2762. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  2763. {
  2764. CChoreoGlobalEventWidget *gew = m_SceneGlobalEvents[ i ];
  2765. if ( !gew || !gew->IsSelected() )
  2766. continue;
  2767. CChoreoEvent *e = gew->GetEvent();
  2768. if ( !e )
  2769. continue;
  2770. e->OffsetTime( dt );
  2771. e->SnapTimes();
  2772. }
  2773. m_nDragType = DRAGTYPE_NONE;
  2774. if ( m_hPrevCursor )
  2775. {
  2776. SetCursor( m_hPrevCursor );
  2777. m_hPrevCursor = 0;
  2778. }
  2779. CChoreoEvent *e = m_pClickedEvent ? m_pClickedEvent->GetEvent() : NULL;
  2780. if ( e )
  2781. {
  2782. // See if event is moving to a new owner
  2783. CChoreoChannelWidget *chOrig, *chNew;
  2784. int dy = my - m_yStart;
  2785. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  2786. if ( !shiftdown )
  2787. {
  2788. dy = 0;
  2789. }
  2790. if ( abs( dy ) < m_pClickedEvent->GetItemHeight() )
  2791. {
  2792. my = m_yStart;
  2793. }
  2794. chNew = GetChannelUnderCursorPos( mx, my );
  2795. InvalidateLayout();
  2796. mx = m_xStart;
  2797. my = m_yStart;
  2798. chOrig = m_pClickedChannel;
  2799. if ( chOrig && chNew && chOrig != chNew )
  2800. {
  2801. // Swap underlying objects
  2802. CChoreoChannel *pOrigChannel, *pNewChannel;
  2803. pOrigChannel = chOrig->GetChannel();
  2804. pNewChannel = chNew->GetChannel();
  2805. Assert( pOrigChannel && pNewChannel );
  2806. // Remove event and move to new object
  2807. DeleteSceneWidgets();
  2808. pOrigChannel->RemoveEvent( e );
  2809. pNewChannel->AddEvent( e );
  2810. e->SetChannel( pNewChannel );
  2811. e->SetActor( pNewChannel->GetActor() );
  2812. CreateSceneWidgets();
  2813. }
  2814. else
  2815. {
  2816. if ( e && e->GetType() == CChoreoEvent::SPEAK )
  2817. {
  2818. // Show phone wav in wav viewer
  2819. SetCurrentWaveFile( va( "sound/%s", FacePoser_TranslateSoundName( e ) ), e );
  2820. }
  2821. }
  2822. }
  2823. PushRedo( desc );
  2824. InvalidateLayout();
  2825. if ( e )
  2826. {
  2827. switch ( e->GetType() )
  2828. {
  2829. default:
  2830. break;
  2831. case CChoreoEvent::FLEXANIMATION:
  2832. {
  2833. g_pExpressionTool->SetEvent( e );
  2834. g_pFlexPanel->SetEvent( e );
  2835. }
  2836. break;
  2837. case CChoreoEvent::GESTURE:
  2838. {
  2839. g_pGestureTool->SetEvent( e );
  2840. }
  2841. break;
  2842. }
  2843. if ( e->HasEndTime() )
  2844. {
  2845. g_pRampTool->SetEvent( e );
  2846. }
  2847. }
  2848. g_pExpressionTool->LayoutItems( true );
  2849. g_pExpressionTool->redraw();
  2850. g_pGestureTool->redraw();
  2851. g_pRampTool->redraw();
  2852. g_pSceneRampTool->redraw();
  2853. }
  2854. //-----------------------------------------------------------------------------
  2855. // Purpose:
  2856. // Input : mx -
  2857. // my -
  2858. //-----------------------------------------------------------------------------
  2859. void CChoreoView::MouseFinishDrag( mxEvent *event, int mx, int my )
  2860. {
  2861. if ( !m_bDragging )
  2862. return;
  2863. ApplyBounds( mx, my );
  2864. switch ( m_nDragType )
  2865. {
  2866. case DRAGTYPE_SCRUBBER:
  2867. {
  2868. DrawFocusRect();
  2869. m_FocusRects.Purge();
  2870. float t = GetTimeValueForMouse( mx );
  2871. t += m_flScrubberTimeOffset;
  2872. m_flScrubberTimeOffset = 0.0f;
  2873. ClampTimeToSelectionInterval( t );
  2874. SetScrubTime( t );
  2875. SetScrubTargetTime( t );
  2876. m_bDragging = false;
  2877. m_nDragType = DRAGTYPE_NONE;
  2878. redraw();
  2879. }
  2880. break;
  2881. case DRAGTYPE_EVENT_MOVE:
  2882. case DRAGTYPE_EVENT_STARTTIME:
  2883. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  2884. case DRAGTYPE_EVENT_ENDTIME:
  2885. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  2886. case DRAGTYPE_EVENTTAG_MOVE:
  2887. case DRAGTYPE_EVENTABSTAG_MOVE:
  2888. case DRAGTYPE_RESCALELEFT:
  2889. case DRAGTYPE_RESCALERIGHT:
  2890. FinishDraggingEvent( event, mx, my );
  2891. break;
  2892. case DRAGTYPE_SCENE_ENDTIME:
  2893. FinishDraggingSceneEndTime( event, mx, my );
  2894. break;
  2895. default:
  2896. break;
  2897. }
  2898. }
  2899. //-----------------------------------------------------------------------------
  2900. // Purpose:
  2901. // Input : *event -
  2902. // Output : int
  2903. //-----------------------------------------------------------------------------
  2904. int CChoreoView::handleEvent( mxEvent *event )
  2905. {
  2906. MDLCACHE_CRITICAL_SECTION_( g_pMDLCache );
  2907. int iret = 0;
  2908. if ( HandleToolEvent( event ) )
  2909. {
  2910. return iret;
  2911. }
  2912. switch ( event->event )
  2913. {
  2914. case mxEvent::MouseWheeled:
  2915. {
  2916. CChoreoScene *scene = GetScene();
  2917. if ( scene )
  2918. {
  2919. int tz = GetTimeZoom( GetToolName() );
  2920. bool shiftdown = ( event->modifiers & mxEvent::KeyShift ) ? true : false;
  2921. int stepMultipiler = shiftdown ? 5 : 1;
  2922. // Zoom time in / out
  2923. if ( event->height > 0 )
  2924. {
  2925. tz = min( tz + TIME_ZOOM_STEP * stepMultipiler, MAX_TIME_ZOOM );
  2926. }
  2927. else
  2928. {
  2929. tz = max( tz - TIME_ZOOM_STEP * stepMultipiler, TIME_ZOOM_STEP );
  2930. }
  2931. SetTimeZoom( GetToolName(), tz, true );
  2932. CUtlVector< CChoreoEvent * > selected;
  2933. RememberSelectedEvents( selected );
  2934. DeleteSceneWidgets();
  2935. CreateSceneWidgets();
  2936. ReselectEvents( selected );
  2937. InvalidateLayout();
  2938. Con_Printf( "Zoom factor %i %%\n", GetTimeZoom( GetToolName() ) );
  2939. }
  2940. iret = 1;
  2941. }
  2942. break;
  2943. case mxEvent::Size:
  2944. {
  2945. // Force scroll bars to recompute
  2946. ForceScrollBarsToRecompute( false );
  2947. InvalidateLayout();
  2948. PositionControls();
  2949. iret = 1;
  2950. }
  2951. break;
  2952. case mxEvent::MouseDown:
  2953. {
  2954. if ( !m_bDragging )
  2955. {
  2956. if ( event->buttons & mxEvent::MouseRightButton )
  2957. {
  2958. if ( IsMouseOverTimeline( (short)event->x, (short)event->y ) )
  2959. {
  2960. PlaceABPoint( (short)event->x );
  2961. redraw();
  2962. }
  2963. else if ( IsMouseOverScrubArea( event ) )
  2964. {
  2965. float t = GetTimeValueForMouse( (short)event->x );
  2966. ClampTimeToSelectionInterval( t );
  2967. SetScrubTime( t );
  2968. SetScrubTargetTime( t );
  2969. sound->Flush();
  2970. // Unpause the scene
  2971. m_bPaused = false;
  2972. redraw();
  2973. }
  2974. else
  2975. {
  2976. // Show right click menu
  2977. ShowContextMenu( (short)event->x, (short)event->y );
  2978. }
  2979. }
  2980. else
  2981. {
  2982. if ( IsMouseOverTimeline( (short)event->x, (short)event->y ) )
  2983. {
  2984. ClearABPoints();
  2985. redraw();
  2986. }
  2987. else
  2988. {
  2989. // Handle mouse dragging here
  2990. MouseStartDrag( event, (short)event->x, (short)event->y );
  2991. }
  2992. }
  2993. }
  2994. iret = 1;
  2995. }
  2996. break;
  2997. case mxEvent::MouseDrag:
  2998. {
  2999. MouseContinueDrag( event, (short)event->x, (short)event->y );
  3000. iret = 1;
  3001. }
  3002. break;
  3003. case mxEvent::MouseUp:
  3004. {
  3005. MouseFinishDrag( event, (short)event->x, (short)event->y );
  3006. iret = 1;
  3007. }
  3008. break;
  3009. case mxEvent::MouseMove:
  3010. {
  3011. MouseMove( (short)event->x, (short)event->y );
  3012. UpdateStatusArea( (short)event->x, (short)event->y );
  3013. iret = 1;
  3014. }
  3015. break;
  3016. case mxEvent::KeyDown:
  3017. {
  3018. iret = 1;
  3019. switch ( event->key )
  3020. {
  3021. default:
  3022. iret = 0;
  3023. break;
  3024. case 'E':
  3025. if ( GetAsyncKeyState( VK_CONTROL ) )
  3026. {
  3027. OnPlaceNextSpeakEvent();
  3028. }
  3029. break;
  3030. case VK_ESCAPE:
  3031. DeselectAll();
  3032. break;
  3033. case 'C':
  3034. CopyEvents();
  3035. iret = 1;
  3036. break;
  3037. case 'V':
  3038. PasteEvents();
  3039. redraw();
  3040. break;
  3041. case VK_DELETE:
  3042. {
  3043. if ( IsActiveTool() )
  3044. {
  3045. DeleteSelectedEvents();
  3046. }
  3047. }
  3048. break;
  3049. case VK_RETURN:
  3050. {
  3051. CUtlVector< CChoreoEvent * > events;
  3052. GetSelectedEvents( events );
  3053. if ( events.Count() == 1 )
  3054. {
  3055. if ( GetAsyncKeyState( VK_MENU ) )
  3056. {
  3057. EditEvent( events[ 0 ] );
  3058. redraw();
  3059. iret = 1;
  3060. }
  3061. }
  3062. }
  3063. break;
  3064. case 'Z': // Undo/Redo
  3065. {
  3066. if ( GetAsyncKeyState( VK_CONTROL ) )
  3067. {
  3068. if ( GetAsyncKeyState( VK_SHIFT ) )
  3069. {
  3070. if ( CanRedo() )
  3071. {
  3072. Con_Printf( "Redo %s\n", GetRedoDescription() );
  3073. Redo();
  3074. iret = 1;
  3075. }
  3076. }
  3077. else
  3078. {
  3079. if ( CanUndo() )
  3080. {
  3081. Con_Printf( "Undo %s\n", GetUndoDescription() );
  3082. Undo();
  3083. iret = 1;
  3084. }
  3085. }
  3086. }
  3087. }
  3088. break;
  3089. case VK_SPACE:
  3090. {
  3091. if ( IsPlayingScene() )
  3092. {
  3093. StopScene();
  3094. }
  3095. }
  3096. break;
  3097. case 188: // VK_OEM_COMMA:
  3098. {
  3099. SetScrubTargetTime( 0.0f );
  3100. }
  3101. break;
  3102. case 190: // VK_OEM_PERIOD:
  3103. {
  3104. CChoreoScene *scene = GetScene();
  3105. if ( scene )
  3106. {
  3107. SetScrubTargetTime( scene->FindStopTime() );
  3108. }
  3109. }
  3110. break;
  3111. case VK_LEFT:
  3112. {
  3113. CChoreoScene *scene = GetScene();
  3114. if ( scene && scene->GetSceneFPS() > 0 )
  3115. {
  3116. float curscrub = m_flScrub;
  3117. curscrub -= ( 1.0f / (float)scene->GetSceneFPS() );
  3118. curscrub = max( curscrub, 0.0f );
  3119. SetScrubTargetTime( curscrub );
  3120. }
  3121. }
  3122. break;
  3123. case VK_RIGHT:
  3124. {
  3125. CChoreoScene *scene = GetScene();
  3126. if ( scene && scene->GetSceneFPS() > 0 )
  3127. {
  3128. float curscrub = m_flScrub;
  3129. curscrub += ( 1.0f / (float)scene->GetSceneFPS() );
  3130. curscrub = min( curscrub, scene->FindStopTime() );
  3131. SetScrubTargetTime( curscrub );
  3132. }
  3133. }
  3134. break;
  3135. case VK_HOME:
  3136. {
  3137. MoveTimeSliderToPos( 0 );
  3138. }
  3139. break;
  3140. case VK_END:
  3141. {
  3142. float maxtime = m_pScene->FindStopTime() - 1.0f;
  3143. int pixels = (int)( maxtime * GetPixelsPerSecond() );
  3144. MoveTimeSliderToPos( pixels - 1 );
  3145. }
  3146. break;
  3147. case VK_PRIOR: // PgUp
  3148. {
  3149. int window = w2() - GetLabelWidth();
  3150. m_flLeftOffset = max( m_flLeftOffset - (float)window, 0.0f );
  3151. MoveTimeSliderToPos( (int)m_flLeftOffset );
  3152. }
  3153. break;
  3154. case VK_NEXT: // PgDown
  3155. {
  3156. int window = w2() - GetLabelWidth();
  3157. int pixels = ComputeHPixelsNeeded();
  3158. m_flLeftOffset = min( m_flLeftOffset + (float)window, (float)pixels );
  3159. MoveTimeSliderToPos( (int)m_flLeftOffset );
  3160. }
  3161. break;
  3162. }
  3163. }
  3164. break;
  3165. case mxEvent::Action:
  3166. {
  3167. iret = 1;
  3168. switch ( event->action )
  3169. {
  3170. default:
  3171. {
  3172. iret = 0;
  3173. int lang_index = event->action - IDC_CV_CC_LANGUAGESTART;
  3174. if ( lang_index >= 0 && lang_index < CC_NUM_LANGUAGES )
  3175. {
  3176. iret = 1;
  3177. SetCloseCaptionLanguageId( lang_index );
  3178. }
  3179. }
  3180. break;
  3181. case IDC_CV_TOGGLECLOSECAPTIONS:
  3182. {
  3183. OnToggleCloseCaptionsForEvent();
  3184. }
  3185. break;
  3186. case IDC_CV_CHANGECLOSECAPTIONTOKEN:
  3187. {
  3188. if ( m_pClickedChannel )
  3189. {
  3190. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  3191. if ( e && e->GetNumSlaves() >= 1 )
  3192. {
  3193. OnChangeCloseCaptionToken( e );
  3194. }
  3195. }
  3196. }
  3197. break;
  3198. case IDC_CV_REMOVESPEAKEVENTFROMGROUP:
  3199. {
  3200. OnRemoveSpeakEventFromGroup();
  3201. }
  3202. break;
  3203. case IDC_CV_COMBINESPEAKEVENTS:
  3204. {
  3205. OnCombineSpeakEvents();
  3206. }
  3207. break;
  3208. case IDC_CV_CC_SHOW:
  3209. {
  3210. OnToggleCloseCaptionTags();
  3211. }
  3212. break;
  3213. case IDC_CV_TOGGLERAMPONLY:
  3214. {
  3215. m_bRampOnly = !m_bRampOnly;
  3216. redraw();
  3217. }
  3218. break;
  3219. case IDC_CV_PROCESSSEQUENCES:
  3220. {
  3221. m_bProcessSequences = !m_bProcessSequences;
  3222. }
  3223. break;
  3224. case IDC_CV_CHECKSEQLENGTHS:
  3225. {
  3226. OnCheckSequenceLengths();
  3227. }
  3228. break;
  3229. case IDC_CV_CHANGESCALE:
  3230. {
  3231. OnChangeScale();
  3232. }
  3233. break;
  3234. case IDC_CHOREO_PLAYBACKRATE:
  3235. {
  3236. m_flPlaybackRate = m_pPlaybackRate->getValue();
  3237. redraw();
  3238. }
  3239. break;
  3240. case IDC_COPYEVENTS:
  3241. CopyEvents();
  3242. break;
  3243. case IDC_PASTEEVENTS:
  3244. PasteEvents();
  3245. redraw();
  3246. break;
  3247. case IDC_IMPORTEVENTS:
  3248. ImportEvents();
  3249. redraw();
  3250. break;
  3251. case IDC_EXPORTEVENTS:
  3252. ExportEvents();
  3253. redraw();
  3254. break;
  3255. case IDC_EXPORT_VCD:
  3256. ExportVCD();
  3257. redraw();
  3258. break;
  3259. case IDC_IMPORT_VCD:
  3260. ImportVCD();
  3261. redraw();
  3262. break;
  3263. case IDC_EXPRESSIONTOOL:
  3264. OnExpressionTool();
  3265. break;
  3266. case IDC_GESTURETOOL:
  3267. OnGestureTool();
  3268. break;
  3269. case IDC_ASSOCIATEBSP:
  3270. AssociateBSP();
  3271. break;
  3272. case IDC_ASSOCIATEMODEL:
  3273. AssociateModel();
  3274. break;
  3275. case IDC_CVUNDO:
  3276. Undo();
  3277. break;
  3278. case IDC_CVREDO:
  3279. Redo();
  3280. break;
  3281. case IDC_SELECTALL:
  3282. SelectAll();
  3283. break;
  3284. case IDC_DESELECTALL:
  3285. DeselectAll();
  3286. break;
  3287. case IDC_PLAYSCENE:
  3288. Con_Printf( "Commencing playback\n" );
  3289. PlayScene( true );
  3290. break;
  3291. case IDC_PAUSESCENE:
  3292. Con_Printf( "Pausing playback\n" );
  3293. PauseScene();
  3294. break;
  3295. case IDC_STOPSCENE:
  3296. Con_Printf( "Canceling playback\n" );
  3297. StopScene();
  3298. break;
  3299. case IDC_CHOREOVSCROLL:
  3300. {
  3301. int offset = 0;
  3302. bool processed = true;
  3303. switch ( event->modifiers )
  3304. {
  3305. case SB_THUMBTRACK:
  3306. offset = event->height;
  3307. break;
  3308. case SB_PAGEUP:
  3309. offset = m_pVertScrollBar->getValue();
  3310. offset -= 20;
  3311. offset = max( offset, m_pVertScrollBar->getMinValue() );
  3312. break;
  3313. case SB_PAGEDOWN:
  3314. offset = m_pVertScrollBar->getValue();
  3315. offset += 20;
  3316. offset = min( offset, m_pVertScrollBar->getMaxValue() );
  3317. break;
  3318. case SB_LINEDOWN:
  3319. offset = m_pVertScrollBar->getValue();
  3320. offset += 10;
  3321. offset = min( offset, m_pVertScrollBar->getMaxValue() );
  3322. break;
  3323. case SB_LINEUP:
  3324. offset = m_pVertScrollBar->getValue();
  3325. offset -= 10;
  3326. offset = max( offset, m_pVertScrollBar->getMinValue() );
  3327. break;
  3328. default:
  3329. processed = false;
  3330. break;
  3331. }
  3332. if ( processed )
  3333. {
  3334. m_pVertScrollBar->setValue( offset );
  3335. InvalidateRect( (HWND)m_pVertScrollBar->getHandle(), NULL, TRUE );
  3336. m_nTopOffset = offset;
  3337. InvalidateLayout();
  3338. }
  3339. }
  3340. break;
  3341. case IDC_CHOREOHSCROLL:
  3342. {
  3343. int offset = 0;
  3344. bool processed = true;
  3345. switch ( event->modifiers )
  3346. {
  3347. case SB_THUMBTRACK:
  3348. offset = event->height;
  3349. break;
  3350. case SB_PAGEUP:
  3351. offset = m_pHorzScrollBar->getValue();
  3352. offset -= 20;
  3353. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  3354. break;
  3355. case SB_PAGEDOWN:
  3356. offset = m_pHorzScrollBar->getValue();
  3357. offset += 20;
  3358. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  3359. break;
  3360. case SB_LINEUP:
  3361. offset = m_pHorzScrollBar->getValue();
  3362. offset -= 10;
  3363. offset = max( offset, m_pHorzScrollBar->getMinValue() );
  3364. break;
  3365. case SB_LINEDOWN:
  3366. offset = m_pHorzScrollBar->getValue();
  3367. offset += 10;
  3368. offset = min( offset, m_pHorzScrollBar->getMaxValue() );
  3369. break;
  3370. default:
  3371. processed = false;
  3372. break;
  3373. }
  3374. if ( processed )
  3375. {
  3376. MoveTimeSliderToPos( offset );
  3377. }
  3378. }
  3379. break;
  3380. case IDC_ADDACTOR:
  3381. {
  3382. NewActor();
  3383. }
  3384. break;
  3385. case IDC_EDITACTOR:
  3386. {
  3387. CChoreoActorWidget *actor = m_pClickedActor;
  3388. if ( actor )
  3389. {
  3390. EditActor( actor->GetActor() );
  3391. }
  3392. }
  3393. break;
  3394. case IDC_DELETEACTOR:
  3395. {
  3396. CChoreoActorWidget *actor = m_pClickedActor;
  3397. if ( actor )
  3398. {
  3399. DeleteActor( actor->GetActor() );
  3400. }
  3401. }
  3402. break;
  3403. case IDC_MOVEACTORUP:
  3404. {
  3405. CChoreoActorWidget *actor = m_pClickedActor;
  3406. if ( actor )
  3407. {
  3408. MoveActorUp( actor->GetActor() );
  3409. }
  3410. }
  3411. break;
  3412. case IDC_MOVEACTORDOWN:
  3413. {
  3414. CChoreoActorWidget *actor = m_pClickedActor;
  3415. if ( actor )
  3416. {
  3417. MoveActorDown( actor->GetActor() );
  3418. }
  3419. }
  3420. break;
  3421. case IDC_CHANNELOPEN:
  3422. {
  3423. CActorBitmapButton *btn = static_cast< CActorBitmapButton * >( event->widget );
  3424. if ( btn )
  3425. {
  3426. CChoreoActorWidget *a = btn->GetActor();
  3427. if ( a )
  3428. {
  3429. a->ShowChannels( true );
  3430. }
  3431. }
  3432. }
  3433. break;
  3434. case IDC_CHANNELCLOSE:
  3435. {
  3436. CActorBitmapButton *btn = static_cast< CActorBitmapButton * >( event->widget );
  3437. if ( btn )
  3438. {
  3439. CChoreoActorWidget *a = btn->GetActor();
  3440. if ( a )
  3441. {
  3442. a->ShowChannels( false );
  3443. }
  3444. }
  3445. }
  3446. break;
  3447. case IDC_ADDEVENT_INTERRUPT:
  3448. {
  3449. AddEvent( CChoreoEvent::INTERRUPT );
  3450. }
  3451. break;
  3452. case IDC_ADDEVENT_PERMITRESPONSES:
  3453. {
  3454. AddEvent( CChoreoEvent::PERMIT_RESPONSES );
  3455. }
  3456. break;
  3457. case IDC_ADDEVENT_EXPRESSION:
  3458. {
  3459. AddEvent( CChoreoEvent::EXPRESSION );
  3460. }
  3461. break;
  3462. case IDC_ADDEVENT_FLEXANIMATION:
  3463. {
  3464. AddEvent( CChoreoEvent::FLEXANIMATION );
  3465. }
  3466. break;
  3467. case IDC_ADDEVENT_GESTURE:
  3468. {
  3469. AddEvent( CChoreoEvent::GESTURE );
  3470. }
  3471. break;
  3472. case IDC_ADDEVENT_NULLGESTURE:
  3473. {
  3474. AddEvent( CChoreoEvent::GESTURE, 1 );
  3475. }
  3476. break;
  3477. case IDC_ADDEVENT_LOOKAT:
  3478. {
  3479. AddEvent( CChoreoEvent::LOOKAT );
  3480. }
  3481. break;
  3482. case IDC_ADDEVENT_MOVETO:
  3483. {
  3484. AddEvent( CChoreoEvent::MOVETO );
  3485. }
  3486. break;
  3487. case IDC_ADDEVENT_FACE:
  3488. {
  3489. AddEvent( CChoreoEvent::FACE );
  3490. }
  3491. break;
  3492. case IDC_ADDEVENT_SPEAK:
  3493. {
  3494. AddEvent( CChoreoEvent::SPEAK );
  3495. }
  3496. break;
  3497. case IDC_ADDEVENT_FIRETRIGGER:
  3498. {
  3499. AddEvent( CChoreoEvent::FIRETRIGGER );
  3500. }
  3501. break;
  3502. case IDC_ADDEVENT_GENERIC:
  3503. {
  3504. AddEvent( CChoreoEvent::GENERIC );
  3505. }
  3506. break;
  3507. case IDC_ADDEVENT_CAMERA:
  3508. {
  3509. AddEvent( CChoreoEvent::CAMERA );
  3510. }
  3511. break;
  3512. case IDC_ADDEVENT_SUBSCENE:
  3513. {
  3514. AddEvent( CChoreoEvent::SUBSCENE );
  3515. }
  3516. break;
  3517. case IDC_ADDEVENT_SEQUENCE:
  3518. {
  3519. AddEvent( CChoreoEvent::SEQUENCE );
  3520. }
  3521. break;
  3522. case IDC_EDITEVENT:
  3523. {
  3524. CChoreoEventWidget *event = m_pClickedEvent;
  3525. if ( event )
  3526. {
  3527. EditEvent( event->GetEvent() );
  3528. redraw();
  3529. }
  3530. }
  3531. break;
  3532. case IDC_DELETEEVENT:
  3533. {
  3534. DeleteSelectedEvents();
  3535. }
  3536. break;
  3537. case IDC_CV_ENABLEEVENTS:
  3538. {
  3539. EnableSelectedEvents( true );
  3540. }
  3541. break;
  3542. case IDC_CV_DISABLEEVENTS:
  3543. {
  3544. EnableSelectedEvents( false );
  3545. }
  3546. break;
  3547. case IDC_MOVETOBACK:
  3548. {
  3549. CChoreoEventWidget *event = m_pClickedEvent;
  3550. if ( event )
  3551. {
  3552. MoveEventToBack( event->GetEvent() );
  3553. }
  3554. }
  3555. break;
  3556. case IDC_DELETERELATIVETAG:
  3557. {
  3558. CChoreoEventWidget *event = m_pClickedEvent;
  3559. if ( event && m_nClickedTag >= 0 )
  3560. {
  3561. DeleteEventRelativeTag( event->GetEvent(), m_nClickedTag );
  3562. }
  3563. }
  3564. break;
  3565. case IDC_ADDTIMINGTAG:
  3566. {
  3567. AddEventRelativeTag();
  3568. }
  3569. break;
  3570. case IDC_ADDEVENT_PAUSE:
  3571. {
  3572. AddGlobalEvent( CChoreoEvent::SECTION );
  3573. }
  3574. break;
  3575. case IDC_ADDEVENT_LOOP:
  3576. {
  3577. AddGlobalEvent( CChoreoEvent::LOOP );
  3578. }
  3579. break;
  3580. case IDC_ADDEVENT_STOPPOINT:
  3581. {
  3582. AddGlobalEvent( CChoreoEvent::STOPPOINT );
  3583. }
  3584. break;
  3585. case IDC_EDITGLOBALEVENT:
  3586. {
  3587. CChoreoGlobalEventWidget *event = m_pClickedGlobalEvent;
  3588. if ( event )
  3589. {
  3590. EditGlobalEvent( event->GetEvent() );
  3591. redraw();
  3592. }
  3593. }
  3594. break;
  3595. case IDC_DELETEGLOBALEVENT:
  3596. {
  3597. CChoreoGlobalEventWidget *event = m_pClickedGlobalEvent;
  3598. if ( event )
  3599. {
  3600. DeleteGlobalEvent( event->GetEvent() );
  3601. }
  3602. }
  3603. break;
  3604. case IDC_ADDCHANNEL:
  3605. {
  3606. NewChannel();
  3607. }
  3608. break;
  3609. case IDC_EDITCHANNEL:
  3610. {
  3611. CChoreoChannelWidget *channel = m_pClickedChannel;
  3612. if ( channel )
  3613. {
  3614. EditChannel( channel->GetChannel() );
  3615. }
  3616. }
  3617. break;
  3618. case IDC_DELETECHANNEL:
  3619. {
  3620. CChoreoChannelWidget *channel = m_pClickedChannel;
  3621. if ( channel )
  3622. {
  3623. DeleteChannel( channel->GetChannel() );
  3624. }
  3625. }
  3626. break;
  3627. case IDC_MOVECHANNELUP:
  3628. {
  3629. CChoreoChannelWidget *channel = m_pClickedChannel;
  3630. if ( channel )
  3631. {
  3632. MoveChannelUp( channel->GetChannel() );
  3633. }
  3634. }
  3635. break;
  3636. case IDC_MOVECHANNELDOWN:
  3637. {
  3638. CChoreoChannelWidget *channel = m_pClickedChannel;
  3639. if ( channel )
  3640. {
  3641. MoveChannelDown( channel->GetChannel() );
  3642. }
  3643. }
  3644. break;
  3645. case IDC_CV_ALLEVENTS_CHANNEL:
  3646. {
  3647. CChoreoChannelWidget *channel = m_pClickedChannel;
  3648. if ( channel )
  3649. {
  3650. SelectAllEventsInChannel( channel );
  3651. }
  3652. }
  3653. break;
  3654. case IDC_CV_ALLEVENTS_ACTOR:
  3655. {
  3656. CChoreoActorWidget *actor = m_pClickedActor;
  3657. if ( actor )
  3658. {
  3659. SelectAllEventsInActor( actor );
  3660. }
  3661. }
  3662. break;
  3663. case IDC_SELECTEVENTS_ALL_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_ALL;
  3670. SelectEvents( params );
  3671. }
  3672. break;
  3673. case IDC_SELECTEVENTS_ALL_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_ALL;
  3680. SelectEvents( params );
  3681. }
  3682. break;
  3683. case IDC_SELECTEVENTS_ACTIVE_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_ACTIVE;
  3690. SelectEvents( params );
  3691. }
  3692. break;
  3693. case IDC_SELECTEVENTS_ACTIVE_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_ACTIVE;
  3700. SelectEvents( params );
  3701. }
  3702. break;
  3703. case IDC_SELECTEVENTS_CHANNEL_BEFORE:
  3704. {
  3705. SelectionParams_t params;
  3706. Q_memset( &params, 0, sizeof( params ) );
  3707. params.forward = false;
  3708. params.time = GetTimeValueForMouse( m_nClickedX );
  3709. params.type = SelectionParams_t::SP_CHANNEL;
  3710. SelectEvents( params );
  3711. }
  3712. break;
  3713. case IDC_SELECTEVENTS_CHANNEL_AFTER:
  3714. {
  3715. SelectionParams_t params;
  3716. Q_memset( &params, 0, sizeof( params ) );
  3717. params.forward = true;
  3718. params.time = GetTimeValueForMouse( m_nClickedX );
  3719. params.type = SelectionParams_t::SP_CHANNEL;
  3720. SelectEvents( params );
  3721. }
  3722. break;
  3723. case IDC_INSERT_TIME:
  3724. {
  3725. OnInsertTime();
  3726. }
  3727. break;
  3728. case IDC_DELETE_TIME:
  3729. {
  3730. OnDeleteTime();
  3731. }
  3732. break;
  3733. case IDC_CV_ALIGN_LEFT:
  3734. {
  3735. OnAlign( true );
  3736. }
  3737. break;
  3738. case IDC_CV_ALIGN_RIGHT:
  3739. {
  3740. OnAlign( false );
  3741. }
  3742. break;
  3743. case IDC_CV_SAMESIZE_SMALLEST:
  3744. {
  3745. OnMakeSameSize( true );
  3746. }
  3747. break;
  3748. case IDC_CV_SAMESIZE_LARGEST:
  3749. {
  3750. OnMakeSameSize( false );
  3751. }
  3752. break;
  3753. }
  3754. if ( iret == 1 )
  3755. {
  3756. SetActiveTool( this );
  3757. }
  3758. }
  3759. break;
  3760. }
  3761. return iret;
  3762. }
  3763. //-----------------------------------------------------------------------------
  3764. // Purpose:
  3765. //-----------------------------------------------------------------------------
  3766. void CChoreoView::PlayScene( bool forward )
  3767. {
  3768. m_bForward = forward;
  3769. if ( !m_pScene )
  3770. return;
  3771. sound->Flush();
  3772. // Make sure phonemes are loaded
  3773. FacePoser_EnsurePhonemesLoaded();
  3774. // Unpause
  3775. if ( m_bSimulating && m_bPaused )
  3776. {
  3777. m_bPaused = false;
  3778. return;
  3779. }
  3780. m_bSimulating = true;
  3781. m_bPaused = false;
  3782. // float soundlatency = max( sound->GetAmountofTimeAhead(), 0.0f );
  3783. // soundlatency = min( 0.5f, soundlatency );
  3784. float soundlatency = 0.0f;
  3785. float sceneendtime = m_pScene->FindStopTime();
  3786. m_pScene->SetSoundFileStartupLatency( soundlatency );
  3787. if ( m_rgABPoints[ 0 ].active ||
  3788. m_rgABPoints[ 1 ].active )
  3789. {
  3790. if ( m_rgABPoints[ 0 ].active &&
  3791. m_rgABPoints[ 1 ].active )
  3792. {
  3793. float st = m_rgABPoints[ 0 ].time;
  3794. float ed = m_rgABPoints[ 1 ].time;
  3795. m_pScene->ResetSimulation( m_bForward, st, ed );
  3796. SetScrubTime( m_bForward ? st : ed );
  3797. SetScrubTargetTime( m_bForward ? ed : st );
  3798. }
  3799. else
  3800. {
  3801. float startonly = m_rgABPoints[ 0 ].active ? m_rgABPoints[ 0 ].time : m_rgABPoints[ 1 ].time;
  3802. m_pScene->ResetSimulation( m_bForward, startonly );
  3803. SetScrubTime( m_bForward ? startonly : sceneendtime );
  3804. SetScrubTargetTime( m_bForward ? sceneendtime : startonly );
  3805. }
  3806. }
  3807. else
  3808. {
  3809. // NO start end/loop
  3810. m_pScene->ResetSimulation( m_bForward );
  3811. SetScrubTime( m_bForward ? 0 : sceneendtime );
  3812. SetScrubTargetTime( m_bForward ? sceneendtime : 0 );
  3813. }
  3814. if ( g_viewerSettings.speedScale == 0.0f )
  3815. {
  3816. m_flLastSpeedScale = g_viewerSettings.speedScale;
  3817. m_bResetSpeedScale = true;
  3818. g_viewerSettings.speedScale = 1.0f;
  3819. Con_Printf( "Resetting speed scale to 1.0\n" );
  3820. }
  3821. }
  3822. //-----------------------------------------------------------------------------
  3823. // Purpose:
  3824. // Input : x -
  3825. //-----------------------------------------------------------------------------
  3826. void CChoreoView::MoveTimeSliderToPos( int x )
  3827. {
  3828. m_flLeftOffset = (float)x;
  3829. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  3830. InvalidateRect( (HWND)m_pHorzScrollBar->getHandle(), NULL, TRUE );
  3831. InvalidateLayout();
  3832. }
  3833. //-----------------------------------------------------------------------------
  3834. // Purpose:
  3835. //-----------------------------------------------------------------------------
  3836. void CChoreoView::PauseScene( void )
  3837. {
  3838. if ( !m_bSimulating )
  3839. return;
  3840. m_bPaused = true;
  3841. sound->StopAll();
  3842. }
  3843. //-----------------------------------------------------------------------------
  3844. // Purpose: Apply expression to actor's face
  3845. // Input : *event -
  3846. // Output : Returns true on success, false on failure.
  3847. //-----------------------------------------------------------------------------
  3848. void CChoreoView::ProcessExpression( CChoreoScene *scene, CChoreoEvent *event )
  3849. {
  3850. Assert( event->GetType() == CChoreoEvent::EXPRESSION );
  3851. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  3852. if ( !model )
  3853. return;
  3854. CStudioHdr *hdr = model->GetStudioHdr();
  3855. if ( !hdr )
  3856. {
  3857. return;
  3858. }
  3859. CExpClass *p = expressions->FindClass( event->GetParameters(), true );
  3860. if ( !p )
  3861. {
  3862. return;
  3863. }
  3864. CExpression *exp = p->FindExpression( event->GetParameters2() );
  3865. if ( !exp )
  3866. {
  3867. return;
  3868. }
  3869. CChoreoActor *a = event->GetActor();
  3870. if ( !a )
  3871. return;
  3872. CChoreoActorWidget *actor = NULL;
  3873. int i;
  3874. for ( i = 0; i < m_SceneActors.Count(); i++ )
  3875. {
  3876. actor = m_SceneActors[ i ];
  3877. if ( !actor )
  3878. continue;
  3879. if ( actor->GetActor() == a )
  3880. break;
  3881. }
  3882. if ( !actor || i >= m_SceneActors.Count() )
  3883. return;
  3884. float *settings = exp->GetSettings();
  3885. Assert( settings );
  3886. float *weights = exp->GetWeights();
  3887. Assert( weights );
  3888. float *current = actor->GetSettings();
  3889. Assert( current );
  3890. float flIntensity = event->GetIntensity( scene->GetTime() );
  3891. // blend in target values for correct actor
  3892. for ( LocalFlexController_t i = (LocalFlexController_t)0; i < hdr->numflexcontrollers(); i++ )
  3893. {
  3894. mstudioflexcontroller_t *pFlex = hdr->pFlexcontroller( i );
  3895. int j = pFlex->localToGlobal;
  3896. if ( j < 0 )
  3897. continue;
  3898. float s = clamp( weights[j] * flIntensity, 0.0, 1.0 );
  3899. current[ j ] = current[j] * (1.0f - s) + settings[ j ] * s;
  3900. }
  3901. }
  3902. //-----------------------------------------------------------------------------
  3903. // Purpose:
  3904. // Input : *hdr -
  3905. // *event -
  3906. //-----------------------------------------------------------------------------
  3907. void SetupFlexControllerTracks( CStudioHdr *hdr, CChoreoEvent *event )
  3908. {
  3909. Assert( hdr );
  3910. Assert( event );
  3911. if ( !hdr )
  3912. return;
  3913. if ( !event )
  3914. return;
  3915. // Already done
  3916. if ( event->GetTrackLookupSet() )
  3917. return;
  3918. /*
  3919. // 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...
  3920. int c = hdr->numflexcontrollerremaps();
  3921. for ( i = 0; i < c; ++i )
  3922. {
  3923. mstudioflexcontrollerremap_t *remap = hdr->pFlexcontrollerRemap( i );
  3924. Msg( "remap %s\n", remap->pszName() );
  3925. Msg( " type %d\n", remap->remaptype );
  3926. Msg( " num remaps %d (stereo %s)\n", remap->numremaps, remap->stereo ? "true" : "false" );
  3927. for ( int j = 0 ; j < remap->numremaps; ++j )
  3928. {
  3929. int index = remap->pRemapControlIndex( j );
  3930. Msg( " %d: maps to %d (%s) with %s\n", j, index, hdr->pFlexcontroller( index )->pszName(), remap->pRemapControl( j ) );
  3931. }
  3932. }
  3933. */
  3934. // Unlink stuff in case it doesn't exist
  3935. int nTrackCount = event->GetNumFlexAnimationTracks();
  3936. for ( int i = 0; i < nTrackCount; ++i )
  3937. {
  3938. CFlexAnimationTrack *pTrack = event->GetFlexAnimationTrack( i );
  3939. pTrack->SetFlexControllerIndex( LocalFlexController_t(-1), -1, 0 );
  3940. pTrack->SetFlexControllerIndex( LocalFlexController_t(-1), -1, 1 );
  3941. }
  3942. for ( LocalFlexController_t i = LocalFlexController_t(0); i < hdr->numflexcontrollers(); ++i )
  3943. {
  3944. int j = hdr->pFlexcontroller( i )->localToGlobal;
  3945. char const *name = hdr->pFlexcontroller( i )->pszName();
  3946. if ( !name )
  3947. continue;
  3948. bool combo = false;
  3949. // Look up or create all necessary tracks
  3950. if ( strncmp( "right_", name, 6 ) == 0 )
  3951. {
  3952. combo = true;
  3953. name = &name[6];
  3954. }
  3955. CFlexAnimationTrack *track = event->FindTrack( name );
  3956. if ( !track )
  3957. {
  3958. track = event->AddTrack( name );
  3959. Assert( track );
  3960. }
  3961. track->SetFlexControllerIndex( i, j, 0 );
  3962. if ( combo )
  3963. {
  3964. track->SetFlexControllerIndex( LocalFlexController_t(i + 1), hdr->pFlexcontroller( LocalFlexController_t(i + 1) )->localToGlobal, 1 );
  3965. track->SetComboType( true );
  3966. }
  3967. float orig_min = track->GetMin( );
  3968. float orig_max = track->GetMax( );
  3969. // set range
  3970. if (hdr->pFlexcontroller( i )->min == 0.0f || hdr->pFlexcontroller( i )->max == 1.0f)
  3971. {
  3972. track->SetInverted( false );
  3973. track->SetMin( hdr->pFlexcontroller( i )->min );
  3974. track->SetMax( hdr->pFlexcontroller( i )->max );
  3975. }
  3976. else
  3977. {
  3978. // invert ranges for wide ranged, makes sense considering flexcontroller names...
  3979. track->SetInverted( true );
  3980. track->SetMin( hdr->pFlexcontroller( i )->max );
  3981. track->SetMax( hdr->pFlexcontroller( i )->min );
  3982. }
  3983. // resample track based on this models dynamic range
  3984. if (track->GetNumSamples( 0 ) > 0)
  3985. {
  3986. float range = track->GetMax( ) - track->GetMin( );
  3987. for (int i = 0; i < track->GetNumSamples( 0 ); i++)
  3988. {
  3989. CExpressionSample *sample = track->GetSample( i, 0 );
  3990. float rangedValue = orig_min * (1 - sample->value) + orig_max * sample->value;
  3991. sample->value = clamp( (rangedValue - track->GetMin( )) / range, 0.0, 1.0 );
  3992. }
  3993. }
  3994. // skip next flex since we've already assigned it
  3995. if ( combo )
  3996. {
  3997. i++;
  3998. }
  3999. }
  4000. event->SetTrackLookupSet( true );
  4001. }
  4002. //-----------------------------------------------------------------------------
  4003. // Purpose: Apply flexanimation to actor's face
  4004. // Input : *event -
  4005. // Output : Returns true on success, false on failure.
  4006. //-----------------------------------------------------------------------------
  4007. void CChoreoView::ProcessFlexAnimation( CChoreoScene *scene, CChoreoEvent *event )
  4008. {
  4009. Assert( event->GetType() == CChoreoEvent::FLEXANIMATION );
  4010. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  4011. if ( !model )
  4012. return;
  4013. CStudioHdr *hdr = model->GetStudioHdr();
  4014. if ( !hdr )
  4015. {
  4016. return;
  4017. }
  4018. CChoreoActor *a = event->GetActor();
  4019. CChoreoActorWidget *actor = NULL;
  4020. int i;
  4021. for ( i = 0; i < m_SceneActors.Count(); i++ )
  4022. {
  4023. actor = m_SceneActors[ i ];
  4024. if ( !actor )
  4025. continue;
  4026. if ( !stricmp( actor->GetActor()->GetName(), a->GetName() ) )
  4027. break;
  4028. }
  4029. if ( !actor || i >= m_SceneActors.Count() )
  4030. return;
  4031. float *current = actor->GetSettings();
  4032. Assert( current );
  4033. if ( !event->GetTrackLookupSet() )
  4034. {
  4035. SetupFlexControllerTracks( hdr, event );
  4036. }
  4037. float weight = event->GetIntensity( scene->GetTime() );
  4038. CChoreoEventWidget *eventwidget = FindWidgetForEvent( event );
  4039. bool bUpdateSliders = (eventwidget && eventwidget->IsSelected() && model == models->GetActiveStudioModel() );
  4040. // Iterate animation tracks
  4041. for ( i = 0; i < event->GetNumFlexAnimationTracks(); i++ )
  4042. {
  4043. CFlexAnimationTrack *track = event->GetFlexAnimationTrack( i );
  4044. if ( !track )
  4045. continue;
  4046. // Disabled
  4047. if ( !track->IsTrackActive() )
  4048. {
  4049. if ( bUpdateSliders )
  4050. {
  4051. for ( int side = 0; side < 1 + track->IsComboType(); side++ )
  4052. {
  4053. int controller = track->GetFlexControllerIndex( side );
  4054. if ( controller != -1 && !g_pFlexPanel->IsEdited( controller ))
  4055. {
  4056. g_pFlexPanel->SetSlider( controller, 0.0 );
  4057. g_pFlexPanel->SetInfluence( controller, 0.0f );
  4058. }
  4059. }
  4060. }
  4061. continue;
  4062. }
  4063. // Map track flex controller to global name
  4064. if ( track->IsComboType() )
  4065. {
  4066. for ( int side = 0; side < 2; side++ )
  4067. {
  4068. int controller = track->GetFlexControllerIndex( side );
  4069. if ( controller != -1 )
  4070. {
  4071. // Get spline intensity for controller
  4072. float flIntensity = track->GetIntensity( scene->GetTime(), side );
  4073. if (bUpdateSliders && !g_pFlexPanel->IsEdited( controller ) )
  4074. {
  4075. g_pFlexPanel->SetSlider( controller, flIntensity );
  4076. g_pFlexPanel->SetInfluence( controller, 1.0f );
  4077. }
  4078. flIntensity = current[ controller ] * (1 - weight) + flIntensity * weight;
  4079. current[ controller ] = flIntensity;
  4080. }
  4081. }
  4082. }
  4083. else
  4084. {
  4085. int controller = track->GetFlexControllerIndex( 0 );
  4086. if ( controller != -1 )
  4087. {
  4088. // Get spline intensity for controller
  4089. float flIntensity = track->GetIntensity( scene->GetTime(), 0 );
  4090. if (bUpdateSliders && !g_pFlexPanel->IsEdited( controller ) )
  4091. {
  4092. g_pFlexPanel->SetSlider( controller, flIntensity );
  4093. g_pFlexPanel->SetInfluence( controller, 1.0f );
  4094. }
  4095. flIntensity = current[ controller ] * (1 - weight) + flIntensity * weight;
  4096. current[ controller ] = flIntensity;
  4097. }
  4098. }
  4099. }
  4100. }
  4101. #include "mapentities.h"
  4102. //-----------------------------------------------------------------------------
  4103. // Purpose: Apply lookat target
  4104. // Input : *event -
  4105. // Output : Returns true on success, false on failure.
  4106. //-----------------------------------------------------------------------------
  4107. void CChoreoView::ProcessLookat( CChoreoScene *scene, CChoreoEvent *event )
  4108. {
  4109. Assert( event->GetType() == CChoreoEvent::LOOKAT );
  4110. if ( !event->GetActor() )
  4111. return;
  4112. CChoreoActor *a = event->GetActor();
  4113. Assert( a );
  4114. StudioModel *model = FindAssociatedModel( scene, a );
  4115. if ( !model )
  4116. {
  4117. return;
  4118. }
  4119. float flIntensity = event->GetIntensity( scene->GetTime() );
  4120. // clamp in-ramp to 0.3 seconds
  4121. float flDuration = scene->GetTime() - event->GetStartTime();
  4122. float flMaxIntensity = flDuration < 0.3f ? SimpleSpline( flDuration / 0.3f ) : 1.0f;
  4123. flDuration = event->GetEndTime() - scene->GetTime();
  4124. flMaxIntensity = min( flMaxIntensity, flDuration < 0.3f ? SimpleSpline( flDuration / 0.3f ) : 1.0f );
  4125. flIntensity = clamp( flIntensity, 0.0f, flMaxIntensity );
  4126. if (!stricmp( event->GetParameters(), a->GetName() ) || !stricmp( event->GetParameters(), "!self" ))
  4127. {
  4128. model->AddLookTargetSelf( flIntensity );
  4129. }
  4130. else if ( !stricmp( event->GetParameters(), "player" ) ||
  4131. !stricmp( event->GetParameters(), "!player" ) )
  4132. {
  4133. Vector vecTarget = model->m_origin;
  4134. vecTarget.z = 0;
  4135. model->AddLookTarget( vecTarget, flIntensity );
  4136. }
  4137. else
  4138. {
  4139. mapentities->CheckUpdateMap( scene->GetMapname() );
  4140. Vector orgActor;
  4141. Vector orgTarget;
  4142. QAngle anglesActor;
  4143. QAngle anglesDummy;
  4144. if ( event->GetPitch() != 0 ||
  4145. event->GetYaw() != 0 )
  4146. {
  4147. QAngle angles( -(float)event->GetPitch(),
  4148. (float)event->GetYaw(),
  4149. 0 );
  4150. matrix3x4_t matrix;
  4151. AngleMatrix( model->m_angles, matrix );
  4152. Vector vecForward;
  4153. AngleVectors( angles, &vecForward );
  4154. Vector eyeTarget;
  4155. VectorRotate( vecForward, matrix, eyeTarget );
  4156. VectorScale( eyeTarget, 75, eyeTarget );
  4157. model->AddLookTarget( eyeTarget, flIntensity );
  4158. }
  4159. else
  4160. {
  4161. if ( mapentities->LookupOrigin( a->GetName(), orgActor, anglesActor ) )
  4162. {
  4163. if ( mapentities->LookupOrigin( event->GetParameters(), orgTarget, anglesDummy ) )
  4164. {
  4165. Vector delta = orgTarget - orgActor;
  4166. matrix3x4_t matrix;
  4167. Vector lookTarget;
  4168. // Rotate around actor's placed forward direction since we look straight down x in faceposer/hlmv
  4169. AngleMatrix( anglesActor, matrix );
  4170. VectorIRotate( delta, matrix, lookTarget );
  4171. model->AddLookTarget( lookTarget, flIntensity );
  4172. return;
  4173. }
  4174. }
  4175. // hack up something based on the name.
  4176. {
  4177. const char *cp = event->GetParameters();
  4178. float value = 0.0;
  4179. while (*cp)
  4180. {
  4181. value += *cp++;
  4182. }
  4183. value = cos( value );
  4184. value = acos( value );
  4185. QAngle angles( 0.0, value * 45 / M_PI, 0.0 );
  4186. matrix3x4_t matrix;
  4187. AngleMatrix( model->m_angles, matrix );
  4188. Vector vecForward;
  4189. AngleVectors( angles, &vecForward );
  4190. Vector eyeTarget;
  4191. VectorRotate( vecForward, matrix, eyeTarget );
  4192. VectorScale( eyeTarget, 75, eyeTarget );
  4193. model->AddLookTarget( eyeTarget, flIntensity );
  4194. }
  4195. }
  4196. }
  4197. }
  4198. //-----------------------------------------------------------------------------
  4199. // Purpose: Returns a target for Faceing
  4200. // Input : *event -
  4201. // Output : Returns true on success, false on failure.
  4202. //-----------------------------------------------------------------------------
  4203. bool CChoreoView::GetTarget( CChoreoScene *scene, CChoreoEvent *event, Vector &vecTarget, QAngle &vecAngle )
  4204. {
  4205. if ( !event->GetActor() )
  4206. return false;
  4207. CChoreoActor *a = event->GetActor();
  4208. Assert( a );
  4209. StudioModel *model = FindAssociatedModel( scene, a );
  4210. if ( !model )
  4211. {
  4212. return false;
  4213. }
  4214. if (!stricmp( event->GetParameters(), a->GetName() ))
  4215. {
  4216. vecTarget = vec3_origin;
  4217. return true;
  4218. }
  4219. else if ( !stricmp( event->GetParameters(), "player" ) ||
  4220. !stricmp( event->GetParameters(), "!player" ) )
  4221. {
  4222. vecTarget = model->m_origin;
  4223. vecTarget.z = 0;
  4224. vecAngle = model->m_angles;
  4225. return true;
  4226. }
  4227. else
  4228. {
  4229. mapentities->CheckUpdateMap( scene->GetMapname() );
  4230. Vector orgActor;
  4231. Vector orgTarget;
  4232. QAngle anglesActor;
  4233. QAngle anglesDummy;
  4234. if ( event->GetPitch() != 0 ||
  4235. event->GetYaw() != 0 )
  4236. {
  4237. QAngle angles( -(float)event->GetPitch(),
  4238. (float)event->GetYaw(),
  4239. 0 );
  4240. matrix3x4_t matrix;
  4241. AngleMatrix( model->m_angles, matrix );
  4242. QAngle angles2 = angles;
  4243. angles2.x *= 0.6f;
  4244. angles2.y *= 0.8f;
  4245. Vector vecForward, vecForward2;
  4246. AngleVectors( angles, &vecForward );
  4247. AngleVectors( angles2, &vecForward2 );
  4248. VectorNormalize( vecForward );
  4249. VectorNormalize( vecForward2 );
  4250. Vector eyeTarget, headTarget;
  4251. VectorRotate( vecForward, matrix, eyeTarget );
  4252. VectorRotate( vecForward2, matrix, headTarget );
  4253. VectorScale( eyeTarget, 150, eyeTarget );
  4254. VectorScale( headTarget, 150, vecTarget );
  4255. return true;
  4256. }
  4257. else
  4258. {
  4259. if ( mapentities->LookupOrigin( a->GetName(), orgActor, anglesActor ) )
  4260. {
  4261. if ( mapentities->LookupOrigin( event->GetParameters(), orgTarget, anglesDummy ) )
  4262. {
  4263. Vector delta = orgTarget - orgActor;
  4264. matrix3x4_t matrix;
  4265. Vector lookTarget;
  4266. // Rotate around actor's placed forward direction since we look straight down x in faceposer/hlmv
  4267. AngleMatrix( anglesActor, matrix );
  4268. VectorIRotate( delta, matrix, vecTarget );
  4269. return true;
  4270. }
  4271. }
  4272. }
  4273. }
  4274. return false;
  4275. }
  4276. //-----------------------------------------------------------------------------
  4277. // Purpose: Apply lookat target
  4278. // Input : *event -
  4279. // Output : Returns true on success, false on failure.
  4280. //-----------------------------------------------------------------------------
  4281. void CChoreoView::ProcessFace( CChoreoScene *scene, CChoreoEvent *event )
  4282. {
  4283. Assert( event->GetType() == CChoreoEvent::FACE );
  4284. if ( !event->GetActor() )
  4285. return;
  4286. CChoreoActor *a = event->GetActor();
  4287. Assert( a );
  4288. StudioModel *model = FindAssociatedModel( scene, a );
  4289. if ( !model )
  4290. {
  4291. return;
  4292. }
  4293. Vector vecTarget;
  4294. QAngle vecAngle;
  4295. if (!GetTarget( scene, event, vecTarget, vecAngle ))
  4296. {
  4297. return;
  4298. }
  4299. /*
  4300. // FIXME: this is broke
  4301. float goalYaw = -(vecAngle.y > 180 ? 360 - vecAngle.y : vecAngle.y );
  4302. float intensity = event->GetIntensity( scene->GetTime() );
  4303. float diff = goalYaw * intensity;
  4304. float dir = 1.0;
  4305. if (diff < 0)
  4306. {
  4307. diff = -diff;
  4308. dir = -1;
  4309. }
  4310. float spineintensity = 0 * max( 0.0, (intensity - 0.5) / 0.5 );
  4311. float goalSpineYaw = min( diff * (1.0 - spineintensity), 30 );
  4312. //float idealYaw = info->m_flInitialYaw + (diff - m_goalBodyYaw * dir - m_goalSpineYaw * dir) * dir;
  4313. // float idealYaw = UTIL_AngleMod( info->m_flInitialYaw + diff * intensity );
  4314. // FIXME: this is broke
  4315. // model->SetSpineYaw( goalSpineYaw * dir);
  4316. // model->SetBodyYaw( goalBodyYaw * dir );
  4317. // Msg("yaw %.1f : %.1f (%.1f)\n", info->m_flInitialYaw, idealYaw, intensity );
  4318. */
  4319. }
  4320. //-----------------------------------------------------------------------------
  4321. // Purpose:
  4322. // Input : *scene -
  4323. // *event -
  4324. //-----------------------------------------------------------------------------
  4325. void CChoreoView::ProcessLoop( CChoreoScene *scene, CChoreoEvent *event )
  4326. {
  4327. Assert( event->GetType() == CChoreoEvent::LOOP );
  4328. // Don't loop when dragging scrubber!
  4329. if ( IsScrubbing() )
  4330. return;
  4331. float backtime = (float)atof( event->GetParameters() );
  4332. bool process = true;
  4333. int counter = event->GetLoopCount();
  4334. if ( counter != -1 )
  4335. {
  4336. int remaining = event->GetNumLoopsRemaining();
  4337. if ( remaining <= 0 )
  4338. {
  4339. process = false;
  4340. }
  4341. else
  4342. {
  4343. event->SetNumLoopsRemaining( --remaining );
  4344. }
  4345. }
  4346. if ( !process )
  4347. return;
  4348. scene->LoopToTime( backtime );
  4349. SetScrubTime( backtime );
  4350. }
  4351. //-----------------------------------------------------------------------------
  4352. // Purpose: Add a gesture layer
  4353. // Input : *event -
  4354. // Output : Returns true on success, false on failure.
  4355. //-----------------------------------------------------------------------------
  4356. void CChoreoView::ProcessGesture( CChoreoScene *scene, CChoreoEvent *event )
  4357. {
  4358. Assert( event->GetType() == CChoreoEvent::GESTURE );
  4359. // NULL event is just a placeholder
  4360. if ( !Q_stricmp( event->GetName(), "NULL" ) )
  4361. {
  4362. return;
  4363. }
  4364. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  4365. if ( !model )
  4366. return;
  4367. if ( !event->GetActor() )
  4368. return;
  4369. CChoreoActor *a = event->GetActor();
  4370. Assert( a );
  4371. int iSequence = model->LookupSequence( event->GetParameters() );
  4372. if (iSequence < 0)
  4373. return;
  4374. // Get spline intensity for controller
  4375. float eventlocaltime = scene->GetTime() - event->GetStartTime();
  4376. float referencetime = event->GetOriginalPercentageFromPlaybackPercentage( eventlocaltime / event->GetDuration() ) * event->GetDuration();
  4377. float resampledtime = event->GetStartTime() + referencetime;
  4378. float cycle = event->GetCompletion( resampledtime );
  4379. int iLayer = model->GetNewAnimationLayer( a->FindChannelIndex( event->GetChannel() ) );
  4380. model->SetOverlaySequence( iLayer, iSequence, event->GetIntensity( scene->GetTime() ) );
  4381. model->SetOverlayRate( iLayer, cycle, 0.0 );
  4382. }
  4383. //-----------------------------------------------------------------------------
  4384. // Purpose: Apply a sequence
  4385. // Input : *event -
  4386. //-----------------------------------------------------------------------------
  4387. void CChoreoView::ProcessSequence( CChoreoScene *scene, CChoreoEvent *event )
  4388. {
  4389. Assert( event->GetType() == CChoreoEvent::SEQUENCE );
  4390. if ( !m_bProcessSequences )
  4391. {
  4392. return;
  4393. }
  4394. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  4395. if ( !model )
  4396. return;
  4397. if ( !event->GetActor() )
  4398. return;
  4399. CChoreoActor *a = event->GetActor();
  4400. Assert( a );
  4401. int iSequence = model->LookupSequence( event->GetParameters() );
  4402. if (iSequence < 0)
  4403. return;
  4404. float flFrameRate;
  4405. float flGroundSpeed;
  4406. model->GetSequenceInfo( iSequence, &flFrameRate, &flGroundSpeed );
  4407. float cycle;
  4408. bool looping = model->GetSequenceLoops( iSequence );
  4409. if (looping)
  4410. {
  4411. float dt = scene->GetTime() - event->m_flPrevTime;
  4412. event->m_flPrevTime = scene->GetTime();
  4413. dt = clamp( dt, 0.0, 0.1 );
  4414. cycle = event->m_flPrevCycle + flFrameRate * dt;
  4415. cycle = cycle - (int)cycle;
  4416. event->m_flPrevCycle = cycle;
  4417. }
  4418. else
  4419. {
  4420. float dt = scene->GetTime() - event->GetStartTime();
  4421. cycle = flFrameRate * dt;
  4422. cycle = cycle - (int)(cycle);
  4423. }
  4424. // FIXME: shouldn't sequences always be lower priority than gestures?
  4425. int iLayer = model->GetNewAnimationLayer( a->FindChannelIndex( event->GetChannel() ) );
  4426. model->SetOverlaySequence( iLayer, iSequence, event->GetIntensity( scene->GetTime() ) );
  4427. model->SetOverlayRate( iLayer, cycle, 0.0 );
  4428. }
  4429. //-----------------------------------------------------------------------------
  4430. // Purpose: Apply a walking animation
  4431. // Input : *event -
  4432. //-----------------------------------------------------------------------------
  4433. void CChoreoView::ProcessMoveto( CChoreoScene *scene, CChoreoEvent *event )
  4434. {
  4435. Assert( event->GetType() == CChoreoEvent::MOVETO );
  4436. if ( !m_bProcessSequences )
  4437. {
  4438. return;
  4439. }
  4440. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  4441. if ( !model )
  4442. return;
  4443. if ( !event->GetActor() )
  4444. return;
  4445. int iSequence = GetMovetoSequence( scene, event, model );
  4446. if (iSequence < 0)
  4447. return;
  4448. float flFrameRate;
  4449. float flGroundSpeed;
  4450. model->GetSequenceInfo( iSequence, &flFrameRate, &flGroundSpeed );
  4451. float dt = scene->GetTime() - event->GetStartTime();
  4452. float cycle = flFrameRate * dt;
  4453. cycle = cycle - (int)(cycle);
  4454. float idealAccel = 100;
  4455. // accel to ideal
  4456. float t1 = flGroundSpeed / idealAccel;
  4457. float intensity = 1.0;
  4458. if (dt < t1)
  4459. {
  4460. intensity = dt / t1;
  4461. }
  4462. else if (event->GetDuration() - dt < t1)
  4463. {
  4464. intensity = (event->GetDuration() - dt) / t1;
  4465. }
  4466. // movement should always be higher priority than postures, but not gestures....grrr, any way to tell them apart?
  4467. int iLayer = model->GetNewAnimationLayer( 0 /* a->FindChannelIndex( event->GetChannel() ) */ );
  4468. model->SetOverlaySequence( iLayer, iSequence, intensity );
  4469. model->SetOverlayRate( iLayer, cycle, 0.0 );
  4470. }
  4471. int CChoreoView::GetMovetoSequence( CChoreoScene *scene, CChoreoEvent *event, StudioModel *model )
  4472. {
  4473. // FIXME: needs to pull from event (activity or sequence?)
  4474. if ( !event->GetParameters2() || !event->GetParameters2()[0] )
  4475. return model->LookupSequence( "walk_all" );
  4476. // Custom distance styles are appended to param2 with a space as a separator
  4477. const char *pszAct = Q_strstr( event->GetParameters2(), " " );
  4478. if ( pszAct )
  4479. {
  4480. char szActName[256];
  4481. Q_strncpy( szActName, event->GetParameters2(), sizeof(szActName) );
  4482. szActName[ (pszAct-event->GetParameters2()) ] = '\0';
  4483. pszAct = szActName;
  4484. }
  4485. else
  4486. {
  4487. pszAct = event->GetParameters2();
  4488. }
  4489. if ( !Q_strcmp( pszAct, "Walk" ) )
  4490. {
  4491. pszAct = "ACT_WALK";
  4492. }
  4493. else if ( !Q_strcmp( pszAct, "Run" ) )
  4494. {
  4495. pszAct = "ACT_RUN";
  4496. }
  4497. else if ( !Q_strcmp( pszAct, "CrouchWalk" ) )
  4498. {
  4499. pszAct = "ACT_WALK_CROUCH";
  4500. }
  4501. int iSequence = model->LookupActivity( pszAct );
  4502. if (iSequence == -1)
  4503. {
  4504. return model->LookupSequence( "walk_all" );
  4505. }
  4506. return iSequence;
  4507. }
  4508. //-----------------------------------------------------------------------------
  4509. // Purpose: Process a pause event
  4510. // Input : *event -
  4511. //-----------------------------------------------------------------------------
  4512. void CChoreoView::ProcessPause( CChoreoScene *scene, CChoreoEvent *event )
  4513. {
  4514. Assert( event->GetType() == CChoreoEvent::SECTION );
  4515. // Don't pause if scrubbing
  4516. bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
  4517. if ( scrubbing )
  4518. return;
  4519. PauseScene();
  4520. m_bAutomated = false;
  4521. m_nAutomatedAction = SCENE_ACTION_UNKNOWN;
  4522. m_flAutomationDelay = 0.0f;
  4523. m_flAutomationTime = 0.0f;
  4524. // Check for auto resume/cancel
  4525. ParseFromMemory( (char *)event->GetParameters(), strlen( event->GetParameters() ) );
  4526. if ( tokenprocessor->TokenAvailable() )
  4527. {
  4528. tokenprocessor->GetToken( false );
  4529. if ( !stricmp( tokenprocessor->CurrentToken(), "automate" ) )
  4530. {
  4531. if ( tokenprocessor->TokenAvailable() )
  4532. {
  4533. tokenprocessor->GetToken( false );
  4534. if ( !stricmp( tokenprocessor->CurrentToken(), "Cancel" ) )
  4535. {
  4536. m_nAutomatedAction = SCENE_ACTION_CANCEL;
  4537. }
  4538. else if ( !stricmp( tokenprocessor->CurrentToken(), "Resume" ) )
  4539. {
  4540. m_nAutomatedAction = SCENE_ACTION_RESUME;
  4541. }
  4542. if ( tokenprocessor->TokenAvailable() &&
  4543. m_nAutomatedAction != SCENE_ACTION_UNKNOWN )
  4544. {
  4545. tokenprocessor->GetToken( false );
  4546. m_flAutomationDelay = (float)atof( tokenprocessor->CurrentToken() );
  4547. if ( m_flAutomationDelay > 0.0f )
  4548. {
  4549. // Success
  4550. m_bAutomated = true;
  4551. m_flAutomationTime = 0.0f;
  4552. }
  4553. }
  4554. }
  4555. }
  4556. }
  4557. }
  4558. //-----------------------------------------------------------------------------
  4559. // Purpose: Main event processor
  4560. // Input : *event -
  4561. // Output : Returns true on success, false on failure.
  4562. //-----------------------------------------------------------------------------
  4563. void CChoreoView::ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  4564. {
  4565. if ( !event || !event->GetActive() )
  4566. return;
  4567. CChoreoActor *actor = event->GetActor();
  4568. if ( actor && !actor->GetActive() )
  4569. {
  4570. return;
  4571. }
  4572. CChoreoChannel *channel = event->GetChannel();
  4573. if ( channel && !channel->GetActive() )
  4574. {
  4575. return;
  4576. }
  4577. switch( event->GetType() )
  4578. {
  4579. case CChoreoEvent::EXPRESSION:
  4580. ProcessExpression( scene, event );
  4581. break;
  4582. case CChoreoEvent::FLEXANIMATION:
  4583. ProcessFlexAnimation( scene, event );
  4584. break;
  4585. case CChoreoEvent::LOOKAT:
  4586. ProcessLookat( scene, event );
  4587. break;
  4588. case CChoreoEvent::FACE:
  4589. ProcessFace( scene, event );
  4590. break;
  4591. case CChoreoEvent::GESTURE:
  4592. ProcessGesture( scene, event );
  4593. break;
  4594. case CChoreoEvent::SEQUENCE:
  4595. ProcessSequence( scene, event );
  4596. break;
  4597. case CChoreoEvent::SUBSCENE:
  4598. ProcessSubscene( scene, event );
  4599. break;
  4600. case CChoreoEvent::SPEAK:
  4601. ProcessSpeak( scene, event );
  4602. break;
  4603. case CChoreoEvent::MOVETO:
  4604. ProcessMoveto( scene, event );
  4605. break;
  4606. case CChoreoEvent::STOPPOINT:
  4607. // Nothing
  4608. break;
  4609. case CChoreoEvent::INTERRUPT:
  4610. ProcessInterrupt( scene, event );
  4611. break;
  4612. case CChoreoEvent::PERMIT_RESPONSES:
  4613. ProcessPermitResponses( scene, event );
  4614. break;
  4615. default:
  4616. break;
  4617. }
  4618. }
  4619. //-----------------------------------------------------------------------------
  4620. // Purpose: Main event completion checker
  4621. // Input : *event -
  4622. // Output : Returns true on success, false on failure.
  4623. //-----------------------------------------------------------------------------
  4624. bool CChoreoView::CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  4625. {
  4626. if ( !event || !event->GetActive() )
  4627. return true;
  4628. CChoreoActor *actor = event->GetActor();
  4629. if ( actor && !actor->GetActive() )
  4630. {
  4631. return true;
  4632. }
  4633. CChoreoChannel *channel = event->GetChannel();
  4634. if ( channel && !channel->GetActive() )
  4635. {
  4636. return true;
  4637. }
  4638. switch( event->GetType() )
  4639. {
  4640. case CChoreoEvent::EXPRESSION:
  4641. break;
  4642. case CChoreoEvent::FLEXANIMATION:
  4643. break;
  4644. case CChoreoEvent::LOOKAT:
  4645. break;
  4646. case CChoreoEvent::GESTURE:
  4647. break;
  4648. case CChoreoEvent::SEQUENCE:
  4649. break;
  4650. case CChoreoEvent::SUBSCENE:
  4651. break;
  4652. case CChoreoEvent::SPEAK:
  4653. break;
  4654. case CChoreoEvent::MOVETO:
  4655. break;
  4656. case CChoreoEvent::INTERRUPT:
  4657. break;
  4658. case CChoreoEvent::PERMIT_RESPONSES:
  4659. break;
  4660. default:
  4661. break;
  4662. }
  4663. return true;
  4664. }
  4665. //-----------------------------------------------------------------------------
  4666. // Purpose:
  4667. //-----------------------------------------------------------------------------
  4668. void CChoreoView::PauseThink( void )
  4669. {
  4670. // FIXME: Game code would check for conditions being met
  4671. if ( !m_bAutomated )
  4672. return;
  4673. m_flAutomationTime += fabs( m_flFrameTime );
  4674. RECT rcPauseRect;
  4675. rcPauseRect.left = 0;
  4676. rcPauseRect.right = w2();
  4677. rcPauseRect.top = GetCaptionHeight() + SCRUBBER_HEIGHT;
  4678. rcPauseRect.bottom = rcPauseRect.top + 10;
  4679. CChoreoWidgetDrawHelper drawHelper( this,
  4680. rcPauseRect,
  4681. COLOR_CHOREO_BACKGROUND );
  4682. DrawSceneABTicks( drawHelper );
  4683. if ( m_flAutomationDelay > 0.0f &&
  4684. m_flAutomationTime < m_flAutomationDelay )
  4685. {
  4686. char sz[ 256 ];
  4687. sprintf( sz, "Pause %.2f/%.2f", m_flAutomationTime, m_flAutomationDelay );
  4688. int textlen = drawHelper.CalcTextWidth( "Arial", 9, FW_NORMAL, sz );
  4689. RECT rcText;
  4690. GetScrubHandleRect( rcText, true );
  4691. rcText.left = ( rcText.left + rcText.right ) / 2;
  4692. rcText.left -= ( textlen * 0.5f );
  4693. rcText.right = rcText.left + textlen + 1;
  4694. rcText.top = rcPauseRect.top;
  4695. rcText.bottom = rcPauseRect.bottom;
  4696. drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, COLOR_CHOREO_PLAYBACKTICKTEXT, rcText, sz );
  4697. return;
  4698. }
  4699. // Time to act
  4700. m_bAutomated = false;
  4701. switch ( m_nAutomatedAction )
  4702. {
  4703. case SCENE_ACTION_RESUME:
  4704. m_bPaused = false;
  4705. sound->StopAll();
  4706. break;
  4707. case SCENE_ACTION_CANCEL:
  4708. FinishSimulation();
  4709. break;
  4710. default:
  4711. break;
  4712. }
  4713. m_nAutomatedAction = SCENE_ACTION_UNKNOWN;
  4714. m_flAutomationTime = 0.0f;
  4715. m_flAutomationDelay = 0.0f;
  4716. }
  4717. //-----------------------------------------------------------------------------
  4718. // Purpose: Conclude simulation
  4719. //-----------------------------------------------------------------------------
  4720. void CChoreoView::FinishSimulation( void )
  4721. {
  4722. if ( !m_bSimulating )
  4723. return;
  4724. // m_pScene->ResetSimulation();
  4725. m_bSimulating = false;
  4726. m_bPaused = false;
  4727. sound->StopAll();
  4728. if ( m_bResetSpeedScale )
  4729. {
  4730. m_bResetSpeedScale = false;
  4731. g_viewerSettings.speedScale = m_flLastSpeedScale;
  4732. m_flLastSpeedScale = 0.0f;
  4733. Con_Printf( "Resetting speed scale to %f\n", m_flLastSpeedScale );
  4734. }
  4735. models->ClearOverlaysSequences();
  4736. // redraw();
  4737. }
  4738. void CChoreoView::SceneThink( float time )
  4739. {
  4740. if ( !m_pScene )
  4741. return;
  4742. if ( m_bSimulating )
  4743. {
  4744. if ( m_bPaused )
  4745. {
  4746. PauseThink();
  4747. }
  4748. else
  4749. {
  4750. m_pScene->SetSoundFileStartupLatency( 0.0f );
  4751. models->CheckResetFlexes();
  4752. ResetTargetSettings();
  4753. models->ClearOverlaysSequences();
  4754. // Tell scene to go
  4755. m_pScene->Think( time );
  4756. // Move flexes toward their targets
  4757. UpdateCurrentSettings();
  4758. }
  4759. }
  4760. else
  4761. {
  4762. FinishSimulation();
  4763. }
  4764. if ( !ShouldProcessSpeak() )
  4765. {
  4766. bool autoprocess = ShouldAutoProcess();
  4767. bool anyscrub = IsAnyToolScrubbing() ;
  4768. bool anyprocessing = IsAnyToolProcessing();
  4769. //Con_Printf( "autoprocess %i anyscrub %i anyprocessing %i\n",
  4770. // autoprocess ? 1 : 0,
  4771. // anyscrub ? 1 : 0,
  4772. // anyprocessing ? 1 : 0 );
  4773. if ( !anyscrub &&
  4774. !anyprocessing &&
  4775. autoprocess &&
  4776. !m_bForceProcess )
  4777. {
  4778. sound->StopAll();
  4779. // why clear lookat?
  4780. //models->ClearModelTargets( false );
  4781. }
  4782. }
  4783. }
  4784. //-----------------------------------------------------------------------------
  4785. // Purpose:
  4786. //-----------------------------------------------------------------------------
  4787. void CChoreoView::LayoutScene( void )
  4788. {
  4789. if ( !m_pScene )
  4790. return;
  4791. if ( m_bLayoutIsValid )
  4792. return;
  4793. m_pScene->ReconcileTags();
  4794. RECT rc;
  4795. GetClientRect( (HWND)getHandle(), &rc );
  4796. RECT rcClient = rc;
  4797. rcClient.top += GetStartRow();
  4798. OffsetRect( &rcClient, 0, -m_nTopOffset );
  4799. m_flStartTime = m_flLeftOffset / GetPixelsPerSecond();
  4800. m_flEndTime = m_flStartTime + (float)( rcClient.right - GetLabelWidth() ) / GetPixelsPerSecond();
  4801. m_rcTimeLine = rcClient;
  4802. m_rcTimeLine.top = GetCaptionHeight() + SCRUBBER_HEIGHT;
  4803. m_rcTimeLine.bottom = m_rcTimeLine.top + 44;
  4804. int currentRow = rcClient.top + 2;
  4805. int itemHeight;
  4806. // Draw actors
  4807. int i;
  4808. for ( i = 0; i < m_SceneActors.Count(); i++ )
  4809. {
  4810. CChoreoActorWidget *a = m_SceneActors[ i ];
  4811. Assert( a );
  4812. if ( !a )
  4813. {
  4814. continue;
  4815. }
  4816. // Figure out rectangle
  4817. itemHeight = a->GetItemHeight();
  4818. RECT rcActor = rcClient;
  4819. rcActor.top = currentRow;
  4820. rcActor.bottom = currentRow + itemHeight;
  4821. a->Layout( rcActor );
  4822. currentRow += itemHeight;
  4823. }
  4824. // Draw section tabs
  4825. for ( i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  4826. {
  4827. CChoreoGlobalEventWidget *e = m_SceneGlobalEvents[ i ];
  4828. if ( !e )
  4829. continue;
  4830. RECT rcEvent;
  4831. rcEvent = m_rcTimeLine;
  4832. float frac = ( e->GetEvent()->GetStartTime() - m_flStartTime ) / ( m_flEndTime - m_flStartTime );
  4833. rcEvent.left = GetLabelWidth() + rcEvent.left + (int)( frac * ( m_rcTimeLine.right - m_rcTimeLine.left - GetLabelWidth() ) );
  4834. rcEvent.left -= 4;
  4835. rcEvent.right = rcEvent.left + 8;
  4836. rcEvent.bottom += 0;
  4837. rcEvent.top = rcEvent.bottom - 8;
  4838. if ( rcEvent.left + 10 < GetLabelWidth() )
  4839. {
  4840. e->setVisible( false );
  4841. }
  4842. else
  4843. {
  4844. e->setVisible( true );
  4845. }
  4846. // OffsetRect( &rcEvent, GetLabelWidth(), 0 );
  4847. e->Layout( rcEvent );
  4848. }
  4849. m_bLayoutIsValid = true;
  4850. }
  4851. //-----------------------------------------------------------------------------
  4852. // Purpose:
  4853. //-----------------------------------------------------------------------------
  4854. void CChoreoView::DeleteSceneWidgets( void )
  4855. {
  4856. bool oldcandraw = m_bCanDraw;
  4857. m_bCanDraw = false;
  4858. int i;
  4859. CChoreoWidget *w;
  4860. ClearStatusArea();
  4861. for( i = 0 ; i < m_SceneActors.Count(); i++ )
  4862. {
  4863. w = m_SceneActors[ i ];
  4864. m_ActorExpanded[ i ].expanded = ((CChoreoActorWidget *)w)->GetShowChannels();
  4865. delete w;
  4866. }
  4867. m_SceneActors.RemoveAll();
  4868. for( i = 0 ; i < m_SceneGlobalEvents.Count(); i++ )
  4869. {
  4870. w = m_SceneGlobalEvents[ i ];
  4871. delete w;
  4872. }
  4873. m_SceneGlobalEvents.RemoveAll();
  4874. m_bCanDraw = oldcandraw;
  4875. // Make sure nobody is still pointing at us
  4876. m_pClickedActor = NULL;
  4877. m_pClickedChannel = NULL;
  4878. m_pClickedEvent = NULL;
  4879. m_pClickedGlobalEvent = NULL;
  4880. }
  4881. //-----------------------------------------------------------------------------
  4882. // Purpose:
  4883. //-----------------------------------------------------------------------------
  4884. void CChoreoView::InvalidateLayout( void )
  4885. {
  4886. if ( m_bSuppressLayout )
  4887. return;
  4888. if ( ComputeHPixelsNeeded() != m_nLastHPixelsNeeded )
  4889. {
  4890. RepositionHSlider();
  4891. }
  4892. if ( ComputeVPixelsNeeded() != m_nLastVPixelsNeeded )
  4893. {
  4894. RepositionVSlider();
  4895. }
  4896. // Recheck gesture start/end times
  4897. if ( m_pScene )
  4898. {
  4899. m_pScene->ReconcileGestureTimes();
  4900. m_pScene->ReconcileCloseCaption();
  4901. }
  4902. m_bLayoutIsValid = false;
  4903. redraw();
  4904. }
  4905. //-----------------------------------------------------------------------------
  4906. // Purpose:
  4907. //-----------------------------------------------------------------------------
  4908. void CChoreoView::CreateSceneWidgets( void )
  4909. {
  4910. DeleteSceneWidgets();
  4911. m_bSuppressLayout = true;
  4912. int i;
  4913. for ( i = 0; i < m_pScene->GetNumActors(); i++ )
  4914. {
  4915. CChoreoActor *a = m_pScene->GetActor( i );
  4916. Assert( a );
  4917. if ( !a )
  4918. continue;
  4919. CChoreoActorWidget *actorWidget = new CChoreoActorWidget( NULL );
  4920. Assert( actorWidget );
  4921. actorWidget->SetActor( a );
  4922. actorWidget->Create();
  4923. m_SceneActors.AddToTail( actorWidget );
  4924. actorWidget->ShowChannels( m_ActorExpanded[ i ].expanded );
  4925. }
  4926. // Find global events
  4927. for ( i = 0; i < m_pScene->GetNumEvents(); i++ )
  4928. {
  4929. CChoreoEvent *e = m_pScene->GetEvent( i );
  4930. if ( !e || e->GetActor() )
  4931. continue;
  4932. CChoreoGlobalEventWidget *eventWidget = new CChoreoGlobalEventWidget( NULL );
  4933. Assert( eventWidget );
  4934. eventWidget->SetEvent( e );
  4935. eventWidget->Create();
  4936. m_SceneGlobalEvents.AddToTail( eventWidget );
  4937. }
  4938. m_bSuppressLayout = false;
  4939. }
  4940. //-----------------------------------------------------------------------------
  4941. // Purpose:
  4942. // Output : int
  4943. //-----------------------------------------------------------------------------
  4944. int CChoreoView::GetLabelWidth( void )
  4945. {
  4946. return m_nLabelWidth;
  4947. }
  4948. //-----------------------------------------------------------------------------
  4949. // Purpose:
  4950. // Output : int
  4951. //-----------------------------------------------------------------------------
  4952. int CChoreoView::GetStartRow( void )
  4953. {
  4954. return m_nStartRow + GetCaptionHeight() + SCRUBBER_HEIGHT;
  4955. }
  4956. //-----------------------------------------------------------------------------
  4957. // Purpose:
  4958. // Output : int
  4959. //-----------------------------------------------------------------------------
  4960. int CChoreoView::GetRowHeight( void )
  4961. {
  4962. return m_nRowHeight;
  4963. }
  4964. //-----------------------------------------------------------------------------
  4965. // Purpose:
  4966. // Output : int
  4967. //-----------------------------------------------------------------------------
  4968. int CChoreoView::GetFontSize( void )
  4969. {
  4970. return m_nFontSize;
  4971. }
  4972. //-----------------------------------------------------------------------------
  4973. // Purpose:
  4974. // Output : int
  4975. //-----------------------------------------------------------------------------
  4976. int CChoreoView::ComputeVPixelsNeeded( void )
  4977. {
  4978. int pixels = 0;
  4979. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  4980. {
  4981. CChoreoActorWidget *actor = m_SceneActors[ i ];
  4982. if ( !actor )
  4983. continue;
  4984. pixels += actor->GetItemHeight() + 2;
  4985. }
  4986. pixels += GetStartRow() + 15;
  4987. // pixels += m_nInfoHeight;
  4988. //pixels += 30;
  4989. return pixels;
  4990. }
  4991. //-----------------------------------------------------------------------------
  4992. // Purpose:
  4993. // Output : int
  4994. //-----------------------------------------------------------------------------
  4995. int CChoreoView::ComputeHPixelsNeeded( void )
  4996. {
  4997. if ( !m_pScene )
  4998. {
  4999. return 0;
  5000. }
  5001. int pixels = 0;
  5002. float maxtime = m_pScene->FindStopTime();
  5003. if ( maxtime < 5.0 )
  5004. {
  5005. maxtime = 5.0f;
  5006. }
  5007. pixels = (int)( ( maxtime + 5.0 ) * GetPixelsPerSecond() );
  5008. return pixels;
  5009. }
  5010. //-----------------------------------------------------------------------------
  5011. // Purpose:
  5012. //-----------------------------------------------------------------------------
  5013. void CChoreoView::RepositionVSlider( void )
  5014. {
  5015. int pixelsneeded = ComputeVPixelsNeeded();
  5016. if ( pixelsneeded <= ( h2() - GetStartRow() ))
  5017. {
  5018. m_pVertScrollBar->setVisible( false );
  5019. m_nTopOffset = 0;
  5020. }
  5021. else
  5022. {
  5023. m_pVertScrollBar->setVisible( true );
  5024. }
  5025. m_pVertScrollBar->setBounds( w2() - m_nScrollbarHeight, GetStartRow(), m_nScrollbarHeight, h2() - m_nScrollbarHeight - GetStartRow() );
  5026. //int visiblepixels = h2() - m_nScrollbarHeight - GetStartRow();
  5027. //m_nTopOffset = min( pixelsneeded - visiblepixels, m_nTopOffset );
  5028. m_nTopOffset = max( 0, m_nTopOffset );
  5029. m_nTopOffset = min( pixelsneeded, m_nTopOffset );
  5030. m_pVertScrollBar->setRange( 0, pixelsneeded );
  5031. m_pVertScrollBar->setValue( m_nTopOffset );
  5032. m_pVertScrollBar->setPagesize( h2() - GetStartRow() );
  5033. m_nLastVPixelsNeeded = pixelsneeded;
  5034. }
  5035. //-----------------------------------------------------------------------------
  5036. // Purpose:
  5037. //-----------------------------------------------------------------------------
  5038. void CChoreoView::RepositionHSlider( void )
  5039. {
  5040. int pixelsneeded = ComputeHPixelsNeeded();
  5041. int w = w2();
  5042. int lw = GetLabelWidth();
  5043. if ( pixelsneeded <= ( w - lw ) )
  5044. {
  5045. m_pHorzScrollBar->setVisible( false );
  5046. }
  5047. else
  5048. {
  5049. m_pHorzScrollBar->setVisible( true );
  5050. }
  5051. m_pHorzScrollBar->setBounds( 0, h2() - m_nScrollbarHeight, w - m_nScrollbarHeight, m_nScrollbarHeight );
  5052. m_flLeftOffset = max( 0, m_flLeftOffset );
  5053. m_flLeftOffset = min( (float)pixelsneeded, m_flLeftOffset );
  5054. m_pHorzScrollBar->setRange( 0, pixelsneeded );
  5055. m_pHorzScrollBar->setValue( (int)m_flLeftOffset );
  5056. m_pHorzScrollBar->setPagesize(w - lw );
  5057. m_nLastHPixelsNeeded = pixelsneeded;
  5058. }
  5059. //-----------------------------------------------------------------------------
  5060. // Purpose:
  5061. // Input : dirty -
  5062. //-----------------------------------------------------------------------------
  5063. void CChoreoView::SetDirty( bool dirty, bool clearundo /*=true*/ )
  5064. {
  5065. bool changed = dirty != m_bDirty;
  5066. m_bDirty = dirty;
  5067. if ( !dirty && clearundo )
  5068. {
  5069. WipeUndo();
  5070. redraw();
  5071. }
  5072. if ( changed )
  5073. {
  5074. SetPrefix( m_bDirty ? "* " : "" );
  5075. }
  5076. }
  5077. //-----------------------------------------------------------------------------
  5078. // Purpose:
  5079. //-----------------------------------------------------------------------------
  5080. void CChoreoView::New( void )
  5081. {
  5082. if ( m_pScene )
  5083. {
  5084. Close( );
  5085. if ( m_pScene )
  5086. {
  5087. return;
  5088. }
  5089. }
  5090. char scenefile[ 512 ];
  5091. if ( FacePoser_ShowSaveFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  5092. {
  5093. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  5094. m_pScene = new CChoreoScene( this );
  5095. g_MDLViewer->InitGridSettings();
  5096. SetChoreoFile( scenefile );
  5097. m_pScene->SetPrintFunc( Con_Printf );
  5098. ShowButtons( true );
  5099. SetDirty( false );
  5100. }
  5101. if ( !m_pScene )
  5102. return;
  5103. // Get first actor name
  5104. CActorParams params;
  5105. memset( &params, 0, sizeof( params ) );
  5106. strcpy( params.m_szDialogTitle, "Create Actor" );
  5107. strcpy( params.m_szName, "" );
  5108. if ( !ActorProperties( &params ) )
  5109. return;
  5110. if ( strlen( params.m_szName ) <= 0 )
  5111. return;
  5112. SetDirty( true );
  5113. PushUndo( "Create Actor" );
  5114. Con_Printf( "Creating scene %s with actor '%s'\n", GetChoreoFile(), params.m_szName );
  5115. CChoreoActor *actor = m_pScene->AllocActor();
  5116. if ( actor )
  5117. {
  5118. actor->SetName( params.m_szName );
  5119. }
  5120. PushRedo( "Create Actor" );
  5121. CreateSceneWidgets();
  5122. // Redraw
  5123. InvalidateLayout();
  5124. }
  5125. //-----------------------------------------------------------------------------
  5126. // Purpose:
  5127. //-----------------------------------------------------------------------------
  5128. void CChoreoView::Save( void )
  5129. {
  5130. if ( !m_pScene )
  5131. return;
  5132. if ( !MakeFileWriteablePrompt( GetChoreoFile(), "VCD File" ) )
  5133. {
  5134. Con_Printf( "Not saving changes to %s\n", GetChoreoFile() );
  5135. return;
  5136. }
  5137. Con_Printf( "Saving changes to %s\n", GetChoreoFile() );
  5138. CP4AutoEditAddFile checkout( GetChoreoFile() );
  5139. if ( !m_pScene->SaveToFile( GetChoreoFile() ) )
  5140. {
  5141. mxMessageBox( this, va( "Unable to write \"%s\"", GetChoreoFile() ),
  5142. "SaveToFile", MX_MB_OK | MX_MB_ERROR );
  5143. }
  5144. g_MDLViewer->OnVCDSaved( GetChoreoFile() );
  5145. // Refresh the suffix
  5146. SetChoreoFile( GetChoreoFile() );
  5147. SetDirty( false, false );
  5148. redraw();
  5149. }
  5150. //-----------------------------------------------------------------------------
  5151. // Purpose:
  5152. //-----------------------------------------------------------------------------
  5153. void CChoreoView::SaveAs( void )
  5154. {
  5155. if ( !m_pScene )
  5156. return;
  5157. char scenefile[ 512 ];
  5158. if ( !FacePoser_ShowSaveFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  5159. return;
  5160. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  5161. Con_Printf( "Saving %s\n", scenefile );
  5162. MakeFileWriteable( scenefile );
  5163. // Change filename
  5164. SetChoreoFile( scenefile );
  5165. // Write it out baby
  5166. CP4AutoEditAddFile checkout( scenefile );
  5167. if (!m_pScene->SaveToFile( scenefile ))
  5168. {
  5169. mxMessageBox( this, va( "Unable to write \"%s\"", scenefile ),
  5170. "SaveToFile", MX_MB_OK | MX_MB_ERROR );
  5171. }
  5172. g_MDLViewer->OnVCDSaved( scenefile );
  5173. SetDirty( false, false );
  5174. }
  5175. //-----------------------------------------------------------------------------
  5176. // Purpose:
  5177. //-----------------------------------------------------------------------------
  5178. void CChoreoView::Load( void )
  5179. {
  5180. char scenefile[ 512 ];
  5181. if ( !FacePoser_ShowOpenFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  5182. {
  5183. return;
  5184. }
  5185. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  5186. LoadSceneFromFile( scenefile );
  5187. m_nextFileList.RemoveAll();
  5188. }
  5189. void CChoreoView::LoadNext( void )
  5190. {
  5191. if (GetChoreoFile() == NULL)
  5192. return;
  5193. char fixedupFile[ 512 ];
  5194. V_FixupPathName( fixedupFile, sizeof( fixedupFile ), GetChoreoFile() );
  5195. char relativeFile[ 512 ];
  5196. filesystem->FullPathToRelativePath( fixedupFile, relativeFile, sizeof( relativeFile ) );
  5197. char relativePath[ 512 ];
  5198. Q_ExtractFilePath( relativeFile, relativePath, sizeof( relativePath ) );
  5199. if (m_nextFileList.Count() == 0)
  5200. {
  5201. // iterate files in the local directory
  5202. char path[ 512 ];
  5203. strcpy( path, relativePath );
  5204. strcat( path, "/*.vcd" );
  5205. FileFindHandle_t hFindFile;
  5206. char const *fn = filesystem->FindFirstEx( path, "MOD", &hFindFile );
  5207. if ( fn )
  5208. {
  5209. while ( fn )
  5210. {
  5211. // Don't do anything with directories
  5212. if ( !filesystem->FindIsDirectory( hFindFile ) )
  5213. {
  5214. CUtlString s = fn;
  5215. m_nextFileList.AddToTail( s );
  5216. }
  5217. fn = filesystem->FindNext( hFindFile );
  5218. }
  5219. filesystem->FindClose( hFindFile );
  5220. }
  5221. }
  5222. // look for a match, then pick the next in the list
  5223. const char *fileBase;
  5224. fileBase = V_UnqualifiedFileName( fixedupFile );
  5225. for (int i = 0; i < m_nextFileList.Count(); i++)
  5226. {
  5227. if (!stricmp( fileBase, m_nextFileList[i] ))
  5228. {
  5229. char fileName[512];
  5230. strcpy( fileName, relativePath );
  5231. if (i < m_nextFileList.Count() - 1)
  5232. {
  5233. strcat( fileName, m_nextFileList[i+1] );
  5234. }
  5235. else
  5236. {
  5237. strcat( fileName, m_nextFileList[0] );
  5238. }
  5239. LoadSceneFromFile( fileName );
  5240. break;
  5241. }
  5242. }
  5243. }
  5244. //-----------------------------------------------------------------------------
  5245. // Purpose:
  5246. // Input : *filename -
  5247. //-----------------------------------------------------------------------------
  5248. void CChoreoView::LoadSceneFromFile( const char *filename )
  5249. {
  5250. if ( filename[ 0 ] == '/' ||
  5251. filename[ 0 ] == '\\' )
  5252. {
  5253. ++filename;
  5254. }
  5255. char fn[ 512 ];
  5256. Q_strncpy( fn, filename, sizeof( fn ) );
  5257. if ( m_pScene )
  5258. {
  5259. Close();
  5260. if ( m_pScene )
  5261. {
  5262. return;
  5263. }
  5264. }
  5265. m_pScene = LoadScene( fn );
  5266. g_MDLViewer->InitGridSettings();
  5267. if ( !m_pScene )
  5268. return;
  5269. g_MDLViewer->OnFileLoaded( fn );
  5270. ShowButtons( true );
  5271. CChoreoWidget::m_pScene = m_pScene;
  5272. SetChoreoFile( fn );
  5273. bool cleaned = FixupSequenceDurations( m_pScene, false );
  5274. SetDirty( cleaned );
  5275. DeleteSceneWidgets();
  5276. CreateSceneWidgets();
  5277. // Force scroll bars to recompute
  5278. ForceScrollBarsToRecompute( false );
  5279. InvalidateLayout();
  5280. }
  5281. //-----------------------------------------------------------------------------
  5282. // Purpose:
  5283. // Input : closing -
  5284. //-----------------------------------------------------------------------------
  5285. void CChoreoView::UnloadScene( void )
  5286. {
  5287. InvalidateLayout();
  5288. ReportSceneClearToTools();
  5289. ClearStatusArea();
  5290. delete m_pScene;
  5291. m_pScene = NULL;
  5292. SetDirty( false );
  5293. SetChoreoFile( "" );
  5294. g_MDLViewer->InitGridSettings();
  5295. CChoreoWidget::m_pScene = NULL;
  5296. DeleteSceneWidgets();
  5297. m_pVertScrollBar->setVisible( false );
  5298. m_pHorzScrollBar->setVisible( false );
  5299. ShowButtons( false );
  5300. }
  5301. //-----------------------------------------------------------------------------
  5302. // Purpose:
  5303. // Input : *channel -
  5304. //-----------------------------------------------------------------------------
  5305. void CChoreoView::DeleteChannel( CChoreoChannel *channel )
  5306. {
  5307. if ( !channel || !m_pScene )
  5308. return;
  5309. SetDirty( true );
  5310. PushUndo( "Delete Channel" );
  5311. DeleteSceneWidgets();
  5312. // Delete channel and it's children
  5313. // Find the appropriate actor
  5314. for ( int i = 0; i < m_pScene->GetNumActors(); i++ )
  5315. {
  5316. CChoreoActor *a = m_pScene->GetActor( i );
  5317. if ( !a )
  5318. continue;
  5319. if ( a->FindChannelIndex( channel ) == -1 )
  5320. continue;
  5321. Con_Printf( "Deleting %s\n", channel->GetName() );
  5322. a->RemoveChannel( channel );
  5323. m_pScene->DeleteReferencedObjects( channel );
  5324. break;
  5325. }
  5326. ReportSceneClearToTools();
  5327. CreateSceneWidgets();
  5328. PushRedo( "Delete Channel" );
  5329. // Redraw
  5330. InvalidateLayout();
  5331. }
  5332. //-----------------------------------------------------------------------------
  5333. // Purpose:
  5334. //-----------------------------------------------------------------------------
  5335. void CChoreoView::NewChannel( void )
  5336. {
  5337. if ( !m_pScene )
  5338. return;
  5339. if ( !m_pScene->GetNumActors() )
  5340. {
  5341. Con_Printf( "You must create an actor before you can add a channel\n" );
  5342. return;
  5343. }
  5344. CChannelParams params;
  5345. memset( &params, 0, sizeof( params ) );
  5346. strcpy( params.m_szDialogTitle, "Create Channel" );
  5347. strcpy( params.m_szName, "" );
  5348. params.m_bShowActors = true;
  5349. strcpy( params.m_szSelectedActor, "" );
  5350. params.m_pScene = m_pScene;
  5351. if ( !ChannelProperties( &params ) )
  5352. {
  5353. return;
  5354. }
  5355. if ( strlen( params.m_szName ) <= 0 )
  5356. {
  5357. return;
  5358. }
  5359. CChoreoActor *actor = m_pScene->FindActor( params.m_szSelectedActor );
  5360. if ( !actor )
  5361. {
  5362. Con_Printf( "Can't add channel %s, actor %s doesn't exist\n", params.m_szName, params.m_szSelectedActor );
  5363. return;
  5364. }
  5365. SetDirty( true );
  5366. PushUndo( "Add Channel" );
  5367. DeleteSceneWidgets();
  5368. CChoreoChannel *channel = m_pScene->AllocChannel();
  5369. if ( !channel )
  5370. {
  5371. Con_Printf( "Unable to allocate channel %s!\n", params.m_szName );
  5372. }
  5373. else
  5374. {
  5375. channel->SetName( params.m_szName );
  5376. channel->SetActor( actor );
  5377. actor->AddChannel( channel );
  5378. }
  5379. CreateSceneWidgets();
  5380. PushRedo( "Add Channel" );
  5381. // Redraw
  5382. InvalidateLayout();
  5383. }
  5384. //-----------------------------------------------------------------------------
  5385. // Purpose:
  5386. // Input : *channel -
  5387. //-----------------------------------------------------------------------------
  5388. void CChoreoView::MoveChannelUp( CChoreoChannel *channel )
  5389. {
  5390. SetDirty( true );
  5391. PushUndo( "Move Channel Up" );
  5392. DeleteSceneWidgets();
  5393. // Find the appropriate actor
  5394. for ( int i = 0; i < m_pScene->GetNumActors(); i++ )
  5395. {
  5396. CChoreoActor *a = m_pScene->GetActor( i );
  5397. if ( !a )
  5398. continue;
  5399. int index = a->FindChannelIndex( channel );
  5400. if ( index == -1 )
  5401. continue;
  5402. if ( index != 0 )
  5403. {
  5404. Con_Printf( "Moving %s up\n", channel->GetName() );
  5405. a->SwapChannels( index, index - 1 );
  5406. }
  5407. break;
  5408. }
  5409. CreateSceneWidgets();
  5410. PushRedo( "Move Channel Up" );
  5411. // Redraw
  5412. InvalidateLayout();
  5413. }
  5414. //-----------------------------------------------------------------------------
  5415. // Purpose:
  5416. // Input : *channel -
  5417. //-----------------------------------------------------------------------------
  5418. void CChoreoView::MoveChannelDown( CChoreoChannel *channel )
  5419. {
  5420. SetDirty( true );
  5421. PushUndo( "Move Channel Down" );
  5422. DeleteSceneWidgets();
  5423. // Find the appropriate actor
  5424. for ( int i = 0; i < m_pScene->GetNumActors(); i++ )
  5425. {
  5426. CChoreoActor *a = m_pScene->GetActor( i );
  5427. if ( !a )
  5428. continue;
  5429. int index = a->FindChannelIndex( channel );
  5430. if ( index == -1 )
  5431. continue;
  5432. if ( index < a->GetNumChannels() - 1 )
  5433. {
  5434. Con_Printf( "Moving %s down\n", channel->GetName() );
  5435. a->SwapChannels( index, index + 1 );
  5436. }
  5437. break;
  5438. }
  5439. CreateSceneWidgets();
  5440. PushRedo( "Move Channel Down" );
  5441. // Redraw
  5442. InvalidateLayout();
  5443. }
  5444. //-----------------------------------------------------------------------------
  5445. // Purpose:
  5446. // Input : *channel -
  5447. //-----------------------------------------------------------------------------
  5448. void CChoreoView::EditChannel( CChoreoChannel *channel )
  5449. {
  5450. if ( !channel )
  5451. return;
  5452. CChannelParams params;
  5453. memset( &params, 0, sizeof( params ) );
  5454. strcpy( params.m_szDialogTitle, "Edit Channel" );
  5455. strcpy( params.m_szName, channel->GetName() );
  5456. if ( !ChannelProperties( &params ) )
  5457. return;
  5458. if ( strlen( params.m_szName ) <= 0 )
  5459. return;
  5460. SetDirty( true );
  5461. PushUndo( "Edit Channel" );
  5462. channel->SetName( params.m_szName );
  5463. PushRedo( "Edit Channel" );
  5464. // Redraw
  5465. InvalidateLayout();
  5466. }
  5467. //-----------------------------------------------------------------------------
  5468. // Purpose:
  5469. // Input : *actor -
  5470. //-----------------------------------------------------------------------------
  5471. void CChoreoView::DeleteActor( CChoreoActor *actor )
  5472. {
  5473. if ( !actor || !m_pScene )
  5474. return;
  5475. SetDirty( true );
  5476. PushUndo( "Delete Actor" );
  5477. DeleteSceneWidgets();
  5478. // Delete channel and it's children
  5479. // Find the appropriate actor
  5480. Con_Printf( "Deleting %s\n", actor->GetName() );
  5481. m_pScene->RemoveActor( actor );
  5482. m_pScene->DeleteReferencedObjects( actor );
  5483. ReportSceneClearToTools();
  5484. CreateSceneWidgets();
  5485. PushRedo( "Delete Actor" );
  5486. // Redraw
  5487. InvalidateLayout();
  5488. }
  5489. //-----------------------------------------------------------------------------
  5490. // Purpose:
  5491. //-----------------------------------------------------------------------------
  5492. void CChoreoView::NewActor( void )
  5493. {
  5494. if ( !m_pScene )
  5495. {
  5496. Con_ErrorPrintf( "You must load or create a scene file first\n" );
  5497. return;
  5498. }
  5499. CActorParams params;
  5500. memset( &params, 0, sizeof( params ) );
  5501. strcpy( params.m_szDialogTitle, "Create Actor" );
  5502. strcpy( params.m_szName, "" );
  5503. if ( !ActorProperties( &params ) )
  5504. return;
  5505. if ( strlen( params.m_szName ) <= 0 )
  5506. return;
  5507. SetDirty( true );
  5508. PushUndo( "Add Actor" );
  5509. DeleteSceneWidgets();
  5510. Con_Printf( "Adding new actor '%s'\n", params.m_szName );
  5511. CChoreoActor *actor = m_pScene->AllocActor();
  5512. if ( actor )
  5513. {
  5514. actor->SetName( params.m_szName );
  5515. }
  5516. CreateSceneWidgets();
  5517. PushRedo( "Add Actor" );
  5518. // Redraw
  5519. InvalidateLayout();
  5520. }
  5521. //-----------------------------------------------------------------------------
  5522. // Purpose:
  5523. // Input : *actor -
  5524. //-----------------------------------------------------------------------------
  5525. void CChoreoView::MoveActorUp( CChoreoActor *actor )
  5526. {
  5527. DeleteSceneWidgets();
  5528. int index = m_pScene->FindActorIndex( actor );
  5529. // found it and it's not first
  5530. if ( index != -1 && index != 0 )
  5531. {
  5532. Con_Printf( "Moving %s up\n", actor->GetName() );
  5533. SetDirty( true );
  5534. PushUndo( "Move Actor Up" );
  5535. m_pScene->SwapActors( index, index - 1 );
  5536. PushRedo( "Move Actor Up" );
  5537. }
  5538. CreateSceneWidgets();
  5539. // Redraw
  5540. InvalidateLayout();
  5541. }
  5542. //-----------------------------------------------------------------------------
  5543. // Purpose:
  5544. // Input : *actor -
  5545. //-----------------------------------------------------------------------------
  5546. void CChoreoView::MoveActorDown( CChoreoActor *actor )
  5547. {
  5548. DeleteSceneWidgets();
  5549. int index = m_pScene->FindActorIndex( actor );
  5550. // found it and it's not first
  5551. if ( index != -1 && ( index < m_pScene->GetNumActors() - 1 ) )
  5552. {
  5553. Con_Printf( "Moving %s down\n", actor->GetName() );
  5554. SetDirty( true );
  5555. PushUndo( "Move Actor Down" );
  5556. m_pScene->SwapActors( index, index + 1 );
  5557. PushRedo( "Move Actor Down" );
  5558. }
  5559. CreateSceneWidgets();
  5560. // Redraw
  5561. InvalidateLayout();
  5562. }
  5563. //-----------------------------------------------------------------------------
  5564. // Purpose:
  5565. // Input : *actor -
  5566. //-----------------------------------------------------------------------------
  5567. void CChoreoView::EditActor( CChoreoActor *actor )
  5568. {
  5569. if ( !actor )
  5570. return;
  5571. CActorParams params;
  5572. memset( &params, 0, sizeof( params ) );
  5573. strcpy( params.m_szDialogTitle, "Edit Actor" );
  5574. strcpy( params.m_szName, actor->GetName() );
  5575. if ( !ActorProperties( &params ) )
  5576. return;
  5577. if ( strlen( params.m_szName ) <= 0 )
  5578. return;
  5579. SetDirty( true );
  5580. PushUndo( "Edit Actor" );
  5581. actor->SetName( params.m_szName );
  5582. PushRedo( "Edit Actor" );
  5583. // Redraw
  5584. InvalidateLayout();
  5585. }
  5586. //-----------------------------------------------------------------------------
  5587. // Purpose:
  5588. // Input : type -
  5589. //-----------------------------------------------------------------------------
  5590. void CChoreoView::AddEvent( int type, int subtype /*= 0*/, char const *defaultparameters /*= NULL*/ )
  5591. {
  5592. int mx, my;
  5593. mx = m_nClickedX;
  5594. my = m_nClickedY;
  5595. CChoreoChannelWidget *channel = m_pClickedChannel;
  5596. if ( !channel || !channel->GetChannel() )
  5597. {
  5598. CChoreoActorWidget *actor = m_pClickedActor;
  5599. if ( actor )
  5600. {
  5601. if ( actor->GetNumChannels() <= 0 )
  5602. return;
  5603. channel = actor->GetChannel( 0 );
  5604. if ( !channel || !channel->GetChannel() )
  5605. return;
  5606. }
  5607. else
  5608. {
  5609. return;
  5610. }
  5611. }
  5612. // Convert click position local to this window
  5613. POINT pt;
  5614. pt.x = mx;
  5615. pt.y = my;
  5616. CEventParams params;
  5617. memset( &params, 0, sizeof( params ) );
  5618. if ( defaultparameters )
  5619. {
  5620. Q_strncpy( params.m_szParameters, defaultparameters, sizeof( params.m_szParameters ) );
  5621. }
  5622. strcpy( params.m_szDialogTitle, "Create Event" );
  5623. params.m_nType = type;
  5624. params.m_pScene = m_pScene;
  5625. params.m_bFixedLength = false;
  5626. params.m_bResumeCondition = false;
  5627. params.m_flStartTime = GetTimeValueForMouse( pt.x );
  5628. params.m_bCloseCaptionNoAttenuate = false;
  5629. params.m_bForceShortMovement = false;
  5630. params.m_bSyncToFollowingGesture = false;
  5631. params.m_bDisabled = false;
  5632. params.m_bPlayOverScript = false;
  5633. switch ( type )
  5634. {
  5635. case CChoreoEvent::EXPRESSION:
  5636. case CChoreoEvent::FLEXANIMATION:
  5637. case CChoreoEvent::GESTURE:
  5638. case CChoreoEvent::SEQUENCE:
  5639. case CChoreoEvent::LOOKAT:
  5640. case CChoreoEvent::MOVETO:
  5641. case CChoreoEvent::FACE:
  5642. case CChoreoEvent::SUBSCENE:
  5643. case CChoreoEvent::INTERRUPT:
  5644. case CChoreoEvent::GENERIC:
  5645. case CChoreoEvent::CAMERA:
  5646. case CChoreoEvent::PERMIT_RESPONSES:
  5647. params.m_bHasEndTime = true;
  5648. params.m_flEndTime = params.m_flStartTime + 0.5f;
  5649. if ( type == CChoreoEvent::GESTURE && subtype == 1 )
  5650. {
  5651. strcpy( params.m_szDialogTitle, "Create <NULL> Gesture" );
  5652. strcpy( params.m_szName, "NULL" );
  5653. }
  5654. break;
  5655. case CChoreoEvent::SPEAK:
  5656. params.m_bFixedLength = true;
  5657. params.m_bHasEndTime = false;
  5658. params.m_flEndTime = -1.0f;
  5659. break;
  5660. default:
  5661. params.m_bHasEndTime = false;
  5662. params.m_flEndTime = -1.0f;
  5663. break;
  5664. }
  5665. params.m_bUsesTag = false;
  5666. while (1)
  5667. {
  5668. SetScrubTargetTime( m_flScrub );
  5669. FinishSimulation();
  5670. sound->Flush();
  5671. m_bForceProcess = true;
  5672. if (!EventProperties( &params ))
  5673. {
  5674. m_bForceProcess = false;
  5675. return;
  5676. }
  5677. m_bForceProcess = false;
  5678. if ( Q_strlen( params.m_szName ) <= 0 )
  5679. {
  5680. mxMessageBox( this, va( "Event must have a valid name" ),
  5681. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  5682. continue;
  5683. }
  5684. if ( Q_strlen( params.m_szParameters ) <= 0 )
  5685. {
  5686. bool shouldBreak = false;
  5687. switch ( params.m_nType )
  5688. {
  5689. case CChoreoEvent::FLEXANIMATION:
  5690. case CChoreoEvent::INTERRUPT:
  5691. case CChoreoEvent::PERMIT_RESPONSES:
  5692. shouldBreak = true;
  5693. break;
  5694. case CChoreoEvent::GESTURE:
  5695. if ( subtype == 1 )
  5696. {
  5697. shouldBreak = true;
  5698. }
  5699. break;
  5700. default:
  5701. // Have to have a non-null parameters block
  5702. break;
  5703. }
  5704. if ( !shouldBreak )
  5705. {
  5706. mxMessageBox( this, va( "No parameters specified for %s\n", params.m_szName ),
  5707. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  5708. continue;
  5709. }
  5710. }
  5711. break;
  5712. }
  5713. SetDirty( true );
  5714. PushUndo( "Add Event" );
  5715. CChoreoEvent *event = m_pScene->AllocEvent();
  5716. if ( event )
  5717. {
  5718. event->SetType( (CChoreoEvent::EVENTTYPE)type );
  5719. event->SetName( params.m_szName );
  5720. event->SetParameters( params.m_szParameters );
  5721. event->SetParameters2( params.m_szParameters2 );
  5722. event->SetParameters3( params.m_szParameters3 );
  5723. event->SetStartTime( params.m_flStartTime );
  5724. event->SetResumeCondition( params.m_bResumeCondition );
  5725. event->SetLockBodyFacing( params.m_bLockBodyFacing );
  5726. event->SetDistanceToTarget( params.m_flDistanceToTarget );
  5727. event->SetForceShortMovement( params.m_bForceShortMovement );
  5728. event->SetSyncToFollowingGesture( params.m_bSyncToFollowingGesture );
  5729. event->SetActive( !params.m_bDisabled );
  5730. event->SetPlayOverScript( params.m_bPlayOverScript );
  5731. if ( params.m_bUsesTag )
  5732. {
  5733. event->SetUsingRelativeTag( true, params.m_szTagName, params.m_szTagWav );
  5734. }
  5735. else
  5736. {
  5737. event->SetUsingRelativeTag( false );
  5738. }
  5739. CChoreoChannel *pchannel = channel->GetChannel();
  5740. event->SetChannel( pchannel );
  5741. event->SetActor( pchannel->GetActor() );
  5742. if ( params.m_bHasEndTime &&
  5743. params.m_flEndTime != -1.0 &&
  5744. params.m_flEndTime > params.m_flStartTime )
  5745. {
  5746. event->SetEndTime( params.m_flEndTime );
  5747. }
  5748. else
  5749. {
  5750. event->SetEndTime( -1.0f );
  5751. }
  5752. switch ( event->GetType() )
  5753. {
  5754. default:
  5755. break;
  5756. case CChoreoEvent::SUBSCENE:
  5757. {
  5758. // Just grab end time
  5759. CChoreoScene *scene = LoadScene( event->GetParameters() );
  5760. if ( scene )
  5761. {
  5762. event->SetEndTime( params.m_flStartTime + scene->FindStopTime() );
  5763. }
  5764. delete scene;
  5765. }
  5766. break;
  5767. case CChoreoEvent::SEQUENCE:
  5768. {
  5769. CheckSequenceLength( event, false );
  5770. // AutoaddSequenceKeys( event);
  5771. }
  5772. break;
  5773. case CChoreoEvent::GESTURE:
  5774. {
  5775. DefaultGestureLength( event, false );
  5776. AutoaddGestureKeys( event, false );
  5777. }
  5778. break;
  5779. case CChoreoEvent::LOOKAT:
  5780. case CChoreoEvent::FACE:
  5781. {
  5782. if ( params.usepitchyaw )
  5783. {
  5784. event->SetPitch( params.pitch );
  5785. event->SetYaw( params.yaw );
  5786. }
  5787. else
  5788. {
  5789. event->SetPitch( 0 );
  5790. event->SetYaw( 0 );
  5791. }
  5792. }
  5793. break;
  5794. case CChoreoEvent::SPEAK:
  5795. {
  5796. // Try and load wav to get length
  5797. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  5798. if ( wave )
  5799. {
  5800. event->SetEndTime( params.m_flStartTime + wave->GetRunningLength() );
  5801. delete wave;
  5802. }
  5803. event->SetSuppressingCaptionAttenuation( params.m_bCloseCaptionNoAttenuate );
  5804. }
  5805. break;
  5806. }
  5807. event->SnapTimes();
  5808. DeleteSceneWidgets();
  5809. // Add to appropriate channel
  5810. pchannel->AddEvent( event );
  5811. CreateSceneWidgets();
  5812. // Redraw
  5813. InvalidateLayout();
  5814. }
  5815. PushRedo( "Add Event" );
  5816. }
  5817. //-----------------------------------------------------------------------------
  5818. // Purpose: Adds a scene "pause" event
  5819. //-----------------------------------------------------------------------------
  5820. void CChoreoView::AddGlobalEvent( CChoreoEvent::EVENTTYPE type )
  5821. {
  5822. int mx, my;
  5823. mx = m_nClickedX;
  5824. my = m_nClickedY;
  5825. // Convert click position local to this window
  5826. POINT pt;
  5827. pt.x = mx;
  5828. pt.y = my;
  5829. CGlobalEventParams params;
  5830. memset( &params, 0, sizeof( params ) );
  5831. params.m_nType = type;
  5832. switch ( type )
  5833. {
  5834. default:
  5835. Assert( 0 );
  5836. strcpy( params.m_szDialogTitle, "???" );
  5837. break;
  5838. case CChoreoEvent::SECTION:
  5839. {
  5840. strcpy( params.m_szDialogTitle, "Add Pause Point" );
  5841. }
  5842. break;
  5843. case CChoreoEvent::LOOP:
  5844. {
  5845. strcpy( params.m_szDialogTitle, "Add Loop Point" );
  5846. }
  5847. break;
  5848. case CChoreoEvent::STOPPOINT:
  5849. {
  5850. strcpy( params.m_szDialogTitle, "Add Fire Completion" );
  5851. }
  5852. break;
  5853. }
  5854. strcpy( params.m_szName, "" );
  5855. strcpy( params.m_szAction, "" );
  5856. params.m_flStartTime = GetTimeValueForMouse( pt.x );
  5857. if ( !GlobalEventProperties( &params ) )
  5858. return;
  5859. if ( strlen( params.m_szName ) <= 0 )
  5860. {
  5861. Con_Printf( "Pause section event must have a valid name\n" );
  5862. return;
  5863. }
  5864. if ( strlen( params.m_szAction ) <= 0 )
  5865. {
  5866. Con_Printf( "No action specified for section pause\n" );
  5867. return;
  5868. }
  5869. char undotext[ 256 ];
  5870. undotext[0]=0;
  5871. switch( type )
  5872. {
  5873. default:
  5874. Assert( 0 );
  5875. break;
  5876. case CChoreoEvent::SECTION:
  5877. {
  5878. Q_strcpy( undotext, "Add Section Pause" );
  5879. }
  5880. break;
  5881. case CChoreoEvent::LOOP:
  5882. {
  5883. Q_strcpy( undotext, "Add Loop Point" );
  5884. }
  5885. break;
  5886. case CChoreoEvent::STOPPOINT:
  5887. {
  5888. Q_strcpy( undotext, "Add Fire Completion" );
  5889. }
  5890. break;
  5891. }
  5892. SetDirty( true );
  5893. PushUndo( undotext );
  5894. CChoreoEvent *event = m_pScene->AllocEvent();
  5895. if ( event )
  5896. {
  5897. event->SetType( type );
  5898. event->SetName( params.m_szName );
  5899. event->SetParameters( params.m_szAction );
  5900. event->SetStartTime( params.m_flStartTime );
  5901. event->SetEndTime( -1.0f );
  5902. switch ( type )
  5903. {
  5904. default:
  5905. break;
  5906. case CChoreoEvent::LOOP:
  5907. {
  5908. event->SetLoopCount( params.m_nLoopCount );
  5909. event->SetParameters( va( "%f", params.m_flLoopTime ) );
  5910. }
  5911. break;
  5912. }
  5913. event->SnapTimes();
  5914. DeleteSceneWidgets();
  5915. CreateSceneWidgets();
  5916. // Redraw
  5917. InvalidateLayout();
  5918. }
  5919. PushRedo( undotext );
  5920. }
  5921. //-----------------------------------------------------------------------------
  5922. // Purpose:
  5923. // Input : *event -
  5924. //-----------------------------------------------------------------------------
  5925. void CChoreoView::EditGlobalEvent( CChoreoEvent *event )
  5926. {
  5927. if ( !event )
  5928. return;
  5929. CGlobalEventParams params;
  5930. memset( &params, 0, sizeof( params ) );
  5931. params.m_nType = event->GetType();
  5932. switch ( event->GetType() )
  5933. {
  5934. default:
  5935. Assert( 0 );
  5936. strcpy( params.m_szDialogTitle, "???" );
  5937. break;
  5938. case CChoreoEvent::SECTION:
  5939. {
  5940. strcpy( params.m_szDialogTitle, "Edit Pause Point" );
  5941. strcpy( params.m_szAction, event->GetParameters() );
  5942. }
  5943. break;
  5944. case CChoreoEvent::LOOP:
  5945. {
  5946. strcpy( params.m_szDialogTitle, "Edit Loop Point" );
  5947. strcpy( params.m_szAction, "" );
  5948. params.m_flLoopTime = (float)atof( event->GetParameters() );
  5949. params.m_nLoopCount = event->GetLoopCount();
  5950. }
  5951. break;
  5952. case CChoreoEvent::STOPPOINT:
  5953. {
  5954. strcpy( params.m_szDialogTitle, "Edit Fire Completion" );
  5955. strcpy( params.m_szAction, "" );
  5956. }
  5957. break;
  5958. }
  5959. strcpy( params.m_szName, event->GetName() );
  5960. params.m_flStartTime = event->GetStartTime();
  5961. if ( !GlobalEventProperties( &params ) )
  5962. return;
  5963. if ( strlen( params.m_szName ) <= 0 )
  5964. {
  5965. Con_Printf( "Event %s must have a valid name\n", event->GetName() );
  5966. return;
  5967. }
  5968. if ( strlen( params.m_szAction ) <= 0 )
  5969. {
  5970. Con_Printf( "No action specified for %s\n", event->GetName() );
  5971. return;
  5972. }
  5973. SetDirty( true );
  5974. char undotext[ 256 ];
  5975. undotext[0]=0;
  5976. switch( event->GetType() )
  5977. {
  5978. default:
  5979. Assert( 0 );
  5980. break;
  5981. case CChoreoEvent::SECTION:
  5982. {
  5983. Q_strcpy( undotext, "Edit Section Pause" );
  5984. }
  5985. break;
  5986. case CChoreoEvent::LOOP:
  5987. {
  5988. Q_strcpy( undotext, "Edit Loop Point" );
  5989. }
  5990. break;
  5991. case CChoreoEvent::STOPPOINT:
  5992. {
  5993. Q_strcpy( undotext, "Edit Fire Completion" );
  5994. }
  5995. break;
  5996. }
  5997. PushUndo( undotext );
  5998. event->SetName( params.m_szName );
  5999. event->SetStartTime( params.m_flStartTime );
  6000. event->SetEndTime( -1.0f );
  6001. switch ( event->GetType() )
  6002. {
  6003. default:
  6004. {
  6005. event->SetParameters( params.m_szAction );
  6006. }
  6007. break;
  6008. case CChoreoEvent::LOOP:
  6009. {
  6010. event->SetLoopCount( params.m_nLoopCount );
  6011. event->SetParameters( va( "%f", params.m_flLoopTime ) );
  6012. }
  6013. break;
  6014. }
  6015. event->SnapTimes();
  6016. PushRedo( undotext );
  6017. // Redraw
  6018. InvalidateLayout();
  6019. }
  6020. //-----------------------------------------------------------------------------
  6021. // Purpose:
  6022. // Input : *event -
  6023. //-----------------------------------------------------------------------------
  6024. void CChoreoView::DeleteGlobalEvent( CChoreoEvent *event )
  6025. {
  6026. if ( !event || !m_pScene )
  6027. return;
  6028. SetDirty( true );
  6029. char undotext[ 256 ];
  6030. undotext[0]=0;
  6031. switch( event->GetType() )
  6032. {
  6033. default:
  6034. Assert( 0 );
  6035. break;
  6036. case CChoreoEvent::SECTION:
  6037. {
  6038. Q_strcpy( undotext, "Delete Section Pause" );
  6039. }
  6040. break;
  6041. case CChoreoEvent::LOOP:
  6042. {
  6043. Q_strcpy( undotext, "Delete Loop Point" );
  6044. }
  6045. break;
  6046. case CChoreoEvent::STOPPOINT:
  6047. {
  6048. Q_strcpy( undotext, "Delete Fire Completion" );
  6049. }
  6050. break;
  6051. }
  6052. PushUndo( undotext );
  6053. DeleteSceneWidgets();
  6054. Con_Printf( "Deleting %s\n", event->GetName() );
  6055. m_pScene->DeleteReferencedObjects( event );
  6056. CreateSceneWidgets();
  6057. PushRedo( undotext );
  6058. // Redraw
  6059. InvalidateLayout();
  6060. }
  6061. //-----------------------------------------------------------------------------
  6062. // Purpose:
  6063. // Input : *event -
  6064. //-----------------------------------------------------------------------------
  6065. void CChoreoView::EditEvent( CChoreoEvent *event )
  6066. {
  6067. if ( !event )
  6068. return;
  6069. CEventParams params;
  6070. memset( &params, 0, sizeof( params ) );
  6071. strcpy( params.m_szDialogTitle, "Edit Event" );
  6072. // Copy in current even properties
  6073. params.m_nType = event->GetType();
  6074. params.m_bDisabled = !event->GetActive();
  6075. switch ( params.m_nType )
  6076. {
  6077. case CChoreoEvent::EXPRESSION:
  6078. case CChoreoEvent::SEQUENCE:
  6079. case CChoreoEvent::MOVETO:
  6080. case CChoreoEvent::SPEAK:
  6081. case CChoreoEvent::GESTURE:
  6082. case CChoreoEvent::INTERRUPT:
  6083. case CChoreoEvent::PERMIT_RESPONSES:
  6084. case CChoreoEvent::GENERIC:
  6085. case CChoreoEvent::CAMERA:
  6086. strcpy( params.m_szParameters3, event->GetParameters3() );
  6087. strcpy( params.m_szParameters2, event->GetParameters2() );
  6088. strcpy( params.m_szParameters, event->GetParameters() );
  6089. strcpy( params.m_szName, event->GetName() );
  6090. break;
  6091. case CChoreoEvent::FACE:
  6092. case CChoreoEvent::LOOKAT:
  6093. case CChoreoEvent::FIRETRIGGER:
  6094. case CChoreoEvent::FLEXANIMATION:
  6095. case CChoreoEvent::SUBSCENE:
  6096. strcpy( params.m_szParameters, event->GetParameters() );
  6097. strcpy( params.m_szName, event->GetName() );
  6098. if ( params.m_nType == CChoreoEvent::LOOKAT || params.m_nType == CChoreoEvent::FACE )
  6099. {
  6100. if ( event->GetPitch() != 0 ||
  6101. event->GetYaw() != 0 )
  6102. {
  6103. params.usepitchyaw = true;
  6104. params.pitch = event->GetPitch();
  6105. params.yaw = event->GetYaw();
  6106. }
  6107. }
  6108. break;
  6109. default:
  6110. Con_Printf( "Don't know how to edit event type %s\n",
  6111. CChoreoEvent::NameForType( (CChoreoEvent::EVENTTYPE)params.m_nType ) );
  6112. return;
  6113. }
  6114. params.m_pScene = m_pScene;
  6115. params.m_pEvent = event;
  6116. params.m_flStartTime = event->GetStartTime();
  6117. params.m_flEndTime = event->GetEndTime();
  6118. params.m_bHasEndTime = event->HasEndTime();
  6119. params.m_bFixedLength = event->IsFixedLength();
  6120. params.m_bResumeCondition = event->IsResumeCondition();
  6121. params.m_bLockBodyFacing = event->IsLockBodyFacing();
  6122. params.m_flDistanceToTarget = event->GetDistanceToTarget();
  6123. params.m_bForceShortMovement = event->GetForceShortMovement();
  6124. params.m_bSyncToFollowingGesture = event->GetSyncToFollowingGesture();
  6125. params.m_bPlayOverScript = event->GetPlayOverScript();
  6126. params.m_bUsesTag = event->IsUsingRelativeTag();
  6127. params.m_bCloseCaptionNoAttenuate = event->IsSuppressingCaptionAttenuation();
  6128. if ( params.m_bUsesTag )
  6129. {
  6130. strcpy( params.m_szTagName, event->GetRelativeTagName() );
  6131. strcpy( params.m_szTagWav, event->GetRelativeWavName() );
  6132. }
  6133. while (1)
  6134. {
  6135. SetScrubTargetTime( m_flScrub );
  6136. FinishSimulation();
  6137. sound->Flush();
  6138. m_bForceProcess = true;
  6139. if (!EventProperties( &params ))
  6140. {
  6141. m_bForceProcess = false;
  6142. return;
  6143. }
  6144. m_bForceProcess = false;
  6145. if ( Q_strlen( params.m_szName ) <= 0 )
  6146. {
  6147. mxMessageBox( this, va( "Event %s must have a valid name", event->GetName() ),
  6148. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  6149. continue;
  6150. }
  6151. if ( Q_strlen( params.m_szParameters ) <= 0 )
  6152. {
  6153. bool shouldBreak = false;
  6154. switch ( params.m_nType )
  6155. {
  6156. case CChoreoEvent::FLEXANIMATION:
  6157. case CChoreoEvent::INTERRUPT:
  6158. case CChoreoEvent::PERMIT_RESPONSES:
  6159. shouldBreak = true;
  6160. break;
  6161. case CChoreoEvent::GESTURE:
  6162. if ( !Q_stricmp( params.m_szName, "NULL" ) )
  6163. {
  6164. shouldBreak = true;
  6165. }
  6166. break;
  6167. default:
  6168. // Have to have a non-null parameters block
  6169. break;
  6170. }
  6171. if ( !shouldBreak )
  6172. {
  6173. mxMessageBox( this, va( "No parameters specified for %s\n", params.m_szName ),
  6174. "Edit Event", MX_MB_OK | MX_MB_ERROR );
  6175. continue;
  6176. }
  6177. }
  6178. break;
  6179. }
  6180. SetDirty( true );
  6181. PushUndo( "Edit Event" );
  6182. event->SetName( params.m_szName );
  6183. event->SetParameters( params.m_szParameters );
  6184. event->SetParameters2( params.m_szParameters2 );
  6185. event->SetParameters3( params.m_szParameters3 );
  6186. event->SetStartTime( params.m_flStartTime );
  6187. event->SetResumeCondition( params.m_bResumeCondition );
  6188. event->SetLockBodyFacing( params.m_bLockBodyFacing );
  6189. event->SetDistanceToTarget( params.m_flDistanceToTarget );
  6190. event->SetForceShortMovement( params.m_bForceShortMovement );
  6191. event->SetSyncToFollowingGesture( params.m_bSyncToFollowingGesture );
  6192. event->SetActive( !params.m_bDisabled );
  6193. event->SetPlayOverScript( params.m_bPlayOverScript );
  6194. if ( params.m_bUsesTag )
  6195. {
  6196. event->SetUsingRelativeTag( true, params.m_szTagName, params.m_szTagWav );
  6197. }
  6198. else
  6199. {
  6200. event->SetUsingRelativeTag( false );
  6201. }
  6202. if ( params.m_bHasEndTime &&
  6203. params.m_flEndTime != -1.0 &&
  6204. params.m_flEndTime > params.m_flStartTime )
  6205. {
  6206. float dt = params.m_flEndTime - event->GetEndTime();
  6207. float newduration = event->GetDuration() + dt;
  6208. RescaleRamp( event, newduration );
  6209. switch ( event->GetType() )
  6210. {
  6211. default:
  6212. break;
  6213. case CChoreoEvent::GESTURE:
  6214. {
  6215. event->RescaleGestureTimes( event->GetStartTime(), event->GetEndTime() + dt, true );
  6216. }
  6217. break;
  6218. case CChoreoEvent::FLEXANIMATION:
  6219. {
  6220. RescaleExpressionTimes( event, event->GetStartTime(), event->GetEndTime() + dt );
  6221. }
  6222. break;
  6223. }
  6224. event->SetEndTime( params.m_flEndTime );
  6225. event->SnapTimes();
  6226. event->ResortRamp();
  6227. }
  6228. else
  6229. {
  6230. event->SetEndTime( -1.0f );
  6231. }
  6232. switch ( event->GetType() )
  6233. {
  6234. default:
  6235. break;
  6236. case CChoreoEvent::SPEAK:
  6237. {
  6238. // Try and load wav to get length
  6239. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  6240. if ( wave )
  6241. {
  6242. event->SetEndTime( params.m_flStartTime + wave->GetRunningLength() );
  6243. delete wave;
  6244. }
  6245. event->SetSuppressingCaptionAttenuation( params.m_bCloseCaptionNoAttenuate );
  6246. }
  6247. break;
  6248. case CChoreoEvent::SUBSCENE:
  6249. {
  6250. // Just grab end time
  6251. CChoreoScene *scene = LoadScene( event->GetParameters() );
  6252. if ( scene )
  6253. {
  6254. event->SetEndTime( params.m_flStartTime + scene->FindStopTime() );
  6255. }
  6256. delete scene;
  6257. }
  6258. break;
  6259. case CChoreoEvent::SEQUENCE:
  6260. {
  6261. CheckSequenceLength( event, false );
  6262. }
  6263. break;
  6264. case CChoreoEvent::GESTURE:
  6265. {
  6266. CheckGestureLength( event, false );
  6267. AutoaddGestureKeys( event, false );
  6268. g_pGestureTool->redraw();
  6269. }
  6270. break;
  6271. case CChoreoEvent::LOOKAT:
  6272. case CChoreoEvent::FACE:
  6273. {
  6274. if ( params.usepitchyaw )
  6275. {
  6276. event->SetPitch( params.pitch );
  6277. event->SetYaw( params.yaw );
  6278. }
  6279. else
  6280. {
  6281. event->SetPitch( 0 );
  6282. event->SetYaw( 0 );
  6283. }
  6284. }
  6285. break;
  6286. }
  6287. event->SnapTimes();
  6288. PushRedo( "Edit Event" );
  6289. // Redraw
  6290. InvalidateLayout();
  6291. }
  6292. void CChoreoView::EnableSelectedEvents( bool state )
  6293. {
  6294. if ( !m_pScene )
  6295. return;
  6296. SetDirty( true );
  6297. // If we right clicked on an unseleced event, then select it for the user.
  6298. if ( CountSelectedEvents() == 0 )
  6299. {
  6300. CChoreoEventWidget *event = m_pClickedEvent;
  6301. if ( event )
  6302. {
  6303. event->SetSelected( true );
  6304. }
  6305. }
  6306. char const *desc = state ? "Enable Events" : "Disable Events";
  6307. PushUndo( desc );
  6308. // Find the appropriate event by iterating across all actors and channels
  6309. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  6310. {
  6311. CChoreoActorWidget *a = m_SceneActors[ i ];
  6312. if ( !a )
  6313. continue;
  6314. for ( int j = 0; j < a->GetNumChannels(); j++ )
  6315. {
  6316. CChoreoChannelWidget *channel = a->GetChannel( j );
  6317. if ( !channel )
  6318. continue;
  6319. for ( int k = channel->GetNumEvents() - 1; k >= 0; k-- )
  6320. {
  6321. CChoreoEventWidget *event = channel->GetEvent( k );
  6322. if ( !event->IsSelected() )
  6323. continue;
  6324. event->GetEvent()->SetActive( state );
  6325. }
  6326. }
  6327. }
  6328. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  6329. {
  6330. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  6331. if ( !event || !event->IsSelected() )
  6332. continue;
  6333. event->GetEvent()->SetActive( state );
  6334. }
  6335. PushRedo( desc );
  6336. // Redraw
  6337. InvalidateLayout();
  6338. }
  6339. //-----------------------------------------------------------------------------
  6340. // Purpose:
  6341. // Input : *event -
  6342. //-----------------------------------------------------------------------------
  6343. void CChoreoView::DeleteSelectedEvents( void )
  6344. {
  6345. if ( !m_pScene )
  6346. return;
  6347. SetDirty( true );
  6348. PushUndo( "Delete Events" );
  6349. int deleteCount = 0;
  6350. float oldstoptime = m_pScene->FindStopTime();
  6351. // Find the appropriate event by iterating across all actors and channels
  6352. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  6353. {
  6354. CChoreoActorWidget *a = m_SceneActors[ i ];
  6355. if ( !a )
  6356. continue;
  6357. for ( int j = 0; j < a->GetNumChannels(); j++ )
  6358. {
  6359. CChoreoChannelWidget *channel = a->GetChannel( j );
  6360. if ( !channel )
  6361. continue;
  6362. for ( int k = channel->GetNumEvents() - 1; k >= 0; k-- )
  6363. {
  6364. CChoreoEventWidget *event = channel->GetEvent( k );
  6365. if ( !event->IsSelected() )
  6366. continue;
  6367. channel->GetChannel()->RemoveEvent( event->GetEvent() );
  6368. m_pScene->DeleteReferencedObjects( event->GetEvent() );
  6369. deleteCount++;
  6370. }
  6371. }
  6372. }
  6373. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  6374. {
  6375. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  6376. if ( !event || !event->IsSelected() )
  6377. continue;
  6378. m_pScene->DeleteReferencedObjects( event->GetEvent() );
  6379. deleteCount++;
  6380. }
  6381. DeleteSceneWidgets();
  6382. ReportSceneClearToTools();
  6383. CreateSceneWidgets();
  6384. PushRedo( "Delete Events" );
  6385. Con_Printf( "Deleted <%i> events\n", deleteCount );
  6386. if ( m_pScene->FindStopTime() != oldstoptime )
  6387. {
  6388. // Force scroll bars to recompute
  6389. ForceScrollBarsToRecompute( false );
  6390. }
  6391. // Redraw
  6392. InvalidateLayout();
  6393. }
  6394. //-----------------------------------------------------------------------------
  6395. // Purpose:
  6396. // Input : resetthumb -
  6397. //-----------------------------------------------------------------------------
  6398. void CChoreoView::ForceScrollBarsToRecompute( bool resetthumb )
  6399. {
  6400. if ( resetthumb )
  6401. {
  6402. m_flLeftOffset = 0.0f;
  6403. }
  6404. m_nLastHPixelsNeeded = -1;
  6405. m_nLastVPixelsNeeded = -1;
  6406. }
  6407. //-----------------------------------------------------------------------------
  6408. // Purpose:
  6409. // Input : *filename -
  6410. // Output : CChoreoScene
  6411. //-----------------------------------------------------------------------------
  6412. CChoreoScene *CChoreoView::LoadScene( char const *filename )
  6413. {
  6414. // If relative path, then make a full path
  6415. char pFullPathBuf[ MAX_PATH ];
  6416. if ( !Q_IsAbsolutePath( filename ) )
  6417. {
  6418. filesystem->RelativePathToFullPath( filename, "GAME", pFullPathBuf, sizeof( pFullPathBuf ) );
  6419. filename = pFullPathBuf;
  6420. }
  6421. if ( !filesystem->FileExists( filename ) )
  6422. return NULL;
  6423. LoadScriptFile( const_cast<char*>( filename ) );
  6424. CChoreoScene *scene = ChoreoLoadScene( filename, this, tokenprocessor, Con_Printf );
  6425. return scene;
  6426. }
  6427. //-----------------------------------------------------------------------------
  6428. // Purpose:
  6429. //-----------------------------------------------------------------------------
  6430. bool CChoreoView::FixupSequenceDurations( CChoreoScene *scene, bool checkonly )
  6431. {
  6432. bool bret = false;
  6433. if ( !scene )
  6434. return bret;
  6435. int c = scene->GetNumEvents();
  6436. for ( int i = 0; i < c; i++ )
  6437. {
  6438. CChoreoEvent *event = scene->GetEvent( i );
  6439. if ( !event )
  6440. continue;
  6441. switch ( event->GetType() )
  6442. {
  6443. default:
  6444. break;
  6445. case CChoreoEvent::SPEAK:
  6446. {
  6447. // Try and load wav to get length
  6448. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  6449. if ( wave )
  6450. {
  6451. float endtime = event->GetStartTime() + wave->GetRunningLength();
  6452. if ( event->GetEndTime() != endtime )
  6453. {
  6454. event->SetEndTime( event->GetStartTime() + wave->GetRunningLength() );
  6455. bret = true;
  6456. }
  6457. delete wave;
  6458. }
  6459. }
  6460. break;
  6461. case CChoreoEvent::SEQUENCE:
  6462. {
  6463. if ( CheckSequenceLength( event, checkonly ) )
  6464. {
  6465. bret = true;
  6466. }
  6467. }
  6468. break;
  6469. case CChoreoEvent::GESTURE:
  6470. {
  6471. if ( CheckGestureLength( event, checkonly ) )
  6472. {
  6473. bret = true;
  6474. }
  6475. if ( AutoaddGestureKeys( event, checkonly ) )
  6476. {
  6477. bret = true;
  6478. }
  6479. }
  6480. break;
  6481. }
  6482. }
  6483. return bret;
  6484. }
  6485. //-----------------------------------------------------------------------------
  6486. // Purpose: IChoreoEventCallback
  6487. // Input : currenttime -
  6488. // *event -
  6489. //-----------------------------------------------------------------------------
  6490. void CChoreoView::StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  6491. {
  6492. if ( !event || !event->GetActive() )
  6493. return;
  6494. CChoreoActor *actor = event->GetActor();
  6495. if ( actor && !actor->GetActive() )
  6496. {
  6497. return;
  6498. }
  6499. CChoreoChannel *channel = event->GetChannel();
  6500. if ( channel && !channel->GetActive() )
  6501. {
  6502. return;
  6503. }
  6504. // Con_Printf( "%8.4f: start %s\n", currenttime, event->GetDescription() );
  6505. switch ( event->GetType() )
  6506. {
  6507. case CChoreoEvent::SEQUENCE:
  6508. {
  6509. ProcessSequence( scene, event );
  6510. }
  6511. break;
  6512. case CChoreoEvent::SUBSCENE:
  6513. {
  6514. if ( !scene->IsSubScene() )
  6515. {
  6516. CChoreoScene *subscene = event->GetSubScene();
  6517. if ( !subscene )
  6518. {
  6519. subscene = LoadScene( event->GetParameters() );
  6520. subscene->SetSubScene( true );
  6521. event->SetSubScene( subscene );
  6522. }
  6523. if ( subscene )
  6524. {
  6525. subscene->ResetSimulation( m_bForward );
  6526. }
  6527. }
  6528. }
  6529. break;
  6530. case CChoreoEvent::SECTION:
  6531. {
  6532. ProcessPause( scene, event );
  6533. }
  6534. break;
  6535. case CChoreoEvent::SPEAK:
  6536. {
  6537. if ( ShouldProcessSpeak() )
  6538. {
  6539. // See if we should trigger CC
  6540. char soundname[ 512 ];
  6541. Q_strncpy( soundname, event->GetParameters(), sizeof( soundname ) );
  6542. float actualEndTime = event->GetEndTime();
  6543. if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
  6544. {
  6545. char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  6546. if ( event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
  6547. {
  6548. float duration = max( event->GetDuration(), event->GetLastSlaveEndTime() - event->GetStartTime() );
  6549. closecaptionmanager->Process( tok, duration, GetCloseCaptionLanguageId() );
  6550. // Use the token as the sound name lookup, too.
  6551. if ( event->IsUsingCombinedFile() &&
  6552. ( event->GetNumSlaves() > 0 ) )
  6553. {
  6554. Q_strncpy( soundname, tok, sizeof( soundname ) );
  6555. actualEndTime = max( actualEndTime, event->GetLastSlaveEndTime() );
  6556. }
  6557. }
  6558. }
  6559. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  6560. CAudioMixer *mixer = event->GetMixer();
  6561. if ( !mixer || !sound->IsSoundPlaying( mixer ) )
  6562. {
  6563. CSoundParameters params;
  6564. float volume = VOL_NORM;
  6565. gender_t gender = GENDER_NONE;
  6566. if (model)
  6567. {
  6568. gender = soundemitter->GetActorGender( model->GetFileName() );
  6569. }
  6570. if ( !Q_stristr( soundname, ".wav" ) &&
  6571. soundemitter->GetParametersForSound( soundname, params, gender ) )
  6572. {
  6573. volume = params.volume;
  6574. }
  6575. sound->PlaySound(
  6576. model,
  6577. volume,
  6578. va( "sound/%s", FacePoser_TranslateSoundName( soundname, model ) ),
  6579. &mixer );
  6580. event->SetMixer( mixer );
  6581. }
  6582. if ( mixer )
  6583. {
  6584. mixer->SetDirection( m_flFrameTime >= 0.0f );
  6585. float starttime, endtime;
  6586. starttime = event->GetStartTime();
  6587. endtime = actualEndTime;
  6588. float soundtime = endtime - starttime;
  6589. if ( soundtime > 0.0f )
  6590. {
  6591. float f = ( currenttime - starttime ) / soundtime;
  6592. f = clamp( f, 0.0f, 1.0f );
  6593. // Compute sample
  6594. float numsamples = (float)mixer->GetSource()->SampleCount();
  6595. int cursample = f * numsamples;
  6596. cursample = clamp( cursample, 0, numsamples - 1 );
  6597. mixer->SetSamplePosition( cursample );
  6598. mixer->SetActive( true );
  6599. }
  6600. }
  6601. }
  6602. }
  6603. break;
  6604. case CChoreoEvent::EXPRESSION:
  6605. {
  6606. }
  6607. break;
  6608. case CChoreoEvent::LOOP:
  6609. {
  6610. ProcessLoop( scene, event );
  6611. }
  6612. break;
  6613. case CChoreoEvent::STOPPOINT:
  6614. {
  6615. // Nothing, this is a symbolic event for keeping the vcd alive for ramping out after the last true event
  6616. }
  6617. break;
  6618. default:
  6619. break;
  6620. }
  6621. }
  6622. //-----------------------------------------------------------------------------
  6623. // Purpose:
  6624. // Input : currenttime -
  6625. // *event -
  6626. //-----------------------------------------------------------------------------
  6627. void CChoreoView::EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event )
  6628. {
  6629. if ( !event || !event->GetActive() )
  6630. return;
  6631. CChoreoActor *actor = event->GetActor();
  6632. if ( actor && !actor->GetActive() )
  6633. {
  6634. return;
  6635. }
  6636. CChoreoChannel *channel = event->GetChannel();
  6637. if ( channel && !channel->GetActive() )
  6638. {
  6639. return;
  6640. }
  6641. switch ( event->GetType() )
  6642. {
  6643. case CChoreoEvent::SUBSCENE:
  6644. {
  6645. CChoreoScene *subscene = event->GetSubScene();
  6646. if ( subscene )
  6647. {
  6648. subscene->ResetSimulation();
  6649. }
  6650. }
  6651. break;
  6652. case CChoreoEvent::SPEAK:
  6653. {
  6654. CAudioMixer *mixer = event->GetMixer();
  6655. if ( mixer && sound->IsSoundPlaying( mixer ) )
  6656. {
  6657. sound->StopSound( mixer );
  6658. }
  6659. event->SetMixer( NULL );
  6660. }
  6661. break;
  6662. default:
  6663. break;
  6664. }
  6665. // Con_Printf( "%8.4f: finish %s\n", currenttime, event->GetDescription() );
  6666. }
  6667. //-----------------------------------------------------------------------------
  6668. // Purpose:
  6669. // Input : *event -
  6670. // mx -
  6671. // my -
  6672. //-----------------------------------------------------------------------------
  6673. int CChoreoView::GetTagUnderCursorPos( CChoreoEventWidget *event, int mx, int my )
  6674. {
  6675. if ( !event )
  6676. {
  6677. return -1;
  6678. }
  6679. for ( int i = 0; i < event->GetEvent()->GetNumRelativeTags(); i++ )
  6680. {
  6681. CEventRelativeTag *tag = event->GetEvent()->GetRelativeTag( i );
  6682. if ( !tag )
  6683. continue;
  6684. // Determine left edcge
  6685. RECT bounds;
  6686. bounds = event->getBounds();
  6687. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  6688. int tolerance = 3;
  6689. if ( abs( mx - left ) < tolerance )
  6690. {
  6691. if ( abs( my - bounds.top ) < tolerance )
  6692. {
  6693. return i;
  6694. }
  6695. }
  6696. }
  6697. return -1;
  6698. }
  6699. //-----------------------------------------------------------------------------
  6700. // Purpose:
  6701. // Input : *event -
  6702. // mx -
  6703. // my -
  6704. //-----------------------------------------------------------------------------
  6705. CEventAbsoluteTag *CChoreoView::GetAbsoluteTagUnderCursorPos( CChoreoEventWidget *event, int mx, int my )
  6706. {
  6707. if ( !event )
  6708. {
  6709. return NULL;
  6710. }
  6711. for ( int i = 0; i < event->GetEvent()->GetNumAbsoluteTags( CChoreoEvent::PLAYBACK ); i++ )
  6712. {
  6713. CEventAbsoluteTag *tag = event->GetEvent()->GetAbsoluteTag( CChoreoEvent::PLAYBACK, i );
  6714. if ( !tag )
  6715. continue;
  6716. // Determine left edcge
  6717. RECT bounds;
  6718. bounds = event->getBounds();
  6719. int left = bounds.left + (int)( tag->GetPercentage() * (float)( bounds.right - bounds.left ) + 0.5f );
  6720. int tolerance = 3;
  6721. if ( abs( mx - left ) < tolerance )
  6722. {
  6723. if ( abs( my - bounds.top ) < tolerance )
  6724. {
  6725. return tag;
  6726. }
  6727. }
  6728. }
  6729. return NULL;
  6730. }
  6731. //-----------------------------------------------------------------------------
  6732. // Purpose:
  6733. // Input : mx -
  6734. // my -
  6735. // **actor -
  6736. // **channel -
  6737. // **event -
  6738. //-----------------------------------------------------------------------------
  6739. void CChoreoView::GetObjectsUnderMouse( int mx, int my, CChoreoActorWidget **actor,
  6740. CChoreoChannelWidget **channel, CChoreoEventWidget **event, CChoreoGlobalEventWidget **globalevent,
  6741. int *clickedTag,
  6742. CEventAbsoluteTag **absolutetag, int *clickedCCArea )
  6743. {
  6744. if ( actor )
  6745. {
  6746. *actor = GetActorUnderCursorPos( mx, my );
  6747. }
  6748. if ( channel )
  6749. {
  6750. *channel = GetChannelUnderCursorPos( mx, my );
  6751. if ( *channel && clickedCCArea )
  6752. {
  6753. *clickedCCArea = (*channel)->GetChannelItemUnderMouse( mx, my );
  6754. }
  6755. }
  6756. if ( event )
  6757. {
  6758. *event = GetEventUnderCursorPos( mx, my );
  6759. }
  6760. if ( globalevent )
  6761. {
  6762. *globalevent = GetGlobalEventUnderCursorPos( mx, my );
  6763. }
  6764. if ( clickedTag )
  6765. {
  6766. if ( event && *event )
  6767. {
  6768. *clickedTag = GetTagUnderCursorPos( *event, mx, my );
  6769. }
  6770. else
  6771. {
  6772. *clickedTag = -1;
  6773. }
  6774. }
  6775. if ( absolutetag )
  6776. {
  6777. if ( event && *event )
  6778. {
  6779. *absolutetag = GetAbsoluteTagUnderCursorPos( *event, mx, my );
  6780. }
  6781. else
  6782. {
  6783. *absolutetag = NULL;
  6784. }
  6785. }
  6786. m_nSelectedEvents = CountSelectedEvents();
  6787. }
  6788. //-----------------------------------------------------------------------------
  6789. // Purpose:
  6790. // Input : mx -
  6791. // my -
  6792. // Output : CChoreoGlobalEventWidget
  6793. //-----------------------------------------------------------------------------
  6794. CChoreoGlobalEventWidget *CChoreoView::GetGlobalEventUnderCursorPos( int mx, int my )
  6795. {
  6796. POINT check;
  6797. check.x = mx;
  6798. check.y = my;
  6799. CChoreoGlobalEventWidget *event;
  6800. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  6801. {
  6802. event = m_SceneGlobalEvents[ i ];
  6803. if ( !event )
  6804. continue;
  6805. RECT bounds;
  6806. event->getBounds( bounds );
  6807. if ( PtInRect( &bounds, check ) )
  6808. {
  6809. return event;
  6810. }
  6811. }
  6812. return NULL;
  6813. }
  6814. //-----------------------------------------------------------------------------
  6815. // Purpose: Caller must first translate mouse into screen coordinates
  6816. // Input : mx -
  6817. // my -
  6818. //-----------------------------------------------------------------------------
  6819. CChoreoActorWidget *CChoreoView::GetActorUnderCursorPos( int mx, int my )
  6820. {
  6821. POINT check;
  6822. check.x = mx;
  6823. check.y = my;
  6824. CChoreoActorWidget *actor;
  6825. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  6826. {
  6827. actor = m_SceneActors[ i ];
  6828. if ( !actor )
  6829. continue;
  6830. RECT bounds;
  6831. actor->getBounds( bounds );
  6832. if ( PtInRect( &bounds, check ) )
  6833. {
  6834. return actor;
  6835. }
  6836. }
  6837. return NULL;
  6838. }
  6839. //-----------------------------------------------------------------------------
  6840. // Purpose: Caller must first translate mouse into screen coordinates
  6841. // Input : mx -
  6842. // my -
  6843. // Output : CChoreoChannelWidget
  6844. //-----------------------------------------------------------------------------
  6845. CChoreoChannelWidget *CChoreoView::GetChannelUnderCursorPos( int mx, int my )
  6846. {
  6847. CChoreoActorWidget *actor = GetActorUnderCursorPos( mx, my );
  6848. if ( !actor )
  6849. {
  6850. return NULL;
  6851. }
  6852. POINT check;
  6853. check.x = mx;
  6854. check.y = my;
  6855. CChoreoChannelWidget *channel;
  6856. for ( int i = 0; i < actor->GetNumChannels(); i++ )
  6857. {
  6858. channel = actor->GetChannel( i );
  6859. if ( !channel )
  6860. continue;
  6861. RECT bounds;
  6862. channel->getBounds( bounds );
  6863. if ( PtInRect( &bounds, check ) )
  6864. {
  6865. return channel;
  6866. }
  6867. }
  6868. return NULL;
  6869. }
  6870. //-----------------------------------------------------------------------------
  6871. // Purpose: Caller must first translate mouse into screen coordinates
  6872. // Input : mx -
  6873. // my -
  6874. //-----------------------------------------------------------------------------
  6875. CChoreoEventWidget *CChoreoView::GetEventUnderCursorPos( int mx, int my )
  6876. {
  6877. CChoreoChannelWidget *channel = GetChannelUnderCursorPos( mx, my );
  6878. if ( !channel )
  6879. {
  6880. return NULL;
  6881. }
  6882. POINT check;
  6883. check.x = mx;
  6884. check.y = my;
  6885. if ( mx < GetLabelWidth() )
  6886. return NULL;
  6887. if ( my < GetStartRow() )
  6888. return NULL;
  6889. if ( my >= h2() - ( m_nInfoHeight + m_nScrollbarHeight ) )
  6890. return NULL;
  6891. CChoreoEventWidget *event;
  6892. for ( int i = 0; i < channel->GetNumEvents(); i++ )
  6893. {
  6894. event = channel->GetEvent( i );
  6895. if ( !event )
  6896. continue;
  6897. RECT bounds;
  6898. event->getBounds( bounds );
  6899. // Events get an expanded border
  6900. InflateRect( &bounds, 8, 4 );
  6901. if ( PtInRect( &bounds, check ) )
  6902. {
  6903. return event;
  6904. }
  6905. }
  6906. return NULL;
  6907. }
  6908. //-----------------------------------------------------------------------------
  6909. // Purpose: Select wave file for phoneme editing
  6910. // Input : *filename -
  6911. //-----------------------------------------------------------------------------
  6912. void CChoreoView::SetCurrentWaveFile( const char *filename, CChoreoEvent *event )
  6913. {
  6914. g_pPhonemeEditor->SetCurrentWaveFile( filename, false, event );
  6915. }
  6916. //-----------------------------------------------------------------------------
  6917. // Purpose:
  6918. // Input : pfn -
  6919. // *param1 -
  6920. //-----------------------------------------------------------------------------
  6921. void CChoreoView::TraverseWidgets( CVMEMBERFUNC pfn, CChoreoWidget *param1 )
  6922. {
  6923. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  6924. {
  6925. CChoreoActorWidget *actor = m_SceneActors[ i ];
  6926. if ( !actor )
  6927. continue;
  6928. (this->*pfn)( actor, param1 );
  6929. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  6930. {
  6931. CChoreoChannelWidget *channel = actor->GetChannel( j );
  6932. if ( !channel )
  6933. continue;
  6934. (this->*pfn)( channel, param1 );
  6935. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  6936. {
  6937. CChoreoEventWidget *event = channel->GetEvent( k );
  6938. if ( !event )
  6939. continue;
  6940. (this->*pfn)( event, param1 );
  6941. }
  6942. }
  6943. }
  6944. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  6945. {
  6946. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  6947. if ( !event )
  6948. continue;
  6949. (this->*pfn)( event, param1 );
  6950. }
  6951. }
  6952. //-----------------------------------------------------------------------------
  6953. // Purpose:
  6954. // Input : *widget -
  6955. // *param1 -
  6956. //-----------------------------------------------------------------------------
  6957. void CChoreoView::Deselect( CChoreoWidget *widget, CChoreoWidget *param1 )
  6958. {
  6959. if ( widget->IsSelected() )
  6960. {
  6961. widget->SetSelected( false );
  6962. }
  6963. }
  6964. //-----------------------------------------------------------------------------
  6965. // Purpose:
  6966. // Input : *widget -
  6967. // *param1 -
  6968. //-----------------------------------------------------------------------------
  6969. void CChoreoView::Select( CChoreoWidget *widget, CChoreoWidget *param1 )
  6970. {
  6971. if ( widget != param1 )
  6972. return;
  6973. if ( widget->IsSelected() )
  6974. return;
  6975. widget->SetSelected( true );
  6976. }
  6977. //-----------------------------------------------------------------------------
  6978. // Purpose:
  6979. // Input : *widget -
  6980. // *param1 -
  6981. //-----------------------------------------------------------------------------
  6982. void CChoreoView::SelectAllEvents( CChoreoWidget *widget, CChoreoWidget *param1 )
  6983. {
  6984. CChoreoEventWidget *ew = dynamic_cast< CChoreoEventWidget * >( widget );
  6985. CChoreoGlobalEventWidget *gew = dynamic_cast< CChoreoGlobalEventWidget * >( widget );
  6986. if ( ew || gew )
  6987. {
  6988. if ( widget->IsSelected() )
  6989. return;
  6990. widget->SetSelected( true );
  6991. }
  6992. }
  6993. bool CChoreoView::CreateAnimationEvent( int mx, int my, char const *animationname )
  6994. {
  6995. if ( !animationname || !animationname[0] )
  6996. return false;
  6997. // Convert screen to client
  6998. POINT pt;
  6999. pt.x = mx;
  7000. pt.y = my;
  7001. ScreenToClient( (HWND)getHandle(), &pt );
  7002. if ( pt.x < 0 || pt.y < 0 )
  7003. return false;
  7004. if ( pt.x > w2() || pt.y > h2() )
  7005. return false;
  7006. pt.x -= GetLabelWidth();
  7007. m_nClickedX = pt.x;
  7008. GetObjectsUnderMouse( pt.x, pt.y, &m_pClickedActor, &m_pClickedChannel, &m_pClickedEvent, &m_pClickedGlobalEvent, &m_nClickedTag, &m_pClickedAbsoluteTag, &m_nClickedChannelCloseCaptionButton );
  7009. // Find channel actor and time ( uses screen space coordinates )
  7010. //
  7011. CChoreoChannelWidget *channel = GetChannelUnderCursorPos( pt.x, pt.y );
  7012. if ( !channel )
  7013. {
  7014. CChoreoActorWidget *actor = GetActorUnderCursorPos( pt.x, pt.y );
  7015. if ( !actor )
  7016. return false;
  7017. // Grab first channel
  7018. if ( !actor->GetNumChannels() )
  7019. return false;
  7020. channel = actor->GetChannel( 0 );
  7021. }
  7022. if ( !channel )
  7023. return false;
  7024. CChoreoChannel *pchannel = channel->GetChannel();
  7025. if ( !pchannel )
  7026. {
  7027. Assert( 0 );
  7028. return false;
  7029. }
  7030. // At this point we need to ask the user what type of even to create (gesture or sequence) and just show the approprite dialog
  7031. CChoiceParams params;
  7032. strcpy( params.m_szDialogTitle, "Create Animation Event" );
  7033. params.m_bPositionDialog = false;
  7034. params.m_nLeft = 0;
  7035. params.m_nTop = 0;
  7036. strcpy( params.m_szPrompt, "Type of event:" );
  7037. params.m_Choices.RemoveAll();
  7038. params.m_nSelected = 0;
  7039. ChoiceText text;
  7040. strcpy( text.choice, "gesture" );
  7041. params.m_Choices.AddToTail( text );
  7042. strcpy( text.choice, "sequence" );
  7043. params.m_Choices.AddToTail( text );
  7044. if ( !ChoiceProperties( &params ) )
  7045. return false;
  7046. if ( params.m_nSelected < 0 )
  7047. return false;
  7048. switch ( params.m_nSelected )
  7049. {
  7050. default:
  7051. case 0:
  7052. AddEvent( CChoreoEvent::GESTURE, 0, animationname );
  7053. break;
  7054. case 1:
  7055. AddEvent( CChoreoEvent::SEQUENCE, 0, animationname );
  7056. break;
  7057. }
  7058. return true;
  7059. }
  7060. //-----------------------------------------------------------------------------
  7061. // Purpose:
  7062. // Input : mx -
  7063. // my -
  7064. // *cl -
  7065. // *exp -
  7066. // Output : Returns true on success, false on failure.
  7067. //-----------------------------------------------------------------------------
  7068. bool CChoreoView::CreateExpressionEvent( int mx, int my, CExpClass *cl, CExpression *exp )
  7069. {
  7070. if ( !m_pScene )
  7071. return false;
  7072. if ( !exp )
  7073. return false;
  7074. // Convert screen to client
  7075. POINT pt;
  7076. pt.x = mx;
  7077. pt.y = my;
  7078. ScreenToClient( (HWND)getHandle(), &pt );
  7079. if ( pt.x < 0 || pt.y < 0 )
  7080. return false;
  7081. if ( pt.x > w2() || pt.y > h2() )
  7082. return false;
  7083. // Find channel actor and time ( uses screen space coordinates )
  7084. //
  7085. CChoreoChannelWidget *channel = GetChannelUnderCursorPos( pt.x, pt.y );
  7086. if ( !channel )
  7087. {
  7088. CChoreoActorWidget *actor = GetActorUnderCursorPos( pt.x, pt.y );
  7089. if ( !actor )
  7090. return false;
  7091. // Grab first channel
  7092. if ( !actor->GetNumChannels() )
  7093. return false;
  7094. channel = actor->GetChannel( 0 );
  7095. }
  7096. if ( !channel )
  7097. return false;
  7098. CChoreoChannel *pchannel = channel->GetChannel();
  7099. if ( !pchannel )
  7100. {
  7101. Assert( 0 );
  7102. return false;
  7103. }
  7104. CChoreoEvent *event = m_pScene->AllocEvent();
  7105. if ( !event )
  7106. {
  7107. Assert( 0 );
  7108. return false;
  7109. }
  7110. float starttime = GetTimeValueForMouse( pt.x, false );
  7111. SetDirty( true );
  7112. PushUndo( "Create Expression" );
  7113. event->SetType( CChoreoEvent::EXPRESSION );
  7114. event->SetName( exp->name );
  7115. event->SetParameters( cl->GetName() );
  7116. event->SetParameters2( exp->name );
  7117. event->SetStartTime( starttime );
  7118. event->SetChannel( pchannel );
  7119. event->SetActor( pchannel->GetActor() );
  7120. event->SetEndTime( starttime + 1.0f );
  7121. event->SnapTimes();
  7122. DeleteSceneWidgets();
  7123. // Add to appropriate channel
  7124. pchannel->AddEvent( event );
  7125. CreateSceneWidgets();
  7126. PushRedo( "Create Expression" );
  7127. // Redraw
  7128. InvalidateLayout();
  7129. return true;
  7130. }
  7131. //-----------------------------------------------------------------------------
  7132. // Purpose:
  7133. // Output : Returns true on success, false on failure.
  7134. //-----------------------------------------------------------------------------
  7135. bool CChoreoView::IsPlayingScene( void )
  7136. {
  7137. return m_bSimulating;
  7138. }
  7139. //-----------------------------------------------------------------------------
  7140. // Purpose:
  7141. //-----------------------------------------------------------------------------
  7142. void CChoreoView::ResetTargetSettings( void )
  7143. {
  7144. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  7145. {
  7146. CChoreoActorWidget *w = m_SceneActors[ i ];
  7147. if ( w )
  7148. {
  7149. w->ResetSettings();
  7150. }
  7151. }
  7152. models->ClearModelTargets( true );
  7153. }
  7154. //-----------------------------------------------------------------------------
  7155. // Purpose: copies the actors "settings" into the models FlexControllers
  7156. // Input : dt -
  7157. //-----------------------------------------------------------------------------
  7158. void CChoreoView::UpdateCurrentSettings( void )
  7159. {
  7160. StudioModel *defaultModel = models->GetActiveStudioModel();
  7161. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  7162. {
  7163. CChoreoActorWidget *w = m_SceneActors[ i ];
  7164. if ( !w )
  7165. continue;
  7166. if ( !w->GetActor()->GetActive() )
  7167. continue;
  7168. StudioModel *model = FindAssociatedModel( m_pScene, w->GetActor() );
  7169. if ( !model )
  7170. continue;
  7171. CStudioHdr *hdr = model->GetStudioHdr();
  7172. if ( !hdr )
  7173. continue;
  7174. float *current = w->GetSettings();
  7175. for ( LocalFlexController_t j = LocalFlexController_t(0); j < hdr->numflexcontrollers(); j++ )
  7176. {
  7177. int k = hdr->pFlexcontroller( j )->localToGlobal;
  7178. if (k != -1)
  7179. {
  7180. if ( defaultModel == model && g_pFlexPanel->IsEdited( k ) )
  7181. {
  7182. model->SetFlexController( j, g_pFlexPanel->GetSlider( k ) );
  7183. }
  7184. else
  7185. {
  7186. model->SetFlexController( j, current[ k ] );
  7187. }
  7188. }
  7189. }
  7190. }
  7191. }
  7192. //-----------------------------------------------------------------------------
  7193. // Purpose:
  7194. // Input : *event -
  7195. // tagnum -
  7196. //-----------------------------------------------------------------------------
  7197. void CChoreoView::DeleteEventRelativeTag( CChoreoEvent *event, int tagnum )
  7198. {
  7199. if ( !event )
  7200. return;
  7201. CEventRelativeTag *tag = event->GetRelativeTag( tagnum );
  7202. if ( !tag )
  7203. return;
  7204. SetDirty( true );
  7205. PushUndo( "Delete Event Tag" );
  7206. event->RemoveRelativeTag( tag->GetName() );
  7207. m_pScene->ReconcileTags();
  7208. PushRedo( "Delete Event Tag" );
  7209. g_pPhonemeEditor->redraw();
  7210. InvalidateLayout();
  7211. }
  7212. //-----------------------------------------------------------------------------
  7213. // Purpose:
  7214. // Input : *event -
  7215. //-----------------------------------------------------------------------------
  7216. void CChoreoView::AddEventRelativeTag( void )
  7217. {
  7218. CChoreoEventWidget *ew = m_pClickedEvent;
  7219. if ( !ew )
  7220. return;
  7221. CChoreoEvent *event = ew->GetEvent();
  7222. if ( !event->GetEndTime() )
  7223. {
  7224. Con_ErrorPrintf( "Event Tag: Can only tag events with an end time\n" );
  7225. return;
  7226. }
  7227. CInputParams params;
  7228. memset( &params, 0, sizeof( params ) );
  7229. strcpy( params.m_szDialogTitle, "Event Tag Name" );
  7230. strcpy( params.m_szPrompt, "Name:" );
  7231. strcpy( params.m_szInputText, "" );
  7232. if ( !InputProperties( &params ) )
  7233. return;
  7234. if ( strlen( params.m_szInputText ) <= 0 )
  7235. {
  7236. Con_ErrorPrintf( "Event Tag Name: No name entered!\n" );
  7237. return;
  7238. }
  7239. RECT bounds = ew->getBounds();
  7240. // Convert click to frac
  7241. float frac = 0.0f;
  7242. if ( bounds.right - bounds.left > 0 )
  7243. {
  7244. frac = (float)( m_nClickedX - bounds.left ) / (float)( bounds.right - bounds.left );
  7245. frac = min( 1.0f, frac );
  7246. frac = max( 0.0f, frac );
  7247. }
  7248. SetDirty( true );
  7249. PushUndo( "Add Event Tag" );
  7250. event->AddRelativeTag( params.m_szInputText, frac );
  7251. PushRedo( "Add Event Tag" );
  7252. InvalidateLayout();
  7253. g_pPhonemeEditor->redraw();
  7254. g_pExpressionTool->redraw();
  7255. g_pGestureTool->redraw();
  7256. g_pRampTool->redraw();
  7257. g_pSceneRampTool->redraw();
  7258. }
  7259. CChoreoChannelWidget *CChoreoView::FindChannelForEvent( CChoreoEvent *event )
  7260. {
  7261. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  7262. {
  7263. CChoreoActorWidget *a = m_SceneActors[ i ];
  7264. if ( !a )
  7265. continue;
  7266. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7267. {
  7268. CChoreoChannelWidget *c = a->GetChannel( j );
  7269. if ( !c )
  7270. continue;
  7271. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7272. {
  7273. CChoreoEventWidget *e = c->GetEvent( k );
  7274. if ( !e )
  7275. continue;
  7276. if ( e->GetEvent() != event )
  7277. continue;
  7278. return c;
  7279. }
  7280. }
  7281. }
  7282. return NULL;
  7283. }
  7284. //-----------------------------------------------------------------------------
  7285. // Purpose:
  7286. // Input : *event -
  7287. // Output : CChoreoEventWidget
  7288. //-----------------------------------------------------------------------------
  7289. CChoreoEventWidget *CChoreoView::FindWidgetForEvent( CChoreoEvent *event )
  7290. {
  7291. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  7292. {
  7293. CChoreoActorWidget *a = m_SceneActors[ i ];
  7294. if ( !a )
  7295. continue;
  7296. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7297. {
  7298. CChoreoChannelWidget *c = a->GetChannel( j );
  7299. if ( !c )
  7300. continue;
  7301. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7302. {
  7303. CChoreoEventWidget *e = c->GetEvent( k );
  7304. if ( !e )
  7305. continue;
  7306. if ( e->GetEvent() != event )
  7307. continue;
  7308. return e;
  7309. }
  7310. }
  7311. }
  7312. return NULL;
  7313. }
  7314. //-----------------------------------------------------------------------------
  7315. // Purpose:
  7316. //-----------------------------------------------------------------------------
  7317. void CChoreoView::SelectAll( void )
  7318. {
  7319. TraverseWidgets( &CChoreoView::SelectAllEvents, NULL );
  7320. redraw();
  7321. }
  7322. //-----------------------------------------------------------------------------
  7323. // Purpose:
  7324. //-----------------------------------------------------------------------------
  7325. void CChoreoView::DeselectAll( void )
  7326. {
  7327. TraverseWidgets( &CChoreoView::Deselect, NULL );
  7328. redraw();
  7329. }
  7330. //-----------------------------------------------------------------------------
  7331. // Purpose:
  7332. // Input : mx -
  7333. // my -
  7334. //-----------------------------------------------------------------------------
  7335. void CChoreoView::UpdateStatusArea( int mx, int my )
  7336. {
  7337. FLYOVER fo;
  7338. GetObjectsUnderMouse( mx, my, &fo.a, &fo.c,
  7339. &fo.e, &fo.ge, &fo.tag, &fo.at, &fo.ccbutton );
  7340. if ( fo.a )
  7341. {
  7342. m_Flyover.a = fo.a;
  7343. }
  7344. if ( fo.e )
  7345. {
  7346. m_Flyover.e = fo.e;
  7347. }
  7348. if ( fo.c )
  7349. {
  7350. m_Flyover.c = fo.c;
  7351. }
  7352. if ( fo.ge )
  7353. {
  7354. m_Flyover.ge = fo.ge;
  7355. }
  7356. if ( fo.tag != -1 )
  7357. {
  7358. m_Flyover.tag = fo.tag;
  7359. }
  7360. if ( fo.ccbutton != -1 )
  7361. {
  7362. m_Flyover.ccbutton = fo.ccbutton;
  7363. // m_Flyover.e = NULL;
  7364. }
  7365. RECT rcClip;
  7366. GetClientRect( (HWND)getHandle(), &rcClip );
  7367. rcClip.bottom -= m_nScrollbarHeight;
  7368. rcClip.top = rcClip.bottom - m_nInfoHeight;
  7369. rcClip.right -= m_nScrollbarHeight;
  7370. CChoreoWidgetDrawHelper drawHelper( this, rcClip, COLOR_CHOREO_BACKGROUND );
  7371. drawHelper.StartClipping( rcClip );
  7372. RedrawStatusArea( drawHelper, rcClip );
  7373. drawHelper.StopClipping();
  7374. ValidateRect( (HWND)getHandle(), &rcClip );
  7375. }
  7376. //-----------------------------------------------------------------------------
  7377. // Purpose:
  7378. //-----------------------------------------------------------------------------
  7379. void CChoreoView::ClearStatusArea( void )
  7380. {
  7381. memset( &m_Flyover, 0, sizeof( m_Flyover ) );
  7382. }
  7383. //-----------------------------------------------------------------------------
  7384. // Purpose:
  7385. // Input : drawHelper -
  7386. // rcStatus -
  7387. //-----------------------------------------------------------------------------
  7388. void CChoreoView::RedrawStatusArea( CChoreoWidgetDrawHelper& drawHelper, RECT& rcStatus )
  7389. {
  7390. drawHelper.DrawFilledRect( COLOR_CHOREO_BACKGROUND, rcStatus );
  7391. drawHelper.DrawColoredLine( COLOR_INFO_BORDER, PS_SOLID, 1, rcStatus.left, rcStatus.top,
  7392. rcStatus.right, rcStatus.top );
  7393. RECT rcInfo = rcStatus;
  7394. rcInfo.top += 2;
  7395. if ( m_Flyover.e )
  7396. {
  7397. m_Flyover.e->redrawStatus( drawHelper, rcInfo );
  7398. }
  7399. if ( m_Flyover.c &&
  7400. m_Flyover.ccbutton != -1 )
  7401. {
  7402. m_Flyover.c->redrawStatus( drawHelper, rcInfo, m_Flyover.ccbutton );
  7403. }
  7404. if ( m_pScene )
  7405. {
  7406. char sz[ 512 ];
  7407. int fontsize = 9;
  7408. int fontweight = FW_NORMAL;
  7409. RECT rcText;
  7410. rcText = rcInfo;
  7411. rcText.bottom = rcText.top + fontsize + 2;
  7412. char const *mapname = m_pScene->GetMapname();
  7413. if ( mapname )
  7414. {
  7415. sprintf( sz, "Associated .bsp: %s", mapname[ 0 ] ? mapname : "none" );
  7416. int len = drawHelper.CalcTextWidth( "Arial", fontsize, fontweight, sz );
  7417. rcText.left = rcText.right - len - 10;
  7418. drawHelper.DrawColoredText( "Arial", fontsize, fontweight, COLOR_INFO_TEXT, rcText, sz );
  7419. OffsetRect( &rcText, 0, fontsize + 2 );
  7420. }
  7421. sprintf( sz, "Scene: %s", GetChoreoFile() );
  7422. int len = drawHelper.CalcTextWidth( "Arial", fontsize, fontweight, sz );
  7423. rcText.left = rcText.right - len - 10;
  7424. drawHelper.DrawColoredText( "Arial", fontsize, fontweight, COLOR_INFO_TEXT, rcText, sz );
  7425. }
  7426. // drawHelper.DrawColoredText( "Arial", 12, 500, Color( 0, 0, 0 ), rcInfo, m_Flyover.e ? m_Flyover.e->GetEvent()->GetName() : "" );
  7427. }
  7428. //-----------------------------------------------------------------------------
  7429. // Purpose:
  7430. // Input : *event -
  7431. //-----------------------------------------------------------------------------
  7432. void CChoreoView::MoveEventToBack( CChoreoEvent *event )
  7433. {
  7434. // Now find channel widget
  7435. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  7436. {
  7437. CChoreoActorWidget *a = m_SceneActors[ i ];
  7438. if ( !a )
  7439. continue;
  7440. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7441. {
  7442. CChoreoChannelWidget *c = a->GetChannel( j );
  7443. if ( !c )
  7444. continue;
  7445. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7446. {
  7447. CChoreoEventWidget *e = c->GetEvent( k );
  7448. if ( !e )
  7449. continue;
  7450. if ( event == e->GetEvent() )
  7451. {
  7452. // Move it to back of channel's list
  7453. c->MoveEventToTail( e );
  7454. InvalidateLayout();
  7455. return;
  7456. }
  7457. }
  7458. }
  7459. }
  7460. }
  7461. //-----------------------------------------------------------------------------
  7462. // Purpose:
  7463. // Output : int
  7464. //-----------------------------------------------------------------------------
  7465. int CChoreoView::GetEndRow( void )
  7466. {
  7467. RECT rcClient;
  7468. GetClientRect( (HWND)getHandle(), &rcClient );
  7469. return rcClient.bottom - ( m_nInfoHeight + m_nScrollbarHeight );
  7470. }
  7471. // Undo/Redo
  7472. void CChoreoView::Undo( void )
  7473. {
  7474. if ( m_UndoStack.Count() > 0 && m_nUndoLevel > 0 )
  7475. {
  7476. m_nUndoLevel--;
  7477. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7478. Assert( u->undo );
  7479. DeleteSceneWidgets();
  7480. *m_pScene = *(u->undo);
  7481. g_MDLViewer->InitGridSettings();
  7482. CreateSceneWidgets();
  7483. ReportSceneClearToTools();
  7484. ClearStatusArea();
  7485. m_pClickedActor = NULL;
  7486. m_pClickedChannel = NULL;
  7487. m_pClickedEvent = NULL;
  7488. m_pClickedGlobalEvent = NULL;
  7489. }
  7490. InvalidateLayout();
  7491. }
  7492. void CChoreoView::Redo( void )
  7493. {
  7494. if ( m_UndoStack.Count() > 0 && m_nUndoLevel <= m_UndoStack.Count() - 1 )
  7495. {
  7496. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7497. Assert( u->redo );
  7498. DeleteSceneWidgets();
  7499. *m_pScene = *(u->redo);
  7500. g_MDLViewer->InitGridSettings();
  7501. CreateSceneWidgets();
  7502. ReportSceneClearToTools();
  7503. ClearStatusArea();
  7504. m_pClickedActor = NULL;
  7505. m_pClickedChannel = NULL;
  7506. m_pClickedEvent = NULL;
  7507. m_pClickedGlobalEvent = NULL;
  7508. m_nUndoLevel++;
  7509. }
  7510. InvalidateLayout();
  7511. }
  7512. static char *CopyString( const char *in )
  7513. {
  7514. int len = strlen( in );
  7515. char *n = new char[ len + 1 ];
  7516. strcpy( n, in );
  7517. return n;
  7518. }
  7519. void CChoreoView::PushUndo( const char *description )
  7520. {
  7521. Assert( !m_bRedoPending );
  7522. m_bRedoPending = true;
  7523. WipeRedo();
  7524. // Copy current data
  7525. CChoreoScene *u = new CChoreoScene( this );
  7526. *u = *m_pScene;
  7527. CVUndo *undo = new CVUndo;
  7528. undo->undo = u;
  7529. undo->redo = NULL;
  7530. undo->udescription = CopyString( description );
  7531. undo->rdescription = NULL;
  7532. m_UndoStack.AddToTail( undo );
  7533. m_nUndoLevel++;
  7534. }
  7535. void CChoreoView::PushRedo( const char *description )
  7536. {
  7537. Assert( m_bRedoPending );
  7538. m_bRedoPending = false;
  7539. // Copy current data
  7540. CChoreoScene *r = new CChoreoScene( this );
  7541. *r = *m_pScene;
  7542. CVUndo *undo = m_UndoStack[ m_nUndoLevel - 1 ];
  7543. undo->redo = r;
  7544. undo->rdescription = CopyString( description );
  7545. // Always redo here to reflect that someone has made a change
  7546. redraw();
  7547. }
  7548. void CChoreoView::WipeUndo( void )
  7549. {
  7550. while ( m_UndoStack.Count() > 0 )
  7551. {
  7552. CVUndo *u = m_UndoStack[ 0 ];
  7553. delete u->undo;
  7554. delete u->redo;
  7555. delete[] u->udescription;
  7556. delete[] u->rdescription;
  7557. delete u;
  7558. m_UndoStack.Remove( 0 );
  7559. }
  7560. m_nUndoLevel = 0;
  7561. }
  7562. void CChoreoView::WipeRedo( void )
  7563. {
  7564. // Wipe everything above level
  7565. while ( m_UndoStack.Count() > m_nUndoLevel )
  7566. {
  7567. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7568. delete u->undo;
  7569. delete u->redo;
  7570. delete[] u->udescription;
  7571. delete[] u->rdescription;
  7572. delete u;
  7573. m_UndoStack.Remove( m_nUndoLevel );
  7574. }
  7575. }
  7576. //-----------------------------------------------------------------------------
  7577. // Purpose:
  7578. // Output : const char
  7579. //-----------------------------------------------------------------------------
  7580. const char *CChoreoView::GetUndoDescription( void )
  7581. {
  7582. if ( CanUndo() )
  7583. {
  7584. CVUndo *u = m_UndoStack[ m_nUndoLevel - 1 ];
  7585. return u->udescription;
  7586. }
  7587. return "???undo";
  7588. }
  7589. //-----------------------------------------------------------------------------
  7590. // Purpose:
  7591. // Output : const char
  7592. //-----------------------------------------------------------------------------
  7593. const char *CChoreoView::GetRedoDescription( void )
  7594. {
  7595. if ( CanRedo() )
  7596. {
  7597. CVUndo *u = m_UndoStack[ m_nUndoLevel ];
  7598. return u->rdescription;
  7599. }
  7600. return "???redo";
  7601. }
  7602. //-----------------------------------------------------------------------------
  7603. // Purpose:
  7604. // Output : Returns true on success, false on failure.
  7605. //-----------------------------------------------------------------------------
  7606. bool CChoreoView::CanUndo()
  7607. {
  7608. return m_nUndoLevel != 0;
  7609. }
  7610. //-----------------------------------------------------------------------------
  7611. // Purpose:
  7612. // Output : Returns true on success, false on failure.
  7613. //-----------------------------------------------------------------------------
  7614. bool CChoreoView::CanRedo()
  7615. {
  7616. return m_nUndoLevel != m_UndoStack.Count();
  7617. }
  7618. //-----------------------------------------------------------------------------
  7619. // Purpose:
  7620. //-----------------------------------------------------------------------------
  7621. void CChoreoView::OnGestureTool( void )
  7622. {
  7623. if ( m_pClickedEvent->GetEvent()->GetType() != CChoreoEvent::GESTURE )
  7624. return;
  7625. g_pGestureTool->SetEvent( m_pClickedEvent->GetEvent() );
  7626. }
  7627. //-----------------------------------------------------------------------------
  7628. // Purpose:
  7629. //-----------------------------------------------------------------------------
  7630. void CChoreoView::OnExpressionTool( void )
  7631. {
  7632. if ( m_pClickedEvent->GetEvent()->GetType() != CChoreoEvent::FLEXANIMATION )
  7633. return;
  7634. g_pExpressionTool->SetEvent( m_pClickedEvent->GetEvent() );
  7635. }
  7636. //-----------------------------------------------------------------------------
  7637. // Purpose:
  7638. // Output : CChoreoScene
  7639. //-----------------------------------------------------------------------------
  7640. CChoreoScene *CChoreoView::GetScene( void )
  7641. {
  7642. return m_pScene;
  7643. }
  7644. bool CChoreoView::CanPaste( void )
  7645. {
  7646. char const *copyfile = COPYPASTE_FILENAME;
  7647. if ( !filesystem->FileExists( copyfile ) )
  7648. {
  7649. return false;
  7650. }
  7651. return true;
  7652. }
  7653. void CChoreoView::CopyEvents( void )
  7654. {
  7655. if ( !m_pScene )
  7656. return;
  7657. char const *copyfile = COPYPASTE_FILENAME;
  7658. MakeFileWriteable( copyfile );
  7659. ExportVCDFile( copyfile );
  7660. }
  7661. void CChoreoView::PasteEvents( void )
  7662. {
  7663. if ( !m_pScene )
  7664. return;
  7665. if ( !CanPaste() )
  7666. return;
  7667. char const *copyfile = COPYPASTE_FILENAME;
  7668. ImportVCDFile( copyfile );
  7669. }
  7670. void CChoreoView::ImportEvents( void )
  7671. {
  7672. if ( !m_pScene )
  7673. return;
  7674. if ( !m_pClickedActor || !m_pClickedChannel )
  7675. return;
  7676. char eventfile[ 512 ];
  7677. if ( !FacePoser_ShowOpenFileNameDialog( eventfile, sizeof( eventfile ), "scenes", "*.vce" ) )
  7678. return;
  7679. char fullpathbuf[ 512 ];
  7680. char *fullpath = eventfile;
  7681. if ( !Q_IsAbsolutePath( eventfile ) )
  7682. {
  7683. filesystem->RelativePathToFullPath( eventfile, "GAME", fullpathbuf, sizeof( fullpathbuf ) );
  7684. fullpath = fullpathbuf;
  7685. }
  7686. if ( !filesystem->FileExists( fullpath ) )
  7687. return;
  7688. LoadScriptFile( fullpath );
  7689. DeselectAll();
  7690. SetDirty( true );
  7691. PushUndo( "Import Events" );
  7692. m_pScene->ImportEvents( tokenprocessor, m_pClickedActor->GetActor(), m_pClickedChannel->GetChannel() );
  7693. PushRedo( "Import Events" );
  7694. CreateSceneWidgets();
  7695. // Redraw
  7696. InvalidateLayout();
  7697. Con_Printf( "Imported events from %s\n", fullpath );
  7698. }
  7699. void CChoreoView::ExportEvents( void )
  7700. {
  7701. char eventfilename[ 512 ];
  7702. if ( !FacePoser_ShowSaveFileNameDialog( eventfilename, sizeof( eventfilename ), "scenes", "*.vce" ) )
  7703. return;
  7704. Q_DefaultExtension( eventfilename, ".vce", sizeof( eventfilename ) );
  7705. Con_Printf( "Exporting events to %s\n", eventfilename );
  7706. // Write to file
  7707. CUtlVector< CChoreoEvent * > events;
  7708. // Find selected eventss
  7709. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  7710. {
  7711. CChoreoActorWidget *a = m_SceneActors[ i ];
  7712. if ( !a )
  7713. continue;
  7714. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7715. {
  7716. CChoreoChannelWidget *c = a->GetChannel( j );
  7717. if ( !c )
  7718. continue;
  7719. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7720. {
  7721. CChoreoEventWidget *e = c->GetEvent( k );
  7722. if ( !e )
  7723. continue;
  7724. if ( !e->IsSelected() )
  7725. continue;
  7726. CChoreoEvent *event = e->GetEvent();
  7727. if ( !event )
  7728. continue;
  7729. events.AddToTail( event );
  7730. }
  7731. }
  7732. }
  7733. if ( events.Count() > 0 )
  7734. {
  7735. m_pScene->ExportEvents( eventfilename, events );
  7736. }
  7737. else
  7738. {
  7739. Con_Printf( "No events selected\n" );
  7740. }
  7741. }
  7742. void CChoreoView::ExportVCDFile( char const *filename )
  7743. {
  7744. Con_Printf( "Exporting to %s\n", filename );
  7745. // Unmark everything
  7746. m_pScene->MarkForSaveAll( false );
  7747. // Mark everything related to selected events
  7748. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  7749. {
  7750. CChoreoActorWidget *a = m_SceneActors[ i ];
  7751. if ( !a )
  7752. continue;
  7753. for ( int j = 0; j < a->GetNumChannels(); j++ )
  7754. {
  7755. CChoreoChannelWidget *c = a->GetChannel( j );
  7756. if ( !c )
  7757. continue;
  7758. for ( int k = 0; k < c->GetNumEvents(); k++ )
  7759. {
  7760. CChoreoEventWidget *e = c->GetEvent( k );
  7761. if ( !e )
  7762. continue;
  7763. if ( !e->IsSelected() )
  7764. continue;
  7765. CChoreoEvent *event = e->GetEvent();
  7766. if ( !event )
  7767. continue;
  7768. event->SetMarkedForSave( true );
  7769. if ( event->GetChannel() )
  7770. {
  7771. event->GetChannel()->SetMarkedForSave( true );
  7772. }
  7773. if ( event->GetActor() )
  7774. {
  7775. event->GetActor()->SetMarkedForSave( true );
  7776. }
  7777. }
  7778. }
  7779. }
  7780. m_pScene->ExportMarkedToFile( filename );
  7781. }
  7782. void CChoreoView::ImportVCDFile( char const *filename )
  7783. {
  7784. CChoreoScene *merge = LoadScene( filename );
  7785. if ( !merge )
  7786. {
  7787. Con_Printf( "Couldn't load from .vcd %s\n", filename );
  7788. return;
  7789. }
  7790. DeselectAll();
  7791. CUtlRBTree< CChoreoEvent *, int > oldEvents( 0, 0, DefLessFunc( CChoreoEvent * ) );
  7792. int i;
  7793. for ( i = 0; i < m_SceneActors.Count(); ++i )
  7794. {
  7795. CChoreoActorWidget *actor = m_SceneActors[ i ];
  7796. if ( !actor )
  7797. continue;
  7798. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  7799. {
  7800. CChoreoChannelWidget *channel = actor->GetChannel( j );
  7801. if ( !channel )
  7802. continue;
  7803. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  7804. {
  7805. CChoreoEventWidget *event = channel->GetEvent( k );
  7806. if ( !event )
  7807. continue;
  7808. oldEvents.Insert( event->GetEvent() );
  7809. }
  7810. }
  7811. }
  7812. SetDirty( true );
  7813. PushUndo( "Merge/Import VCD" );
  7814. m_pScene->Merge( merge );
  7815. PushRedo( "Merge/Import VCD" );
  7816. DeleteSceneWidgets();
  7817. CreateSceneWidgets();
  7818. // Force scroll bars to recompute
  7819. ForceScrollBarsToRecompute( false );
  7820. // Now walk through the "new" events and select everything that wasn't already there (all of the stuff that was "added" during the merge)
  7821. for ( i = 0; i < m_SceneActors.Count(); ++i )
  7822. {
  7823. CChoreoActorWidget *actor = m_SceneActors[ i ];
  7824. if ( !actor )
  7825. continue;
  7826. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  7827. {
  7828. CChoreoChannelWidget *channel = actor->GetChannel( j );
  7829. if ( !channel )
  7830. continue;
  7831. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  7832. {
  7833. CChoreoEventWidget *event = channel->GetEvent( k );
  7834. if ( !event )
  7835. continue;
  7836. if ( oldEvents.Find( event->GetEvent() ) == oldEvents.InvalidIndex() )
  7837. {
  7838. event->SetSelected( true );
  7839. }
  7840. }
  7841. }
  7842. }
  7843. // Redraw
  7844. InvalidateLayout();
  7845. Con_Printf( "Imported vcd '%s'\n", filename );
  7846. delete merge;
  7847. redraw();
  7848. }
  7849. void CChoreoView::ExportVCD()
  7850. {
  7851. char scenefile[ 512 ];
  7852. if ( !FacePoser_ShowSaveFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  7853. {
  7854. return;
  7855. }
  7856. Q_DefaultExtension( scenefile, ".vcd", sizeof( scenefile ) );
  7857. ExportVCDFile( scenefile );
  7858. }
  7859. void CChoreoView::ImportVCD()
  7860. {
  7861. if ( !m_pScene )
  7862. return;
  7863. if ( !m_pClickedActor || !m_pClickedChannel )
  7864. return;
  7865. char scenefile[ 512 ];
  7866. if ( !FacePoser_ShowOpenFileNameDialog( scenefile, sizeof( scenefile ), "scenes", "*.vcd" ) )
  7867. {
  7868. return;
  7869. }
  7870. ImportVCDFile( scenefile );
  7871. }
  7872. //-----------------------------------------------------------------------------
  7873. // Purpose:
  7874. // Output : Returns true on success, false on failure.
  7875. //-----------------------------------------------------------------------------
  7876. bool CChoreoView::IsProcessing( void )
  7877. {
  7878. if ( !m_pScene )
  7879. return false;
  7880. if ( m_flScrub != m_flScrubTarget )
  7881. return true;
  7882. return false;
  7883. }
  7884. //-----------------------------------------------------------------------------
  7885. // Purpose:
  7886. // Output : Returns true on success, false on failure.
  7887. //-----------------------------------------------------------------------------
  7888. bool CChoreoView::ShouldProcessSpeak( void )
  7889. {
  7890. if ( !g_pControlPanel->AllToolsDriveSpeech() )
  7891. {
  7892. if ( !IsActiveTool() )
  7893. return false;
  7894. }
  7895. if ( IFacePoserToolWindow::IsAnyToolScrubbing() )
  7896. return true;
  7897. if ( IFacePoserToolWindow::IsAnyToolProcessing() )
  7898. return true;
  7899. return false;
  7900. }
  7901. //-----------------------------------------------------------------------------
  7902. // Purpose:
  7903. // Input : *scene -
  7904. // *event -
  7905. //-----------------------------------------------------------------------------
  7906. void CChoreoView::ProcessSpeak( CChoreoScene *scene, CChoreoEvent *event )
  7907. {
  7908. if ( !ShouldProcessSpeak() )
  7909. return;
  7910. Assert( event->GetType() == CChoreoEvent::SPEAK );
  7911. Assert( scene );
  7912. float t = scene->GetTime();
  7913. StudioModel *model = FindAssociatedModel( scene, event->GetActor() );
  7914. // See if we should trigger CC
  7915. char soundname[ 512 ];
  7916. Q_strncpy( soundname, event->GetParameters(), sizeof( soundname ) );
  7917. float actualEndTime = event->GetEndTime();
  7918. if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
  7919. {
  7920. char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  7921. if ( event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
  7922. {
  7923. // Use the token as the sound name lookup, too.
  7924. if ( event->IsUsingCombinedFile() &&
  7925. ( event->GetNumSlaves() > 0 ) )
  7926. {
  7927. Q_strncpy( soundname, tok, sizeof( soundname ) );
  7928. actualEndTime = max( actualEndTime, event->GetLastSlaveEndTime() );
  7929. }
  7930. }
  7931. }
  7932. CAudioMixer *mixer = event->GetMixer();
  7933. if ( !mixer || !sound->IsSoundPlaying( mixer ) )
  7934. {
  7935. CSoundParameters params;
  7936. float volume = VOL_NORM;
  7937. gender_t gender = GENDER_NONE;
  7938. if (model)
  7939. {
  7940. gender = soundemitter->GetActorGender( model->GetFileName() );
  7941. }
  7942. if ( !Q_stristr( soundname, ".wav" ) &&
  7943. soundemitter->GetParametersForSound( soundname, params, gender ) )
  7944. {
  7945. volume = params.volume;
  7946. }
  7947. sound->PlaySound(
  7948. model,
  7949. volume,
  7950. va( "sound/%s", FacePoser_TranslateSoundName( soundname, model ) ),
  7951. &mixer );
  7952. event->SetMixer( mixer );
  7953. }
  7954. mixer = event->GetMixer();
  7955. if ( !mixer )
  7956. return;
  7957. mixer->SetDirection( m_flFrameTime >= 0.0f );
  7958. float starttime, endtime;
  7959. starttime = event->GetStartTime();
  7960. endtime = actualEndTime;
  7961. float soundtime = endtime - starttime;
  7962. if ( soundtime <= 0.0f )
  7963. return;
  7964. float f = ( t - starttime ) / soundtime;
  7965. f = clamp( f, 0.0f, 1.0f );
  7966. // Compute sample
  7967. float numsamples = (float)mixer->GetSource()->SampleCount();
  7968. int cursample = f * numsamples;
  7969. cursample = clamp( cursample, 0, numsamples - 1 );
  7970. int realsample = mixer->GetSamplePosition();
  7971. int dsample = cursample - realsample;
  7972. int samplelimit = mixer->GetSource()->SampleRate() * 0.02f; // don't shift until samples are off by this much
  7973. if (IsScrubbing())
  7974. {
  7975. samplelimit = mixer->GetSource()->SampleRate() * 0.01f; // make it shorter tolerance when scrubbing
  7976. }
  7977. if ( abs( dsample ) > samplelimit )
  7978. {
  7979. mixer->SetSamplePosition( cursample, IsScrubbing() );
  7980. }
  7981. mixer->SetActive( true );
  7982. }
  7983. //-----------------------------------------------------------------------------
  7984. // Purpose:
  7985. // Input : *event -
  7986. // Output : Returns true on success, false on failure.
  7987. //-----------------------------------------------------------------------------
  7988. void CChoreoView::ProcessSubscene( CChoreoScene *scene, CChoreoEvent *event )
  7989. {
  7990. Assert( event->GetType() == CChoreoEvent::SUBSCENE );
  7991. CChoreoScene *subscene = event->GetSubScene();
  7992. if ( !subscene )
  7993. return;
  7994. if ( subscene->SimulationFinished() )
  7995. return;
  7996. // Have subscenes think for appropriate time
  7997. subscene->Think( m_flScrub );
  7998. }
  7999. void CChoreoView::PositionControls()
  8000. {
  8001. int topx = GetCaptionHeight() + SCRUBBER_HEIGHT;
  8002. int bx = 2;
  8003. int bw = 16;
  8004. m_btnPlay->setBounds( bx, topx + 14, 16, 16 );
  8005. bx += bw + 2;
  8006. m_btnPause->setBounds( bx, topx + 14, 16, 16 );
  8007. bx += bw + 2;
  8008. m_btnStop->setBounds( bx, topx + 14, 16, 16 );
  8009. bx += bw + 2;
  8010. m_pPlaybackRate->setBounds( bx, topx + 14, 100, 16 );
  8011. }
  8012. void CChoreoView::SetChoreoFile( char const *filename )
  8013. {
  8014. strcpy( m_szChoreoFile, filename );
  8015. if ( m_szChoreoFile[ 0 ] )
  8016. {
  8017. char sz[ 256 ];
  8018. if ( IsFileWriteable( m_szChoreoFile ) )
  8019. {
  8020. Q_snprintf( sz, sizeof( sz ), " - %s", m_szChoreoFile );
  8021. }
  8022. else
  8023. {
  8024. Q_snprintf( sz, sizeof( sz ), " - %s [Read-Only]", m_szChoreoFile );
  8025. }
  8026. SetSuffix( sz );
  8027. }
  8028. else
  8029. {
  8030. SetSuffix( "" );
  8031. }
  8032. }
  8033. char const *CChoreoView::GetChoreoFile( void ) const
  8034. {
  8035. return m_szChoreoFile;
  8036. }
  8037. //-----------------------------------------------------------------------------
  8038. // Purpose:
  8039. // Input : rcHandle -
  8040. //-----------------------------------------------------------------------------
  8041. void CChoreoView::GetScrubHandleRect( RECT& rcHandle, bool clipped )
  8042. {
  8043. float pixel = 0.0f;
  8044. if ( m_pScene )
  8045. {
  8046. float currenttime = m_flScrub;
  8047. float starttime = m_flStartTime;
  8048. float endtime = m_flEndTime;
  8049. float screenfrac = ( currenttime - starttime ) / ( endtime - starttime );
  8050. pixel = GetLabelWidth() + screenfrac * ( w2() - GetLabelWidth() );
  8051. if ( clipped )
  8052. {
  8053. pixel = clamp( pixel, SCRUBBER_HANDLE_WIDTH/2, w2() - SCRUBBER_HANDLE_WIDTH/2 );
  8054. }
  8055. }
  8056. rcHandle.left = pixel-SCRUBBER_HANDLE_WIDTH/2;
  8057. rcHandle.right = pixel + SCRUBBER_HANDLE_WIDTH/2;
  8058. rcHandle.top = 2 + GetCaptionHeight();
  8059. rcHandle.bottom = rcHandle.top + SCRUBBER_HANDLE_HEIGHT;
  8060. }
  8061. //-----------------------------------------------------------------------------
  8062. // Purpose:
  8063. // Input : rcArea -
  8064. //-----------------------------------------------------------------------------
  8065. void CChoreoView::GetScrubAreaRect( RECT& rcArea )
  8066. {
  8067. rcArea.left = 0;
  8068. rcArea.right = w2();
  8069. rcArea.top = 2 + GetCaptionHeight();
  8070. rcArea.bottom = rcArea.top + SCRUBBER_HEIGHT - 4;
  8071. }
  8072. //-----------------------------------------------------------------------------
  8073. // Purpose:
  8074. // Input : drawHelper -
  8075. // rcHandle -
  8076. //-----------------------------------------------------------------------------
  8077. void CChoreoView::DrawScrubHandle( CChoreoWidgetDrawHelper& drawHelper )
  8078. {
  8079. RECT rcHandle;
  8080. GetScrubHandleRect( rcHandle, true );
  8081. HBRUSH br = CreateSolidBrush( ColorToRGB( Color( 0, 150, 100 ) ) );
  8082. drawHelper.DrawFilledRect( br, rcHandle );
  8083. //
  8084. char sz[ 48 ];
  8085. if ( m_bScrubSeconds )
  8086. {
  8087. sprintf( sz, "%.3f", m_flScrub );
  8088. }
  8089. else
  8090. {
  8091. sprintf( sz, "%i", (int) ( m_flScrub * (float)( GetScene()->GetSceneFPS() ) ) );
  8092. }
  8093. int len = drawHelper.CalcTextWidth( "Arial", 9, 500, sz );
  8094. RECT rcText = rcHandle;
  8095. int textw = rcText.right - rcText.left;
  8096. rcText.left += ( textw - len ) / 2;
  8097. drawHelper.DrawColoredText( "Arial", 9, 500, Color( 255, 255, 255 ), rcText, sz );
  8098. DeleteObject( br );
  8099. //
  8100. // Draw the timeline
  8101. //
  8102. /* if ( !m_bPaused )
  8103. {
  8104. //
  8105. // Draw the focus rect
  8106. //
  8107. m_FocusRects.Purge();
  8108. RECT rcScrub;
  8109. GetScrubHandleRect( rcScrub, true );
  8110. // Go through all selected events
  8111. RECT rcFocus;
  8112. rcFocus.top = GetStartRow();
  8113. rcFocus.bottom = h2() - m_nScrollbarHeight - m_nInfoHeight;
  8114. rcFocus.left = ( rcScrub.left + rcScrub.right ) / 2;
  8115. rcFocus.right = rcFocus.left;
  8116. POINT pt;
  8117. pt.x = pt.y = 0;
  8118. ClientToScreen( (HWND)getHandle(), &pt );
  8119. OffsetRect( &rcFocus, pt.x, pt.y );
  8120. CFocusRect fr;
  8121. fr.m_rcFocus = rcFocus;
  8122. fr.m_rcOrig = rcFocus;
  8123. m_FocusRects.AddToTail( fr );
  8124. DrawFocusRect();
  8125. } */
  8126. }
  8127. //-----------------------------------------------------------------------------
  8128. // Purpose:
  8129. // Input : *event -
  8130. // Output : Returns true on success, false on failure.
  8131. //-----------------------------------------------------------------------------
  8132. bool CChoreoView::IsMouseOverScrubHandle( mxEvent *event )
  8133. {
  8134. RECT rcHandle;
  8135. GetScrubHandleRect( rcHandle, true );
  8136. InflateRect( &rcHandle, 2, 2 );
  8137. POINT pt;
  8138. pt.x = (short)event->x;
  8139. pt.y = (short)event->y;
  8140. if ( PtInRect( &rcHandle, pt ) )
  8141. {
  8142. return true;
  8143. }
  8144. return false;
  8145. }
  8146. bool CChoreoView::IsMouseOverScrubArea( mxEvent *event )
  8147. {
  8148. RECT rcArea;
  8149. GetScrubAreaRect( rcArea );
  8150. InflateRect( &rcArea, 2, 2 );
  8151. POINT pt;
  8152. pt.x = (short)event->x;
  8153. pt.y = (short)event->y;
  8154. if ( PtInRect( &rcArea, pt ) )
  8155. {
  8156. return true;
  8157. }
  8158. return false;
  8159. }
  8160. bool CChoreoView::IsScrubbing( void ) const
  8161. {
  8162. bool scrubbing = ( m_nDragType == DRAGTYPE_SCRUBBER ) ? true : false;
  8163. return scrubbing;
  8164. }
  8165. //-----------------------------------------------------------------------------
  8166. // Purpose:
  8167. // Input : dt -
  8168. //-----------------------------------------------------------------------------
  8169. void CChoreoView::Think( float dt )
  8170. {
  8171. bool scrubbing = IFacePoserToolWindow::IsAnyToolScrubbing();
  8172. ScrubThink( dt, scrubbing, this );
  8173. }
  8174. static int lastthinkframe = -1;
  8175. void CChoreoView::ScrubThink( float dt, bool scrubbing, IFacePoserToolWindow *invoker )
  8176. {
  8177. // Make sure we don't get called more than once per frame
  8178. int thisframe = g_MDLViewer->GetCurrentFrame();
  8179. if ( thisframe == lastthinkframe )
  8180. return;
  8181. lastthinkframe = thisframe;
  8182. if ( !m_pScene )
  8183. return;
  8184. if ( m_flScrubTarget == m_flScrub && !scrubbing )
  8185. {
  8186. // Act like it's paused
  8187. if ( IFacePoserToolWindow::ShouldAutoProcess() )
  8188. {
  8189. m_bSimulating = true;
  8190. SceneThink( m_flScrub );
  8191. }
  8192. if ( m_bSimulating && !m_bPaused )
  8193. {
  8194. //FinishSimulation();
  8195. }
  8196. return;
  8197. }
  8198. // Make sure we're solving head turns during playback
  8199. models->SetSolveHeadTurn( 1 );
  8200. if ( m_bPaused )
  8201. {
  8202. SceneThink( m_flScrub );
  8203. return;
  8204. }
  8205. // Make sure phonemes are loaded
  8206. FacePoser_EnsurePhonemesLoaded();
  8207. if ( !m_bSimulating )
  8208. {
  8209. m_bSimulating = true;
  8210. }
  8211. float d = m_flScrubTarget - m_flScrub;
  8212. int sign = d > 0.0f ? 1 : -1;
  8213. float maxmove = dt * m_flPlaybackRate;
  8214. float prevScrub = m_flScrub;
  8215. if ( sign > 0 )
  8216. {
  8217. if ( d < maxmove )
  8218. {
  8219. m_flScrub = m_flScrubTarget;
  8220. }
  8221. else
  8222. {
  8223. m_flScrub += maxmove;
  8224. }
  8225. }
  8226. else
  8227. {
  8228. if ( -d < maxmove )
  8229. {
  8230. m_flScrub = m_flScrubTarget;
  8231. }
  8232. else
  8233. {
  8234. m_flScrub -= maxmove;
  8235. }
  8236. }
  8237. m_flFrameTime = ( m_flScrub - prevScrub );
  8238. SceneThink( m_flScrub );
  8239. DrawScrubHandle();
  8240. if ( scrubbing )
  8241. {
  8242. g_pMatSysWindow->Frame();
  8243. }
  8244. if ( invoker != g_pExpressionTool )
  8245. {
  8246. g_pExpressionTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8247. }
  8248. if ( invoker != g_pGestureTool )
  8249. {
  8250. g_pGestureTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8251. }
  8252. if ( invoker != g_pRampTool )
  8253. {
  8254. g_pRampTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8255. }
  8256. if ( invoker != g_pSceneRampTool )
  8257. {
  8258. g_pSceneRampTool->ForceScrubPositionFromSceneTime( m_flScrub );
  8259. }
  8260. }
  8261. void CChoreoView::DrawScrubHandle( void )
  8262. {
  8263. if ( !m_bCanDraw )
  8264. return;
  8265. // Handle new time and
  8266. RECT rcArea;
  8267. GetScrubAreaRect( rcArea );
  8268. CChoreoWidgetDrawHelper drawHelper( this, rcArea, COLOR_CHOREO_BACKGROUND );
  8269. DrawScrubHandle( drawHelper );
  8270. }
  8271. void CChoreoView::SetScrubTime( float t )
  8272. {
  8273. m_flScrub = t;
  8274. m_bPaused = false;
  8275. }
  8276. void CChoreoView::SetScrubTargetTime( float t )
  8277. {
  8278. m_flScrubTarget = t;
  8279. m_bPaused = false;
  8280. }
  8281. void CChoreoView::ClampTimeToSelectionInterval( float& timeval )
  8282. {
  8283. // FIXME hook this up later
  8284. return;
  8285. }
  8286. //-----------------------------------------------------------------------------
  8287. // Purpose:
  8288. // Input : show -
  8289. //-----------------------------------------------------------------------------
  8290. void CChoreoView::ShowButtons( bool show )
  8291. {
  8292. m_btnPlay->setVisible( show );
  8293. m_btnPause->setVisible( show );
  8294. m_btnStop->setVisible( show );
  8295. m_pPlaybackRate->setVisible( show );
  8296. }
  8297. void CChoreoView::RememberSelectedEvents( CUtlVector< CChoreoEvent * >& list )
  8298. {
  8299. GetSelectedEvents( list );
  8300. }
  8301. void CChoreoView::ReselectEvents( CUtlVector< CChoreoEvent * >& list )
  8302. {
  8303. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  8304. {
  8305. CChoreoActorWidget *actor = m_SceneActors[ i ];
  8306. if ( !actor )
  8307. continue;
  8308. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  8309. {
  8310. CChoreoChannelWidget *channel = actor->GetChannel( j );
  8311. if ( !channel )
  8312. continue;
  8313. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  8314. {
  8315. CChoreoEventWidget *event = channel->GetEvent( k );
  8316. if ( !event )
  8317. continue;
  8318. CChoreoEvent *check = event->GetEvent();
  8319. if ( list.Find( check ) != list.InvalidIndex() )
  8320. {
  8321. event->SetSelected( true );
  8322. }
  8323. }
  8324. }
  8325. }
  8326. }
  8327. void CChoreoView::OnChangeScale( void )
  8328. {
  8329. CChoreoScene *scene = m_pScene;
  8330. if ( !scene )
  8331. {
  8332. return;
  8333. }
  8334. // Zoom time in / out
  8335. CInputParams params;
  8336. memset( &params, 0, sizeof( params ) );
  8337. strcpy( params.m_szDialogTitle, "Change Zoom" );
  8338. strcpy( params.m_szPrompt, "New scale (e.g., 2.5x):" );
  8339. Q_snprintf( params.m_szInputText, sizeof( params.m_szInputText ), "%.2f", (float)GetTimeZoom( GetToolName() ) / 100.0f );
  8340. if ( !InputProperties( &params ) )
  8341. return;
  8342. SetTimeZoom( GetToolName(), clamp( (int)( 100.0f * atof( params.m_szInputText ) ), 1, MAX_TIME_ZOOM ), false );
  8343. // Force scroll bars to recompute
  8344. ForceScrollBarsToRecompute( false );
  8345. CUtlVector< CChoreoEvent * > selected;
  8346. RememberSelectedEvents( selected );
  8347. DeleteSceneWidgets();
  8348. CreateSceneWidgets();
  8349. ReselectEvents( selected );
  8350. InvalidateLayout();
  8351. Con_Printf( "Zoom factor %i %%\n", GetTimeZoom( GetToolName() ) );
  8352. }
  8353. void CChoreoView::OnCheckSequenceLengths( void )
  8354. {
  8355. if ( !m_pScene )
  8356. return;
  8357. Con_Printf( "Checking sequence durations...\n" );
  8358. bool changed = FixupSequenceDurations( m_pScene, true );
  8359. if ( !changed )
  8360. {
  8361. Con_Printf( " no changes...\n" );
  8362. return;
  8363. }
  8364. SetDirty( true );
  8365. PushUndo( "Check sequence lengths" );
  8366. FixupSequenceDurations( m_pScene, false );
  8367. PushRedo( "Check sequence lengths" );
  8368. InvalidateLayout();
  8369. }
  8370. //-----------------------------------------------------------------------------
  8371. // Purpose:
  8372. // Input : *scene -
  8373. //-----------------------------------------------------------------------------
  8374. void CChoreoView::InvalidateTrackLookup_R( CChoreoScene *scene )
  8375. {
  8376. // No need to undo since this data doesn't matter
  8377. int c = scene->GetNumEvents();
  8378. for ( int i = 0; i < c; i++ )
  8379. {
  8380. CChoreoEvent *event = scene->GetEvent( i );
  8381. if ( !event )
  8382. continue;
  8383. switch ( event->GetType() )
  8384. {
  8385. default:
  8386. break;
  8387. case CChoreoEvent::FLEXANIMATION:
  8388. {
  8389. event->SetTrackLookupSet( false );
  8390. }
  8391. break;
  8392. case CChoreoEvent::SUBSCENE:
  8393. {
  8394. CChoreoScene *sub = event->GetSubScene();
  8395. // NOTE: Don't bother loading it now if it's not on hand
  8396. if ( sub )
  8397. {
  8398. InvalidateTrackLookup_R( sub );
  8399. }
  8400. }
  8401. break;
  8402. }
  8403. }
  8404. }
  8405. //-----------------------------------------------------------------------------
  8406. // Purpose: Model changed so we'll have to re-index flex anim tracks
  8407. //-----------------------------------------------------------------------------
  8408. void CChoreoView::InvalidateTrackLookup( void )
  8409. {
  8410. if ( !m_pScene )
  8411. return;
  8412. InvalidateTrackLookup_R( m_pScene );
  8413. }
  8414. bool CChoreoView::IsRampOnly( void ) const
  8415. {
  8416. return m_bRampOnly;
  8417. }
  8418. //-----------------------------------------------------------------------------
  8419. // Purpose:
  8420. // Input : *scene -
  8421. // *event -
  8422. //-----------------------------------------------------------------------------
  8423. void CChoreoView::ProcessInterrupt( CChoreoScene *scene, CChoreoEvent *event )
  8424. {
  8425. }
  8426. //-----------------------------------------------------------------------------
  8427. // Purpose:
  8428. // Input : *scene -
  8429. // *event -
  8430. //-----------------------------------------------------------------------------
  8431. void CChoreoView::ProcessPermitResponses( CChoreoScene *scene, CChoreoEvent *event )
  8432. {
  8433. }
  8434. void CChoreoView::ApplyBounds( int& mx, int& my )
  8435. {
  8436. if ( !m_bUseBounds )
  8437. return;
  8438. mx = clamp( mx, m_nMinX, m_nMaxX );
  8439. }
  8440. //-----------------------------------------------------------------------------
  8441. // Purpose: Returns -1 if no event found
  8442. // Input : *channel -
  8443. // *e -
  8444. // forward -
  8445. // Output : float
  8446. //-----------------------------------------------------------------------------
  8447. float CChoreoView::FindNextEventTime( CChoreoEvent::EVENTTYPE type, CChoreoChannel *channel, CChoreoEvent *e, bool forward )
  8448. {
  8449. bool foundone = false;
  8450. float bestTime = -1.0f;
  8451. float bestGap = 999999.0f;
  8452. int c = channel->GetNumEvents();
  8453. for ( int i = 0; i < c; i++ )
  8454. {
  8455. CChoreoEvent *test = channel->GetEvent( i );
  8456. if ( test->GetType() != type )
  8457. continue;
  8458. if ( forward )
  8459. {
  8460. float dt = test->GetStartTime() - e->GetEndTime();
  8461. if ( dt <= 0.0f )
  8462. continue;
  8463. if ( dt < bestGap )
  8464. {
  8465. foundone = true;
  8466. bestGap = dt;
  8467. bestTime = test->GetStartTime();
  8468. }
  8469. }
  8470. else
  8471. {
  8472. float dt = e->GetStartTime() - test->GetEndTime();
  8473. if ( dt <= 0.0f )
  8474. continue;
  8475. if ( dt < bestGap )
  8476. {
  8477. foundone = true;
  8478. bestGap = dt;
  8479. bestTime = test->GetEndTime();
  8480. }
  8481. }
  8482. }
  8483. return bestTime;
  8484. }
  8485. void CChoreoView::CalcBounds( int movetype )
  8486. {
  8487. m_bUseBounds = false;
  8488. m_nMinX = 0;
  8489. m_nMaxX = 0;
  8490. if ( !m_pClickedEvent )
  8491. return;
  8492. switch ( movetype )
  8493. {
  8494. default:
  8495. break;
  8496. case DRAGTYPE_EVENT_MOVE:
  8497. case DRAGTYPE_EVENT_STARTTIME:
  8498. case DRAGTYPE_EVENT_ENDTIME:
  8499. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  8500. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  8501. {
  8502. m_nMinX = GetPixelForTimeValue( 0 );
  8503. m_nMaxX = GetPixelForTimeValue( m_pScene->FindStopTime() );
  8504. CChoreoEvent *e = m_pClickedEvent->GetEvent();
  8505. m_bUseBounds = false; // e && e->GetType() == CChoreoEvent::GESTURE;
  8506. // FIXME: use this for finding adjacent gesture edges (kenb)
  8507. if ( m_bUseBounds )
  8508. {
  8509. CChoreoChannel *channel = e->GetChannel();
  8510. Assert( channel );
  8511. float forwardTime = FindNextEventTime( e->GetType(), channel, e, true );
  8512. float reverseTime = FindNextEventTime( e->GetType(), channel, e, false );
  8513. // Compute pixel for time
  8514. int nextPixel = forwardTime != -1 ? GetPixelForTimeValue( forwardTime ) : m_nMaxX;
  8515. int prevPixel = reverseTime != -1 ? GetPixelForTimeValue( reverseTime ) : m_nMinX;
  8516. int startPixel = GetPixelForTimeValue( e->GetStartTime() );
  8517. int endPixel = GetPixelForTimeValue( e->GetEndTime() );
  8518. switch ( movetype )
  8519. {
  8520. case DRAGTYPE_EVENT_MOVE:
  8521. {
  8522. m_nMinX = prevPixel + ( m_xStart - startPixel ) + 1;
  8523. m_nMaxX = nextPixel - ( endPixel - m_xStart ) - 1;
  8524. }
  8525. break;
  8526. case DRAGTYPE_EVENT_STARTTIME:
  8527. case DRAGTYPE_EVENT_STARTTIME_RESCALE:
  8528. {
  8529. m_nMinX = prevPixel + ( m_xStart - startPixel ) + 1;
  8530. }
  8531. break;
  8532. case DRAGTYPE_EVENT_ENDTIME:
  8533. case DRAGTYPE_EVENT_ENDTIME_RESCALE:
  8534. {
  8535. m_nMaxX = nextPixel - ( endPixel - m_xStart ) - 1;
  8536. }
  8537. break;
  8538. }
  8539. }
  8540. }
  8541. break;
  8542. }
  8543. }
  8544. bool CChoreoView::ShouldSelectEvent( SelectionParams_t &params, CChoreoEvent *event )
  8545. {
  8546. if ( params.forward )
  8547. {
  8548. if ( event->GetStartTime() >= params.time )
  8549. return true;
  8550. }
  8551. else
  8552. {
  8553. float endtime = event->HasEndTime() ? event->GetEndTime() : event->GetStartTime();
  8554. if ( endtime <= params.time )
  8555. return true;
  8556. }
  8557. return false;
  8558. }
  8559. void CChoreoView::SelectEvents( SelectionParams_t& params )
  8560. {
  8561. if ( !m_pScene )
  8562. return;
  8563. if ( !m_pClickedActor )
  8564. return;
  8565. if ( params.type == SelectionParams_t::SP_CHANNEL && !m_pClickedChannel )
  8566. return;
  8567. //CChoreoActor *actor = m_pClickedActor->GetActor();
  8568. CChoreoChannel *channel = m_pClickedChannel ? m_pClickedChannel->GetChannel() : NULL;
  8569. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  8570. {
  8571. CChoreoActorWidget *a = m_SceneActors[ i ];
  8572. if ( !a )
  8573. continue;
  8574. //if ( a->GetActor() != actor )
  8575. // continue;
  8576. for ( int j = 0; j < a->GetNumChannels(); j++ )
  8577. {
  8578. CChoreoChannelWidget *c = a->GetChannel( j );
  8579. if ( !c )
  8580. continue;
  8581. if ( params.type == SelectionParams_t::SP_CHANNEL &&
  8582. c->GetChannel() != channel )
  8583. continue;
  8584. if ( params.type == SelectionParams_t::SP_ACTIVE &&
  8585. !c->GetChannel()->GetActive() )
  8586. continue;
  8587. for ( int k = 0; k < c->GetNumEvents(); k++ )
  8588. {
  8589. CChoreoEventWidget *e = c->GetEvent( k );
  8590. if ( !e )
  8591. continue;
  8592. CChoreoEvent *event = e->GetEvent();
  8593. if ( !event )
  8594. continue;
  8595. if ( !ShouldSelectEvent( params, event ) )
  8596. continue;
  8597. e->SetSelected( true );
  8598. }
  8599. }
  8600. }
  8601. // Now handle global events, too
  8602. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  8603. {
  8604. CChoreoGlobalEventWidget *e = m_SceneGlobalEvents[ i ];
  8605. if ( !e )
  8606. continue;
  8607. CChoreoEvent *event = e->GetEvent();
  8608. if ( !event )
  8609. continue;
  8610. if ( !ShouldSelectEvent( params, event ) )
  8611. continue;
  8612. e->SetSelected( true );
  8613. }
  8614. redraw();
  8615. }
  8616. void CChoreoView::SetTimeZoom( char const *tool, int tz, bool preserveFocus )
  8617. {
  8618. if ( !m_pScene )
  8619. return;
  8620. // No change
  8621. int oldZoom = GetTimeZoom( tool );
  8622. if ( tz == oldZoom )
  8623. return;
  8624. SetDirty( true );
  8625. POINT pt;
  8626. ::GetCursorPos( &pt );
  8627. ::ScreenToClient( (HWND)getHandle(), &pt );
  8628. // Now figure out time under cursor at old zoom scale
  8629. float t = GetTimeValueForMouse( pt.x, true );
  8630. m_pScene->SetTimeZoom( tool, tz );
  8631. if ( preserveFocus )
  8632. {
  8633. RECT rc;
  8634. GetClientRect( (HWND)getHandle(), &rc );
  8635. RECT rcClient = rc;
  8636. rcClient.top += GetStartRow();
  8637. OffsetRect( &rcClient, 0, -m_nTopOffset );
  8638. m_flStartTime = m_flLeftOffset / GetPixelsPerSecond();
  8639. m_flEndTime = m_flStartTime + (float)( rcClient.right - GetLabelWidth() ) / GetPixelsPerSecond();
  8640. // Now figure out tie under pt.x
  8641. float newT = GetTimeValueForMouse( pt.x, true );
  8642. if ( newT != t )
  8643. {
  8644. // We need to scroll over a bit
  8645. float pps = GetPixelsPerSecond();
  8646. float movePixels = pps * ( newT - t );
  8647. m_flLeftOffset -= movePixels;
  8648. if ( m_flLeftOffset < 0.0f )
  8649. {
  8650. //float fixup = - m_flLeftOffset;
  8651. m_flLeftOffset = 0;
  8652. }
  8653. // float maxtime = m_pScene->FindStopTime();
  8654. float flApparentEndTime = max( m_pScene->FindStopTime(), 5.0f ) + 5.0f;
  8655. if ( m_flEndTime > flApparentEndTime )
  8656. {
  8657. movePixels = pps * ( m_flEndTime - flApparentEndTime );
  8658. m_flLeftOffset = max( 0.0f, m_flLeftOffset - movePixels );
  8659. }
  8660. }
  8661. }
  8662. // Deal with the slider
  8663. RepositionHSlider();
  8664. redraw();
  8665. }
  8666. int CChoreoView::GetTimeZoom( char const *tool )
  8667. {
  8668. if ( !m_pScene )
  8669. return 100;
  8670. return m_pScene->GetTimeZoom( tool );
  8671. }
  8672. void CChoreoView::CheckInsertTime( CChoreoEvent *e, float dt, float starttime, float endtime )
  8673. {
  8674. // Not influenced
  8675. float eventend = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime();
  8676. if ( eventend < starttime )
  8677. return;
  8678. if ( e->GetStartTime() > starttime )
  8679. {
  8680. e->OffsetTime( dt );
  8681. e->SnapTimes();
  8682. }
  8683. 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
  8684. {
  8685. float newduration = e->GetDuration() + dt;
  8686. RescaleRamp( e, newduration );
  8687. switch ( e->GetType() )
  8688. {
  8689. default:
  8690. break;
  8691. case CChoreoEvent::GESTURE:
  8692. {
  8693. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() + dt, true );
  8694. }
  8695. break;
  8696. case CChoreoEvent::FLEXANIMATION:
  8697. {
  8698. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() + dt );
  8699. }
  8700. break;
  8701. }
  8702. e->OffsetEndTime( dt );
  8703. e->SnapTimes();
  8704. e->ResortRamp();
  8705. }
  8706. switch ( e->GetType() )
  8707. {
  8708. default:
  8709. break;
  8710. case CChoreoEvent::SPEAK:
  8711. {
  8712. // Try and load wav to get length
  8713. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  8714. if ( wave )
  8715. {
  8716. e->SetEndTime( e->GetStartTime() + wave->GetRunningLength() );
  8717. delete wave;
  8718. }
  8719. }
  8720. break;
  8721. case CChoreoEvent::SEQUENCE:
  8722. {
  8723. CheckSequenceLength( e, false );
  8724. }
  8725. break;
  8726. case CChoreoEvent::GESTURE:
  8727. {
  8728. CheckGestureLength( e, false );
  8729. }
  8730. break;
  8731. }
  8732. }
  8733. void CChoreoView::OnInsertTime()
  8734. {
  8735. if ( !m_rgABPoints[ 0 ].active &&
  8736. !m_rgABPoints[ 1 ].active )
  8737. {
  8738. return;
  8739. }
  8740. Con_Printf( "OnInsertTime()\n" );
  8741. float starttime = m_rgABPoints[ 0 ].time;
  8742. float endtime = m_rgABPoints[ 1 ].time;
  8743. // Sort samples correctly
  8744. if ( starttime > endtime )
  8745. {
  8746. float temp = starttime;
  8747. starttime = endtime;
  8748. endtime = temp;
  8749. }
  8750. float dt = endtime - starttime;
  8751. if ( dt == 0.0f )
  8752. {
  8753. // Nothing to do...
  8754. return;
  8755. }
  8756. SetDirty( true );
  8757. PushUndo( "Insert Time" );
  8758. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  8759. {
  8760. CChoreoActorWidget *actor = m_SceneActors[ i ];
  8761. if ( !actor )
  8762. continue;
  8763. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  8764. {
  8765. CChoreoChannelWidget *channel = actor->GetChannel( j );
  8766. if ( !channel )
  8767. continue;
  8768. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  8769. {
  8770. CChoreoEventWidget *event = channel->GetEvent( k );
  8771. if ( !event )
  8772. continue;
  8773. CChoreoEvent *e = event->GetEvent();
  8774. if ( !e )
  8775. continue;
  8776. CheckInsertTime( e, dt, starttime, endtime );
  8777. }
  8778. }
  8779. }
  8780. // Now handle global events, too
  8781. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  8782. {
  8783. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  8784. if ( !event )
  8785. continue;
  8786. CChoreoEvent *e = event->GetEvent();
  8787. if ( !e )
  8788. continue;
  8789. CheckInsertTime( e, dt, starttime, endtime );
  8790. }
  8791. PushRedo( "Insert Time" );
  8792. InvalidateLayout();
  8793. g_pExpressionTool->LayoutItems( true );
  8794. g_pExpressionTool->redraw();
  8795. g_pGestureTool->redraw();
  8796. g_pRampTool->redraw();
  8797. g_pSceneRampTool->redraw();
  8798. }
  8799. void CChoreoView::CheckDeleteTime( CChoreoEvent *e, float dt, float starttime, float endtime, bool& deleteEvent )
  8800. {
  8801. deleteEvent = false;
  8802. // Not influenced
  8803. float eventend = e->HasEndTime() ? e->GetEndTime() : e->GetStartTime();
  8804. if ( eventend < starttime )
  8805. {
  8806. return;
  8807. }
  8808. // On right side of start mark, just shift left
  8809. if ( e->GetStartTime() > starttime )
  8810. {
  8811. // If it has no duration and it's in the bounds then kill it.
  8812. if ( !e->HasEndTime() && e->GetStartTime() < endtime )
  8813. {
  8814. deleteEvent = true;
  8815. return;
  8816. }
  8817. else
  8818. {
  8819. float shift = e->GetStartTime() - starttime;
  8820. float maxoffset = min( dt, shift );
  8821. e->OffsetTime( -maxoffset );
  8822. e->SnapTimes();
  8823. }
  8824. }
  8825. 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
  8826. {
  8827. float shiftend = e->GetEndTime() - starttime;
  8828. float maxoffset = min( dt, shiftend );
  8829. float newduration = e->GetDuration() - maxoffset;
  8830. if ( newduration <= 0.0f )
  8831. {
  8832. deleteEvent = true;
  8833. return;
  8834. }
  8835. else
  8836. {
  8837. RescaleRamp( e, newduration );
  8838. switch ( e->GetType() )
  8839. {
  8840. default:
  8841. break;
  8842. case CChoreoEvent::GESTURE:
  8843. {
  8844. e->RescaleGestureTimes( e->GetStartTime(), e->GetEndTime() - maxoffset, true );
  8845. }
  8846. break;
  8847. case CChoreoEvent::FLEXANIMATION:
  8848. {
  8849. RescaleExpressionTimes( e, e->GetStartTime(), e->GetEndTime() - maxoffset );
  8850. }
  8851. break;
  8852. }
  8853. e->OffsetEndTime( -maxoffset );
  8854. e->SnapTimes();
  8855. e->ResortRamp();
  8856. }
  8857. }
  8858. switch ( e->GetType() )
  8859. {
  8860. default:
  8861. break;
  8862. case CChoreoEvent::SPEAK:
  8863. {
  8864. // Try and load wav to get length
  8865. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  8866. if ( wave )
  8867. {
  8868. e->SetEndTime( e->GetStartTime() + wave->GetRunningLength() );
  8869. delete wave;
  8870. }
  8871. }
  8872. break;
  8873. case CChoreoEvent::SEQUENCE:
  8874. {
  8875. CheckSequenceLength( e, false );
  8876. }
  8877. break;
  8878. case CChoreoEvent::GESTURE:
  8879. {
  8880. CheckGestureLength( e, false );
  8881. }
  8882. break;
  8883. }
  8884. }
  8885. void CChoreoView::OnDeleteTime()
  8886. {
  8887. if ( !m_rgABPoints[ 0 ].active &&
  8888. !m_rgABPoints[ 1 ].active )
  8889. {
  8890. return;
  8891. }
  8892. Con_Printf( "OnDeleteTime()\n" );
  8893. float starttime = m_rgABPoints[ 0 ].time;
  8894. float endtime = m_rgABPoints[ 1 ].time;
  8895. // Sort samples correctly
  8896. if ( starttime > endtime )
  8897. {
  8898. float temp = starttime;
  8899. starttime = endtime;
  8900. endtime = temp;
  8901. }
  8902. float dt = endtime - starttime;
  8903. if ( dt == 0.0f )
  8904. {
  8905. // Nothing to do...
  8906. return;
  8907. }
  8908. SetDirty( true );
  8909. PushUndo( "Delete Time" );
  8910. CUtlVector< CChoreoEventWidget * > deletions;
  8911. CUtlVector< CChoreoGlobalEventWidget * > global_deletions;
  8912. for ( int i = 0; i < m_SceneActors.Count(); i++ )
  8913. {
  8914. CChoreoActorWidget *actor = m_SceneActors[ i ];
  8915. if ( !actor )
  8916. continue;
  8917. for ( int j = 0; j < actor->GetNumChannels(); j++ )
  8918. {
  8919. CChoreoChannelWidget *channel = actor->GetChannel( j );
  8920. if ( !channel )
  8921. continue;
  8922. for ( int k = 0; k < channel->GetNumEvents(); k++ )
  8923. {
  8924. CChoreoEventWidget *event = channel->GetEvent( k );
  8925. if ( !event )
  8926. continue;
  8927. CChoreoEvent *e = event->GetEvent();
  8928. if ( !e )
  8929. continue;
  8930. bool deleteEvent = false;
  8931. CheckDeleteTime( e, dt, starttime, endtime, deleteEvent );
  8932. if ( deleteEvent )
  8933. {
  8934. deletions.AddToTail( event );
  8935. }
  8936. }
  8937. }
  8938. }
  8939. // Now handle global events, too
  8940. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  8941. {
  8942. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  8943. if ( !event )
  8944. continue;
  8945. CChoreoEvent *e = event->GetEvent();
  8946. if ( !e )
  8947. continue;
  8948. bool deleteEvent = false;
  8949. CheckDeleteTime( e, dt, starttime, endtime, deleteEvent );
  8950. if ( deleteEvent )
  8951. {
  8952. global_deletions.AddToTail( event );
  8953. }
  8954. }
  8955. for ( int i = 0; i < deletions.Count(); i++ )
  8956. {
  8957. CChoreoEventWidget *w = deletions[ i ];
  8958. CChoreoEvent *e = w->GetEvent();
  8959. CChoreoChannel *channel = e->GetChannel();
  8960. if ( channel )
  8961. {
  8962. channel->RemoveEvent( e );
  8963. }
  8964. m_pScene->DeleteReferencedObjects( e );
  8965. }
  8966. for ( int i = 0; i < global_deletions.Count(); i++ )
  8967. {
  8968. CChoreoGlobalEventWidget *w = global_deletions[ i ];
  8969. CChoreoEvent *e = w->GetEvent();
  8970. m_pScene->DeleteReferencedObjects( e );
  8971. }
  8972. // Force scroll bars to recompute
  8973. ForceScrollBarsToRecompute( false );
  8974. if ( deletions.Count() > 0 || global_deletions.Count() > 0 )
  8975. {
  8976. DeleteSceneWidgets();
  8977. CreateSceneWidgets();
  8978. }
  8979. PushRedo( "Delete Time" );
  8980. InvalidateLayout();
  8981. g_pExpressionTool->LayoutItems( true );
  8982. g_pExpressionTool->redraw();
  8983. g_pGestureTool->redraw();
  8984. g_pRampTool->redraw();
  8985. g_pSceneRampTool->redraw();
  8986. }
  8987. void CChoreoView::OnModelChanged()
  8988. {
  8989. InvalidateTrackLookup();
  8990. // OnCheckSequenceLengths();
  8991. }
  8992. void CChoreoView::SetShowCloseCaptionData( bool show )
  8993. {
  8994. m_bShowCloseCaptionData = show;
  8995. }
  8996. bool CChoreoView::GetShowCloseCaptionData( void ) const
  8997. {
  8998. return m_bShowCloseCaptionData;
  8999. }
  9000. void CChoreoView::OnToggleCloseCaptionTags()
  9001. {
  9002. m_bShowCloseCaptionData = !m_bShowCloseCaptionData;
  9003. InvalidateLayout();
  9004. }
  9005. static bool EventStartTimeLessFunc( CChoreoEvent * const &p1, CChoreoEvent * const &p2 )
  9006. {
  9007. CChoreoEvent *w1;
  9008. CChoreoEvent *w2;
  9009. w1 = const_cast< CChoreoEvent * >( p1 );
  9010. w2 = const_cast< CChoreoEvent * >( p2 );
  9011. return w1->GetStartTime() < w2->GetStartTime();
  9012. }
  9013. bool CChoreoView::GenerateCombinedFile( char const *outfilename, char const *cctoken, gender_t gender, CUtlRBTree< CChoreoEvent * >& sorted )
  9014. {
  9015. CUtlVector< CombinerEntry > work;
  9016. char actualfile[ 512 ];
  9017. soundemitter->GenderExpandString( gender, outfilename, actualfile, sizeof( actualfile ) );
  9018. if ( Q_strlen( actualfile ) <= 0 )
  9019. {
  9020. return false;
  9021. }
  9022. int i = sorted.FirstInorder();
  9023. if ( i != sorted.InvalidIndex() )
  9024. {
  9025. CChoreoEvent *e = sorted[ i ];
  9026. float startoffset = e->GetStartTime();
  9027. do
  9028. {
  9029. e = sorted[ i ];
  9030. float curoffset = e->GetStartTime();
  9031. CombinerEntry ce;
  9032. Q_snprintf( ce.wavefile, sizeof( ce.wavefile ), "sound/%s", FacePoser_TranslateSoundNameGender( e->GetParameters(), gender ) );
  9033. ce.startoffset = curoffset - startoffset;
  9034. work.AddToTail( ce );
  9035. i = sorted.NextInorder( i );
  9036. }
  9037. while ( i != sorted.InvalidIndex() );
  9038. }
  9039. bool ok = soundcombiner->CombineSoundFiles( filesystem, actualfile, work );
  9040. if ( !ok )
  9041. {
  9042. Con_ErrorPrintf( "Failed to create combined sound '%s':'%s'\n", cctoken, actualfile );
  9043. return false;
  9044. }
  9045. Con_Printf( "Created combined sound '%s':'%s'\n", cctoken, actualfile );
  9046. return true;
  9047. }
  9048. bool CChoreoView::ValidateCombinedFileCheckSum( char const *outfilename, char const *cctoken, gender_t gender, CUtlRBTree< CChoreoEvent * >& sorted )
  9049. {
  9050. CUtlVector< CombinerEntry > work;
  9051. char actualfile[ 512 ];
  9052. soundemitter->GenderExpandString( gender, outfilename, actualfile, sizeof( actualfile ) );
  9053. if ( Q_strlen( actualfile ) <= 0 )
  9054. {
  9055. return false;
  9056. }
  9057. int i = sorted.FirstInorder();
  9058. if ( i != sorted.InvalidIndex() )
  9059. {
  9060. CChoreoEvent *e = sorted[ i ];
  9061. float startoffset = e->GetStartTime();
  9062. do
  9063. {
  9064. e = sorted[ i ];
  9065. float curoffset = e->GetStartTime();
  9066. CombinerEntry ce;
  9067. Q_snprintf( ce.wavefile, sizeof( ce.wavefile ), "sound/%s", FacePoser_TranslateSoundNameGender( e->GetParameters(), gender ) );
  9068. ce.startoffset = curoffset - startoffset;
  9069. work.AddToTail( ce );
  9070. i = sorted.NextInorder( i );
  9071. }
  9072. while ( i != sorted.InvalidIndex() );
  9073. }
  9074. return soundcombiner->IsCombinedFileChecksumValid( filesystem, actualfile, work );
  9075. }
  9076. void SuggestCaption( char *dest, int destlen, CUtlVector< CChoreoEvent * >& events )
  9077. {
  9078. // Walk through events and concatenate current captions, or raw wav data if have any
  9079. dest[ 0 ] = 0;
  9080. int c = events.Count();
  9081. for ( int i = 0 ; i < c; ++i )
  9082. {
  9083. CChoreoEvent *e = events[ i ];
  9084. bool found = false;
  9085. char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  9086. if ( e->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
  9087. {
  9088. wchar_t *localized = g_pLocalize->Find( tok );
  9089. if ( localized )
  9090. {
  9091. found = true;
  9092. char ansi[ 1024 ];
  9093. g_pLocalize->ConvertUnicodeToANSI( localized, ansi, sizeof( ansi ) );
  9094. Q_strncat( dest, ansi, destlen, COPY_ALL_CHARACTERS );
  9095. }
  9096. }
  9097. if ( !found )
  9098. {
  9099. // See if the wav file has data...
  9100. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( e ) ) );
  9101. if ( wave )
  9102. {
  9103. CSentence *sentence = wave->GetSentence();
  9104. if ( sentence )
  9105. {
  9106. Q_strncat( dest, sentence->GetText(), destlen, COPY_ALL_CHARACTERS );
  9107. found = true;
  9108. }
  9109. }
  9110. }
  9111. if ( found && Q_strlen( dest ) > 0 && i != c - 1 )
  9112. {
  9113. Q_strncat( dest, " ", destlen, COPY_ALL_CHARACTERS );
  9114. }
  9115. }
  9116. }
  9117. void CChoreoView::OnCombineSpeakEvents()
  9118. {
  9119. if ( !m_pScene )
  9120. return;
  9121. CChoreoChannel *firstChannel = NULL;
  9122. CUtlVector< CChoreoEvent * > selected;
  9123. GetSelectedEvents( selected );
  9124. int c = selected.Count();
  9125. // Find the appropriate event by iterating across all actors and channels
  9126. for ( int i = c - 1; i >= 0; --i )
  9127. {
  9128. CChoreoEvent *e = selected[ i ];
  9129. if ( e->GetType() != CChoreoEvent::SPEAK )
  9130. {
  9131. Con_ErrorPrintf( "Can't combine events, all events must be SPEAK events.\n" );
  9132. return;
  9133. }
  9134. if ( !firstChannel )
  9135. {
  9136. firstChannel = e->GetChannel();
  9137. }
  9138. else if ( e->GetChannel() != firstChannel )
  9139. {
  9140. Con_ErrorPrintf( "Can't combine events, all events must reside in the same channel.\n" );
  9141. return;
  9142. }
  9143. }
  9144. if ( selected.Count() < 2 )
  9145. {
  9146. Con_ErrorPrintf( "Can't combine events, must have at least two events selected.\n" );
  9147. return;
  9148. }
  9149. // Let the user pick a CC phrase
  9150. CCloseCaptionLookupParams params;
  9151. Q_strncpy( params.m_szDialogTitle, "Choose Close Caption Token", sizeof( params.m_szDialogTitle ) );
  9152. params.m_bPositionDialog = false;
  9153. params.m_nLeft = 0;
  9154. params.m_nTop = 0;
  9155. char playbacktoken[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  9156. if ( !selected[0]->GetPlaybackCloseCaptionToken( playbacktoken, sizeof( playbacktoken ) ) )
  9157. {
  9158. return;
  9159. }
  9160. if ( !Q_stristr( playbacktoken, "_cc" ) )
  9161. {
  9162. Q_strncpy( params.m_szCCToken, va( "%s_cc", playbacktoken ), sizeof( params.m_szCCToken ) );
  9163. }
  9164. else
  9165. {
  9166. Q_strncpy( params.m_szCCToken, va( "%s", playbacktoken ), sizeof( params.m_szCCToken ) );
  9167. }
  9168. // User hit okay and value actually changed?
  9169. if ( !CloseCaptionLookup( &params ) &&
  9170. params.m_szCCToken[0] != 0 )
  9171. {
  9172. return;
  9173. }
  9174. // See if the token exists?
  9175. StringIndex_t stringIndex = g_pLocalize->FindIndex( params.m_szCCToken );
  9176. if ( INVALID_STRING_INDEX == stringIndex )
  9177. {
  9178. // Add token to closecaption_english file.
  9179. // Guess at string and ask user to confirm.
  9180. CInputParams ip;
  9181. memset( &ip, 0, sizeof( ip ) );
  9182. Q_strncpy( ip.m_szDialogTitle, "Add Close Caption", sizeof( ip.m_szDialogTitle ) );
  9183. Q_snprintf( ip.m_szPrompt, sizeof( ip.m_szPrompt ), "Token (%s):", params.m_szCCToken );
  9184. char suggested[ 2048 ];
  9185. SuggestCaption( suggested, sizeof( suggested ), selected );
  9186. Q_snprintf( ip.m_szInputText, sizeof( ip.m_szInputText ), "%s", suggested );
  9187. if ( !InputProperties( &ip ) )
  9188. {
  9189. Con_Printf( "Combining of sound events cancelled\n" );
  9190. return;
  9191. }
  9192. if ( Q_strlen( ip.m_szInputText ) == 0 )
  9193. {
  9194. Q_snprintf( ip.m_szInputText, sizeof( ip.m_szInputText ), "!!!%s", params.m_szCCToken );
  9195. }
  9196. char const *captionFile = "resource/closecaption_english.txt";
  9197. if ( !filesystem->IsFileWritable( captionFile, "GAME" ) )
  9198. {
  9199. Warning( "Forcing %s to be writable!!!\n", captionFile );
  9200. MakeFileWriteable( captionFile );
  9201. }
  9202. wchar_t unicode[ 2048 ];
  9203. g_pLocalize->ConvertANSIToUnicode( ip.m_szInputText, unicode, sizeof( unicode ) );
  9204. g_pLocalize->AddString( params.m_szCCToken, unicode, captionFile );
  9205. g_pLocalize->SaveToFile( captionFile );
  9206. }
  9207. SetDirty( true );
  9208. PushUndo( "Combine Sound Events" );
  9209. c = selected.Count();
  9210. for ( int i = 0 ; i < c; ++i )
  9211. {
  9212. selected[ i ]->SetCloseCaptionToken( params.m_szCCToken );
  9213. }
  9214. PushRedo( "Combine Sound Events" );
  9215. // Redraw
  9216. InvalidateLayout();
  9217. Con_Printf( "Changed %i events to use close caption token '%s'\n", c, params.m_szCCToken );
  9218. // Sort the sounds by start time
  9219. CUtlRBTree< CChoreoEvent * > sorted( 0, 0, EventStartTimeLessFunc );
  9220. // Sort items
  9221. c = selected.Count();
  9222. bool genderwildcard = false;
  9223. for ( int i = 0; i < c; i++ )
  9224. {
  9225. CChoreoEvent *e = selected[ i ];
  9226. sorted.Insert( e );
  9227. // Get the sound entry name and use it to look up the gender info
  9228. // Look up the sound level from the soundemitter system
  9229. if ( !genderwildcard )
  9230. {
  9231. genderwildcard = soundemitter->IsUsingGenderToken( e->GetParameters() );
  9232. }
  9233. }
  9234. char outfilename[ 512 ];
  9235. Q_memset( outfilename, 0, sizeof( outfilename ) );
  9236. CChoreoEvent *e = sorted[ sorted.FirstInorder() ];
  9237. // Update whether we use the $gender token
  9238. e->SetCombinedUsingGenderToken( genderwildcard );
  9239. if ( !e->ComputeCombinedBaseFileName( outfilename, sizeof( outfilename ), genderwildcard ) )
  9240. {
  9241. Con_ErrorPrintf( "Unable to regenerate wav file name for combined sound\n" );
  9242. return;
  9243. }
  9244. int soundindex = soundemitter->GetSoundIndex( e->GetParameters() );
  9245. char const *scriptfile = soundemitter->GetSourceFileForSound( soundindex );
  9246. if ( !scriptfile || !scriptfile[0] )
  9247. {
  9248. Con_ErrorPrintf( "Unable to find existing script to use for new combined sound entry.\n" );
  9249. return;
  9250. }
  9251. // Create a new sound entry for this sound
  9252. CAddSoundParams asp;
  9253. Q_memset( &asp, 0, sizeof( asp ) );
  9254. Q_strncpy( asp.m_szDialogTitle, "Add Combined Sound Entry", sizeof( asp.m_szDialogTitle ) );
  9255. Q_strncpy( asp.m_szWaveFile, outfilename + Q_strlen( "sound/"), sizeof( asp.m_szWaveFile ) );
  9256. Q_strncpy( asp.m_szScriptName, scriptfile, sizeof( asp.m_szScriptName ) );
  9257. Q_strncpy( asp.m_szSoundName, params.m_szCCToken, sizeof( asp.m_szSoundName ) );
  9258. asp.m_bAllowExistingSound = true;
  9259. asp.m_bReadOnlySoundName = true;
  9260. if ( !AddSound( &asp, (HWND)g_MDLViewer->getHandle() ) )
  9261. {
  9262. return;
  9263. }
  9264. if ( genderwildcard )
  9265. {
  9266. GenerateCombinedFile( outfilename, params.m_szCCToken, GENDER_MALE, sorted );
  9267. GenerateCombinedFile( outfilename, params.m_szCCToken, GENDER_FEMALE, sorted );
  9268. }
  9269. else
  9270. {
  9271. GenerateCombinedFile( outfilename, params.m_szCCToken, GENDER_NONE, sorted );
  9272. }
  9273. }
  9274. bool CChoreoView::ValidateCombinedSoundCheckSum( CChoreoEvent *e )
  9275. {
  9276. if ( !e || e->GetType() != CChoreoEvent::SPEAK )
  9277. return false;
  9278. bool genderwildcard = e->IsCombinedUsingGenderToken();
  9279. char outfilename[ 512 ];
  9280. Q_memset( outfilename, 0, sizeof( outfilename ) );
  9281. if ( !e->ComputeCombinedBaseFileName( outfilename, sizeof( outfilename ), genderwildcard ) )
  9282. {
  9283. Con_ErrorPrintf( "Unable to regenerate wav file name for combined sound (%s)\n", e->GetCloseCaptionToken() );
  9284. return false;
  9285. }
  9286. bool checksumvalid = false;
  9287. CUtlRBTree< CChoreoEvent * > eventList( 0, 0, EventStartTimeLessFunc );
  9288. if ( !e->GetChannel()->GetSortedCombinedEventList( e->GetCloseCaptionToken(), eventList ) )
  9289. {
  9290. Con_ErrorPrintf( "Unable to generated combined event list (%s)\n", e->GetCloseCaptionToken() );
  9291. return false;
  9292. }
  9293. if ( genderwildcard )
  9294. {
  9295. checksumvalid = ValidateCombinedFileCheckSum( outfilename, e->GetCloseCaptionToken(), GENDER_MALE, eventList );
  9296. checksumvalid &= ValidateCombinedFileCheckSum( outfilename, e->GetCloseCaptionToken(), GENDER_FEMALE, eventList );
  9297. }
  9298. else
  9299. {
  9300. checksumvalid = ValidateCombinedFileCheckSum( outfilename, e->GetCloseCaptionToken(), GENDER_NONE, eventList );
  9301. }
  9302. return checksumvalid;
  9303. }
  9304. void CChoreoView::OnRemoveSpeakEventFromGroup()
  9305. {
  9306. if ( !m_pScene )
  9307. return;
  9308. int i, c;
  9309. CUtlVector< CChoreoEvent * > selected;
  9310. CUtlVector< CChoreoEvent * > processlist;
  9311. if ( GetSelectedEvents( selected ) > 0 )
  9312. {
  9313. int c = selected.Count();
  9314. // Find the appropriate event by iterating across all actors and channels
  9315. for ( i = c - 1; i >= 0; --i )
  9316. {
  9317. CChoreoEvent *e = selected[ i ];
  9318. if ( e->GetType() != CChoreoEvent::SPEAK )
  9319. {
  9320. selected.Remove( i );
  9321. continue;
  9322. }
  9323. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED )
  9324. {
  9325. selected.Remove( i );
  9326. continue;
  9327. }
  9328. m_pClickedChannel->GetMasterAndSlaves( e, processlist );
  9329. }
  9330. }
  9331. else
  9332. {
  9333. m_pClickedChannel->GetMasterAndSlaves( m_pClickedChannel->GetCaptionClickedEvent(), processlist );
  9334. }
  9335. if ( selected.Count() < 1 )
  9336. {
  9337. Con_ErrorPrintf( "No eligible SPEAK event selected.\n" );
  9338. return;
  9339. }
  9340. SetDirty( true );
  9341. PushUndo( "Remove speak event(s)" );
  9342. c = processlist.Count();
  9343. for ( i = 0 ; i < c; ++i )
  9344. {
  9345. processlist[ i ]->SetCloseCaptionToken( "" );
  9346. processlist[ i ]->SetCloseCaptionType( CChoreoEvent::CC_MASTER );
  9347. processlist[ i ]->SetUsingCombinedFile( false );
  9348. processlist[ i ]->SetRequiredCombinedChecksum( 0 );
  9349. processlist[ i ]->SetNumSlaves( 0 );
  9350. processlist[ i ]->SetLastSlaveEndTime( 0.0f );
  9351. }
  9352. PushRedo( "Remove speak event(s)" );
  9353. // Redraw
  9354. InvalidateLayout();
  9355. Con_Printf( "Reverted %i events to use default close caption token\n", c );
  9356. }
  9357. bool CChoreoView::AreSelectedEventsCombinable()
  9358. {
  9359. CUtlVector< CChoreoEvent * > events;
  9360. if ( GetSelectedEvents( events ) <= 0 )
  9361. return false;
  9362. CChoreoChannel *firstChannel = NULL;
  9363. CUtlVector< CChoreoEvent * > selected;
  9364. GetSelectedEvents( selected );
  9365. int c = selected.Count();
  9366. // Find the appropriate event by iterating across all actors and channels
  9367. for ( int i = c - 1; i >= 0; --i )
  9368. {
  9369. CChoreoEvent *e = selected[ i ];
  9370. if ( e->GetType() != CChoreoEvent::SPEAK )
  9371. {
  9372. return false;
  9373. }
  9374. if ( !firstChannel )
  9375. {
  9376. firstChannel = e->GetChannel();
  9377. }
  9378. else if ( e->GetChannel() != firstChannel )
  9379. {
  9380. return false;
  9381. }
  9382. }
  9383. return selected.Count() >= 2 ? true : false;
  9384. }
  9385. bool CChoreoView::AreSelectedEventsInSpeakGroup()
  9386. {
  9387. CUtlVector< CChoreoEvent * > selected;
  9388. if ( GetSelectedEvents( selected ) <= 0 )
  9389. {
  9390. if ( m_pClickedChannel )
  9391. {
  9392. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  9393. if ( e && e->GetCloseCaptionType() == CChoreoEvent::CC_MASTER &&
  9394. e->GetNumSlaves() >= 1 )
  9395. {
  9396. return true;
  9397. }
  9398. }
  9399. return false;
  9400. }
  9401. int c = selected.Count();
  9402. // Find the appropriate event by iterating across all actors and channels
  9403. for ( int i = c - 1; i >= 0; --i )
  9404. {
  9405. CChoreoEvent *e = selected[ i ];
  9406. if ( e->GetType() != CChoreoEvent::SPEAK )
  9407. {
  9408. selected.Remove( i );
  9409. continue;
  9410. }
  9411. if ( e->GetCloseCaptionType() == CChoreoEvent::CC_DISABLED )
  9412. {
  9413. selected.Remove( i );
  9414. continue;
  9415. }
  9416. }
  9417. return selected.Count() >= 1 ? true : false;
  9418. }
  9419. void CChoreoView::OnChangeCloseCaptionToken( CChoreoEvent *e )
  9420. {
  9421. CCloseCaptionLookupParams params;
  9422. Q_strncpy( params.m_szDialogTitle, "Close Caption Token Lookup", sizeof( params.m_szDialogTitle ) );
  9423. params.m_bPositionDialog = false;
  9424. params.m_nLeft = 0;
  9425. params.m_nTop = 0;
  9426. // strcpy( params.m_szPrompt, "Choose model:" );
  9427. Q_strncpy( params.m_szCCToken, e->GetCloseCaptionToken(), sizeof( params.m_szCCToken ) );
  9428. // User hit okay and value actually changed?
  9429. if ( CloseCaptionLookup( &params ) &&
  9430. Q_stricmp( e->GetCloseCaptionToken(), params.m_szCCToken ) )
  9431. {
  9432. char oldToken[ CChoreoEvent::MAX_CCTOKEN_STRING ];
  9433. Q_strncpy( oldToken, e->GetCloseCaptionToken(), sizeof( oldToken ) );
  9434. CUtlVector< CChoreoEvent * > events;
  9435. m_pClickedChannel->GetMasterAndSlaves( e, events );
  9436. if ( events.Count() < 2 )
  9437. {
  9438. Con_ErrorPrintf( "Can't combine events, must have at least two events selected.\n" );
  9439. }
  9440. SetDirty( true );
  9441. PushUndo( "Change closecaption token" );
  9442. // Make the change...
  9443. int c = events.Count();
  9444. for ( int i = 0 ; i < c; ++i )
  9445. {
  9446. events[i]->SetCloseCaptionToken( params.m_szCCToken );
  9447. }
  9448. PushRedo( "Change closecaption token" );
  9449. InvalidateLayout();
  9450. Con_Printf( "Close Caption token for '%s' changed to '%s'\n", e->GetName(), params.m_szCCToken );
  9451. }
  9452. }
  9453. void CChoreoView::OnToggleCloseCaptionsForEvent()
  9454. {
  9455. if ( !m_pClickedChannel )
  9456. {
  9457. return;
  9458. }
  9459. CChoreoEvent *e = m_pClickedChannel->GetCaptionClickedEvent();
  9460. if ( !e )
  9461. {
  9462. return;
  9463. }
  9464. CChoreoEvent::CLOSECAPTION newType = CChoreoEvent::CC_MASTER;
  9465. // Can't mess with slave
  9466. switch ( e->GetCloseCaptionType() )
  9467. {
  9468. default:
  9469. case CChoreoEvent::CC_SLAVE:
  9470. return;
  9471. case CChoreoEvent::CC_MASTER:
  9472. newType = CChoreoEvent::CC_DISABLED;
  9473. break;
  9474. case CChoreoEvent::CC_DISABLED:
  9475. newType = CChoreoEvent::CC_MASTER;
  9476. break;
  9477. }
  9478. SetDirty( true );
  9479. PushUndo( "Enable/disable captions" );
  9480. // Make the change...
  9481. e->SetCloseCaptionType( newType );
  9482. PushRedo( "Enable/disable captions" );
  9483. InvalidateLayout();
  9484. Con_Printf( "Close Caption type for '%s' changed to '%s'\n", e->GetName(), CChoreoEvent::NameForCCType( newType ) );
  9485. }
  9486. void CChoreoView::StopScene()
  9487. {
  9488. SetScrubTargetTime( m_flScrub );
  9489. FinishSimulation();
  9490. sound->Flush();
  9491. }
  9492. //-----------------------------------------------------------------------------
  9493. // Purpose:
  9494. // Input : -
  9495. //-----------------------------------------------------------------------------
  9496. template <class T>
  9497. void DeleteAllAndPurge( T &tree )
  9498. {
  9499. T::IndexType_t i;
  9500. for ( i = tree.FirstInorder(); i != T::InvalidIndex(); i = tree.NextInorder( i ) )
  9501. {
  9502. delete tree[i];
  9503. }
  9504. tree.Purge();
  9505. }
  9506. void CChoreoView::OnPlaceNextSpeakEvent()
  9507. {
  9508. CUtlVector< CChoreoEvent * > list;
  9509. GetSelectedEvents( list );
  9510. if ( list.Count() != 1 )
  9511. {
  9512. Warning( "Can't place sound event, nothing selected\n" );
  9513. return;
  9514. }
  9515. CChoreoEvent *ev = list[ 0 ];
  9516. if ( ev->GetType() != CChoreoEvent::SPEAK )
  9517. {
  9518. Warning( "Can't place sound event, no previous sound event selected\n" );
  9519. return;
  9520. }
  9521. CChoreoChannelWidget *widget = FindChannelForEvent( ev );
  9522. if ( !widget )
  9523. {
  9524. Warning( "Can't place sound event, can't find channel widget for event\n" );
  9525. return;
  9526. }
  9527. CChoreoChannel *channel = widget->GetChannel();
  9528. if ( !channel )
  9529. {
  9530. Warning( "Can't place sound event, can't find channel for new event\n" );
  9531. return;
  9532. }
  9533. CUtlRBTree< char const *, int > m_SortedNames( 0, 0, NameLessFunc );
  9534. int c = soundemitter->GetSoundCount();
  9535. for ( int i = 0; i < c; i++ )
  9536. {
  9537. char const *name = soundemitter->GetSoundName( i );
  9538. if ( name && name[ 0 ] )
  9539. {
  9540. m_SortedNames.Insert( strdup( name ) );
  9541. }
  9542. }
  9543. int idx = m_SortedNames.Find( ev->GetParameters() );
  9544. if ( idx == m_SortedNames.InvalidIndex() )
  9545. {
  9546. Warning( "Can't place sound event, can't find '%s' in sound list\n", ev->GetParameters() );
  9547. DeleteAllAndPurge( m_SortedNames );
  9548. return;
  9549. }
  9550. int nextIdx = m_SortedNames.NextInorder( idx );
  9551. if ( nextIdx == m_SortedNames.InvalidIndex() )
  9552. {
  9553. Warning( "Can't place sound event, can't next sound after '%s' in sound list\n", ev->GetParameters() );
  9554. DeleteAllAndPurge( m_SortedNames );
  9555. return;
  9556. }
  9557. DeselectAll();
  9558. SetDirty( true );
  9559. PushUndo( "Place Next Speak Event" );
  9560. CChoreoEvent *event = m_pScene->AllocEvent();
  9561. Assert( event );
  9562. if ( event )
  9563. {
  9564. // Copy everything for source event
  9565. *event = *ev;
  9566. event->SetParameters( m_SortedNames[ nextIdx ] );
  9567. // Start it at the end time...
  9568. event->SetStartTime( event->GetEndTime() );
  9569. event->SetResumeCondition( false );
  9570. event->ClearAllRelativeTags();
  9571. event->ClearAllTimingTags();
  9572. event->ClearAllAbsoluteTags( CChoreoEvent::PLAYBACK );
  9573. event->ClearAllAbsoluteTags( CChoreoEvent::ORIGINAL );
  9574. event->SetChannel( channel );
  9575. event->SetActor( channel->GetActor() );
  9576. // Try and load wav to get length
  9577. CAudioSource *wave = sound->LoadSound( va( "sound/%s", FacePoser_TranslateSoundName( event ) ) );
  9578. if ( wave )
  9579. {
  9580. event->SetEndTime( event->GetStartTime() + wave->GetRunningLength() );
  9581. delete wave;
  9582. }
  9583. DeleteSceneWidgets();
  9584. // Add to appropriate channel
  9585. channel->AddEvent( event );
  9586. CreateSceneWidgets();
  9587. CChoreoEventWidget *eventWidget = FindWidgetForEvent( event );
  9588. if ( eventWidget )
  9589. {
  9590. eventWidget->SetSelected( true );
  9591. }
  9592. // Redraw
  9593. InvalidateLayout();
  9594. }
  9595. PushRedo( "Place Next Speak Event" );
  9596. DeleteAllAndPurge( m_SortedNames );
  9597. }
  9598. enum
  9599. {
  9600. FM_LEFT = 0,
  9601. FM_RIGHT,
  9602. FM_SMALLESTWIDE,
  9603. FM_LARGESTWIDE
  9604. };
  9605. static int FindMetric( int type, CUtlVector< CChoreoEvent * > &list, float& value )
  9606. {
  9607. float bestVal = 999999.0f;
  9608. int bestIndex = -1;
  9609. bool greater = true;
  9610. switch ( type )
  9611. {
  9612. default:
  9613. case FM_LEFT:
  9614. case FM_SMALLESTWIDE:
  9615. greater = false;
  9616. break;
  9617. case FM_RIGHT:
  9618. case FM_LARGESTWIDE:
  9619. bestVal = -bestVal;
  9620. greater = true;
  9621. break;
  9622. }
  9623. int c = list.Count();
  9624. for ( int i = 0; i < c; ++i )
  9625. {
  9626. CChoreoEvent *e = list[ i ];
  9627. if ( type != FM_LEFT &&
  9628. !e->HasEndTime() )
  9629. continue;
  9630. float val;
  9631. switch ( type )
  9632. {
  9633. default:
  9634. case FM_LEFT:
  9635. val = e->GetStartTime();
  9636. break;
  9637. case FM_RIGHT:
  9638. val = e->GetEndTime();
  9639. break;
  9640. case FM_SMALLESTWIDE:
  9641. case FM_LARGESTWIDE:
  9642. val = e->GetDuration();
  9643. break;
  9644. }
  9645. if ( greater )
  9646. {
  9647. if ( val <= bestVal )
  9648. continue;
  9649. }
  9650. else
  9651. {
  9652. if ( val >= bestVal )
  9653. continue;
  9654. }
  9655. bestVal = val;
  9656. bestIndex = i;
  9657. }
  9658. value = bestVal;
  9659. return bestIndex;
  9660. }
  9661. void CChoreoView::OnAlign( bool left )
  9662. {
  9663. CUtlVector< CChoreoEvent * > list;
  9664. GetSelectedEvents( list );
  9665. if ( left )
  9666. {
  9667. for ( int i = 0; i < m_SceneGlobalEvents.Count(); i++ )
  9668. {
  9669. CChoreoGlobalEventWidget *event = m_SceneGlobalEvents[ i ];
  9670. if ( !event || !event->IsSelected() )
  9671. continue;
  9672. list.AddToTail( event->GetEvent() );
  9673. }
  9674. }
  9675. int numSel = list.Count();
  9676. if ( numSel < 2 )
  9677. {
  9678. Warning( "Can't align, must have at least two events selected\n" );
  9679. return;
  9680. }
  9681. float value;
  9682. int idx = FindMetric( left ? FM_LEFT : FM_RIGHT, list, value );
  9683. if ( idx == -1 )
  9684. {
  9685. return;
  9686. }
  9687. SetDirty( true );
  9688. char undotext[ 128 ];
  9689. Q_snprintf( undotext, sizeof( undotext ), "Align %s", left ? "Left" : "Right" );
  9690. PushUndo( undotext );
  9691. for ( int i = 0; i < numSel; ++i )
  9692. {
  9693. if ( i == idx )
  9694. continue;
  9695. CChoreoEvent *e = list[ i ];
  9696. float newStartTime = left ? value : ( value - e->GetDuration() );
  9697. float offset = newStartTime - e->GetStartTime();
  9698. e->OffsetTime( offset );
  9699. }
  9700. PushRedo( undotext );
  9701. InvalidateLayout();
  9702. }
  9703. void CChoreoView::OnMakeSameSize( bool smallest )
  9704. {
  9705. CUtlVector< CChoreoEvent * > list;
  9706. int numSel = GetSelectedEvents( list );
  9707. if ( numSel < 2 )
  9708. {
  9709. Warning( "Can't align, must have at least two events selected\n" );
  9710. return;
  9711. }
  9712. float value;
  9713. int idx = FindMetric( smallest ? FM_SMALLESTWIDE : FM_LARGESTWIDE, list, value );
  9714. if ( idx == -1 )
  9715. {
  9716. return;
  9717. }
  9718. SetDirty( true );
  9719. char undotext[ 128 ];
  9720. Q_snprintf( undotext, sizeof( undotext ), "Size to %s", smallest ? "Smallest" : "Largest" );
  9721. PushUndo( undotext );
  9722. for ( int i = 0; i < numSel; ++i )
  9723. {
  9724. if ( i == idx )
  9725. continue;
  9726. list[ i ]->SetEndTime( list[ i ]->GetStartTime() + value );
  9727. }
  9728. PushRedo( undotext );
  9729. InvalidateLayout();
  9730. }
  9731. void CChoreoView::SelectAllEventsInActor( CChoreoActorWidget *actor )
  9732. {
  9733. TraverseWidgets( &CChoreoView::SelectInActor, actor );
  9734. redraw();
  9735. }
  9736. void CChoreoView::SelectAllEventsInChannel( CChoreoChannelWidget *channel )
  9737. {
  9738. TraverseWidgets( &CChoreoView::SelectInChannel, channel );
  9739. redraw();
  9740. }
  9741. void CChoreoView::SelectInActor( CChoreoWidget *widget, CChoreoWidget *param1 )
  9742. {
  9743. CChoreoEventWidget *ev = dynamic_cast< CChoreoEventWidget * >( widget );
  9744. if ( !ev )
  9745. return;
  9746. if ( ev->IsSelected() )
  9747. return;
  9748. CChoreoChannel *ch = ev->GetEvent()->GetChannel();
  9749. if ( !ch )
  9750. return;
  9751. CChoreoActor *actor = ch->GetActor();
  9752. if ( !actor )
  9753. return;
  9754. CChoreoActorWidget *actorw = dynamic_cast< CChoreoActorWidget * >( param1 );
  9755. if ( !actorw )
  9756. return;
  9757. if ( actorw->GetActor() != actor )
  9758. return;
  9759. widget->SetSelected( true );
  9760. }
  9761. void CChoreoView::SelectInChannel( CChoreoWidget *widget, CChoreoWidget *param1 )
  9762. {
  9763. CChoreoEventWidget *ev = dynamic_cast< CChoreoEventWidget * >( widget );
  9764. if ( !ev )
  9765. return;
  9766. if ( ev->IsSelected() )
  9767. return;
  9768. CChoreoChannel *ch = ev->GetEvent()->GetChannel();
  9769. if ( !ch )
  9770. return;
  9771. CChoreoChannelWidget *chw = dynamic_cast< CChoreoChannelWidget * >( param1 );
  9772. if ( !chw )
  9773. return;
  9774. if ( chw->GetChannel() != ch )
  9775. return;
  9776. widget->SetSelected( true );
  9777. }
  9778. void CChoreoView::SetScrubUnitSeconds( bool bUseSeconds)
  9779. {
  9780. m_bScrubSeconds = bUseSeconds;
  9781. redraw();
  9782. }