//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //============================================================================= #include "stdafx.h" #include "hammer.h" #include "ScenePreviewDlg.h" #include "choreoscene.h" #include "soundsystem.h" // memdbgon must be the last include file in a .cpp file!!! #include #define WM_SCENEPREVIEW_IDLE (WM_USER+1) BEGIN_MESSAGE_MAP(CScenePreviewDlg, CDialog) //{{AFX_MSG_MAP(CScenePreviewDlg) ON_BN_CLICKED(IDCANCEL, OnCancel) //}}AFX_MSG_MAP END_MESSAGE_MAP() CScenePreviewDlg::CScenePreviewDlg( CChoreoScene *pScene, const char *pFilename, CWnd* pParent /*=NULL*/ ) : CDialog(CScenePreviewDlg::IDD, pParent) { //{{AFX_DATA_INIT(CScenePreviewDlg) m_pScene = pScene; m_iLastEventPlayed = -2; // Don't do anything yet. m_hExitThreadEvent = NULL; m_hIdleEventHandledEvent = NULL; m_hIdleThread = NULL; V_strncpy( m_SceneFilename, pFilename, sizeof( m_SceneFilename ) ); } CScenePreviewDlg::~CScenePreviewDlg() { EndThread(); delete m_pScene; } void CScenePreviewDlg::EndThread() { if ( m_hIdleThread ) { SetEvent( m_hExitThreadEvent ); WaitForSingleObject( m_hIdleThread, INFINITE ); CloseHandle( m_hIdleThread ); CloseHandle( m_hExitThreadEvent ); CloseHandle( m_hIdleEventHandledEvent ); m_hIdleThread = m_hExitThreadEvent = m_hIdleEventHandledEvent = NULL; } } BOOL CScenePreviewDlg::OnInitDialog() { CDialog::OnInitDialog(); // Setup the control showing the scene name. CString str; GetDlgItemText( IDC_SCENE_NAME, str ); str = str + " " + m_SceneFilename; SetDlgItemText( IDC_SCENE_NAME, str ); CString strNone; strNone.LoadString( IDS_NONE ); SetDlgItemText( IDC_CURRENT_SOUND, strNone ); SetDlgItemText( IDC_NEXT_SOUND, strNone ); m_iLastEventPlayed = -1; m_flStartTime = Plat_FloatTime(); // Start on the first event.. for ( int i = 0; i < m_pScene->GetNumEvents(); i++ ) { CChoreoEvent *e = m_pScene->GetEvent( i ); if ( e && e->GetType() == CChoreoEvent::SPEAK ) { m_flStartTime -= e->GetStartTime(); break; } } // Create our idle thread. m_hExitThreadEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); m_hIdleEventHandledEvent = CreateEvent( NULL, FALSE, FALSE, NULL ); m_hIdleThread = CreateThread( NULL, 0, &CScenePreviewDlg::StaticIdleThread, this, 0, NULL ); return TRUE; } DWORD CScenePreviewDlg::StaticIdleThread( LPVOID pParameter ) { return ((CScenePreviewDlg*)pParameter)->IdleThread(); } DWORD CScenePreviewDlg::IdleThread() { HANDLE handles[2] = {m_hExitThreadEvent, m_hIdleEventHandledEvent}; while ( 1 ) { // Send the event to the window. PostMessage( WM_SCENEPREVIEW_IDLE, 0, 0 ); DWORD ret = WaitForMultipleObjects( ARRAYSIZE( handles ), handles, false, INFINITE ); if ( ret == WAIT_OBJECT_0 || ret == WAIT_TIMEOUT ) return 0; Sleep( 100 ); // Only handle idle 10x/sec. } } void CScenePreviewDlg::OnIdle() { double flElapsed = Plat_FloatTime() - m_flStartTime; // Find the next sound to play. int iLastSound = -1; for ( int i = 0; i < m_pScene->GetNumEvents(); i++ ) { CChoreoEvent *e = m_pScene->GetEvent( i ); if ( !e || e->GetType() != CChoreoEvent::SPEAK ) continue; if ( flElapsed > e->GetStartTime() ) iLastSound = i; } // Is there another sound to play in here? if ( iLastSound >= 0 && iLastSound != m_iLastEventPlayed ) { m_iLastEventPlayed = iLastSound; // Play the current sound. CChoreoEvent *pChoreoEvent = m_pScene->GetEvent( iLastSound ); const char *pSoundName = pChoreoEvent->GetParameters(); SoundType_t soundType; int nIndex; if ( g_Sounds.FindSoundByName( pSoundName, &soundType, &nIndex ) ) { bool bRet = g_Sounds.Play( soundType, nIndex ); CString curSound = pSoundName; if ( !bRet ) { CString strErrorPlaying; strErrorPlaying.LoadString( IDS_ERROR_PLAYING ); curSound += " " + strErrorPlaying; } SetDlgItemText( IDC_CURRENT_SOUND, curSound ); } // Find the next sound event. CString str; str.LoadString( IDS_NONE ); for ( int i=iLastSound+1; i < m_pScene->GetNumEvents(); i++ ) { CChoreoEvent *e = m_pScene->GetEvent( i ); if ( e && e->GetType() == CChoreoEvent::SPEAK ) { str = e->GetParameters(); break; } } SetDlgItemText( IDC_NEXT_SOUND, str ); } } LRESULT CScenePreviewDlg::DefWindowProc( UINT message, WPARAM wParam, LPARAM lParam ) { // We handle the enter key specifically because the default combo box behavior is to // reset the text and all this stuff we don't want. if ( message == WM_SCENEPREVIEW_IDLE ) { OnIdle(); SetEvent( m_hIdleEventHandledEvent ); return 0; } return CDialog::DefWindowProc( message, wParam, lParam ); } void CScenePreviewDlg::OnCancel(void) { g_Sounds.StopSound(); EndThread(); EndDialog( 0 ); }