summaryrefslogtreecommitdiff
path: root/utils/scenemanager
diff options
context:
space:
mode:
Diffstat (limited to 'utils/scenemanager')
-rw-r--r--utils/scenemanager/audiowaveoutput.h127
-rw-r--r--utils/scenemanager/basedialogparams.cpp65
-rw-r--r--utils/scenemanager/basedialogparams.h26
-rw-r--r--utils/scenemanager/cbase.cpp15
-rw-r--r--utils/scenemanager/cbase.h28
-rw-r--r--utils/scenemanager/drawhelper.cpp1033
-rw-r--r--utils/scenemanager/drawhelper.h107
-rw-r--r--utils/scenemanager/fileloaderthread.cpp369
-rw-r--r--utils/scenemanager/ico00001.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/ico00002.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/ico00003.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/ico00004.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/ico00005.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/ico00006.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/ico00007.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/icon1.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/ifileloader.h29
-rw-r--r--utils/scenemanager/inputproperties.cpp79
-rw-r--r--utils/scenemanager/inputproperties.h29
-rw-r--r--utils/scenemanager/iscenemanagersound.h45
-rw-r--r--utils/scenemanager/itreeitem.cpp84
-rw-r--r--utils/scenemanager/itreeitem.h89
-rw-r--r--utils/scenemanager/multiplerequest.cpp138
-rw-r--r--utils/scenemanager/multiplerequest.h39
-rw-r--r--utils/scenemanager/project.cpp416
-rw-r--r--utils/scenemanager/project.h88
-rw-r--r--utils/scenemanager/project1.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/resource.h72
-rw-r--r--utils/scenemanager/scene.cpp243
-rw-r--r--utils/scenemanager/scene.h75
-rw-r--r--utils/scenemanager/scenemanager.cpp220
-rw-r--r--utils/scenemanager/scenemanager.rc269
-rw-r--r--utils/scenemanager/scenemanager.vpc261
-rw-r--r--utils/scenemanager/scenemanager_tools.cpp846
-rw-r--r--utils/scenemanager/scenemanager_tools.h58
-rw-r--r--utils/scenemanager/snd_audio_source.cpp56
-rw-r--r--utils/scenemanager/snd_audio_source.h119
-rw-r--r--utils/scenemanager/snd_wave_mixer.cpp492
-rw-r--r--utils/scenemanager/snd_wave_mixer.h24
-rw-r--r--utils/scenemanager/snd_wave_mixer_adpcm.cpp511
-rw-r--r--utils/scenemanager/snd_wave_mixer_adpcm.h24
-rw-r--r--utils/scenemanager/snd_wave_mixer_private.h94
-rw-r--r--utils/scenemanager/snd_wave_source.cpp590
-rw-r--r--utils/scenemanager/snd_wave_source.h77
-rw-r--r--utils/scenemanager/sound.cpp1182
-rw-r--r--utils/scenemanager/sound.h97
-rw-r--r--utils/scenemanager/soundbrowser.cpp964
-rw-r--r--utils/scenemanager/soundbrowser.h89
-rw-r--r--utils/scenemanager/soundentry.cpp334
-rw-r--r--utils/scenemanager/soundentry.h95
-rw-r--r--utils/scenemanager/soundproperties.cpp616
-rw-r--r--utils/scenemanager/soundproperties.h44
-rw-r--r--utils/scenemanager/soundproperties_multiple.cpp240
-rw-r--r--utils/scenemanager/soundproperties_multiple.h20
-rw-r--r--utils/scenemanager/statuswindow.cpp245
-rw-r--r--utils/scenemanager/statuswindow.h57
-rw-r--r--utils/scenemanager/tabwindow.cpp484
-rw-r--r--utils/scenemanager/tabwindow.h103
-rw-r--r--utils/scenemanager/vcd1.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/vcdfile.cpp284
-rw-r--r--utils/scenemanager/vcdfile.h90
-rw-r--r--utils/scenemanager/vssproperties.cpp83
-rw-r--r--utils/scenemanager/vssproperties.h27
-rw-r--r--utils/scenemanager/wav1.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/wavebrowser.cpp1066
-rw-r--r--utils/scenemanager/wavebrowser.h102
-rw-r--r--utils/scenemanager/wavefile.cpp379
-rw-r--r--utils/scenemanager/wavefile.h103
-rw-r--r--utils/scenemanager/waveproperties.cpp193
-rw-r--r--utils/scenemanager/waveproperties.h41
-rw-r--r--utils/scenemanager/workspac.icobin0 -> 1078 bytes
-rw-r--r--utils/scenemanager/workspace.cpp473
-rw-r--r--utils/scenemanager/workspace.h90
-rw-r--r--utils/scenemanager/workspacebrowser.cpp258
-rw-r--r--utils/scenemanager/workspacebrowser.h67
-rw-r--r--utils/scenemanager/workspacemanager.cpp2004
-rw-r--r--utils/scenemanager/workspacemanager.h184
77 files changed, 16851 insertions, 0 deletions
diff --git a/utils/scenemanager/audiowaveoutput.h b/utils/scenemanager/audiowaveoutput.h
new file mode 100644
index 0000000..c169c16
--- /dev/null
+++ b/utils/scenemanager/audiowaveoutput.h
@@ -0,0 +1,127 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef AUDIOWAVEOUTPUT_H
+#define AUDIOWAVEOUTPUT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "sound.h"
+#include "utlvector.h"
+
+#define OUTPUT_BUFFER_COUNT 32
+#define MAX_CHANNELS 16
+
+class CAudioMixer;
+
+class CAudioMixerState
+{
+public:
+ CAudioMixer *mixer;
+ int submit_mixer_sample;
+};
+
+class CAudioBuffer
+{
+public:
+ WAVEHDR *hdr;
+ bool submitted;
+ int submit_sample_count;
+
+ CUtlVector< CAudioMixerState > m_Referenced;
+};
+
+#define OUTPUT_SAMPLE_RATE 44100
+#define PAINTBUFFER_SIZE 1024
+
+typedef struct
+{
+ int left;
+ int right;
+} portable_samplepair_t;
+
+class CAudioDeviceSWMix : public IAudioDevice
+{
+public:
+ virtual void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true );
+ virtual void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true );
+ virtual void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true );
+ virtual void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true );
+ virtual int MaxSampleCount( void );
+ virtual void MixBegin( void );
+
+ void TransferBufferStereo16( short *pOutput, int sampleCount );
+
+private:
+ portable_samplepair_t m_paintbuffer[ PAINTBUFFER_SIZE ];
+};
+
+class CAudioWaveOutput : public CAudioOutput
+{
+public:
+ CAudioWaveOutput( void );
+ ~CAudioWaveOutput( void );
+
+ // returns the size of each sample in bytes
+ virtual int SampleSize( void ) { return 2; }
+
+ // returns the sampling rate of the data
+ virtual int SampleRate( void ) { return OUTPUT_SAMPLE_RATE; }
+
+ // returns the mono/stereo status of this device (true if stereo)
+ virtual bool IsStereo( void ) { return true; }
+
+ // mix a buffer up to time (time is absolute)
+ virtual void Update( float time );
+
+ virtual void Flush( void );
+
+ virtual void AddSource( CAudioMixer *pSource );
+ virtual void StopSounds( void );
+ virtual int FindSourceIndex( CAudioMixer *pSource );
+
+ virtual int GetOutputPosition( void );
+ virtual float GetAmountofTimeAhead( void );
+ virtual int GetNumberofSamplesAhead( void );
+
+ virtual CAudioMixer *GetMixerForSource( CAudioSource *pSource );
+
+
+private:
+ void OpenDevice( void );
+ bool ValidDevice( void ) { return m_deviceHandle != 0; }
+ void ClearDevice( void ) { m_deviceHandle = NULL; }
+ CAudioBuffer *GetEmptyBuffer( void );
+ void SilenceBuffer( short *pSamples, int sampleCount );
+
+ void SetChannel( int channelIndex, CAudioMixer *pSource );
+ void FreeChannel( int channelIndex );
+
+ void RemoveMixerChannelReferences( CAudioMixer *mixer );
+ void AddToReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer );
+ void RemoveFromReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer );
+ bool IsSourceReferencedByActiveBuffer( CAudioMixer *mixer );
+ bool IsSoundInReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer );
+
+ // Compute how many samples we've mixed since most recent buffer submission
+ void ComputeSampleAheadAmount( void );
+
+ HWAVEOUT m_deviceHandle;
+
+ float m_mixTime;
+ float m_baseTime;
+ int m_sampleIndex;
+ CAudioBuffer m_buffers[ OUTPUT_BUFFER_COUNT ];
+
+ CAudioMixer *m_sourceList[MAX_CHANNELS];
+ int m_nEstimatedSamplesAhead;
+public:
+ CAudioDeviceSWMix m_audioDevice;
+
+};
+#endif // AUDIOWAVEOUTPUT_H
diff --git a/utils/scenemanager/basedialogparams.cpp b/utils/scenemanager/basedialogparams.cpp
new file mode 100644
index 0000000..4287981
--- /dev/null
+++ b/utils/scenemanager/basedialogparams.cpp
@@ -0,0 +1,65 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include <mxtk/mx.h>
+#include "tier0/dbg.h"
+#include "basedialogparams.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : self -
+//-----------------------------------------------------------------------------
+void CBaseDialogParams::PositionSelf( void *self )
+{
+ RECT rcDlg;
+ HWND dlgWindow = (HWND)self;
+ GetWindowRect( dlgWindow, &rcDlg );
+
+ // Get relative to primary monitor instead of actual window parent
+ RECT rcParent;
+ rcParent.left = 0;
+ rcParent.right = rcParent.left + GetSystemMetrics( SM_CXFULLSCREEN );
+ rcParent.top = 0;
+ rcParent.bottom = rcParent.top + GetSystemMetrics( SM_CYFULLSCREEN );
+
+ int dialogw, dialogh;
+ int parentw, parenth;
+
+ parentw = rcParent.right - rcParent.left;
+ parenth = rcParent.bottom - rcParent.top;
+ dialogw = rcDlg.right - rcDlg.left;
+ dialogh = rcDlg.bottom - rcDlg.top;
+
+ int dlgleft, dlgtop;
+ dlgleft = ( parentw - dialogw ) / 2;
+ dlgtop = ( parenth - dialogh ) / 2;
+
+ if ( m_bPositionDialog )
+ {
+ int top = m_nTop - dialogh - 5;
+ int left = m_nLeft;
+
+ MoveWindow( dlgWindow,
+ left,
+ top,
+ dialogw,
+ dialogh,
+ TRUE );
+ }
+ else
+ {
+
+ MoveWindow( dlgWindow,
+ dlgleft,
+ dlgtop,
+ dialogw,
+ dialogh,
+ TRUE
+ );
+ }
+
+} \ No newline at end of file
diff --git a/utils/scenemanager/basedialogparams.h b/utils/scenemanager/basedialogparams.h
new file mode 100644
index 0000000..14f1e12
--- /dev/null
+++ b/utils/scenemanager/basedialogparams.h
@@ -0,0 +1,26 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef BASEDIALOGPARAMS_H
+#define BASEDIALOGPARAMS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+struct CBaseDialogParams
+{
+ // i dialog title
+ char m_szDialogTitle[ 128 ];
+
+ bool m_bPositionDialog;
+ int m_nLeft;
+ int m_nTop;
+
+ void PositionSelf( void * self );
+};
+
+#endif // BASEDIALOGPARAMS_H
diff --git a/utils/scenemanager/cbase.cpp b/utils/scenemanager/cbase.cpp
new file mode 100644
index 0000000..11ea67e
--- /dev/null
+++ b/utils/scenemanager/cbase.cpp
@@ -0,0 +1,15 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+// stdafx.cpp : source file that includes just the standard includes
+// scenemanager.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "cbase.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/utils/scenemanager/cbase.h b/utils/scenemanager/cbase.h
new file mode 100644
index 0000000..bb73b41
--- /dev/null
+++ b/utils/scenemanager/cbase.h
@@ -0,0 +1,28 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//===========================================================================//
+
+#ifndef CBASE_H
+#define CBASE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+// cbase.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+// TODO: reference additional headers your program requires here
+#include "mxtk/mx.h"
+#include "mxtk/mxwindow.h"
+#include "tier0/dbg.h"
+#include "utlvector.h"
+#include "vstdlib/random.h"
+#include "sharedInterface.h"
+#include "scenemanager_tools.h"
+#include "tier3/tier3.h"
+
+#endif // CBASE_H
diff --git a/utils/scenemanager/drawhelper.cpp b/utils/scenemanager/drawhelper.cpp
new file mode 100644
index 0000000..f7703dd
--- /dev/null
+++ b/utils/scenemanager/drawhelper.cpp
@@ -0,0 +1,1033 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "tier0/dbg.h"
+#include <stdio.h>
+#include "drawhelper.h"
+
+// #define COLOR_BACKGROUND RGB( 120, 120, 150 )
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *widget -
+//-----------------------------------------------------------------------------
+CDrawHelper::CDrawHelper( mxWindow *widget )
+{
+ Init( widget, 0, 0, 0, 0, COLOR_BACKGROUND );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *widget -
+//-----------------------------------------------------------------------------
+CDrawHelper::CDrawHelper( mxWindow *widget, COLORREF bgColor )
+{
+ Init( widget, 0, 0, 0, 0, bgColor );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *widget -
+// bounds -
+//-----------------------------------------------------------------------------
+CDrawHelper::CDrawHelper( mxWindow *widget, RECT& bounds )
+{
+ Init( widget, bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top, COLOR_BACKGROUND );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *widget -
+// x -
+// y -
+// w -
+// h -
+//-----------------------------------------------------------------------------
+CDrawHelper::CDrawHelper( mxWindow *widget, int x, int y, int w, int h, COLORREF bgColor )
+{
+ Init( widget, x, y, w, h, bgColor );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *widget -
+// bounds -
+// bgColor -
+//-----------------------------------------------------------------------------
+CDrawHelper::CDrawHelper( mxWindow *widget, RECT& bounds, COLORREF bgColor )
+{
+ Init( widget, bounds.left, bounds.top, bounds.right - bounds.left, bounds.bottom - bounds.top, bgColor );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *widget -
+// x -
+// y -
+// w -
+// h -
+//-----------------------------------------------------------------------------
+void CDrawHelper::Init( mxWindow *widget, int x, int y, int w, int h, COLORREF bgColor )
+{
+ m_x = x;
+ m_y = y;
+
+ m_w = w ? w : widget->w2();
+ m_h = h ? h : widget->h2();
+
+ m_hWnd = (HWND)widget->getHandle();
+ Assert( m_hWnd );
+ m_dcReal = GetDC( m_hWnd );
+ m_rcClient.left = m_x;
+ m_rcClient.top = m_y;
+ m_rcClient.right = m_x + m_w;
+ m_rcClient.bottom = m_y + m_h;
+
+ m_dcMemory = CreateCompatibleDC( m_dcReal );
+ m_bmMemory = CreateCompatibleBitmap( m_dcReal, m_w, m_h );
+ m_bmOld = (HBITMAP)SelectObject( m_dcMemory, m_bmMemory );
+
+ m_clrOld = SetBkColor( m_dcMemory, bgColor );
+
+ HBRUSH br = CreateSolidBrush( bgColor );
+
+ RECT rcFill = m_rcClient;
+ OffsetRect( &rcFill, -m_rcClient.left, -m_rcClient.top );
+ FillRect( m_dcMemory, &rcFill, br );
+
+ DeleteObject( br );
+
+ m_ClipRegion = (HRGN)0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Finish up
+//-----------------------------------------------------------------------------
+CDrawHelper::~CDrawHelper( void )
+{
+ SelectClipRgn( m_dcMemory, NULL );
+
+ while ( m_ClipRects.Size() > 0 )
+ {
+ StopClipping();
+ }
+
+ BitBlt( m_dcReal, m_x, m_y, m_w, m_h, m_dcMemory, 0, 0, SRCCOPY );
+
+ SetBkColor( m_dcMemory, m_clrOld );
+
+ SelectObject( m_dcMemory, m_bmOld );
+ DeleteObject( m_bmMemory );
+
+ DeleteObject( m_dcMemory );
+
+ ReleaseDC( m_hWnd, m_dcReal );
+
+ ValidateRect( m_hWnd, &m_rcClient );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CDrawHelper::GetWidth( void )
+{
+ return m_w;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CDrawHelper::GetHeight( void )
+{
+ return m_h;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : rc -
+//-----------------------------------------------------------------------------
+void CDrawHelper::GetClientRect( RECT& rc )
+{
+ rc.left = rc.top = 0;
+ rc.right = m_w;
+ rc.bottom = m_h;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : HDC
+//-----------------------------------------------------------------------------
+HDC CDrawHelper::GrabDC( void )
+{
+ return m_dcMemory;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *font -
+// pointsize -
+// weight -
+// maxwidth -
+// rcText -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CDrawHelper::CalcTextRect( const char *font, int pointsize, int weight, int maxwidth, RECT& rcText, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ HFONT fnt = CreateFont(
+ -pointsize,
+ 0,
+ 0,
+ 0,
+ weight,
+ FALSE,
+ FALSE,
+ FALSE,
+ ANSI_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ font );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, fnt );
+
+ DrawText( m_dcMemory, output, -1, &rcText, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_WORDBREAK | DT_CALCRECT );
+
+ SelectObject( m_dcMemory, oldFont );
+ DeleteObject( fnt );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *font -
+// pointsize -
+// weight -
+// *fmt -
+// ... -
+// Output : int
+//-----------------------------------------------------------------------------
+int CDrawHelper::CalcTextWidth( const char *font, int pointsize, int weight, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ HFONT fnt = CreateFont(
+ -pointsize,
+ 0,
+ 0,
+ 0,
+ weight,
+ FALSE,
+ FALSE,
+ FALSE,
+ ANSI_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ font );
+
+ HDC screen = GetDC( NULL );
+
+ HFONT oldFont = (HFONT)SelectObject( screen, fnt );
+
+ RECT rcText;
+ rcText.left = rcText.top = 0;
+ rcText.bottom = pointsize + 5;
+ rcText.right = rcText.left + 2048;
+
+ DrawText( screen, output, -1, &rcText, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT );
+
+ SelectObject( screen, oldFont );
+ DeleteObject( fnt );
+
+ ReleaseDC( NULL, screen );
+
+ return rcText.right;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *font -
+// pointsize -
+// weight -
+// *fmt -
+// ... -
+// Output : int
+//-----------------------------------------------------------------------------
+int CDrawHelper::CalcTextWidthW( const char *font, int pointsize, int weight, const wchar_t *fmt, ... )
+{
+ va_list args;
+ static wchar_t output[1024];
+
+ va_start( args, fmt );
+ vwprintf( fmt, args );
+ vswprintf( output, fmt, args );
+
+ HFONT fnt = CreateFont(
+ -pointsize,
+ 0,
+ 0,
+ 0,
+ weight,
+ FALSE,
+ FALSE,
+ FALSE,
+ ANSI_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ font );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, fnt );
+
+ RECT rcText;
+ rcText.left = rcText.top = 0;
+ rcText.bottom = pointsize + 5;
+ rcText.right = rcText.left + 2048;
+
+ DrawTextW( m_dcMemory, output, -1, &rcText, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT );
+
+ SelectObject( m_dcMemory, oldFont );
+ DeleteObject( fnt );
+
+ return rcText.right;
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : fnt -
+// *fmt -
+// ... -
+// Output : int
+//-----------------------------------------------------------------------------
+int CDrawHelper::CalcTextWidth( HFONT fnt, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ HDC screen = GetDC( NULL );
+
+ HFONT oldFont = (HFONT)SelectObject( screen, fnt );
+
+ RECT rcText;
+ rcText.left = rcText.top = 0;
+ rcText.bottom = 1000;
+ rcText.right = rcText.left + 2048;
+
+ DrawText( screen, output, -1, &rcText, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT );
+
+ SelectObject( screen, oldFont );
+
+ ReleaseDC( NULL, screen );
+
+ return rcText.right;
+}
+
+int CDrawHelper::CalcTextWidthW( HFONT fnt, const wchar_t *fmt, ... )
+{
+ va_list args;
+ static wchar_t output[1024];
+
+ va_start( args, fmt );
+ vwprintf( fmt, args );
+ vswprintf( output, fmt, args );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, fnt );
+
+ RECT rcText;
+ rcText.left = rcText.top = 0;
+ rcText.bottom = 1000;
+ rcText.right = rcText.left + 2048;
+
+ DrawTextW( m_dcMemory, output, -1, &rcText, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT );
+
+ SelectObject( m_dcMemory, oldFont );
+
+ return rcText.right;
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *font -
+// pointsize -
+// weight -
+// clr -
+// rcText -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredText( const char *font, int pointsize, int weight, COLORREF clr, RECT& rcText, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vsprintf( output, fmt, args );
+ va_end( args );
+
+ DrawColoredTextCharset( font, pointsize, weight, ANSI_CHARSET, clr, rcText, output );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *font -
+// pointsize -
+// weight -
+// clr -
+// rcText -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredTextW( const char *font, int pointsize, int weight, COLORREF clr, RECT& rcText, const wchar_t *fmt, ... )
+{
+ va_list args;
+ static wchar_t output[1024];
+
+ va_start( args, fmt );
+ vswprintf( output, fmt, args );
+ va_end( args );
+
+ DrawColoredTextCharsetW( font, pointsize, weight, ANSI_CHARSET, clr, rcText, output );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : font -
+// clr -
+// rcText -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredText( HFONT font, COLORREF clr, RECT& rcText, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vsprintf( output, fmt, args );
+ va_end( args );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, font );
+ COLORREF oldColor = SetTextColor( m_dcMemory, clr );
+ int oldMode = SetBkMode( m_dcMemory, TRANSPARENT );
+
+ RECT rcTextOffset = rcText;
+ OffsetSubRect( rcTextOffset );
+
+ DrawText( m_dcMemory, output, -1, &rcTextOffset, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS );
+
+ SetBkMode( m_dcMemory, oldMode );
+
+ SetTextColor( m_dcMemory, oldColor );
+
+ SelectObject( m_dcMemory, oldFont );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : font -
+// clr -
+// rcText -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredTextW( HFONT font, COLORREF clr, RECT& rcText, const wchar_t *fmt, ... )
+{
+ va_list args;
+ static wchar_t output[1024];
+
+ va_start( args, fmt );
+ vswprintf( output, fmt, args );
+ va_end( args );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, font );
+ COLORREF oldColor = SetTextColor( m_dcMemory, clr );
+ int oldMode = SetBkMode( m_dcMemory, TRANSPARENT );
+
+ RECT rcTextOffset = rcText;
+ OffsetSubRect( rcTextOffset );
+
+ DrawTextW( m_dcMemory, output, -1, &rcTextOffset, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS );
+
+ SetBkMode( m_dcMemory, oldMode );
+
+ SetTextColor( m_dcMemory, oldColor );
+
+ SelectObject( m_dcMemory, oldFont );
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *font -
+// pointsize -
+// weight -
+// clr -
+// rcText -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredTextCharset( const char *font, int pointsize, int weight, DWORD charset, COLORREF clr, RECT& rcText, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vsprintf( output, fmt, args );
+ va_end( args );
+
+
+ HFONT fnt = CreateFont(
+ -pointsize,
+ 0,
+ 0,
+ 0,
+ weight,
+ FALSE,
+ FALSE,
+ FALSE,
+ charset,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ font );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, fnt );
+ COLORREF oldColor = SetTextColor( m_dcMemory, clr );
+ int oldMode = SetBkMode( m_dcMemory, TRANSPARENT );
+
+ RECT rcTextOffset = rcText;
+ OffsetSubRect( rcTextOffset );
+
+ DrawText( m_dcMemory, output, -1, &rcTextOffset, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS );
+
+ SetBkMode( m_dcMemory, oldMode );
+
+ SetTextColor( m_dcMemory, oldColor );
+
+ SelectObject( m_dcMemory, oldFont );
+ DeleteObject( fnt );
+}
+
+void CDrawHelper::DrawColoredTextCharsetW( const char *font, int pointsize, int weight, DWORD charset, COLORREF clr, RECT& rcText, const wchar_t *fmt, ... )
+{
+ va_list args;
+ static wchar_t output[1024];
+
+ va_start( args, fmt );
+ vswprintf( output, fmt, args );
+ va_end( args );
+
+
+ HFONT fnt = CreateFont(
+ -pointsize,
+ 0,
+ 0,
+ 0,
+ weight,
+ FALSE,
+ FALSE,
+ FALSE,
+ charset,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ font );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, fnt );
+ COLORREF oldColor = SetTextColor( m_dcMemory, clr );
+ int oldMode = SetBkMode( m_dcMemory, TRANSPARENT );
+
+ RECT rcTextOffset = rcText;
+ OffsetSubRect( rcTextOffset );
+
+ DrawTextW( m_dcMemory, output, -1, &rcTextOffset, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_SINGLELINE | DT_WORD_ELLIPSIS );
+
+ SetBkMode( m_dcMemory, oldMode );
+
+ SetTextColor( m_dcMemory, oldColor );
+
+ SelectObject( m_dcMemory, oldFont );
+ DeleteObject( fnt );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *font -
+// pointsize -
+// weight -
+// clr -
+// rcText -
+// *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredTextMultiline( const char *font, int pointsize, int weight, COLORREF clr, RECT& rcText, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ HFONT fnt = CreateFont(
+ -pointsize,
+ 0,
+ 0,
+ 0,
+ weight,
+ FALSE,
+ FALSE,
+ FALSE,
+ ANSI_CHARSET,
+ OUT_TT_PRECIS,
+ CLIP_DEFAULT_PRECIS,
+ ANTIALIASED_QUALITY,
+ DEFAULT_PITCH,
+ font );
+
+ HFONT oldFont = (HFONT)SelectObject( m_dcMemory, fnt );
+ COLORREF oldColor = SetTextColor( m_dcMemory, clr );
+ int oldMode = SetBkMode( m_dcMemory, TRANSPARENT );
+
+ RECT rcTextOffset = rcText;
+ OffsetSubRect( rcTextOffset );
+
+ DrawText( m_dcMemory, output, -1, &rcTextOffset, DT_LEFT | DT_NOPREFIX | DT_VCENTER | DT_WORDBREAK | DT_WORD_ELLIPSIS );
+
+ SetBkMode( m_dcMemory, oldMode );
+
+ SetTextColor( m_dcMemory, oldColor );
+
+ SelectObject( m_dcMemory, oldFont );
+ DeleteObject( fnt );
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : r -
+// g -
+// b -
+// style -
+// width -
+// x1 -
+// y1 -
+// x2 -
+// y2 -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredLine( COLORREF clr, int style, int width, int x1, int y1, int x2, int y2 )
+{
+ HPEN pen = CreatePen( style, width, clr );
+ HPEN oldPen = (HPEN)SelectObject( m_dcMemory, pen );
+ MoveToEx( m_dcMemory, x1-m_x, y1-m_y, NULL );
+ LineTo( m_dcMemory, x2-m_x, y2-m_y );
+ SelectObject( m_dcMemory, oldPen );
+ DeleteObject( pen );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : clr -
+// style -
+// width -
+// count -
+// *pts -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawColoredPolyLine( COLORREF clr, int style, int width, CUtlVector< POINT >& points )
+{
+ int c = points.Count();
+ if ( c < 2 )
+ return;
+
+ HPEN pen = CreatePen( style, width, clr );
+ HPEN oldPen = (HPEN)SelectObject( m_dcMemory, pen );
+
+ POINT *temp = (POINT *)_alloca( c * sizeof( POINT ) );
+ Assert( temp );
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ POINT *pt = &points[ i ];
+
+ temp[ i ].x = pt->x - m_x;
+ temp[ i ].y = pt->y - m_y;
+ }
+
+ Polyline( m_dcMemory, temp, c );
+
+ SelectObject( m_dcMemory, oldPen );
+ DeleteObject( pen );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : r -
+// g -
+// b -
+// style -
+// width -
+// x1 -
+// y1 -
+// x2 -
+// y2 -
+//-----------------------------------------------------------------------------
+POINTL CDrawHelper::DrawColoredRamp( COLORREF clr, int style, int width, int x1, int y1, int x2, int y2, float rate, float sustain )
+{
+ HPEN pen = CreatePen( style, width, clr );
+ HPEN oldPen = (HPEN)SelectObject( m_dcMemory, pen );
+ MoveToEx( m_dcMemory, x1-m_x, y1-m_y, NULL );
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+
+ POINTL p;
+ p.x = 0L;
+ p.y = 0L;
+ for (float i = 0.1f; i <= 1.09f; i += 0.1f)
+ {
+ float j = 3.0f * i * i - 2.0f * i * i * i;
+ p.x = x1+(int)(dx*i*(1.0f-rate))-m_x;
+ p.y = y1+(int)(dy*sustain*j)-m_y;
+ LineTo( m_dcMemory, p.x, p.y );
+ }
+ SelectObject( m_dcMemory, oldPen );
+ DeleteObject( pen );
+
+ return p;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw a filled rect
+// Input : clr -
+// x1 -
+// y1 -
+// x2 -
+// y2 -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawFilledRect( COLORREF clr, RECT& rc )
+{
+ RECT rcCopy = rc;
+
+ HBRUSH br = CreateSolidBrush( clr );
+ OffsetSubRect( rcCopy );
+ FillRect( m_dcMemory, &rcCopy, br );
+ DeleteObject( br );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw a filled rect
+// Input : clr -
+// x1 -
+// y1 -
+// x2 -
+// y2 -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawFilledRect( COLORREF clr, int x1, int y1, int x2, int y2 )
+{
+ HBRUSH br = CreateSolidBrush( clr );
+ RECT rc;
+ rc.left = x1;
+ rc.right = x2;
+ rc.top = y1;
+ rc.bottom = y2;
+ OffsetSubRect( rc );
+ FillRect( m_dcMemory, &rc, br );
+ DeleteObject( br );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : clr -
+// style -
+// width -
+// rc -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawOutlinedRect( COLORREF clr, int style, int width, RECT& rc )
+{
+ DrawOutlinedRect( clr, style, width, rc.left, rc.top, rc.right, rc.bottom );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Draw an outlined rect
+// Input : clr -
+// style -
+// width -
+// x1 -
+// y1 -
+// x2 -
+// y2 -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawOutlinedRect( COLORREF clr, int style, int width, int x1, int y1, int x2, int y2 )
+{
+ HPEN oldpen, pen;
+ HBRUSH oldbrush, brush;
+
+ pen = CreatePen( PS_SOLID, width, clr );
+ oldpen = (HPEN)SelectObject( m_dcMemory, pen );
+
+ brush = (HBRUSH)GetStockObject( NULL_BRUSH );
+ oldbrush = (HBRUSH)SelectObject( m_dcMemory, brush );
+
+ RECT rc;
+ rc.left = x1;
+ rc.right = x2;
+ rc.top = y1;
+ rc.bottom = y2;
+ OffsetSubRect( rc);
+
+ Rectangle( m_dcMemory, rc.left, rc.top, rc.right, rc.bottom );
+
+ SelectObject( m_dcMemory, oldbrush );
+ DeleteObject( brush );
+ SelectObject( m_dcMemory, oldpen );
+ DeleteObject( pen );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : x1 -
+// y1 -
+// x2 -
+// y2 -
+// clr -
+// thickness -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawLine( int x1, int y1, int x2, int y2, COLORREF clr, int thickness )
+{
+ HPEN oldpen, pen;
+ HBRUSH oldbrush, brush;
+
+ pen = CreatePen( PS_SOLID, thickness, clr );
+ oldpen = (HPEN)SelectObject( m_dcMemory, pen );
+
+ brush = (HBRUSH)GetStockObject( NULL_BRUSH );
+ oldbrush = (HBRUSH)SelectObject( m_dcMemory, brush );
+
+ // Offset
+ x1 -= m_x;
+ x2 -= m_x;
+ y1 -= m_y;
+ y2 -= m_y;
+
+ MoveToEx( m_dcMemory, x1, y1, NULL );
+ LineTo( m_dcMemory, x2, y2 );
+
+ SelectObject( m_dcMemory, oldbrush );
+ DeleteObject( brush );
+ SelectObject( m_dcMemory, oldpen );
+ DeleteObject( pen );
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : rc -
+// fillr -
+// fillg -
+// fillb -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawTriangleMarker( RECT& rc, COLORREF fill, bool inverted /*= false*/ )
+{
+ POINT region[3];
+ int cPoints = 3;
+
+ if ( !inverted )
+ {
+ region[ 0 ].x = rc.left - m_x;
+ region[ 0 ].y = rc.top - m_y;
+
+ region[ 1 ].x = rc.right - m_x;
+ region[ 1 ].y = rc.top - m_y;
+
+ region[ 2 ].x = ( ( rc.left + rc.right ) / 2 ) - m_x;
+ region[ 2 ].y = rc.bottom - m_y;
+ }
+ else
+ {
+ region[ 0 ].x = rc.left - m_x;
+ region[ 0 ].y = rc.bottom - m_y;
+
+ region[ 1 ].x = rc.right - m_x;
+ region[ 1 ].y = rc.bottom - m_y;
+
+ region[ 2 ].x = ( ( rc.left + rc.right ) / 2 ) - m_x;
+ region[ 2 ].y = rc.top - m_y;
+ }
+
+ HRGN rgn = CreatePolygonRgn( region, cPoints, ALTERNATE );
+
+ int oldPF = SetPolyFillMode( m_dcMemory, ALTERNATE );
+
+ HBRUSH brFace = CreateSolidBrush( fill );
+
+ FillRgn( m_dcMemory, rgn, brFace );
+
+ DeleteObject( brFace );
+
+ SetPolyFillMode( m_dcMemory, oldPF );
+
+ DeleteObject( rgn );
+}
+
+void CDrawHelper::StartClipping( RECT& clipRect )
+{
+ RECT fixed = clipRect;
+ OffsetSubRect( fixed );
+
+ m_ClipRects.AddToTail( fixed );
+
+ ClipToRects();
+}
+
+void CDrawHelper::StopClipping( void )
+{
+ Assert( m_ClipRects.Size() > 0 );
+ if ( m_ClipRects.Size() <= 0 )
+ return;
+
+ m_ClipRects.Remove( m_ClipRects.Size() - 1 );
+
+ ClipToRects();
+}
+
+void CDrawHelper::ClipToRects( void )
+{
+ SelectClipRgn( m_dcMemory, NULL );
+ if ( m_ClipRegion )
+ {
+ DeleteObject( m_ClipRegion );
+ m_ClipRegion = HRGN( 0 );
+ }
+
+ if ( m_ClipRects.Size() > 0 )
+ {
+ RECT rc = m_ClipRects[ 0 ];
+ m_ClipRegion = CreateRectRgn( rc.left, rc.top, rc.right, rc.bottom );
+ for ( int i = 1; i < m_ClipRects.Size(); i++ )
+ {
+ RECT add = m_ClipRects[ i ];
+
+ HRGN addIn = CreateRectRgn( add.left, add.top, add.right, add.bottom );
+ HRGN result = CreateRectRgn( 0, 0, 100, 100 );
+
+ CombineRgn( result, m_ClipRegion, addIn, RGN_AND );
+
+ DeleteObject( m_ClipRegion );
+ DeleteObject( addIn );
+
+ m_ClipRegion = result;
+ }
+ }
+
+ SelectClipRgn( m_dcMemory, m_ClipRegion );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : rc -
+//-----------------------------------------------------------------------------
+void CDrawHelper::OffsetSubRect( RECT& rc )
+{
+ OffsetRect( &rc, -m_x, -m_y );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : br -
+// rc -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawFilledRect( HBRUSH br, RECT& rc )
+{
+ RECT rcFill = rc;
+ OffsetSubRect( rcFill );
+ FillRect( m_dcMemory, &rcFill, br );
+}
+
+void CDrawHelper::DrawCircle( COLORREF clr, int x, int y, int radius, bool filled /*= true*/ )
+{
+ RECT rc;
+ rc.left = x - radius / 2;
+ rc.right = rc.left + radius;
+ rc.top = y - radius / 2;
+ rc.bottom = y + radius;
+
+ OffsetSubRect( rc );
+
+ HPEN pen = CreatePen( PS_SOLID, 1, clr );
+ HBRUSH br = CreateSolidBrush( clr );
+
+ HPEN oldPen = (HPEN)SelectObject( m_dcMemory, pen );
+ HBRUSH oldBr = (HBRUSH)SelectObject( m_dcMemory, br );
+
+ if ( filled )
+ {
+ Ellipse( m_dcMemory, rc.left, rc.top, rc.right, rc.bottom );
+ }
+ else
+ {
+ Arc( m_dcMemory, rc.left, rc.top, rc.right, rc.bottom,
+ rc.left, rc.top, rc.left, rc.top );
+ }
+
+ SelectObject( m_dcMemory, oldPen );
+ SelectObject( m_dcMemory, oldBr );
+
+ DeleteObject( pen );
+ DeleteObject( br );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : rc -
+// clr1 -
+// clr2 -
+// vertical -
+//-----------------------------------------------------------------------------
+void CDrawHelper::DrawGradientFilledRect( RECT& rc, COLORREF clr1, COLORREF clr2, bool vertical )
+{
+ RECT rcDraw = rc;
+ OffsetRect( &rcDraw, -m_x, -m_y );
+
+ TRIVERTEX vert[2] ;
+ GRADIENT_RECT gradient_rect;
+ vert[0].x = rcDraw.left;
+ vert[0].y = rcDraw.top;
+ vert[0].Red = GetRValue( clr1 ) << 8;
+ vert[0].Green = GetGValue( clr1 ) << 8;
+ vert[0].Blue = GetBValue( clr1 ) << 8;
+ vert[0].Alpha = 0x0000;
+
+ vert[1].x = rcDraw.right;
+ vert[1].y = rcDraw.bottom;
+ vert[1].Red = GetRValue( clr2 ) << 8;
+ vert[1].Green = GetGValue( clr2 ) << 8;
+ vert[1].Blue = GetBValue( clr2 ) << 8;
+ vert[1].Alpha = 0x0000;
+
+ gradient_rect.UpperLeft = 0;
+ gradient_rect.LowerRight = 1;
+
+ GradientFill(
+ m_dcMemory,
+ vert, 2,
+ &gradient_rect, 1,
+ vertical ? GRADIENT_FILL_RECT_V : GRADIENT_FILL_RECT_H );
+}
diff --git a/utils/scenemanager/drawhelper.h b/utils/scenemanager/drawhelper.h
new file mode 100644
index 0000000..551c1e9
--- /dev/null
+++ b/utils/scenemanager/drawhelper.h
@@ -0,0 +1,107 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include <mxtk/mx.h>
+#include "utlvector.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper class that automagically sets up and destroys a memory device-
+// context for flicker-free refershes
+//-----------------------------------------------------------------------------
+class CDrawHelper
+{
+public:
+ // Construction/destruction
+ CDrawHelper( mxWindow *widget);
+ CDrawHelper( mxWindow *widget, COLORREF bgColor );
+ CDrawHelper( mxWindow *widget, int x, int y, int w, int h, COLORREF bgColor );
+ CDrawHelper( mxWindow *widget, RECT& bounds );
+ CDrawHelper( mxWindow *widget, RECT& bounds, COLORREF bgColor );
+ virtual ~CDrawHelper( void );
+
+ // Allow caller to draw onto the memory dc, too
+ HDC GrabDC( void );
+
+ // Compute text size
+ static int CalcTextWidth( const char *font, int pointsize, int weight, PRINTF_FORMAT_STRING const char *fmt, ... );
+ static int CalcTextWidth( HFONT font, PRINTF_FORMAT_STRING const char *fmt, ... );
+
+ int CalcTextWidthW( const char *font, int pointsize, int weight, PRINTF_FORMAT_STRING const wchar_t *fmt, ... );
+ int CalcTextWidthW( HFONT font, PRINTF_FORMAT_STRING const wchar_t *fmt, ... );
+ void DrawColoredTextW( const char *font, int pointsize, int weight, COLORREF clr, RECT& rcText, PRINTF_FORMAT_STRING const wchar_t *fmt, ... );
+ void DrawColoredTextW( HFONT font, COLORREF clr, RECT& rcText, PRINTF_FORMAT_STRING const wchar_t *fmt, ... );
+ void DrawColoredTextCharsetW( const char *font, int pointsize, int weight, DWORD charset, COLORREF clr, RECT& rcText, PRINTF_FORMAT_STRING const wchar_t *fmt, ... );
+
+ void CalcTextRect( const char *font, int pointsize, int weight, int maxwidth, RECT& rcText, PRINTF_FORMAT_STRING const char *fmt, ... );
+
+ // Draw text
+ void DrawColoredText( const char *font, int pointsize, int weight, COLORREF clr, RECT& rcText, PRINTF_FORMAT_STRING const char *fmt, ... );
+ void DrawColoredText( HFONT font, COLORREF clr, RECT& rcText, PRINTF_FORMAT_STRING const char *fmt, ... );
+ void DrawColoredTextCharset( const char *font, int pointsize, int weight, DWORD charset, COLORREF clr, RECT& rcText, PRINTF_FORMAT_STRING const char *fmt, ... );
+ void DrawColoredTextMultiline( const char *font, int pointsize, int weight, COLORREF clr, RECT& rcText, PRINTF_FORMAT_STRING const char *fmt, ... );
+ // Draw a line
+ void DrawColoredLine( COLORREF clr, int style, int width, int x1, int y1, int x2, int y2 );
+ void DrawColoredPolyLine( COLORREF clr, int style, int width, CUtlVector< POINT >& points );
+
+ // Draw a blending ramp
+ POINTL DrawColoredRamp( COLORREF clr, int style, int width, int x1, int y1, int x2, int y2, float rate, float sustain );
+ // Draw a filled rect
+ void DrawFilledRect( COLORREF clr, int x1, int y1, int x2, int y2 );
+ // Draw an outlined rect
+ void DrawOutlinedRect( COLORREF clr, int style, int width, int x1, int y1, int x2, int y2 );
+ void DrawOutlinedRect( COLORREF clr, int style, int width, RECT& rc );
+
+ void DrawFilledRect( HBRUSH br, RECT& rc );
+ void DrawFilledRect( COLORREF clr, RECT& rc );
+
+ void DrawGradientFilledRect( RECT& rc, COLORREF clr1, COLORREF clr2, bool vertical );
+
+ void DrawLine( int x1, int y1, int x2, int y2, COLORREF clr, int thickness );
+
+ // Draw a triangle
+ void DrawTriangleMarker( RECT& rc, COLORREF fill, bool inverted = false );
+
+ void DrawCircle( COLORREF clr, int x, int y, int radius, bool filled = true );
+
+ // Get width/height of draw area
+ int GetWidth( void );
+ int GetHeight( void );
+
+ // Get client rect for drawing
+ void GetClientRect( RECT& rc );
+
+ void StartClipping( RECT& clipRect );
+ void StopClipping( void );
+
+ // Remap rect if we're using a clipped viewport
+ void OffsetSubRect( RECT& rc );
+
+private:
+ // Internal initializer
+ void Init( mxWindow *widget, int x, int y, int w, int h, COLORREF bgColor);
+
+ void ClipToRects( void );
+
+ // The window we are drawing on
+ HWND m_hWnd;
+ // The final DC
+ HDC m_dcReal;
+ // The working DC
+ HDC m_dcMemory;
+ // Client area and offsets
+ RECT m_rcClient;
+ int m_x, m_y;
+ int m_w, m_h;
+ // Bitmap for drawing in the memory DC
+ HBITMAP m_bmMemory;
+ HBITMAP m_bmOld;
+ // Remember the original default color
+ COLORREF m_clrOld;
+
+ CUtlVector < RECT > m_ClipRects;
+ HRGN m_ClipRegion;
+};
diff --git a/utils/scenemanager/fileloaderthread.cpp b/utils/scenemanager/fileloaderthread.cpp
new file mode 100644
index 0000000..28de511
--- /dev/null
+++ b/utils/scenemanager/fileloaderthread.cpp
@@ -0,0 +1,369 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "sentence.h"
+#include "wavefile.h"
+#include "tier2/riff.h"
+#include "filesystem.h"
+#include <io.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include "IFileLoader.h"
+
+bool SceneManager_LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io );
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements the RIFF i/o interface on stdio
+//-----------------------------------------------------------------------------
+class ThreadIOReadBinary : public IFileReadBinary
+{
+public:
+ int open( const char *pFileName )
+ {
+ char filename[ 512 ];
+ Q_snprintf( filename, sizeof( filename ), "%s%s", SceneManager_GetGameDirectory(), pFileName );
+ return (int)_open( filename, _O_BINARY | _O_RDONLY );
+ }
+
+ int read( void *pOutput, int size, int file )
+ {
+ if ( file == -1 )
+ return 0;
+
+ return _read( file, pOutput, size );
+ }
+
+ void seek( int file, int pos )
+ {
+ if ( file == -1 )
+ return;
+
+ _lseek( file, pos, SEEK_SET );
+ }
+
+ unsigned int tell( int file )
+ {
+ if ( file == -1 )
+ return 0;
+
+ return _tell( file );
+ }
+
+ unsigned int size( int file )
+ {
+ if ( file == -1 )
+ return 0;
+
+ long curpos = tell( file );
+ _lseek( file, 0, SEEK_END );
+ int s = tell( file );
+ _lseek( file, curpos, SEEK_SET );
+
+ return s;
+ }
+
+ void close( int file )
+ {
+ if ( file == -1 )
+ return;
+
+ _close( file );
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: All wavefile I/O occurs on a thread
+//-----------------------------------------------------------------------------
+class CFileLoaderThread : public IFileLoader
+{
+public:
+ struct SentenceRequest
+ {
+ SentenceRequest()
+ {
+ filename[ 0 ] = 0;
+ sentence.Reset();
+ wavefile = NULL;
+ valid = false;
+ }
+
+ bool valid;
+ char filename[ 256 ];
+ CSentence sentence;
+
+ CWaveFile *wavefile;
+ };
+
+ // Construction
+ CFileLoaderThread( void );
+ virtual ~CFileLoaderThread( void );
+
+ // Sockets add/remove themselves via their constructor
+ virtual void AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles );
+
+ // Lock changes to wavefile list, etc.
+ virtual void Lock( void );
+ // Unlock wavefile list, etc.
+ virtual void Unlock( void );
+
+ // Retrieve handle to shutdown event
+ virtual HANDLE GetShutdownHandle( void );
+
+ // Caller should call lock before accessing any of these methods and unlock afterwards!!!
+ virtual int ProcessCompleted();
+
+ int DoThreadWork();
+
+ virtual void Start();
+
+private:
+ // Critical section used for synchronizing access to wavefile list
+ CRITICAL_SECTION cs;
+ // List of wavefiles we are listening on
+ CUtlVector< SentenceRequest * > m_FileList;
+
+ CUtlVector< SentenceRequest * > m_Pending;
+ CUtlVector< SentenceRequest * > m_Completed;
+ // Thread handle
+ HANDLE m_hThread;
+ // Thread id
+ DWORD m_nThreadId;
+ // Event to set when we want to tell the thread to shut itself down
+ HANDLE m_hShutdown;
+
+ ThreadIOReadBinary m_ThreadIO;
+ bool m_bLocked;
+
+ int m_nTotalAdds;
+ int m_nTotalPending;
+ int m_nTotalProcessed;
+ int m_nTotalCompleted;
+};
+
+// Singleton handler
+static CFileLoaderThread g_WaveLoader;
+extern IFileLoader *fileloader = &g_WaveLoader;
+
+int CFileLoaderThread::DoThreadWork()
+{
+ int i;
+ // Check for shutdown event
+ if ( WAIT_OBJECT_0 == WaitForSingleObject( GetShutdownHandle(), 0 ) )
+ {
+ return 0;
+ }
+
+ // No changes to list right now
+ Lock();
+ // Move new items to work list
+ int newItems = m_FileList.Count();
+ for ( i = 0; i < newItems; i++ )
+ {
+ // Move to pending and issue async i/o calls
+ m_Pending.AddToTail( m_FileList[ i ] );
+
+ m_nTotalPending++;
+ }
+ m_FileList.RemoveAll();
+ // Done adding new work items
+ Unlock();
+
+ int remaining = m_Pending.Count();
+ if ( !remaining )
+ return 1;
+
+ int workitems = remaining; // min( remaining, 1000 );
+
+ CUtlVector< SentenceRequest * > transfer;
+
+ for ( i = 0; i < workitems; i++ )
+ {
+ SentenceRequest *r = m_Pending[ 0 ];
+ m_Pending.Remove( 0 );
+
+ transfer.AddToTail( r );
+ // Do the work
+
+ m_nTotalProcessed++;
+
+ r->valid = SceneManager_LoadSentenceFromWavFileUsingIO( r->filename, r->sentence, m_ThreadIO );
+ }
+
+ // Now move to completed list
+ Lock();
+ for ( i = 0; i < workitems; i++ )
+ {
+ SentenceRequest *r = transfer[ i ];
+ if ( r->valid )
+ {
+ m_nTotalCompleted++;
+
+ m_Completed.AddToTail( r );
+ }
+ else
+ {
+ delete r;
+ }
+ }
+ Unlock();
+ return 1;
+}
+
+int CFileLoaderThread::ProcessCompleted()
+{
+ Lock();
+ int c = m_Completed.Count();
+ for ( int i = c - 1; i >= 0 ; i-- )
+ {
+ SentenceRequest *r = m_Completed[ i ];
+
+ r->wavefile->SetThreadLoadedSentence( r->sentence );
+
+ delete r;
+ }
+ m_Completed.RemoveAll();
+ Unlock();
+ return c;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Main winsock processing thread
+// Input : threadobject -
+// Output : static DWORD WINAPI
+//-----------------------------------------------------------------------------
+static DWORD WINAPI FileLoaderThreadFunc( LPVOID threadobject )
+{
+ // Get pointer to CFileLoaderThread object
+ CFileLoaderThread *wavefilethread = ( CFileLoaderThread * )threadobject;
+ Assert( wavefilethread );
+ if ( !wavefilethread )
+ {
+ return 0;
+ }
+
+ // Keep looking for data until shutdown event is triggered
+ while ( 1 )
+ {
+ if( !wavefilethread->DoThreadWork() )
+ break;
+
+ // Yield a small bit of time to main app
+ Sleep( 100 );
+ }
+
+ ExitThread( 0 );
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Construction
+//-----------------------------------------------------------------------------
+CFileLoaderThread::CFileLoaderThread( void )
+{
+ m_nTotalAdds = 0;
+ m_nTotalProcessed = 0;
+ m_nTotalCompleted = 0;
+ m_nTotalPending = 0;
+
+ m_bLocked = false;
+
+ InitializeCriticalSection( &cs );
+
+ m_hShutdown = CreateEvent( NULL, TRUE, FALSE, NULL );
+ Assert( m_hShutdown );
+
+ m_hThread = NULL;
+ Start();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CFileLoaderThread::Start()
+{
+ m_hThread = CreateThread( NULL, 0, FileLoaderThreadFunc, (void *)this, 0, &m_nThreadId );
+ Assert( m_hThread );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CFileLoaderThread::~CFileLoaderThread( void )
+{
+ Lock();
+ {
+ SetEvent( m_hShutdown );
+ Sleep( 2 );
+ TerminateThread( m_hThread, 0 );
+ }
+ Unlock();
+
+ // Kill the wavefile
+//!! need to validate this line
+// Assert( !m_FileList );
+
+ CloseHandle( m_hThread );
+
+ CloseHandle( m_hShutdown );
+
+ DeleteCriticalSection( &cs );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Returns handle of shutdown event
+// Output : HANDLE
+//-----------------------------------------------------------------------------
+HANDLE CFileLoaderThread::GetShutdownHandle( void )
+{
+ return m_hShutdown;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Locks object and adds wavefile to thread
+// Input : *wavefile -
+//-----------------------------------------------------------------------------
+void CFileLoaderThread::AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles )
+{
+ Lock();
+
+ int c = wavefiles.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ SentenceRequest *request = new SentenceRequest;
+ request->wavefile = wavefiles[ i ];
+ Q_strncpy( request->filename, request->wavefile->GetFileName(), sizeof( request->filename ) );
+
+
+ m_FileList.AddToTail( request );
+
+ m_nTotalAdds++;
+ }
+
+ Unlock();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CFileLoaderThread::Lock( void )
+{
+ EnterCriticalSection( &cs );
+ Assert( !m_bLocked );
+ m_bLocked = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CFileLoaderThread::Unlock( void )
+{
+ Assert( m_bLocked );
+ m_bLocked = false;
+ LeaveCriticalSection( &cs );
+} \ No newline at end of file
diff --git a/utils/scenemanager/ico00001.ico b/utils/scenemanager/ico00001.ico
new file mode 100644
index 0000000..c7d9da9
--- /dev/null
+++ b/utils/scenemanager/ico00001.ico
Binary files differ
diff --git a/utils/scenemanager/ico00002.ico b/utils/scenemanager/ico00002.ico
new file mode 100644
index 0000000..ad48cbf
--- /dev/null
+++ b/utils/scenemanager/ico00002.ico
Binary files differ
diff --git a/utils/scenemanager/ico00003.ico b/utils/scenemanager/ico00003.ico
new file mode 100644
index 0000000..b61e1b1
--- /dev/null
+++ b/utils/scenemanager/ico00003.ico
Binary files differ
diff --git a/utils/scenemanager/ico00004.ico b/utils/scenemanager/ico00004.ico
new file mode 100644
index 0000000..ff2e77c
--- /dev/null
+++ b/utils/scenemanager/ico00004.ico
Binary files differ
diff --git a/utils/scenemanager/ico00005.ico b/utils/scenemanager/ico00005.ico
new file mode 100644
index 0000000..1fa01d2
--- /dev/null
+++ b/utils/scenemanager/ico00005.ico
Binary files differ
diff --git a/utils/scenemanager/ico00006.ico b/utils/scenemanager/ico00006.ico
new file mode 100644
index 0000000..b27f13f
--- /dev/null
+++ b/utils/scenemanager/ico00006.ico
Binary files differ
diff --git a/utils/scenemanager/ico00007.ico b/utils/scenemanager/ico00007.ico
new file mode 100644
index 0000000..35868d9
--- /dev/null
+++ b/utils/scenemanager/ico00007.ico
Binary files differ
diff --git a/utils/scenemanager/icon1.ico b/utils/scenemanager/icon1.ico
new file mode 100644
index 0000000..8251647
--- /dev/null
+++ b/utils/scenemanager/icon1.ico
Binary files differ
diff --git a/utils/scenemanager/ifileloader.h b/utils/scenemanager/ifileloader.h
new file mode 100644
index 0000000..2865591
--- /dev/null
+++ b/utils/scenemanager/ifileloader.h
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef IFILELOADER_H
+#define IFILELOADER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "utlvector.h"
+
+class CWaveFile;
+
+class IFileLoader
+{
+public:
+ virtual void AddWaveFilesToThread( CUtlVector< CWaveFile * >& wavefiles ) = 0;
+
+ virtual int ProcessCompleted() = 0;
+
+ virtual void Start() = 0;
+};
+
+extern IFileLoader *fileloader;
+
+#endif // IFILELOADER_H
diff --git a/utils/scenemanager/inputproperties.cpp b/utils/scenemanager/inputproperties.cpp
new file mode 100644
index 0000000..a623e7e
--- /dev/null
+++ b/utils/scenemanager/inputproperties.cpp
@@ -0,0 +1,79 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "resource.h"
+#include "InputProperties.h"
+#include "workspacemanager.h"
+
+static CInputParams g_Params;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+// uMsg -
+// wParam -
+// lParam -
+// Output : static BOOL CALLBACK
+//-----------------------------------------------------------------------------
+static BOOL CALLBACK InputPropertiesDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ // Insert code here to put the string (to find and replace with)
+ // into the edit controls.
+ // ...
+ {
+ g_Params.PositionSelf( hwndDlg );
+
+ SetDlgItemText( hwndDlg, IDC_INPUTSTRING, g_Params.m_szInputText );
+ SetDlgItemText( hwndDlg, IDC_STATIC_PROMPT, g_Params.m_szPrompt );
+
+ SetWindowText( hwndDlg, g_Params.m_szDialogTitle );
+
+ SetFocus( GetDlgItem( hwndDlg, IDC_INPUTSTRING ) );
+ SendMessage( GetDlgItem( hwndDlg, IDC_INPUTSTRING ), EM_SETSEL, 0, MAKELONG(0, 0xffff) );
+
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ g_Params.m_szInputText[ 0 ] = 0;
+ GetDlgItemText( hwndDlg, IDC_INPUTSTRING, g_Params.m_szInputText, sizeof( g_Params.m_szInputText ) );
+ EndDialog( hwndDlg, 1 );
+ break;
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *view -
+// *actor -
+// Output : int
+//-----------------------------------------------------------------------------
+int InputProperties( CInputParams *params )
+{
+ g_Params = *params;
+
+ int retval = DialogBox( (HINSTANCE)GetModuleHandle( 0 ),
+ MAKEINTRESOURCE( IDD_INPUTDIALOG ),
+ (HWND)GetWorkspaceManager()->getHandle(),
+ (DLGPROC)InputPropertiesDialogProc );
+
+ *params = g_Params;
+
+ return retval;
+} \ No newline at end of file
diff --git a/utils/scenemanager/inputproperties.h b/utils/scenemanager/inputproperties.h
new file mode 100644
index 0000000..250ccfa
--- /dev/null
+++ b/utils/scenemanager/inputproperties.h
@@ -0,0 +1,29 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef INPUTPROPERTIES_H
+#define INPUTPROPERTIES_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialogparams.h"
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+struct CInputParams : public CBaseDialogParams
+{
+ char m_szPrompt[ 256 ];
+
+ // i/o input text
+ char m_szInputText[ 1024 ];
+};
+
+// Display/create dialog
+int InputProperties( CInputParams *params );
+
+#endif // INPUTPROPERTIES_H
diff --git a/utils/scenemanager/iscenemanagersound.h b/utils/scenemanager/iscenemanagersound.h
new file mode 100644
index 0000000..28d620a
--- /dev/null
+++ b/utils/scenemanager/iscenemanagersound.h
@@ -0,0 +1,45 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef ISCENEMANAGERSOUND_H
+#define ISCENEMANAGERSOUND_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CAudioSource;
+class CAudioMixer;
+class CAudioOuput;
+
+class ISceneManagerSound
+{
+public:
+
+ virtual void Init( void ) = 0;
+ virtual void Shutdown( void ) = 0;
+ virtual void Update( float time ) = 0;
+ virtual void Flush( void ) = 0;
+
+ virtual CAudioSource *LoadSound( const char *wavfile ) = 0;
+
+ virtual void PlaySound( const char *wavfile, CAudioMixer **ppMixer ) = 0;
+
+ virtual void PlaySound( CAudioSource *source, CAudioMixer **ppMixer ) = 0;
+
+ virtual bool IsSoundPlaying( CAudioMixer *pMixer ) = 0;
+ virtual CAudioMixer *FindMixer( CAudioSource *source ) = 0;
+
+ virtual void StopAll( void ) = 0;
+ virtual void StopSound( CAudioMixer *mixer ) = 0;
+
+ virtual CAudioOuput *GetAudioOutput( void ) = 0;
+
+ virtual CAudioSource *FindOrAddSound( const char *filename ) = 0;
+};
+
+extern ISceneManagerSound *sound;
+
+#endif // ISCENEMANAGERSOUND_H
diff --git a/utils/scenemanager/itreeitem.cpp b/utils/scenemanager/itreeitem.cpp
new file mode 100644
index 0000000..c21b7c4
--- /dev/null
+++ b/utils/scenemanager/itreeitem.cpp
@@ -0,0 +1,84 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "itreeitem.h"
+#include "mxtk/mxTreeView.h"
+#include "project.h"
+#include "scene.h"
+#include "soundentry.h"
+#include "vcdfile.h"
+#include "wavefile.h"
+#include "workspace.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *tree -
+// *parent -
+// Output : mxTreeViewItem
+//-----------------------------------------------------------------------------
+mxTreeViewItem *ITreeItem::FindItem( mxTreeView *tree, mxTreeViewItem *parent, bool recurse )
+{
+ if ( !tree )
+ return NULL;
+
+ mxTreeViewItem *child = tree->getFirstChild( parent );
+ while ( child )
+ {
+ ITreeItem *treeItem = (ITreeItem *)tree->getUserData( child );
+ if ( treeItem )
+ {
+ if ( treeItem == this )
+ {
+ return child;
+ }
+
+ if ( recurse )
+ {
+ mxTreeViewItem *found = FindItem( tree, child, recurse );
+ if ( found )
+ {
+ return found;
+ }
+ }
+ }
+
+ child = tree->getNextChild( child );
+ }
+
+ return NULL;
+}
+
+ITreeItem *ITreeItem::GetParentItem()
+{
+ if ( GetSoundEntry() )
+ {
+ return GetSoundEntry()->GetOwnerVCDFile();
+ }
+
+ if ( GetVCDFile() )
+ {
+ return GetVCDFile()->GetOwnerScene();
+ }
+
+ if ( GetScene() )
+ {
+ return GetScene()->GetOwnerProject();
+ }
+
+ if ( GetProject() )
+ {
+ return GetProject()->GetOwnerWorkspace();
+ }
+
+ if ( GetWaveFile() )
+ {
+ return GetWaveFile()->GetOwnerSoundEntry();
+ }
+
+ return NULL;
+}
diff --git a/utils/scenemanager/itreeitem.h b/utils/scenemanager/itreeitem.h
new file mode 100644
index 0000000..b10fe3f
--- /dev/null
+++ b/utils/scenemanager/itreeitem.h
@@ -0,0 +1,89 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef ITREEITEM_H
+#define ITREEITEM_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CWorkspace;
+class CProject;
+class CScene;
+class CVCDFile;
+class CSoundEntry;
+class CWaveFile;
+class mxTreeView;
+
+class ITreeItem
+{
+public:
+ ITreeItem()
+ {
+ m_bExpanded = false;
+ m_nOrdinal = -1;
+ }
+
+ virtual char const *GetName() const = 0;
+
+ ITreeItem *GetParentItem();
+
+ virtual CWorkspace *GetWorkspace() = 0;
+ virtual CProject *GetProject() = 0;
+ virtual CScene *GetScene() = 0;
+ virtual CVCDFile *GetVCDFile() = 0;
+ virtual CSoundEntry *GetSoundEntry() = 0;
+ virtual CWaveFile *GetWaveFile() = 0;
+
+ virtual int GetIconIndex() const = 0;
+
+ bool IsExpanded() const
+ {
+ return m_bExpanded;
+ }
+
+ void SetExpanded( bool exp )
+ {
+ m_bExpanded = exp;
+ }
+
+ mxTreeViewItem *FindItem( mxTreeView *tree, mxTreeViewItem *parent, bool recurse = false );
+
+ virtual void Checkout( bool updatestateicons = true ) = 0;
+ virtual void Checkin( bool updatestateicons = true ) = 0;
+
+ virtual void MoveChildUp( ITreeItem *child ) = 0;
+ virtual void MoveChildDown( ITreeItem *child ) = 0;
+
+ virtual bool IsFirstChild()
+ {
+ if ( !GetParentItem() )
+ return false;
+
+ return GetParentItem()->IsChildFirst( this );
+ }
+
+ virtual bool IsLastChild()
+ {
+ if ( !GetParentItem() )
+ return false;
+
+ return GetParentItem()->IsChildLast( this );
+ }
+
+ virtual bool IsChildFirst( ITreeItem *child ) = 0;
+ virtual bool IsChildLast( ITreeItem *child ) = 0;
+
+ void SetOrdinal( int ordinal ) { m_nOrdinal = ordinal; }
+ int GetOrdinal( void ) const { return m_nOrdinal; }
+
+ virtual void SetDirty( bool dirty ) = 0;
+private:
+ bool m_bExpanded;
+ int m_nOrdinal;
+};
+
+#endif // ITREEITEM_H
diff --git a/utils/scenemanager/multiplerequest.cpp b/utils/scenemanager/multiplerequest.cpp
new file mode 100644
index 0000000..88ba0bb
--- /dev/null
+++ b/utils/scenemanager/multiplerequest.cpp
@@ -0,0 +1,138 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "resource.h"
+#include "MultipleRequest.h"
+#include "workspacemanager.h"
+
+static CMultipleParams g_Params;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+// uMsg -
+// wParam -
+// lParam -
+// Output : static BOOL CALLBACK
+//-----------------------------------------------------------------------------
+static BOOL CALLBACK MultipleRequestDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ // Insert code here to put the string (to find and replace with)
+ // into the edit controls.
+ // ...
+ {
+ g_Params.PositionSelf( hwndDlg );
+
+ SetDlgItemText( hwndDlg, IDC_PROMPT, g_Params.m_szPrompt );
+
+ SetWindowText( hwndDlg, g_Params.m_szDialogTitle );
+
+ SetFocus( GetDlgItem( hwndDlg, IDC_INPUTSTRING ) );
+ SendMessage( GetDlgItem( hwndDlg, IDC_INPUTSTRING ), EM_SETSEL, 0, MAKELONG(0, 0xffff) );
+
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDC_YESALL:
+ EndDialog( hwndDlg, CMultipleParams::YES_ALL );
+ break;
+ case IDC_YES:
+ EndDialog( hwndDlg, CMultipleParams::YES );
+ break;
+ case IDC_NOSINGLE:
+ EndDialog( hwndDlg, CMultipleParams::NO );
+ break;
+ case IDC_NOALL:
+ EndDialog( hwndDlg, CMultipleParams::NO_ALL );
+ break;
+ //case IDCANCEL:
+ // EndDialog( hwndDlg, CMultipleParams::CANCEL );
+ // break;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static int g_MRContext = 1;
+static int g_MRCurrentContext;
+static int g_MRLastResult = -1;
+
+void MultipleRequestChangeContext()
+{
+ ++g_MRContext;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *view -
+// *actor -
+// Output : int
+//-----------------------------------------------------------------------------
+int _MultipleRequest( CMultipleParams *params )
+{
+ int retval = -1;
+
+ if ( g_MRCurrentContext == g_MRContext &&
+ g_MRLastResult != -1 )
+ {
+ if ( g_MRLastResult == CMultipleParams::YES_ALL )
+ {
+ retval = 0;
+ }
+ if ( g_MRLastResult == CMultipleParams::NO_ALL )
+ {
+ retval = 1;
+ }
+ }
+
+ if ( retval == -1 )
+ {
+ g_Params = *params;
+
+ retval = DialogBox( (HINSTANCE)GetModuleHandle( 0 ),
+ MAKEINTRESOURCE( IDD_MULTIPLEQUESTION ),
+ (HWND)GetWorkspaceManager()->getHandle(),
+ (DLGPROC)MultipleRequestDialogProc );
+
+ *params = g_Params;
+ }
+
+ g_MRCurrentContext = g_MRContext;
+ g_MRLastResult = retval;
+ switch ( retval )
+ {
+ case CMultipleParams::YES_ALL:
+ case CMultipleParams::YES:
+ return 0;
+ case CMultipleParams::NO_ALL:
+ case CMultipleParams::NO:
+ return 1;
+ default:
+ case CMultipleParams::CANCEL:
+ return 2;
+ }
+
+ Assert( 0 );
+ return 1;
+}
+
+int MultipleRequest( char const *prompt )
+{
+ CMultipleParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_strcpy( params.m_szDialogTitle, g_appTitle );
+ Q_strncpy( params.m_szPrompt, prompt, sizeof( params.m_szPrompt ) );
+
+ return _MultipleRequest( &params );
+} \ No newline at end of file
diff --git a/utils/scenemanager/multiplerequest.h b/utils/scenemanager/multiplerequest.h
new file mode 100644
index 0000000..6632213
--- /dev/null
+++ b/utils/scenemanager/multiplerequest.h
@@ -0,0 +1,39 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef MULTIPLEREQUEST_H
+#define MULTIPLEREQUEST_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialogparams.h"
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+struct CMultipleParams : public CBaseDialogParams
+{
+ enum
+ {
+ YES_ALL = 0,
+ YES,
+ NO,
+ NO_ALL,
+ CANCEL,
+ };
+
+ char m_szPrompt[ 256 ];
+};
+
+// Display/create dialog
+int MultipleRequest( char const *prompt );
+int _MultipleRequest( CMultipleParams *params );
+
+void MultipleRequestChangeContext();
+
+
+#endif // MULTIPLEREQUEST_H
diff --git a/utils/scenemanager/project.cpp b/utils/scenemanager/project.cpp
new file mode 100644
index 0000000..48710f2
--- /dev/null
+++ b/utils/scenemanager/project.cpp
@@ -0,0 +1,416 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include "project.h"
+#include "cmdlib.h"
+#include <KeyValues.h>
+#include "scene.h"
+#include "UtlBuffer.h"
+#include "vcdfile.h"
+#include "workspacemanager.h"
+#include "workspacebrowser.h"
+
+CProject::CProject( CWorkspace *ws, char const *filename ) : m_pOwner( ws )
+{
+ Q_strncpy( m_szFile, filename, sizeof( m_szFile ) );
+ // By default, name is the same as the filename
+ Q_FileBase( m_szFile, m_szName, sizeof( m_szName ) );
+
+ m_bDirty = false;
+ m_pszComments = NULL;
+
+ LoadFromFile();
+}
+
+CProject::~CProject()
+{
+ while ( m_Scenes.Count() > 0 )
+ {
+ CScene *p = m_Scenes[ 0 ];
+ m_Scenes.Remove( 0 );
+ delete p;
+ }
+ delete[] m_pszComments;
+}
+
+CWorkspace *CProject::GetOwnerWorkspace()
+{
+ return m_pOwner;
+}
+
+char const *CProject::GetName() const
+{
+ return m_szName;
+}
+
+char const *CProject::GetFileName() const
+{
+ return m_szFile;
+}
+
+bool CProject::IsDirty( void ) const
+{
+ return m_bDirty;
+}
+
+void CProject::SetDirty( bool dirty )
+{
+ m_bDirty = dirty;
+}
+
+void CProject::SetComments( char const *comments )
+{
+ delete[] m_pszComments;
+ m_pszComments = V_strdup( comments );
+
+ SetDirty( true );
+}
+
+char const *CProject::GetComments() const
+{
+ return m_pszComments ? m_pszComments : "";
+}
+
+int CProject::GetSceneCount() const
+{
+ return m_Scenes.Count();
+}
+
+CScene *CProject::GetScene( int index ) const
+{
+ if ( index < 0 || index >= m_Scenes.Count() )
+ return NULL;
+ return m_Scenes[ index ];
+}
+
+void CProject::AddScene( CScene *scene )
+{
+ SetDirty( true );
+
+ Assert( m_Scenes.Find( scene ) == m_Scenes.InvalidIndex() );
+
+ m_Scenes.AddToTail( scene );
+}
+
+void CProject::RemoveScene( CScene *scene )
+{
+ if ( m_Scenes.Find( scene ) == m_Scenes.InvalidIndex() )
+ return;
+
+ m_Scenes.FindAndRemove( scene );
+ SetDirty( true );
+}
+
+void CProject::LoadFromFile()
+{
+ KeyValues *kv = new KeyValues( m_szName );
+ if ( kv->LoadFromFile( filesystem, m_szFile ) )
+ {
+ for ( KeyValues *s = kv->GetFirstSubKey(); s; s = s->GetNextKey() )
+ {
+ if ( !Q_stricmp( s->GetName(), "comments" ) )
+ {
+ SetComments( s->GetString() );
+ continue;
+ }
+
+ // Add named scenes
+ CScene *scene = new CScene( this, s->GetName() );
+
+ for ( KeyValues *sub = s->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
+ {
+ if ( !Q_stricmp( sub->GetName(), "comments" ) )
+ {
+ scene->SetComments( sub->GetString() );
+ continue;
+ }
+
+ if ( !Q_stricmp( sub->GetName(), "expanded" ) )
+ {
+ scene->SetExpanded( sub->GetInt() ? true : false );
+ continue;
+ }
+
+ if ( !Q_stricmp( sub->GetName(), "vcd" ) )
+ {
+ char filename[ 256 ];
+ char comments[ 512 ];
+ bool expanded = false;
+
+ filename[ 0 ] = 0;
+ comments[ 0 ] = 0;
+
+ for ( KeyValues *vcdKeys = sub->GetFirstSubKey(); vcdKeys; vcdKeys = vcdKeys->GetNextKey() )
+ {
+ if ( !Q_stricmp( vcdKeys->GetName(), "expanded" ) )
+ {
+ expanded = vcdKeys->GetInt() ? true : false;
+ continue;
+ }
+ else if ( !Q_stricmp( vcdKeys->GetName(), "file" ) )
+ {
+ Q_strncpy( filename, vcdKeys->GetString(), sizeof( filename ) );
+ continue;
+ }
+ if ( !Q_stricmp( vcdKeys->GetName(), "comments" ) )
+ {
+ Q_strncpy( comments, vcdKeys->GetString(), sizeof( comments ) );
+ continue;
+ }
+
+ Assert( 0 );
+
+ }
+
+ CVCDFile *file = new CVCDFile( scene, filename);
+ file->SetExpanded( expanded );
+ if ( comments[0] )
+ {
+ file->SetComments( comments );
+ }
+
+ scene->AddVCD( file );
+ continue;
+ }
+
+ Assert( !va( "Unknown scene token %s\n", sub->GetName() ) );
+ }
+
+ m_Scenes.AddToTail( scene );
+ }
+ }
+ kv->deleteThis();
+
+ SetDirty( false );
+}
+
+void CProject::SaveToFile()
+{
+ SetDirty( false );
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "%s\n{\n", GetName() );
+
+ if ( GetComments() && GetComments()[0] )
+ {
+ buf.Printf( "\t\"comments\"\t\"%s\"\n",
+ GetComments() );
+ }
+
+ // walk projects
+ int c = GetSceneCount();
+ for ( int i = 0; i < c; i++ )
+ {
+ CScene *scene = GetScene( i );
+ Assert( scene );
+
+ buf.Printf( "\t\"%s\"\n", scene->GetName() );
+ buf.Printf( "\t{\n" );
+
+ buf.Printf( "\t\t\"expanded\"\t\"%i\"\n", scene->IsExpanded() ? 1 : 0 );
+
+ if ( scene->GetComments() && scene->GetComments()[0] )
+ {
+ buf.Printf( "\t\t\"comments\"\t\"%s\"\n",
+ scene->GetComments() );
+ }
+
+ int vcdcount = scene->GetVCDCount();
+ for ( int j = 0; j < vcdcount; j++ )
+ {
+ CVCDFile *vcd = scene->GetVCD( j );
+ Assert( vcd );
+
+ buf.Printf( "\t\tvcd\n" );
+ buf.Printf( "\t\t{\n" );
+
+ buf.Printf( "\t\t\t\"expanded\"\t\"%i\"\n",
+ vcd->IsExpanded() ? 1 : 0 );
+ buf.Printf( "\t\t\t\"file\"\t\"%s\"\n",
+ vcd->GetName() );
+ if ( vcd->GetComments() && vcd->GetComments()[0] )
+ {
+ buf.Printf( "\t\t\t\"comments\"\t\"%s\"\n",
+ vcd->GetComments() );
+ }
+
+ buf.Printf( "\t\t}\n" );
+ }
+
+ buf.Printf( "\t}\n" );
+
+ if ( i != c - 1 )
+ {
+ buf.Printf( "\n" );
+ }
+ }
+
+ buf.Printf( "}\n" );
+
+ // Write it out baby
+ FileHandle_t fh = filesystem->Open( m_szFile, "wt" );
+ if (fh)
+ {
+ filesystem->Write( buf.Base(), buf.TellPut(), fh );
+ filesystem->Close(fh);
+ }
+ else
+ {
+ Con_Printf( "CWorkspace::SaveToFile: Unable to write file %s!!!\n", m_szFile );
+ }
+}
+
+void CProject::SaveChanges()
+{
+ if ( !IsDirty() )
+ return;
+
+ SaveToFile();
+}
+
+void CProject::ValidateTree( mxTreeView *tree, mxTreeViewItem* parent )
+{
+ CUtlVector< mxTreeViewItem * > m_KnownItems;
+
+ int c = GetSceneCount();
+ CScene *scene;
+ for ( int i = 0; i < c; i++ )
+ {
+ scene = GetScene( i );
+ if ( !scene )
+ continue;
+
+ char sz[ 256 ];
+ if ( scene->GetComments() && scene->GetComments()[0] )
+ {
+ Q_snprintf( sz, sizeof( sz ) , "%s : %s", scene->GetName(), scene->GetComments() );
+ }
+ else
+ {
+ Q_snprintf( sz, sizeof( sz ) , "%s", scene->GetName() );
+ }
+
+
+ mxTreeViewItem *spot = scene->FindItem( tree, parent );
+ if ( !spot )
+ {
+ spot = tree->add( parent, sz );
+ }
+
+ m_KnownItems.AddToTail( spot );
+
+ scene->SetOrdinal( i );
+
+ tree->setLabel( spot, sz );
+
+ tree->setImages( spot, scene->GetIconIndex(), scene->GetIconIndex() );
+ tree->setUserData( spot, scene );
+ //tree->setOpen( spot, scene->IsExpanded() );
+
+ scene->ValidateTree( tree, spot );
+ }
+
+ mxTreeViewItem *start = tree->getFirstChild( parent );
+ while ( start )
+ {
+ mxTreeViewItem *next = tree->getNextChild( start );
+
+ if ( m_KnownItems.Find( start ) == m_KnownItems.InvalidIndex() )
+ {
+ tree->remove( start );
+ }
+
+ start = next;
+ }
+
+ tree->sortTree( parent, true, CWorkspaceBrowser::CompareFunc, 0 );
+}
+
+void CProject::Checkout(bool updatestateicons /*= true*/)
+{
+ VSS_Checkout( GetFileName(), updatestateicons );
+}
+
+void CProject::Checkin(bool updatestateicons /*= true*/)
+{
+ VSS_Checkin( GetFileName(), updatestateicons );
+}
+
+bool CProject::IsCheckedOut() const
+{
+ return filesystem->IsFileWritable( GetFileName() );
+}
+
+int CProject::GetIconIndex() const
+{
+ if ( IsCheckedOut() )
+ {
+ return IMAGE_PROJECT_CHECKEDOUT;
+ }
+ else
+ {
+ return IMAGE_PROJECT;
+ }
+}
+
+bool CProject::IsChildFirst( ITreeItem *child )
+{
+ int idx = m_Scenes.Find( (CScene *)child );
+ if ( idx == m_Scenes.InvalidIndex() )
+ return false;
+
+ if ( idx != 0 )
+ return false;
+
+ return true;
+}
+
+bool CProject::IsChildLast( ITreeItem *child )
+{
+ int idx = m_Scenes.Find( (CScene *)child );
+ if ( idx == m_Scenes.InvalidIndex() )
+ return false;
+
+ if ( idx != m_Scenes.Count() - 1 )
+ return false;
+
+ return true;
+}
+
+void CProject::MoveChildUp( ITreeItem *child )
+{
+ int c = GetSceneCount();
+ for ( int i = 1; i < c; i++ )
+ {
+ CScene *p = GetScene( i );
+ if ( p != child )
+ continue;
+
+ CScene *prev = GetScene( i - 1 );
+ // Swap
+ m_Scenes[ i - 1 ] = p;
+ m_Scenes[ i ] = prev;
+ return;
+ }
+}
+
+void CProject::MoveChildDown( ITreeItem *child )
+{
+ int c = GetSceneCount();
+ for ( int i = 0; i < c - 1; i++ )
+ {
+ CScene *p = GetScene( i );
+ if ( p != child )
+ continue;
+
+ CScene *next = GetScene( i + 1 );
+ // Swap
+ m_Scenes[ i ] = next;
+ m_Scenes[ i + 1 ] = p;
+ return;
+ }
+}
diff --git a/utils/scenemanager/project.h b/utils/scenemanager/project.h
new file mode 100644
index 0000000..4a8be8c
--- /dev/null
+++ b/utils/scenemanager/project.h
@@ -0,0 +1,88 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef PROJECT_H
+#define PROJECT_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CScene;
+class mxTreeView;
+class CWorkspace;
+
+#include "itreeitem.h"
+
+class CProject : public ITreeItem
+{
+public:
+ CProject( CWorkspace *ws, char const *filename );
+ ~CProject();
+
+ CWorkspace *GetOwnerWorkspace();
+
+ char const *GetName() const;
+ char const *GetFileName() const;
+
+
+ bool IsDirty( void ) const;
+ void SetDirty( bool dirty );
+
+ void SetComments( char const *comments );
+ char const *GetComments( void ) const;
+
+ int GetSceneCount() const;
+ CScene *GetScene( int index ) const;
+ void AddScene( CScene *scene );
+ void RemoveScene( CScene *scene );
+
+ void ValidateTree( mxTreeView *tree, mxTreeViewItem* parent );
+
+ void SaveChanges();
+
+ virtual CWorkspace *GetWorkspace() { return NULL; }
+ virtual CProject *GetProject() { return this; }
+ virtual CScene *GetScene() { return NULL; }
+ virtual CVCDFile *GetVCDFile() { return NULL; }
+ virtual CSoundEntry *GetSoundEntry() { return NULL; }
+ virtual CWaveFile *GetWaveFile() { return NULL; }
+
+ virtual void Checkout( bool updatestateicons = true );
+ virtual void Checkin( bool updatestateicons = true );
+
+ bool IsCheckedOut() const;
+ int GetIconIndex() const;
+
+ virtual void MoveChildUp( ITreeItem *child );
+ virtual void MoveChildDown( ITreeItem *child );
+
+ virtual bool IsChildFirst( ITreeItem *child );
+ virtual bool IsChildLast( ITreeItem *child );
+
+private:
+
+ void LoadFromFile();
+ void SaveToFile();
+
+ enum
+ {
+ MAX_PROJECT_NAME = 128,
+ MAX_PROJECT_FILENAME = 256
+ };
+
+ char m_szName[ MAX_PROJECT_NAME ];
+ char m_szFile[ MAX_PROJECT_FILENAME ];
+
+ char *m_pszComments;
+
+ bool m_bDirty;
+
+ CUtlVector< CScene * > m_Scenes;
+
+ CWorkspace *m_pOwner;
+};
+
+#endif // PROJECT_H
diff --git a/utils/scenemanager/project1.ico b/utils/scenemanager/project1.ico
new file mode 100644
index 0000000..3e2b5c5
--- /dev/null
+++ b/utils/scenemanager/project1.ico
Binary files differ
diff --git a/utils/scenemanager/resource.h b/utils/scenemanager/resource.h
new file mode 100644
index 0000000..f380810
--- /dev/null
+++ b/utils/scenemanager/resource.h
@@ -0,0 +1,72 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by scenemanager.rc
+//
+#define IDC_NOSINGLE 3
+#define IDC_NOALL 4
+#define IDI_PLUS 104
+#define IDI_WORKSPACE 104
+#define IDI_MINUS 105
+#define IDI_PROJECT 105
+#define IDI_SCENE 106
+#define IDI_VCD 107
+#define IDI_WAV 108
+#define IDI_SPEAK 109
+#define IDD_INPUTDIALOG 110
+#define IDI_SPEAK_CHECKEDOUT 112
+#define IDI_WAV_CHECKEDOUT 113
+#define IDD_VSSPROPERTIES 113
+#define IDI_WORKSPACE_CHECKEDOUT 114
+#define IDI_VCD_CHECKEDOUT 115
+#define IDI_PROJECT_CHECKEDOUT 116
+#define IDD_SOUNDPROPERTIES 117
+#define IDD_WAVEPROPERTIES 118
+#define IDD_SOUNDPROPERTIES_MULTIPLE 119
+#define IDD_MULTIPLEQUESTION 120
+#define IDC_INPUTSTRING 1000
+#define IDC_STATIC_PROMPT 1001
+#define IDC_VSS_USERNAME 1002
+#define IDC_VSS_PROJECT 1003
+#define IDC_SOUNDNAME 1004
+#define IDC_SOUNDSCRIPT 1005
+#define IDC_CHANNEL 1007
+#define IDC_VOLUME 1008
+#define IDC_SOUNDLEVEL 1009
+#define IDC_PITCH 1010
+#define IDC_WAVELIST 1013
+#define IDC_ADDWAVE 1014
+#define IDC_REMOVEWAVE 1015
+#define IDC_WAVELIST_AVAILABLE 1016
+#define IDC_OWNERONLY 1017
+#define IDC_STATIC_SENTENCETEXT 1018
+#define IDC_WAVENAME 1019
+#define IDC_STATIC_CLOSECAPTION 1019
+#define IDC_VOICEDUCK 1020
+#define IDC_SENTENCETEXT 1021
+#define IDC_WAVEPROPERTIES 1022
+#define IDC_CCTEXT 1022
+#define IDC_PROMPT 1023
+#define IDC_YESALL 1024
+#define IDC_YES 1025
+#define IDC_CCRESET 1026
+#define IDC_EXPORTSENTENCE 1027
+#define IDC_IMPORTSENTENCE 1028
+#define IDC_STATIC_CCTEXT 1029
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 121
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1030
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/utils/scenemanager/scene.cpp b/utils/scenemanager/scene.cpp
new file mode 100644
index 0000000..d535952
--- /dev/null
+++ b/utils/scenemanager/scene.cpp
@@ -0,0 +1,243 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "scene.h"
+#include "vcdfile.h"
+#include "project.h"
+#include "workspacemanager.h"
+#include "workspacebrowser.h"
+
+CScene::CScene( CProject *proj, char const *name ) : m_pOwner( proj )
+{
+ Q_strncpy( m_szName, name, sizeof( m_szName ) );
+ m_pszComments = NULL;
+}
+
+CScene::~CScene()
+{
+ while ( m_Files.Count() > 0 )
+ {
+ CVCDFile *f = m_Files[ 0 ];
+ m_Files.Remove( 0 );
+ delete f;
+ }
+ delete[] m_pszComments;
+}
+
+CProject *CScene::GetOwnerProject()
+{
+ return m_pOwner;
+}
+
+void CScene::SetComments( char const *comments )
+{
+ delete[] m_pszComments;
+ m_pszComments = V_strdup( comments );
+
+ GetOwnerProject()->SetDirty( true );
+}
+
+char const *CScene::GetComments( void ) const
+{
+ return m_pszComments ? m_pszComments : "";
+}
+
+char const *CScene::GetName() const
+{
+ return m_szName;
+}
+
+int CScene::GetVCDCount() const
+{
+ return m_Files.Count();
+}
+
+CVCDFile *CScene::GetVCD( int index )
+{
+ if ( index < 0 || index >= m_Files.Count() )
+ return NULL;
+ return m_Files[ index ];
+}
+
+void CScene::AddVCD( CVCDFile *vcd )
+{
+ Assert( m_Files.Find( vcd ) == m_Files.InvalidIndex() );
+
+ m_Files.AddToTail( vcd );
+
+ GetOwnerProject()->SetDirty( true );
+}
+
+void CScene::RemoveVCD( CVCDFile *vcd )
+{
+ if ( m_Files.Find( vcd ) == m_Files.InvalidIndex() )
+ return;
+
+ m_Files.FindAndRemove( vcd );
+
+ GetOwnerProject()->SetDirty( true );
+}
+
+CVCDFile *CScene::FindVCD( char const *filename )
+{
+ int c = GetVCDCount();
+ CVCDFile *vcd;
+ for ( int i = 0; i < c; i++ )
+ {
+ vcd = GetVCD( i );
+ if ( !vcd )
+ continue;
+
+ if ( !Q_stricmp( filename, vcd->GetName() ) )
+ return vcd;
+ }
+ return NULL;
+}
+
+void CScene::ValidateTree( mxTreeView *tree, mxTreeViewItem* parent )
+{
+ CUtlVector< mxTreeViewItem * > m_KnownItems;
+
+ int c = GetVCDCount();
+ CVCDFile *vcd;
+ for ( int i = 0; i < c; i++ )
+ {
+ vcd = GetVCD( i );
+ if ( !vcd )
+ continue;
+
+ char sz[ 256 ];
+ if ( vcd->GetComments() && vcd->GetComments()[0] )
+ {
+ Q_snprintf( sz, sizeof( sz ), "%s : %s", vcd->GetName(), vcd->GetComments() );
+ }
+ else
+ {
+ Q_snprintf( sz, sizeof( sz ), "%s", vcd->GetName() );
+ }
+
+ mxTreeViewItem *spot = vcd->FindItem( tree, parent );
+ if ( !spot )
+ {
+ spot = tree->add( parent, sz );
+ }
+
+ m_KnownItems.AddToTail( spot );
+
+ vcd->SetOrdinal( i );
+
+ tree->setLabel( spot, sz );
+
+ tree->setImages( spot, vcd->GetIconIndex(), vcd->GetIconIndex() );
+ tree->setUserData( spot, vcd );
+ //tree->setOpen( spot, vcd->IsExpanded() );
+
+ vcd->ValidateTree( tree, spot );
+ }
+
+ mxTreeViewItem *start = tree->getFirstChild( parent );
+ while ( start )
+ {
+ mxTreeViewItem *next = tree->getNextChild( start );
+
+ if ( m_KnownItems.Find( start ) == m_KnownItems.InvalidIndex() )
+ {
+ tree->remove( start );
+ }
+
+ start = next;
+ }
+
+ tree->sortTree( parent, true, CWorkspaceBrowser::CompareFunc, 0 );
+}
+
+bool CScene::IsCheckedOut() const
+{
+ return false;
+}
+
+int CScene::GetIconIndex() const
+{
+ /*
+ if ( IsCheckedOut() )
+ {
+ return IMAGE_SCENE_CHECKEDOUT;
+ }
+ else
+ */
+ {
+ return IMAGE_SCENE;
+ }
+}
+
+void CScene::Checkout(bool updatestateicons /*= true*/)
+{
+ // Scenes aren't made for checkin / checkout
+}
+
+void CScene::Checkin(bool updatestateicons /*= true*/)
+{
+ // Scenes aren't made for checkin / checkout
+}
+
+void CScene::MoveChildUp( ITreeItem *child )
+{
+ int c = GetVCDCount();
+ for ( int i = 1; i < c; i++ )
+ {
+ CVCDFile *p = GetVCD( i );
+ if ( p != child )
+ continue;
+
+ CVCDFile *prev = GetVCD( i - 1 );
+ // Swap
+ m_Files[ i - 1 ] = p;
+ m_Files[ i ] = prev;
+ return;
+ }
+}
+
+void CScene::MoveChildDown( ITreeItem *child )
+{
+ int c = GetVCDCount();
+ for ( int i = 0; i < c - 1; i++ )
+ {
+ CVCDFile *p = GetVCD( i );
+ if ( p != child )
+ continue;
+
+ CVCDFile *next = GetVCD( i + 1 );
+ // Swap
+ m_Files[ i ] = next;
+ m_Files[ i + 1 ] = p;
+ return;
+ }
+}
+
+bool CScene::IsChildFirst( ITreeItem *child )
+{
+ int idx = m_Files.Find( (CVCDFile *)child );
+ if ( idx == m_Files.InvalidIndex() )
+ return false;
+
+ if ( idx != 0 )
+ return false;
+
+ return true;
+}
+
+bool CScene::IsChildLast( ITreeItem *child )
+{
+ int idx = m_Files.Find( (CVCDFile *)child );
+ if ( idx == m_Files.InvalidIndex() )
+ return false;
+
+ if ( idx != m_Files.Count() - 1 )
+ return false;
+
+ return true;
+}
diff --git a/utils/scenemanager/scene.h b/utils/scenemanager/scene.h
new file mode 100644
index 0000000..5ca1217
--- /dev/null
+++ b/utils/scenemanager/scene.h
@@ -0,0 +1,75 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SCENE_H
+#define SCENE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CVCDFile;
+class CProject;
+
+#include "itreeitem.h"
+
+class CScene : public ITreeItem
+{
+public:
+ CScene( CProject *proj, char const *name );
+ ~CScene();
+
+ CProject *GetOwnerProject();
+
+ void SetComments( char const *comments );
+ char const *GetComments( void ) const;
+ char const *GetName() const;
+
+ int GetVCDCount() const;
+ CVCDFile *GetVCD( int index );
+ void AddVCD( CVCDFile *vcd );
+ void RemoveVCD( CVCDFile *vcd );
+ CVCDFile *FindVCD( char const *filename );
+
+ void ValidateTree( mxTreeView *tree, mxTreeViewItem* parent );
+
+ virtual CWorkspace *GetWorkspace() { return NULL; }
+ virtual CProject *GetProject() { return NULL; }
+ virtual CScene *GetScene() { return this; }
+ virtual CVCDFile *GetVCDFile() { return NULL; }
+ virtual CSoundEntry *GetSoundEntry() { return NULL; }
+ virtual CWaveFile *GetWaveFile() { return NULL; }
+
+ bool IsCheckedOut() const;
+ int GetIconIndex() const;
+
+ virtual void Checkout( bool updatestateicons = true );
+ virtual void Checkin( bool updatestateicons = true );
+
+ virtual void MoveChildUp( ITreeItem *child );
+ virtual void MoveChildDown( ITreeItem *child );
+
+ void SetDirty( bool dirty )
+ {
+ }
+
+ virtual bool IsChildFirst( ITreeItem *child );
+ virtual bool IsChildLast( ITreeItem *child );
+
+private:
+ enum
+ {
+ MAX_SCENE_NAME = 128,
+ };
+
+ char m_szName[ MAX_SCENE_NAME ];
+ char *m_pszComments;
+
+ CUtlVector< CVCDFile * > m_Files;
+
+ CProject *m_pOwner;
+};
+
+#endif // SCENE_H
diff --git a/utils/scenemanager/scenemanager.cpp b/utils/scenemanager/scenemanager.cpp
new file mode 100644
index 0000000..7bf42c8
--- /dev/null
+++ b/utils/scenemanager/scenemanager.cpp
@@ -0,0 +1,220 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+// scenemanager.cpp : Defines the entry point for the console application.
+//
+
+#include "cbase.h"
+#include "appframework/tier3app.h"
+#include "workspacemanager.h"
+#include "filesystem.h"
+#include "FileSystem_Tools.h"
+#include "cmdlib.h"
+#include "vstdlib/random.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "iscenemanagersound.h"
+#include <vgui/ILocalize.h>
+#include <vgui/IVGui.h>
+#include "tier0/icommandline.h"
+#include "icvar.h"
+#include "vstdlib/cvar.h"
+#include "mathlib/mathlib.h"
+
+char cmdline[1024] = "";
+
+static CUniformRandomStream g_Random;
+IUniformRandomStream *random = &g_Random;
+
+IFileSystem *filesystem = NULL;
+
+SpewRetval_t SceneManagerSpewFunc( SpewType_t spewType, char const *pMsg )
+{
+ switch (spewType)
+ {
+ case SPEW_ERROR:
+ {
+ MessageBox(NULL, pMsg, "FATAL ERROR", MB_OK);
+ }
+ return SPEW_ABORT;
+ case SPEW_WARNING:
+ {
+ Con_ColorPrintf( 255, 0, 0, pMsg );
+ }
+ break;
+ case SPEW_ASSERT:
+ {
+ Con_ColorPrintf( 255, 0, 0, pMsg );
+ }
+#ifdef _DEBUG
+ return SPEW_DEBUGGER;
+#else
+ return SPEW_CONTINUE;
+#endif
+ default:
+ {
+ Con_Printf(pMsg);
+ }
+ break;
+ }
+
+ return SPEW_CONTINUE;
+}
+
+
+//-----------------------------------------------------------------------------
+// The application object
+//-----------------------------------------------------------------------------
+class CHLSceneManagerApp : public CTier3SteamApp
+{
+ typedef CTier3SteamApp BaseClass;
+
+public:
+ // Methods of IApplication
+ virtual bool Create();
+ virtual bool PreInit();
+ virtual int Main();
+ virtual void PostShutdown();
+ virtual void Destroy();
+
+private:
+ // Sets up the search paths
+ bool SetupSearchPaths();
+};
+
+
+bool CHLSceneManagerApp::Create()
+{
+ SpewOutputFunc( SceneManagerSpewFunc );
+
+ AppSystemInfo_t appSystems[] =
+ {
+ { "vgui2.dll", VGUI_IVGUI_INTERFACE_VERSION },
+ { "soundemittersystem.dll", SOUNDEMITTERSYSTEM_INTERFACE_VERSION },
+
+ { "", "" } // Required to terminate the list
+ };
+
+ return AddSystems( appSystems );
+}
+
+void CHLSceneManagerApp::Destroy()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Sets up the game path
+//-----------------------------------------------------------------------------
+bool CHLSceneManagerApp::SetupSearchPaths()
+{
+ if ( !BaseClass::SetupSearchPaths( NULL, false, true ) )
+ return false;
+
+ // Set gamedir.
+ Q_MakeAbsolutePath( gamedir, sizeof( gamedir ), GetGameInfoPath() );
+ Q_AppendSlash( gamedir, sizeof( gamedir ) );
+
+ return true;
+}
+
+
+//-----------------------------------------------------------------------------
+// Init, shutdown
+//-----------------------------------------------------------------------------
+bool CHLSceneManagerApp::PreInit( )
+{
+ MathLib_Init( 2.2f, 2.2f, 0.0f, 2.0f, false, false, false, false );
+
+ if ( !BaseClass::PreInit() )
+ return false;
+
+ g_pFileSystem = filesystem = g_pFullFileSystem;
+ if ( !g_pSoundEmitterSystem || !g_pVGuiLocalize || !g_pFileSystem )
+ {
+ Error("Unable to load required library interface!\n");
+ return false;
+ }
+
+ filesystem->SetWarningFunc( Warning );
+
+ // Add paths...
+ if ( !SetupSearchPaths() )
+ return false;
+
+ return true;
+}
+
+void CHLSceneManagerApp::PostShutdown()
+{
+ g_pFileSystem = filesystem = NULL;
+ BaseClass::PostShutdown();
+}
+
+
+//-----------------------------------------------------------------------------
+// main application
+//-----------------------------------------------------------------------------
+int CHLSceneManagerApp::Main()
+{
+ g_pSoundEmitterSystem->ModInit();
+
+ sound->Init();
+
+ CWorkspaceManager *sm = new CWorkspaceManager();
+
+ bool workspace_loaded = false;
+ for ( int i = 1; i < CommandLine()->ParmCount(); i++ )
+ {
+ char const *argv = CommandLine()->GetParm( i );
+
+ if ( !workspace_loaded && strstr (argv, ".vsw") )
+ {
+ workspace_loaded = true;
+
+ // Strip game directory and slash
+ char workspace_name[ 512 ];
+ filesystem->FullPathToRelativePath( argv, workspace_name, sizeof( workspace_name ) );
+
+ sm->AutoLoad( workspace_name );
+ }
+ }
+
+ if ( !workspace_loaded )
+ {
+ sm->AutoLoad( NULL );
+ }
+
+ int retval = mx::run ();
+
+ sound->Shutdown();
+
+ g_pSoundEmitterSystem->ModShutdown();
+
+ return retval;
+}
+
+int main (int argc, char *argv[])
+{
+ CommandLine()->CreateCmdLine( argc, argv );
+ CoInitialize(NULL);
+
+ // make sure, we start in the right directory
+ char szName[256];
+ strcpy (szName, mx::getApplicationPath() );
+ mx::init (argc, argv);
+
+ char workingdir[ 256 ];
+ workingdir[0] = 0;
+ Q_getwd( workingdir, sizeof( workingdir ) );
+
+ CHLSceneManagerApp sceneManagerApp;
+ CSteamApplication steamApplication( &sceneManagerApp );
+ int nRetVal = steamApplication.Run();
+
+ CoUninitialize();
+
+ return nRetVal;
+}
diff --git a/utils/scenemanager/scenemanager.rc b/utils/scenemanager/scenemanager.rc
new file mode 100644
index 0000000..d903e00
--- /dev/null
+++ b/utils/scenemanager/scenemanager.rc
@@ -0,0 +1,269 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_WORKSPACE ICON DISCARDABLE "icon1.ico"
+MX_ICON ICON DISCARDABLE "ico00006.ico"
+IDI_SCENE ICON DISCARDABLE "ico00002.ico"
+IDI_VCD ICON DISCARDABLE "ico00003.ico"
+IDI_WAV ICON DISCARDABLE "ico00004.ico"
+IDI_SPEAK ICON DISCARDABLE "ico00005.ico"
+IDI_SPEAK_CHECKEDOUT ICON DISCARDABLE "ico00007.ico"
+IDI_WAV_CHECKEDOUT ICON DISCARDABLE "wav1.ico"
+IDI_WORKSPACE_CHECKEDOUT ICON DISCARDABLE "workspac.ico"
+IDI_VCD_CHECKEDOUT ICON DISCARDABLE "vcd1.ico"
+IDI_PROJECT ICON DISCARDABLE "ico00001.ico"
+IDI_PROJECT_CHECKEDOUT ICON DISCARDABLE "project1.ico"
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "#include ""afxres.h""\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE DISCARDABLE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_INPUTDIALOG DIALOG DISCARDABLE 0, 0, 361, 73
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Input:"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,128,47,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,186,47,50,14
+ EDITTEXT IDC_INPUTSTRING,7,25,347,14,ES_AUTOHSCROLL
+ LTEXT "Static",IDC_STATIC_PROMPT,7,7,347,16
+END
+
+IDD_VSSPROPERTIES DIALOG DISCARDABLE 0, 0, 246, 82
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Dialog"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,189,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,189,24,50,14
+ LTEXT "VSS User Name:",IDC_STATIC,7,7,106,10
+ EDITTEXT IDC_VSS_USERNAME,7,22,164,14,ES_AUTOHSCROLL
+ LTEXT "VSS Project: e.g., $/HL2/release/dev/hl2/",IDC_STATIC,
+ 7,42,232,13
+ EDITTEXT IDC_VSS_PROJECT,7,58,232,15,ES_AUTOHSCROLL
+END
+
+IDD_SOUNDPROPERTIES DIALOG DISCARDABLE 0, 0, 512, 313
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Sound Properites"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,455,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,455,25,50,14
+ LTEXT "Sound Name:",IDC_STATIC,7,7,174,13
+ EDITTEXT IDC_SOUNDNAME,7,19,247,14,ES_AUTOHSCROLL
+ LTEXT "Sound Script File:",IDC_STATIC,7,37,178,12
+ COMBOBOX IDC_SOUNDSCRIPT,7,50,248,89,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ LTEXT "Sentence Text:",IDC_STATIC,131,110,55,12
+ LTEXT "Channel:",IDC_STATIC,269,10,52,13
+ LTEXT "Volume:",IDC_STATIC,269,27,52,13
+ LTEXT "Soundlevel:",IDC_STATIC,269,44,52,13
+ LTEXT "Pitch:",IDC_STATIC,269,61,52,13
+ COMBOBOX IDC_CHANNEL,323,7,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_VOLUME,323,24,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_SOUNDLEVEL,323,41,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_PITCH,323,58,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ GROUPBOX "Wave Files: ",IDC_STATIC,7,96,498,210
+ LISTBOX IDC_WAVELIST,7,195,210,111,LBS_MULTIPLESEL |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "<- Add",IDC_ADDWAVE,228,198,50,14
+ PUSHBUTTON "Remove ->",IDC_REMOVEWAVE,227,216,50,14
+ CONTROL "Play to Owner Entity Only",IDC_OWNERONLY,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,71,105,10
+ LTEXT "SENTENCE TEXT GOES HERE",IDC_STATIC_SENTENCETEXT,193,
+ 110,304,27
+ LTEXT "Members:",IDC_STATIC,11,181,45,10
+ PUSHBUTTON "Properties...",IDC_WAVEPROPERTIES,228,234,50,13
+ LISTBOX IDC_WAVELIST_AVAILABLE,287,195,214,111,LBS_MULTIPLESEL |
+ LBS_NOINTEGRALHEIGHT | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Available:",IDC_STATIC,299,181,45,10
+ LTEXT "Close Caption:",IDC_STATIC,132,147,55,12
+ LTEXT "CLOSE CAPTION GOES HERE",IDC_STATIC_CLOSECAPTION,194,
+ 147,304,27
+END
+
+IDD_WAVEPROPERTIES DIALOG DISCARDABLE 0, 0, 351, 142
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Wave Properites"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,294,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,294,25,50,14
+ LTEXT "Wav Name:",-1,7,7,174,13
+ LTEXT "Sentence Text:",-1,7,37,72,12
+ CONTROL "Enable voice ducking",IDC_VOICEDUCK,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,79,105,10
+ LTEXT "WAVE NAME",IDC_WAVENAME,7,20,257,14
+ EDITTEXT IDC_SENTENCETEXT,7,49,337,27,ES_AUTOHSCROLL
+ PUSHBUTTON "Export Sentence Data...",IDC_EXPORTSENTENCE,7,93,91,15
+ PUSHBUTTON "Import Sentence Data...",IDC_IMPORTSENTENCE,7,114,91,15
+END
+
+IDD_SOUNDPROPERTIES_MULTIPLE DIALOG DISCARDABLE 0, 0, 263, 126
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Multiple Sound Properites"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "OK",IDOK,206,7,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,206,25,50,14
+ LTEXT "Channel:",-1,7,10,52,13
+ LTEXT "Volume:",-1,7,27,52,13
+ LTEXT "Soundlevel:",-1,7,44,52,13
+ LTEXT "Pitch:",-1,7,61,52,13
+ COMBOBOX IDC_CHANNEL,61,7,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_VOLUME,61,24,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_SOUNDLEVEL,61,41,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ COMBOBOX IDC_PITCH,61,58,110,96,CBS_DROPDOWN | WS_VSCROLL |
+ WS_TABSTOP
+ CONTROL "Play to Owner Entity Only",IDC_OWNERONLY,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,7,82,105,10
+END
+
+IDD_MULTIPLEQUESTION DIALOG DISCARDABLE 0, 0, 351, 59
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Check Out Multiple"
+FONT 8, "MS Sans Serif"
+BEGIN
+ DEFPUSHBUTTON "Yes",IDC_YES,122,34,50,14
+ LTEXT "PROMPT GOES HERE",IDC_PROMPT,7,7,337,11
+ PUSHBUTTON "Yes All",IDC_YESALL,66,34,50,14
+ DEFPUSHBUTTON "No",IDC_NOSINGLE,178,34,50,14
+ DEFPUSHBUTTON "No All",IDC_NOALL,234,34,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_INPUTDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 354
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 66
+ END
+
+ IDD_VSSPROPERTIES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 239
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 75
+ END
+
+ IDD_SOUNDPROPERTIES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 505
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 306
+ END
+
+ IDD_WAVEPROPERTIES, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 344
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 135
+ END
+
+ IDD_SOUNDPROPERTIES_MULTIPLE, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 256
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 119
+ END
+
+ IDD_MULTIPLEQUESTION, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 344
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 52
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/utils/scenemanager/scenemanager.vpc b/utils/scenemanager/scenemanager.vpc
new file mode 100644
index 0000000..a4565d1
--- /dev/null
+++ b/utils/scenemanager/scenemanager.vpc
@@ -0,0 +1,261 @@
+//-----------------------------------------------------------------------------
+// SCENEMANAGER.VPC
+//
+// Project Script
+//-----------------------------------------------------------------------------
+
+$Macro SRCDIR "..\.."
+$Macro OUTBINDIR "$SRCDIR\..\game\bin"
+
+$Include "$SRCDIR\vpc_scripts\source_exe_base.vpc"
+
+$Configuration
+{
+ $Compiler
+ {
+ $AdditionalIncludeDirectories "$BASE,..\common,$SRCDIR\game\shared"
+ $PreprocessorDefinitions "$BASE;PROTECTED_THINGS_DISABLE"
+ $Create/UsePrecompiledHeader "Use Precompiled Header (/Yu)"
+ $Create/UsePCHThroughFile "cbase.h"
+ $PrecompiledHeaderFile "Debug/scenemanager.pch"
+ }
+
+ $Linker
+ {
+ $AdditionalDependencies "$BASE Winmm.lib Msimg32.lib comctl32.lib odbc32.lib odbccp32.lib"
+ $EntryPoint "mainCRTStartup"
+ }
+}
+
+$Project "Scenemanager"
+{
+ $Folder "Precompiled Header"
+ {
+ $File "cbase.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Create Precompiled Header (/Yc)"
+ }
+ }
+ }
+ }
+
+ $Folder "Source Files"
+ {
+ $File "basedialogparams.cpp"
+ $File "basedialogparams.h"
+ $File "cbase.h"
+ $File "drawhelper.cpp"
+ $File "drawhelper.h"
+ $File "fileloaderthread.cpp"
+ $File "ifileloader.h"
+ $File "inputproperties.cpp"
+ $File "inputproperties.h"
+ $File "itreeitem.h"
+ $File "multiplerequest.cpp"
+ $File "multiplerequest.h"
+ $File "project.cpp"
+ $File "project.h"
+ $File "scene.cpp"
+ $File "scene.h"
+ $File "scenemanager.cpp"
+ $File "scenemanager_tools.cpp"
+ $File "scenemanager_tools.h"
+ $File "soundbrowser.cpp"
+ $File "soundbrowser.h"
+ $File "soundentry.cpp"
+ $File "soundentry.h"
+ $File "$SRCDIR\public\SoundParametersInternal.cpp"
+ $File "soundproperties.cpp"
+ $File "soundproperties.h"
+ $File "soundproperties_multiple.cpp"
+ $File "soundproperties_multiple.h"
+ $File "statuswindow.cpp"
+ $File "statuswindow.h"
+ $File "tabwindow.cpp"
+ $File "tabwindow.h"
+ $File "vcdfile.cpp"
+ $File "vcdfile.h"
+ $File "vssproperties.cpp"
+ $File "vssproperties.h"
+ $File "wavebrowser.cpp"
+ $File "wavebrowser.h"
+ $File "wavefile.cpp"
+ $File "wavefile.h"
+ $File "waveproperties.cpp"
+ $File "waveproperties.h"
+ $File "workspace.cpp"
+ $File "workspace.h"
+ $File "workspacebrowser.cpp"
+ $File "workspacebrowser.h"
+ $File "workspacemanager.cpp"
+ $File "workspacemanager.h"
+
+ $File "..\common\cmdlib.cpp" \
+ "$SRCDIR\public\filesystem_helpers.cpp" \
+ "$SRCDIR\public\filesystem_init.cpp" \
+ "..\common\filesystem_tools.cpp" \
+ "$SRCDIR\public\interpolatortypes.cpp" \
+ "$SRCDIR\game\shared\interval.cpp" \
+ "itreeitem.cpp" \
+ "..\common\scriplib.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Not Using Precompiled Headers"
+ }
+ }
+ }
+ }
+
+ $Folder "Resource Files"
+ {
+ $File "ico00001.ico"
+ $File "ico00002.ico"
+ $File "ico00003.ico"
+ $File "ico00004.ico"
+ $File "ico00005.ico"
+ $File "ico00006.ico"
+ $File "ico00007.ico"
+ $File "icon1.ico"
+ $File "project1.ico"
+ $File "resource.h"
+ $File "scenemanager.rc"
+ $File "vcd1.ico"
+ $File "wav1.ico"
+ $File "workspac.ico"
+ }
+
+ $Folder "Public Headers"
+ {
+ $File "$SRCDIR\public\mathlib\amd3dx.h"
+ $File "$SRCDIR\public\tier0\basetypes.h"
+ $File "$SRCDIR\public\tier1\characterset.h"
+ $File "..\common\cmdlib.h"
+ $File "$SRCDIR\public\tier0\commonmacros.h"
+ $File "$SRCDIR\public\tier1\convar.h"
+ $File "$SRCDIR\public\tier0\dbg.h"
+ $File "$SRCDIR\game\shared\ExpressionSample.h"
+ $File "$SRCDIR\public\tier0\fasttimer.h"
+ $File "$SRCDIR\public\filesystem.h"
+ $File "$SRCDIR\public\filesystem_helpers.h"
+ $File "..\common\filesystem_tools.h"
+ $File "$SRCDIR\public\appframework\IAppSystem.h"
+ $File "$SRCDIR\game\shared\ichoreoeventcallback.h"
+ $File "$SRCDIR\public\engine\IEngineSound.h"
+ $File "$SRCDIR\public\tier1\interface.h"
+ $File "$SRCDIR\public\interpolatortypes.h"
+ $File "$SRCDIR\game\shared\interval.h"
+ $File "$SRCDIR\public\irecipientfilter.h"
+ $File "$SRCDIR\game\shared\iscenetokenprocessor.h"
+ $File "$SRCDIR\public\tier1\KeyValues.h"
+ $File "$SRCDIR\public\mathlib\mathlib.h"
+ $File "$SRCDIR\public\tier0\mem.h"
+ $File "$SRCDIR\public\tier0\memdbgoff.h"
+ $File "$SRCDIR\public\tier0\memdbgon.h"
+ $File "$SRCDIR\public\tier1\mempool.h"
+ $File "..\..\public\mxtk\mx.h"
+ $File "..\..\public\mxtk\mxButton.h"
+ $File "..\..\public\mxtk\mxCheckBox.h"
+ $File "..\..\public\mxtk\mxChoice.h"
+ $File "..\..\public\mxtk\mxChooseColor.h"
+ $File "..\..\public\mxtk\mxEvent.h"
+ $File "..\..\public\mxtk\mxFileDialog.h"
+ $File "..\..\public\mxtk\mxGlWindow.h"
+ $File "..\..\public\mxtk\mxGroupBox.h"
+ $File "..\..\public\mxtk\mxInit.h"
+ $File "..\..\public\mxtk\mxLabel.h"
+ $File "..\..\public\mxtk\mxLineEdit.h"
+ $File "..\..\public\mxtk\mxLinkedList.h"
+ $File "..\..\public\mxtk\mxListBox.h"
+ $File "..\..\public\mxtk\mxlistview.h"
+ $File "..\..\public\mxtk\mxMenu.h"
+ $File "..\..\public\mxtk\mxMenuBar.h"
+ $File "..\..\public\mxtk\mxMessageBox.h"
+ $File "..\..\public\mxtk\mxpath.h"
+ $File "..\..\public\mxtk\mxPopupMenu.h"
+ $File "..\..\public\mxtk\mxProgressBar.h"
+ $File "..\..\public\mxtk\mxRadioButton.h"
+ $File "..\..\public\mxtk\mxScrollbar.h"
+ $File "..\..\public\mxtk\mxSlider.h"
+ $File "..\..\public\mxtk\mxstring.h"
+ $File "..\..\public\mxtk\mxTab.h"
+ $File "..\..\public\mxtk\mxToggleButton.h"
+ $File "..\..\public\mxtk\mxToolTip.h"
+ $File "..\..\public\mxtk\mxTreeView.h"
+ $File "..\..\public\mxtk\mxWidget.h"
+ $File "..\..\public\mxtk\mxWindow.h"
+ $File "$SRCDIR\public\networkvar.h"
+ $File "$SRCDIR\public\tier0\platform.h"
+ $File "$SRCDIR\public\tier1\processor_detect.h"
+ $File "$SRCDIR\public\tier0\protected_things.h"
+ $File "$SRCDIR\public\vstdlib\random.h"
+ $File "..\common\scriplib.h"
+ $File "$SRCDIR\game\shared\sharedInterface.h"
+ $File "$SRCDIR\public\soundflags.h"
+ $File "$SRCDIR\public\string_t.h"
+ $File "$SRCDIR\public\tier1\strtools.h"
+ $File "$SRCDIR\public\tier1\utlbuffer.h"
+ $File "$SRCDIR\public\tier1\utldict.h"
+ $File "$SRCDIR\public\tier1\utllinkedlist.h"
+ $File "$SRCDIR\public\tier1\utlmemory.h"
+ $File "$SRCDIR\public\tier1\utlrbtree.h"
+ $File "$SRCDIR\public\tier1\utlsymbol.h"
+ $File "$SRCDIR\public\tier1\utlvector.h"
+ $File "$SRCDIR\public\mathlib\vector.h"
+ $File "$SRCDIR\public\mathlib\vector2d.h"
+ $File "$SRCDIR\public\vstdlib\vstdlib.h"
+ }
+
+ $Folder "Choreography"
+ {
+ $File "$SRCDIR\game\shared\choreoactor.h"
+ $File "$SRCDIR\game\shared\choreochannel.h"
+ $File "$SRCDIR\game\shared\choreoevent.h"
+ $File "$SRCDIR\game\shared\choreoscene.h"
+ }
+
+ $Folder "Audio"
+ {
+ $File "audiowaveoutput.h"
+ $File "iscenemanagersound.h"
+ $File "$SRCDIR\public\sentence.h"
+ $File "snd_audio_source.cpp"
+ $File "snd_audio_source.h"
+ $File "snd_wave_mixer.cpp"
+ $File "snd_wave_mixer.h"
+ $File "snd_wave_mixer_adpcm.cpp"
+ $File "snd_wave_mixer_adpcm.h"
+ $File "snd_wave_mixer_private.h"
+ $File "snd_wave_source.cpp"
+ $File "snd_wave_source.h"
+ $File "sound.cpp"
+ $File "sound.h"
+
+ $File "$SRCDIR\public\sentence.cpp"
+ {
+ $Configuration
+ {
+ $Compiler
+ {
+ $Create/UsePrecompiledHeader "Not Using Precompiled Headers"
+ }
+ }
+ }
+ }
+
+ $Folder "Link Libraries"
+ {
+ $Lib appframework
+ $Lib choreoobjects
+ $Lib mathlib
+ $Lib $LIBCOMMON\mxtoolkitwin32
+ $Lib tier2
+ $Lib tier3
+ }
+}
diff --git a/utils/scenemanager/scenemanager_tools.cpp b/utils/scenemanager/scenemanager_tools.cpp
new file mode 100644
index 0000000..884ee49
--- /dev/null
+++ b/utils/scenemanager/scenemanager_tools.cpp
@@ -0,0 +1,846 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//===========================================================================//
+#include "cbase.h"
+#include "StatusWindow.h"
+#include "cmdlib.h"
+#include <sys/stat.h>
+#include "workspace.h"
+#include "workspacemanager.h"
+#include "workspacebrowser.h"
+#include "tier2/riff.h"
+#include "sentence.h"
+#include "utlbuffer.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include <KeyValues.h>
+#include "MultipleRequest.h"
+
+bool SceneManager_HasWindowStyle( mxWindow *w, int bits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ return ( style & bits ) ? true : false;
+}
+
+bool SceneManager_HasWindowExStyle( mxWindow *w, int bits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_EXSTYLE );
+ return ( style & bits ) ? true : false;
+}
+
+void SceneManager_AddWindowStyle( mxWindow *w, int addbits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ style |= addbits;
+ SetWindowLong( wnd, GWL_STYLE, style );
+}
+
+void SceneManager_AddWindowExStyle( mxWindow *w, int addbits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_EXSTYLE );
+ style |= addbits;
+ SetWindowLong( wnd, GWL_EXSTYLE, style );
+}
+
+void SceneManager_RemoveWindowStyle( mxWindow *w, int removebits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ style &= ~removebits;
+ SetWindowLong( wnd, GWL_STYLE, style );
+}
+
+void SceneManager_RemoveWindowExStyle( mxWindow *w, int removebits )
+{
+ HWND wnd = (HWND)w->getHandle();
+ DWORD style = GetWindowLong( wnd, GWL_EXSTYLE );
+ style &= ~removebits;
+ SetWindowLong( wnd, GWL_EXSTYLE, style );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *w -
+//-----------------------------------------------------------------------------
+void SceneManager_MakeToolWindow( mxWindow *w, bool smallcaption )
+{
+ SceneManager_AddWindowStyle( w, WS_VISIBLE | WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+
+ if ( smallcaption )
+ {
+ SceneManager_AddWindowExStyle( w, WS_EX_OVERLAPPEDWINDOW );
+ SceneManager_AddWindowExStyle( w, WS_EX_TOOLWINDOW );
+ }
+ else
+ {
+ SceneManager_RemoveWindowStyle( w, WS_SYSMENU );
+ }
+}
+
+char *va( const char *fmt, ... )
+{
+ va_list args;
+ static char output[4][1024];
+ static int outbuffer = 0;
+
+ outbuffer++;
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output[ outbuffer & 3 ], fmt, args );
+ return output[ outbuffer & 3 ];
+}
+
+void Con_Overprintf( const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ if ( !g_pStatusWindow )
+ {
+ return;
+ }
+
+ g_pStatusWindow->StatusPrint( CONSOLE_R, CONSOLE_G, CONSOLE_B, true, output );
+}
+
+void Con_Printf( const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+// vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+ va_end( args );
+
+ if ( !g_pStatusWindow )
+ {
+ return;
+ }
+
+ g_pStatusWindow->StatusPrint( CONSOLE_R, CONSOLE_G, CONSOLE_B, false, output );
+}
+
+void Con_ColorPrintf( int r, int g, int b, const char *fmt, ... )
+{
+ va_list args;
+ static char output[1024];
+
+ va_start( args, fmt );
+ vprintf( fmt, args );
+ vsprintf( output, fmt, args );
+
+ if ( !g_pStatusWindow )
+ {
+ return;
+ }
+
+ g_pStatusWindow->StatusPrint( r, g, b, false, output );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pname -
+// Output : char
+//-----------------------------------------------------------------------------
+char *SceneManager_MakeWindowsSlashes( char *pname )
+{
+ static char returnString[ 4096 ];
+ strcpy( returnString, pname );
+ pname = returnString;
+
+ while ( *pname ) {
+ if ( *pname == '/' )
+ *pname = '\\';
+ pname++;
+ }
+
+ return returnString;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : const char
+//-----------------------------------------------------------------------------
+const char *SceneManager_GetGameDirectory( void )
+{
+ // Todo: Make SceneManager only use the filesystem read/write paths.
+ return gamedir;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Takes a full path and determines if the file exists on the disk
+// Input : *filename -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool SceneManager_FullpathFileExists( const char *filename )
+{
+ // Should be a full path
+ Assert( strchr( filename, ':' ) );
+
+ struct _stat buf;
+ int result = _stat( filename, &buf );
+ if ( result != -1 )
+ return true;
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: converts an english string to unicode
+//-----------------------------------------------------------------------------
+int ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSize)
+{
+ return ::MultiByteToWideChar(CP_ACP, 0, ansi, -1, unicode, unicodeBufferSize);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: converts an unicode string to an english string
+//-----------------------------------------------------------------------------
+int ConvertUnicodeToANSI(const wchar_t *unicode, char *ansi, int ansiBufferSize)
+{
+ return ::WideCharToMultiByte(CP_ACP, 0, unicode, -1, ansi, ansiBufferSize, NULL, NULL);
+}
+
+int Sys_Exec( const char *pProgName, const char *pCmdLine, bool verbose )
+{
+#if 0
+ int count = 0;
+ char cmdLine[1024];
+ STARTUPINFO si;
+
+ memset( &si, 0, sizeof(si) );
+ si.cb = sizeof(si);
+ //GetStartupInfo( &si );
+
+ sprintf( cmdLine, "%s %s", pProgName, pCmdLine );
+
+ PROCESS_INFORMATION pi;
+ memset( &pi, 0, sizeof( pi ) );
+
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+
+ if ( CreateProcess( NULL, cmdLine, NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi ) )
+ {
+ WaitForSingleObject( pi.hProcess, INFINITE );
+ /*
+ do
+ {
+ WaitForInputIdle( pi.hProcess, 100 );
+ count++;
+ } while ( count < 100 );
+ */
+
+ /*
+ DWORD exitCode = STILL_ACTIVE;
+ do
+ {
+ BOOL ok = GetExitCodeProcess( pi.hProcess, &exitCode );
+ if ( !ok )
+ break;
+ Sleep( 100 );
+ } while ( exitCode == STILL_ACTIVE );
+ */
+
+ DWORD exitCode;
+
+ GetExitCodeProcess( pi.hProcess, &exitCode );
+
+ Con_Printf( "Finished\n" );
+
+ CloseHandle( pi.hProcess );
+ return (int)exitCode;
+ }
+ else
+ {
+ char *lpMsgBuf;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ Con_Printf( "error %s\n", lpMsgBuf );
+
+ LocalFree( (HLOCAL)lpMsgBuf );
+ }
+
+ return false;
+#else
+ char tmp[1024];
+ sprintf( tmp, "%s %s\n", pProgName, pCmdLine );
+
+ _strlwr( tmp );
+
+ int iret = system( tmp );
+ if ( iret != 0 && verbose )
+ {
+ Con_Printf( "Execution failed: %s\n", tmp );
+ }
+
+ return iret;
+#endif
+}
+
+//-----------------------------------------------------------------------------
+// Checks it out/ checks it in baby
+//-----------------------------------------------------------------------------
+
+static void SceneManager_VSSCheckout( char const *pUserName, char const *pProjectDir,
+ char const* pRelativeDir, char const* pDestPath, char const* pFileNameWithExtension )
+{
+ char buf[1024];
+
+ // Check for the existence of the file in source safe...
+ sprintf( buf, "filetype %s/%s%s -O- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pUserName );
+ int retVal = Sys_Exec( "ss.exe", buf, false );
+ if (retVal != 0 )
+ {
+ Con_Printf( "File %s missing from VSS\n", pFileNameWithExtension );
+ return;
+ }
+
+ // It's there, try to check it out
+ sprintf( buf, "checkout %s/%s%s -GL%s -GWA -O- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pDestPath, pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+}
+
+//-----------------------------------------------------------------------------
+// Checks it out/ checks it in baby
+//-----------------------------------------------------------------------------
+
+static void SceneManager_VSSCheckin( char const *pUserName, char const *pProjectDir,
+ char const* pRelativeDir, char const* pDestPath, char const* pFileNameWithExtension )
+{
+ char buf[1024];
+
+ // Check for the existence of the file on disk. If it's not there, don't bother
+ sprintf( buf, "%s%s", pDestPath, pFileNameWithExtension );
+ struct _stat statbuf;
+ int result = _stat( buf, &statbuf );
+ if (result != 0)
+ return;
+
+ // Check for the existence of the file in source safe...
+ sprintf( buf, "filetype %s/%s%s -O- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pUserName );
+ int retVal = Sys_Exec( "ss.exe", buf, false );
+ if (retVal != 0)
+ {
+ sprintf( buf, "Cp %s -O- -y%s\n",
+ pProjectDir ,
+ pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+
+ // Try to add the file to source safe...
+ sprintf( buf, "add %s%s -GL%s -O- -I- -y%s\n",
+ pRelativeDir, pFileNameWithExtension,
+ pDestPath, pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+ }
+ else
+ {
+ // It's there, just check it in
+ sprintf( buf, "checkin %s/%s%s -GL%s -O- -I- -y%s\n",
+ pProjectDir, pRelativeDir, pFileNameWithExtension,
+ pDestPath, pUserName );
+ Sys_Exec( "ss.exe", buf, true );
+ }
+}
+
+void SplitFileName( char const *in, char *path, int maxpath, char *filename, int maxfilename )
+{
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+
+ _splitpath( in, drive, dir, fname, ext );
+
+ if ( dir[0] )
+ {
+ Q_snprintf( path, maxpath, "\\%s", dir );
+ }
+ else
+ {
+ path[0] = 0;
+ }
+ Q_snprintf( filename, maxfilename, "%s%s", fname, ext );
+}
+
+
+void VSS_Checkout( char const *name, bool updatestaticons /*= true*/ )
+{
+ CWorkspace *ws = GetWorkspaceManager()->GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ return;
+ }
+
+ if ( filesystem->IsFileWritable( name ) )
+ {
+ return;
+ }
+
+ char path[ 256 ];
+ char filename[ 256 ];
+
+ SplitFileName( name, path, sizeof( path ), filename, sizeof( filename ) );
+
+ Con_ColorPrintf( 200, 200, 100, "VSS Checkout: '%s'\n", name );
+
+ SceneManager_VSSCheckout(
+ ws->GetVSSUserName(),
+ ws->GetVSSProject(),
+ path,
+ va( "%s%s", gamedir, path ),
+ filename );
+
+ if ( updatestaticons )
+ {
+ GetWorkspaceManager()->RefreshBrowsers();
+ }
+}
+
+void VSS_Checkin( char const *name, bool updatestaticons /*= true*/ )
+{
+ CWorkspace *ws = GetWorkspaceManager()->GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ return;
+ }
+
+ if ( !filesystem->IsFileWritable( name ) )
+ {
+ return;
+ }
+
+ char path[ 256 ];
+ char filename[ 256 ];
+
+ SplitFileName( name, path, sizeof( path ), filename, sizeof( filename ) );
+
+ Con_ColorPrintf( 200, 200, 100, "VSS Checkin: '%s'\n", name );
+
+ SceneManager_VSSCheckin(
+ ws->GetVSSUserName(),
+ ws->GetVSSProject(),
+ path,
+ va( "%s%s", gamedir, path ),
+ filename );
+
+ if ( updatestaticons )
+ {
+ GetWorkspaceManager()->RefreshBrowsers();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements the RIFF i/o interface on stdio
+//-----------------------------------------------------------------------------
+class StdIOReadBinary : public IFileReadBinary
+{
+public:
+ int open( const char *pFileName )
+ {
+ return (int)filesystem->Open( pFileName, "rb" );
+ }
+
+ int read( void *pOutput, int size, int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Read( pOutput, size, (FileHandle_t)file );
+ }
+
+ void seek( int file, int pos )
+ {
+ if ( !file )
+ return;
+
+ filesystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
+ }
+
+ unsigned int tell( int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Tell( (FileHandle_t)file );
+ }
+
+ unsigned int size( int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Size( (FileHandle_t)file );
+ }
+
+ void close( int file )
+ {
+ if ( !file )
+ return;
+
+ filesystem->Close( (FileHandle_t)file );
+ }
+};
+
+class StdIOWriteBinary : public IFileWriteBinary
+{
+public:
+ int create( const char *pFileName )
+ {
+ return (int)filesystem->Open( pFileName, "wb" );
+ }
+
+ int write( void *pData, int size, int file )
+ {
+ return filesystem->Write( pData, size, (FileHandle_t)file );
+ }
+
+ void close( int file )
+ {
+ filesystem->Close( (FileHandle_t)file );
+ }
+
+ void seek( int file, int pos )
+ {
+ filesystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
+ }
+
+ unsigned int tell( int file )
+ {
+ return filesystem->Tell( (FileHandle_t)file );
+ }
+};
+
+static StdIOReadBinary io_in;
+static StdIOWriteBinary io_out;
+
+#define RIFF_WAVE MAKEID('W','A','V','E')
+#define WAVE_FMT MAKEID('f','m','t',' ')
+#define WAVE_DATA MAKEID('d','a','t','a')
+#define WAVE_FACT MAKEID('f','a','c','t')
+#define WAVE_CUE MAKEID('c','u','e',' ')
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &walk -
+//-----------------------------------------------------------------------------
+static void SceneManager_ParseSentence( CSentence& sentence, IterateRIFF &walk )
+{
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.EnsureCapacity( walk.ChunkSize() );
+ walk.ChunkRead( buf.Base() );
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, walk.ChunkSize() );
+
+ sentence.InitFromDataChunk( buf.Base(), buf.TellPut() );
+}
+
+bool SceneManager_LoadSentenceFromWavFileUsingIO( char const *wavfile, CSentence& sentence, IFileReadBinary& io )
+{
+ sentence.Reset();
+
+ InFileRIFF riff( wavfile, io );
+
+ // UNDONE: Don't use printf to handle errors
+ if ( riff.RIFFName() != RIFF_WAVE )
+ {
+ return false;
+ }
+
+ // set up the iterator for the whole file (root RIFF is a chunk)
+ IterateRIFF walk( riff, riff.RIFFSize() );
+
+ // This chunk must be first as it contains the wave's format
+ // break out when we've parsed it
+ bool found = false;
+ while ( walk.ChunkAvailable() && !found )
+ {
+ switch( walk.ChunkName() )
+ {
+ case WAVE_VALVEDATA:
+ {
+ found = true;
+ SceneManager_ParseSentence( sentence, walk );
+ }
+ break;
+ }
+ walk.ChunkNext();
+ }
+
+ return true;
+}
+
+bool SceneManager_LoadSentenceFromWavFile( char const *wavfile, CSentence& sentence )
+{
+ return SceneManager_LoadSentenceFromWavFileUsingIO( wavfile, sentence, io_in );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : store -
+//-----------------------------------------------------------------------------
+static void SceneManager_StoreValveDataChunk( CSentence& sentence, IterateOutputRIFF& store )
+{
+ // Buffer and dump data
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ sentence.SaveToBuffer( buf );
+
+ // Copy into store
+ store.ChunkWriteData( buf.Base(), buf.TellPut() );
+}
+
+bool SceneManager_SaveSentenceToWavFile( char const *wavfile, CSentence& sentence )
+{
+ char tempfile[ 512 ];
+
+ Q_StripExtension( wavfile, tempfile, sizeof( tempfile ) );
+ Q_DefaultExtension( tempfile, ".tmp", sizeof( tempfile ) );
+
+ if ( filesystem->FileExists( tempfile, "GAME" ) )
+ {
+ filesystem->RemoveFile( tempfile, "GAME" );
+ }
+
+ if ( !filesystem->IsFileWritable( wavfile ) )
+ {
+ int retval = MultipleRequest( va( "Check out '%s'?", wavfile ) );
+ if ( retval != 0 )
+ return false;
+
+ VSS_Checkout( wavfile );
+ }
+
+ if ( !filesystem->IsFileWritable( wavfile ) )
+ {
+ Con_Printf( "%s is not writable, can't save sentence data to file\n", wavfile );
+ return false;
+ }
+
+ // Rename original wavfile to temp
+ filesystem->RenameFile( wavfile, tempfile, "GAME" );
+
+ // NOTE: Put this in it's own scope so that the destructor for outfileRFF actually closes the file!!!!
+ {
+ // Read from Temp
+ InFileRIFF riff( tempfile, io_in );
+ Assert( riff.RIFFName() == RIFF_WAVE );
+
+ // set up the iterator for the whole file (root RIFF is a chunk)
+ IterateRIFF walk( riff, riff.RIFFSize() );
+
+ // And put data back into original wavfile by name
+ OutFileRIFF riffout( wavfile, io_out );
+
+ IterateOutputRIFF store( riffout );
+
+ bool wordtrackwritten = false;
+
+ // Walk input chunks and copy to output
+ while ( walk.ChunkAvailable() )
+ {
+ store.ChunkStart( walk.ChunkName() );
+
+ switch ( walk.ChunkName() )
+ {
+ case WAVE_VALVEDATA:
+ {
+ // Overwrite data
+ SceneManager_StoreValveDataChunk( sentence, store );
+ wordtrackwritten = true;
+ }
+ break;
+ default:
+ store.CopyChunkData( walk );
+ break;
+ }
+
+ store.ChunkFinish();
+
+ walk.ChunkNext();
+ }
+
+ // If we didn't write it above, write it now
+ if ( !wordtrackwritten )
+ {
+ store.ChunkStart( WAVE_VALVEDATA );
+ SceneManager_StoreValveDataChunk( sentence, store );
+ store.ChunkFinish();
+ }
+ }
+
+ // Remove temp file
+ filesystem->RemoveFile( tempfile, NULL );
+
+ return true;
+}
+
+
+void SceneManager_LoadWindowPositions( KeyValues *kv, mxWindow *wnd )
+{
+ bool zoomed = kv->GetInt( "zoomed", 0 ) ? true : false;
+ int x = kv->GetInt( "x", 0 );
+ int y = kv->GetInt( "y", 0 );
+ int w = kv->GetInt( "w", 400 );
+ int h = kv->GetInt( "h", 300 );
+
+ wnd->setBounds( x, y, w, h );
+ if ( zoomed )
+ {
+ ShowWindow( (HWND)wnd->getHandle(), SW_SHOWMAXIMIZED );
+ }
+}
+
+static void Indent( CUtlBuffer& buf, int numtabs )
+{
+ for ( int i = 0 ; i < numtabs; i++ )
+ {
+ buf.Printf( "\t" );
+ }
+}
+
+void SceneManager_SaveWindowPositions( CUtlBuffer& buf, int indent, mxWindow *wnd )
+{
+ int x, y, w, h;
+
+ x = wnd->x();
+ y = wnd->y();
+ w = wnd->w();
+ h = wnd->h();
+
+ // xpos and ypos are screen space
+ POINT pt;
+ pt.x = x;
+ pt.y = y;
+
+ // Convert from screen space to relative to client area of parent window so
+ // the setBounds == MoveWindow call will offset to the same location
+ if ( wnd->getParent() )
+ {
+ ScreenToClient( (HWND)wnd->getParent()->getHandle(), &pt );
+ x = (short)pt.x;
+ y = (short)pt.y;
+ }
+
+
+ Indent( buf, indent );
+ buf.Printf( "\"x\"\t\"%i\"\n", x );
+
+ Indent( buf, indent );
+ buf.Printf( "\"y\"\t\"%i\"\n", y );
+
+ Indent( buf, indent );
+ buf.Printf( "\"w\"\t\"%i\"\n", w );
+
+ Indent( buf, indent );
+ buf.Printf( "\"h\"\t\"%i\"\n", h );
+
+ bool zoomed = IsZoomed( (HWND)wnd->getHandle() ) ? true : false;
+
+ Indent( buf, indent );
+ buf.Printf( "\"zoomed\"\t\"%i\"\n", zoomed ? 1 : 0 );
+
+}
+#if defined( _WIN32 ) || defined( WIN32 )
+#define PATHSEPARATOR(c) ((c) == '\\' || (c) == '/')
+#else //_WIN32
+#define PATHSEPARATOR(c) ((c) == '/')
+#endif //_WIN32
+
+static bool charsmatch( char c1, char c2 )
+{
+ if ( tolower( c1 ) == tolower( c2 ) )
+ return true;
+ if ( PATHSEPARATOR( c1 ) && PATHSEPARATOR( c2 ) )
+ return true;
+ return false;
+}
+
+
+char *Q_stristr_slash( char const *pStr, char const *pSearch )
+{
+ AssertValidStringPtr(pStr);
+ AssertValidStringPtr(pSearch);
+
+ if (!pStr || !pSearch)
+ return 0;
+
+ char const* pLetter = pStr;
+
+ // Check the entire string
+ while (*pLetter != 0)
+ {
+ // Skip over non-matches
+ if ( charsmatch( *pLetter, *pSearch ) )
+ {
+ // Check for match
+ char const* pMatch = pLetter + 1;
+ char const* pTest = pSearch + 1;
+ while (*pTest != 0)
+ {
+ // We've run off the end; don't bother.
+ if (*pMatch == 0)
+ return 0;
+
+ if ( !charsmatch( *pMatch, *pTest ) )
+ break;
+
+ ++pMatch;
+ ++pTest;
+ }
+
+ // Found a match!
+ if (*pTest == 0)
+ return (char *)pLetter;
+ }
+
+ ++pLetter;
+ }
+
+ return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *filename -
+//-----------------------------------------------------------------------------
+void MakeFileWriteable( const char *filename )
+{
+ Assert( filesystem );
+ char fullpath[ 512 ];
+ if (filesystem->GetLocalPath( filename, fullpath, sizeof(fullpath) ))
+ {
+ Q_FixSlashes( fullpath );
+ SetFileAttributes( fullpath, FILE_ATTRIBUTE_NORMAL );
+ }
+} \ No newline at end of file
diff --git a/utils/scenemanager/scenemanager_tools.h b/utils/scenemanager/scenemanager_tools.h
new file mode 100644
index 0000000..8bbef40
--- /dev/null
+++ b/utils/scenemanager/scenemanager_tools.h
@@ -0,0 +1,58 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SCENEMANAGER_TOOLS_H
+#define SCENEMANAGER_TOOLS_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class mxWindow;
+class ITreeItem;
+
+#define ERROR_R 255
+#define ERROR_G 102
+#define ERROR_B 0
+
+#define CONSOLE_R 82
+#define CONSOLE_G 173
+#define CONSOLE_B 216
+
+class CSentence;
+class KeyValues;
+class CUtlBuffer;
+
+bool SceneManager_LoadSentenceFromWavFile( char const *wavfile, CSentence& sentence );
+bool SceneManager_SaveSentenceToWavFile( char const *wavfile, CSentence& sentence );
+
+void SceneManager_AddWindowStyle( mxWindow *w, int addbits );
+void SceneManager_MakeToolWindow( mxWindow *w, bool smallcaption );
+
+char *va( PRINTF_FORMAT_STRING const char *fmt, ... );
+void Con_Printf( PRINTF_FORMAT_STRING const char *fmt, ... );
+void Con_Overprintf( PRINTF_FORMAT_STRING const char *fmt, ... );
+void Con_ColorPrintf( int r, int g, int b, PRINTF_FORMAT_STRING const char *fmt, ... );
+
+char *SceneManager_MakeWindowsSlashes( char *pname );
+const char *SceneManager_GetGameDirectory( void );
+bool SceneManager_FullpathFileExists( const char *filename );
+
+int ConvertANSIToUnicode(const char *ansi, wchar_t *unicode, int unicodeBufferSize);
+int ConvertUnicodeToANSI(const wchar_t *unicode, char *ansi, int ansiBufferSize);
+
+extern class IFileSystem *filesystem;
+
+extern char g_appTitle[];
+
+void VSS_Checkout( char const *name, bool updatestaticons = true );
+void VSS_Checkin( char const *name, bool updatestaticons = true );
+
+void SceneManager_LoadWindowPositions( KeyValues *kv, mxWindow *wnd );
+void SceneManager_SaveWindowPositions( CUtlBuffer& buf, int indent, mxWindow *wnd );
+
+void MakeFileWriteable( const char *filename );
+
+#endif // SCENEMANAGER_TOOLS_H
diff --git a/utils/scenemanager/snd_audio_source.cpp b/utils/scenemanager/snd_audio_source.cpp
new file mode 100644
index 0000000..3688a8a
--- /dev/null
+++ b/utils/scenemanager/snd_audio_source.cpp
@@ -0,0 +1,56 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include <stdio.h>
+#include "snd_audio_source.h"
+#include "iscenemanagersound.h"
+
+extern CAudioSource *Audio_CreateMemoryWave( const char *pName );
+
+//-----------------------------------------------------------------------------
+// Purpose: Simple wrapper to crack naming convention and create the proper wave source
+// Input : *pName - WAVE filename
+// Output : CAudioSource
+//-----------------------------------------------------------------------------
+CAudioSource *AudioSource_Create( const char *pName )
+{
+ if ( !pName )
+ return NULL;
+
+// if ( pName[0] == '!' ) // sentence
+ ;
+
+ // Names that begin with "*" are streaming.
+ // Skip over the * and create a streamed source
+ if ( pName[0] == '*' )
+ {
+
+ return NULL;
+ }
+
+ // These are loaded into memory directly
+ return Audio_CreateMemoryWave( pName );
+}
+
+CAudioSource::~CAudioSource( void )
+{
+ CAudioMixer *mixer;
+
+ while ( 1 )
+ {
+ mixer = sound->FindMixer( this );
+ if ( !mixer )
+ break;
+
+ sound->StopSound( mixer );
+ }
+}
+
+CAudioSource::CAudioSource( void )
+{
+}
diff --git a/utils/scenemanager/snd_audio_source.h b/utils/scenemanager/snd_audio_source.h
new file mode 100644
index 0000000..4df17f6
--- /dev/null
+++ b/utils/scenemanager/snd_audio_source.h
@@ -0,0 +1,119 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SND_AUDIO_SOURCE_H
+#define SND_AUDIO_SOURCE_H
+#pragma once
+
+
+// fixed point stuff for real-time resampling
+#define FIX_BITS 28
+#define FIX_SCALE (1 << FIX_BITS)
+#define FIX_MASK ((1 << FIX_BITS)-1)
+#define FIX_FLOAT(a) ((int)((a) * FIX_SCALE))
+#define FIX(a) (((int)(a)) << FIX_BITS)
+#define FIX_INTPART(a) (((int)(a)) >> FIX_BITS)
+#define FIX_FRACTION(a,b) (FIX(a)/(b))
+#define FIX_FRACPART(a) ((a) & FIX_MASK)
+
+typedef unsigned int fixedint;
+
+typedef struct channel_s channel_t;
+
+class CAudioSource;
+
+class IAudioDevice
+{
+public:
+ // Add a virtual destructor to silence the clang warning.
+ // This is harmless but not important since the only derived class
+ // doesn't have a destructor.
+ virtual ~IAudioDevice() {}
+
+ virtual void MixBegin( void ) = 0;
+ virtual void Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0;
+ virtual void Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0;
+ virtual void Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0;
+ virtual void Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward = true ) = 0;
+ virtual int MaxSampleCount( void ) = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: This is an instance of an audio source.
+// Mixers are attached to channels and reference an audio source.
+// Mixers are specific to the sample format and source format.
+// Mixers are never re-used, so they can track instance data like
+// sample position, fractional sample, stream cache, faders, etc.
+//-----------------------------------------------------------------------------
+class CAudioMixer
+{
+public:
+ virtual ~CAudioMixer( void ) {}
+
+ // UNDONE: time compress
+ virtual bool MixDataToDevice( IAudioDevice *pDevice, channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward = true ) = 0;
+ virtual void IncrementSamples( channel_t *pChannel, int startSample, int sampleCount,int outputRate, bool forward = true ) = 0;
+ virtual bool SkipSamples( channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward = true ) = 0;
+
+ virtual CAudioSource *GetSource( void ) = 0;
+
+ virtual int GetSamplePosition( void ) = 0;
+
+ virtual bool SetSamplePosition( int position ) = 0;
+ virtual void SetLoopPosition( int position ) = 0;
+ virtual int GetStartPosition( void ) = 0;
+
+ virtual bool GetActive( void ) = 0;
+ virtual void SetActive( bool active ) = 0;
+
+ virtual void SetModelIndex( int index ) = 0;
+ virtual int GetModelIndex( void ) const = 0;
+
+ virtual void SetDirection( bool forward ) = 0;
+ virtual bool GetDirection( void ) const = 0;
+
+ virtual void SetAutoDelete( bool autodelete ) = 0;
+ virtual bool GetAutoDelete( void ) const = 0;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: A source is an abstraction for a stream, cached file, or procedural
+// source of audio.
+//-----------------------------------------------------------------------------
+class CSentence;
+
+class CAudioSource
+{
+public:
+ CAudioSource( void );
+ virtual ~CAudioSource( void );
+
+ // Create an instance (mixer) of this audio source
+ virtual CAudioMixer *CreateMixer( void ) = 0;
+ virtual int GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward = true ) = 0;
+ virtual int SampleRate( void ) = 0;
+ virtual int SampleSize( void ) = 0;
+ virtual int SampleCount( void ) = 0;
+ virtual float TrueSampleSize( void ) = 0;
+ virtual bool IsLooped( void ) = 0;
+ virtual bool IsStreaming( void ) = 0;
+ virtual float GetRunningLength( void ) = 0;
+
+ virtual CSentence *GetSentence( void ) { return NULL; };
+
+};
+
+
+extern CAudioSource *AudioSource_Create( const char *pName );
+
+#endif // SND_AUDIO_SOURCE_H
diff --git a/utils/scenemanager/snd_wave_mixer.cpp b/utils/scenemanager/snd_wave_mixer.cpp
new file mode 100644
index 0000000..50f4a48
--- /dev/null
+++ b/utils/scenemanager/snd_wave_mixer.cpp
@@ -0,0 +1,492 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include <stdio.h>
+#include <windows.h>
+#include "snd_audio_source.h"
+#include "snd_wave_source.h"
+#include "snd_wave_mixer_private.h"
+#include "snd_wave_mixer_adpcm.h"
+#include "iscenemanagersound.h"
+#include "AudioWaveOutput.h"
+#include "tier2/riff.h"
+
+typedef struct channel_s
+{
+ int leftvol;
+ int rightvol;
+ int rleftvol;
+ int rrightvol;
+ float pitch;
+} channel_t;
+
+//-----------------------------------------------------------------------------
+// These mixers provide an abstraction layer between the audio device and
+// mixing/decoding code. They allow data to be decoded and mixed using
+// optimized, format sensitive code by calling back into the device that
+// controls them.
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// Purpose: maps mixing to 8-bit mono mixer
+//-----------------------------------------------------------------------------
+class CAudioMixerWave8Mono : public CAudioMixerWave
+{
+public:
+ CAudioMixerWave8Mono( CWaveData *data ) : CAudioMixerWave( data ) {}
+ virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true )
+ {
+ pDevice->Mix8Mono( pChannel, (char *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward );
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: maps mixing to 8-bit stereo mixer
+//-----------------------------------------------------------------------------
+class CAudioMixerWave8Stereo : public CAudioMixerWave
+{
+public:
+ CAudioMixerWave8Stereo( CWaveData *data ) : CAudioMixerWave( data ) {}
+ virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true )
+ {
+ pDevice->Mix8Stereo( pChannel, (char *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward );
+ }
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: maps mixing to 16-bit mono mixer
+//-----------------------------------------------------------------------------
+class CAudioMixerWave16Mono : public CAudioMixerWave
+{
+public:
+ CAudioMixerWave16Mono( CWaveData *data ) : CAudioMixerWave( data ) {}
+ virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true )
+ {
+ pDevice->Mix16Mono( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward );
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: maps mixing to 16-bit stereo mixer
+//-----------------------------------------------------------------------------
+class CAudioMixerWave16Stereo : public CAudioMixerWave
+{
+public:
+ CAudioMixerWave16Stereo( CWaveData *data ) : CAudioMixerWave( data ) {}
+ virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true )
+ {
+ pDevice->Mix16Stereo( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward );
+ }
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Create an approprite mixer type given the data format
+// Input : *data - data access abstraction
+// format - pcm or adpcm (1 or 2 -- RIFF format)
+// channels - number of audio channels (1 = mono, 2 = stereo)
+// bits - bits per sample
+// Output : CAudioMixer * abstract mixer type that maps mixing to appropriate code
+//-----------------------------------------------------------------------------
+CAudioMixer *CreateWaveMixer( CWaveData *data, int format, int channels, int bits )
+{
+ if ( format == WAVE_FORMAT_PCM )
+ {
+ if ( channels > 1 )
+ {
+ if ( bits == 8 )
+ return new CAudioMixerWave8Stereo( data );
+ else
+ return new CAudioMixerWave16Stereo( data );
+ }
+ else
+ {
+ if ( bits == 8 )
+ return new CAudioMixerWave8Mono( data );
+ else
+ return new CAudioMixerWave16Mono( data );
+ }
+ }
+ else if ( format == WAVE_FORMAT_ADPCM )
+ {
+ return CreateADPCMMixer( data );
+ }
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Init the base WAVE mixer.
+// Input : *data - data access object
+//-----------------------------------------------------------------------------
+CAudioMixerWave::CAudioMixerWave( CWaveData *data ) : m_pData(data)
+{
+ m_loop = 0;
+ m_sample = 0;
+ m_absoluteSample = 0;
+ m_fracOffset = 0;
+ m_bActive = false;
+ m_nModelIndex = -1;
+ m_bForward = true;
+ m_bAutoDelete = true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Frees the data access object (we own it after construction)
+//-----------------------------------------------------------------------------
+CAudioMixerWave::~CAudioMixerWave( void )
+{
+ delete m_pData;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Decode and read the data
+// by default we just pass the request on to the data access object
+// other mixers may need to buffer or decode the data for some reason
+//
+// Input : **pData - dest pointer
+// sampleCount - number of samples needed
+// Output : number of samples available in this batch
+//-----------------------------------------------------------------------------
+int CAudioMixerWave::GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward /*= true*/ )
+{
+ if ( samplePosition != m_sample )
+ {
+ // Seek
+ m_sample = samplePosition;
+ m_absoluteSample = samplePosition;
+ }
+
+ return m_pData->ReadSourceData( pData, m_sample, sampleCount, forward );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: calls through the wavedata to get the audio source
+// Output : CAudioSource
+//-----------------------------------------------------------------------------
+CAudioSource *CAudioMixerWave::GetSource( void )
+{
+ if ( m_pData )
+ return &m_pData->Source();
+
+ return NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Gets the current sample location in playback
+// Output : int (samples from start of wave)
+//-----------------------------------------------------------------------------
+int CAudioMixerWave::GetSamplePosition( void )
+{
+ return m_sample;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : position -
+//-----------------------------------------------------------------------------
+bool CAudioMixerWave::SetSamplePosition( int position )
+{
+ position = max( 0, position );
+
+ m_sample = position;
+ m_absoluteSample = position;
+ m_startpos = m_sample;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : position -
+//-----------------------------------------------------------------------------
+void CAudioMixerWave::SetLoopPosition( int position )
+{
+ m_loop = position;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CAudioMixerWave::GetStartPosition( void )
+{
+ return m_startpos;
+}
+
+bool CAudioMixerWave::GetActive( void )
+{
+ return m_bActive;
+}
+
+void CAudioMixerWave::SetActive( bool active )
+{
+ m_bActive = active;
+}
+
+void CAudioMixerWave::SetModelIndex( int index )
+{
+ m_nModelIndex = index;
+}
+
+int CAudioMixerWave::GetModelIndex( void ) const
+{
+ return m_nModelIndex;
+}
+
+void CAudioMixerWave::SetDirection( bool forward )
+{
+ m_bForward = forward;
+}
+
+bool CAudioMixerWave::GetDirection( void ) const
+{
+ return m_bForward;
+}
+
+void CAudioMixerWave::SetAutoDelete( bool autodelete )
+{
+ m_bAutoDelete = autodelete;
+}
+
+bool CAudioMixerWave::GetAutoDelete( void ) const
+{
+ return m_bAutoDelete;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *pChannel -
+// sampleCount -
+// outputRate -
+//-----------------------------------------------------------------------------
+void CAudioMixerWave::IncrementSamples( channel_t *pChannel, int startSample, int sampleCount,int outputRate, bool forward /*= true*/ )
+{
+ int inputSampleRate = (int)(pChannel->pitch * m_pData->Source().SampleRate());
+ float rate = (float)inputSampleRate / outputRate;
+
+ int startpos = startSample;
+
+ if ( !forward )
+ {
+ int requestedstart = startSample - (int)( sampleCount * rate );
+ if ( requestedstart < 0 )
+ return;
+
+ startpos = max( 0, requestedstart );
+ SetSamplePosition( startpos );
+ }
+
+ while ( sampleCount > 0 )
+ {
+ int inputSampleCount;
+ int outputSampleCount = sampleCount;
+
+ if ( outputRate != inputSampleRate )
+ {
+ inputSampleCount = (int)(sampleCount * rate);
+ }
+ else
+ {
+ inputSampleCount = sampleCount;
+ }
+
+ sampleCount -= outputSampleCount;
+ if ( forward )
+ {
+ m_sample += inputSampleCount;
+ m_absoluteSample += inputSampleCount;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The device calls this to request data. The mixer must provide the
+// full amount of samples or have silence in its output stream.
+// Input : *pDevice - requesting device
+// sampleCount - number of samples at the output rate
+// outputRate - sampling rate of the request
+// Output : Returns true to keep mixing, false to delete this mixer
+//-----------------------------------------------------------------------------
+bool CAudioMixerWave::SkipSamples( channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward /*= true*/ )
+{
+ int offset = 0;
+
+ int inputSampleRate = (int)(pChannel->pitch * m_pData->Source().SampleRate());
+ float rate = (float)inputSampleRate / outputRate;
+ // fixedint fracstep = FIX_FLOAT( rate );
+
+ sampleCount = min( sampleCount, PAINTBUFFER_SIZE );
+
+ int startpos = startSample;
+
+ if ( !forward )
+ {
+ int requestedstart = startSample - (int)( sampleCount * rate );
+ if ( requestedstart < 0 )
+ return false;
+
+ startpos = max( 0, requestedstart );
+ SetSamplePosition( startpos );
+ }
+
+ while ( sampleCount > 0 )
+ {
+ int availableSamples;
+ int inputSampleCount;
+ char *pData = NULL;
+ int outputSampleCount = sampleCount;
+
+ if ( outputRate != inputSampleRate )
+ {
+ inputSampleCount = (int)(sampleCount * rate);
+ if ( !forward )
+ {
+ startSample = max( 0, startSample - inputSampleCount );
+ }
+ int availableSamples = GetOutputData( (void **)&pData, startSample, inputSampleCount, forward );
+ if ( !availableSamples )
+ break;
+
+ if ( availableSamples < inputSampleCount )
+ {
+ outputSampleCount = (int)(availableSamples / rate);
+ inputSampleCount = availableSamples;
+ }
+
+ // compute new fraction part of sample index
+ float offset = (m_fracOffset / FIX_SCALE) + (rate * outputSampleCount);
+ offset = offset - (float)((int)offset);
+ m_fracOffset = FIX_FLOAT(offset);
+ }
+ else
+ {
+ if ( !forward )
+ {
+ startSample = max( 0, startSample - sampleCount );
+ }
+ availableSamples = GetOutputData( (void **)&pData, startSample, sampleCount, forward );
+ if ( !availableSamples )
+ break;
+ outputSampleCount = availableSamples;
+ inputSampleCount = availableSamples;
+
+ }
+ offset += outputSampleCount;
+ sampleCount -= outputSampleCount;
+ if ( forward )
+ {
+ m_sample += inputSampleCount;
+ m_absoluteSample += inputSampleCount;
+ }
+
+ if ( m_loop != 0 && m_sample >= m_loop )
+ {
+ SetSamplePosition( m_startpos );
+ }
+
+ }
+
+ if ( sampleCount > 0 )
+ return false;
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: The device calls this to request data. The mixer must provide the
+// full amount of samples or have silence in its output stream.
+// Input : *pDevice - requesting device
+// sampleCount - number of samples at the output rate
+// outputRate - sampling rate of the request
+// Output : Returns true to keep mixing, false to delete this mixer
+//-----------------------------------------------------------------------------
+bool CAudioMixerWave::MixDataToDevice( IAudioDevice *pDevice, channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward /*= true*/ )
+{
+ int offset = 0;
+
+ int inputSampleRate = (int)(pChannel->pitch * m_pData->Source().SampleRate());
+ float rate = (float)inputSampleRate / outputRate;
+ fixedint fracstep = FIX_FLOAT( rate );
+
+ sampleCount = min( sampleCount, PAINTBUFFER_SIZE );
+
+ int startpos = startSample;
+
+ if ( !forward )
+ {
+ int requestedstart = startSample - (int)( sampleCount * rate );
+ if ( requestedstart < 0 )
+ return false;
+
+ startpos = max( 0, requestedstart );
+ SetSamplePosition( startpos );
+ }
+
+ while ( sampleCount > 0 )
+ {
+ int availableSamples;
+ int inputSampleCount;
+ char *pData = NULL;
+ int outputSampleCount = sampleCount;
+
+
+ if ( outputRate != inputSampleRate )
+ {
+ inputSampleCount = (int)(sampleCount * rate);
+
+ int availableSamples = GetOutputData( (void **)&pData, startpos, inputSampleCount, forward );
+ if ( !availableSamples )
+ break;
+
+ if ( availableSamples < inputSampleCount )
+ {
+ outputSampleCount = (int)(availableSamples / rate);
+ inputSampleCount = availableSamples;
+ }
+
+ Mix( pDevice, pChannel, pData, offset, m_fracOffset, fracstep, outputSampleCount, 0, forward );
+
+ // compute new fraction part of sample index
+ float offset = (m_fracOffset / FIX_SCALE) + (rate * outputSampleCount);
+ offset = offset - (float)((int)offset);
+ m_fracOffset = FIX_FLOAT(offset);
+ }
+ else
+ {
+ availableSamples = GetOutputData( (void **)&pData, startpos, sampleCount, forward );
+ if ( !availableSamples )
+ break;
+
+ outputSampleCount = availableSamples;
+ inputSampleCount = availableSamples;
+
+ Mix( pDevice, pChannel, pData, offset, m_fracOffset, FIX(1), outputSampleCount, 0, forward );
+ }
+ offset += outputSampleCount;
+ sampleCount -= outputSampleCount;
+
+ if ( forward )
+ {
+ m_sample += inputSampleCount;
+ m_absoluteSample += inputSampleCount;
+ }
+
+ if ( m_loop != 0 && m_sample >= m_loop )
+ {
+ SetSamplePosition( m_startpos );
+ }
+
+ }
+
+ if ( sampleCount > 0 )
+ return false;
+
+ return true;
+}
diff --git a/utils/scenemanager/snd_wave_mixer.h b/utils/scenemanager/snd_wave_mixer.h
new file mode 100644
index 0000000..07e019b
--- /dev/null
+++ b/utils/scenemanager/snd_wave_mixer.h
@@ -0,0 +1,24 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SND_WAVE_MIXER_H
+#define SND_WAVE_MIXER_H
+#pragma once
+
+class CWaveData;
+class CAudioMixer;
+
+CAudioMixer *CreateWaveMixer( CWaveData *data, int format, int channels, int bits );
+
+
+#endif // SND_WAVE_MIXER_H
diff --git a/utils/scenemanager/snd_wave_mixer_adpcm.cpp b/utils/scenemanager/snd_wave_mixer_adpcm.cpp
new file mode 100644
index 0000000..e3f7497
--- /dev/null
+++ b/utils/scenemanager/snd_wave_mixer_adpcm.cpp
@@ -0,0 +1,511 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#include <mmreg.h>
+#include "snd_wave_source.h"
+#include "snd_wave_mixer_adpcm.h"
+#include "snd_wave_mixer_private.h"
+
+// max size of ADPCM block in bytes
+#define MAX_BLOCK_SIZE 4096
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Mixer for ADPCM encoded audio
+//-----------------------------------------------------------------------------
+class CAudioMixerWaveADPCM : public CAudioMixerWave
+{
+public:
+ CAudioMixerWaveADPCM( CWaveData *data );
+ ~CAudioMixerWaveADPCM( void );
+
+ virtual void Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward = true );
+ virtual int GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward = true );
+
+ virtual bool SetSamplePosition( int position );
+
+private:
+ bool DecodeBlock( void );
+ int NumChannels( void );
+ void DecompressBlockMono( short *pOut, const char *pIn, int count );
+ void DecompressBlockStereo( short *pOut, const char *pIn, int count );
+
+ void SetCurrentBlock( int block );
+ int GetCurrentBlock( void ) const;
+ int GetBlockNumberForSample( int samplePosition );
+ bool IsSampleInCurrentBlock( int samplePosition );
+ int GetFirstSampleForBlock( int blocknum ) const;
+
+ const ADPCMWAVEFORMAT *m_pFormat;
+ const ADPCMCOEFSET *m_pCoefficients;
+
+ short *m_pSamples;
+ int m_sampleCount;
+ int m_samplePosition;
+
+ int m_blockSize;
+ int m_offset;
+
+ int m_currentBlock;
+};
+
+
+CAudioMixerWaveADPCM::CAudioMixerWaveADPCM( CWaveData *data ) : CAudioMixerWave( data )
+{
+ m_currentBlock = -1;
+ m_pSamples = NULL;
+ m_sampleCount = 0;
+ m_samplePosition = 0;
+ m_offset = 0;
+
+ m_pFormat = (const ADPCMWAVEFORMAT *)m_pData->Source().GetHeader();
+ if ( m_pFormat )
+ {
+ m_pCoefficients = (ADPCMCOEFSET *)((char *)m_pFormat + sizeof(WAVEFORMATEX) + 4);
+
+ // create the decode buffer
+ m_pSamples = new short[m_pFormat->wSamplesPerBlock * m_pFormat->wfx.nChannels];
+
+ // number of bytes for samples
+ m_blockSize = ((m_pFormat->wSamplesPerBlock - 2) * m_pFormat->wfx.nChannels ) / 2;
+ // size of channel header
+ m_blockSize += 7 * m_pFormat->wfx.nChannels;
+// Assert(m_blockSize < MAX_BLOCK_SIZE);
+ }
+}
+
+
+CAudioMixerWaveADPCM::~CAudioMixerWaveADPCM( void )
+{
+ delete[] m_pSamples;
+}
+
+
+int CAudioMixerWaveADPCM::NumChannels( void )
+{
+ if ( m_pFormat )
+ {
+ return m_pFormat->wfx.nChannels;
+ }
+ return 0;
+}
+
+void CAudioMixerWaveADPCM::Mix( IAudioDevice *pDevice, channel_t *pChannel, void *pData, int outputOffset, int inputOffset, fixedint fracRate, int outCount, int timecompress, bool forward /*= true*/ )
+{
+ if ( NumChannels() == 1 )
+ pDevice->Mix16Mono( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward );
+ else
+ pDevice->Mix16Stereo( pChannel, (short *)pData, outputOffset, inputOffset, fracRate, outCount, timecompress, forward );
+}
+
+
+static int error_sign_lut[] = { 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1 };
+static int error_coefficients_lut[] = { 230, 230, 230, 230, 307, 409, 512, 614,
+ 768, 614, 512, 409, 307, 230, 230, 230 };
+
+//-----------------------------------------------------------------------------
+// Purpose: ADPCM decompress a single block of 1-channel audio
+// Input : *pOut - output buffer 16-bit
+// *pIn - input block
+// count - number of samples to decode (to support partial blocks)
+//-----------------------------------------------------------------------------
+void CAudioMixerWaveADPCM::DecompressBlockMono( short *pOut, const char *pIn, int count )
+{
+
+ int pred = *pIn++;
+ int co1 = m_pCoefficients[pred].iCoef1;
+ int co2 = m_pCoefficients[pred].iCoef2;
+
+ // read initial delta
+ int delta = *((short *)pIn);
+ pIn += 2;
+
+ // read initial samples for prediction
+ int samp1 = *((short *)pIn);
+ pIn += 2;
+
+ int samp2 = *((short *)pIn);
+ pIn += 2;
+
+ // write out the initial samples (stored in reverse order)
+ *pOut++ = (short)samp2;
+ *pOut++ = (short)samp1;
+
+ // subtract the 2 samples in the header
+ count -= 2;
+
+ // this is a toggle to read nibbles, first nibble is high
+ int high = 1;
+
+ int error = 0, sample = 0;
+
+ // now process the block
+ while ( count )
+ {
+ // read the error nibble from the input stream
+ if ( high )
+ {
+ sample = (unsigned char) (*pIn++);
+ // high nibble
+ error = sample >> 4;
+ // cache low nibble for next read
+ sample = sample & 0xf;
+ // Next read is from cache, not stream
+ high = 0;
+ }
+ else
+ {
+ // stored in previous read (low nibble)
+ error = sample;
+ // next read is from stream
+ high = 1;
+ }
+ // convert to signed with LUT
+ int errorSign = error_sign_lut[error];
+
+ // interpolate the new sample
+ int predSample = (samp1 * co1) + (samp2 * co2);
+ // coefficients are fixed point 8-bit, so shift back to 16-bit integer
+ predSample >>= 8;
+
+ // Add in current error estimate
+ predSample += (errorSign * delta);
+
+ // Correct error estimate
+ delta = (delta * error_coefficients_lut[error]) >> 8;
+ // Clamp error estimate
+ if ( delta < 16 )
+ delta = 16;
+
+ // clamp
+ if ( predSample > 32767L )
+ predSample = 32767L;
+ else if ( predSample < -32768L )
+ predSample = -32768L;
+
+ // output
+ *pOut++ = (short)predSample;
+ // move samples over
+ samp2 = samp1;
+ samp1 = predSample;
+
+ count--;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Decode a single block of stereo ADPCM audio
+// Input : *pOut - 16-bit output buffer
+// *pIn - ADPCM encoded block data
+// count - number of sample pairs to decode
+//-----------------------------------------------------------------------------
+void CAudioMixerWaveADPCM::DecompressBlockStereo( short *pOut, const char *pIn, int count )
+{
+ int pred[2], co1[2], co2[2];
+ int i;
+
+ for ( i = 0; i < 2; i++ )
+ {
+ pred[i] = *pIn++;
+ co1[i] = m_pCoefficients[pred[i]].iCoef1;
+ co2[i] = m_pCoefficients[pred[i]].iCoef2;
+ }
+
+ int delta[2], samp1[2], samp2[2];
+
+ for ( i = 0; i < 2; i++, pIn += 2 )
+ {
+ // read initial delta
+ delta[i] = *((short *)pIn);
+ }
+
+ // read initial samples for prediction
+ for ( i = 0; i < 2; i++, pIn += 2 )
+ {
+ samp1[i] = *((short *)pIn);
+ }
+ for ( i = 0; i < 2; i++, pIn += 2 )
+ {
+ samp2[i] = *((short *)pIn);
+ }
+
+ // write out the initial samples (stored in reverse order)
+ *pOut++ = (short)samp2[0]; // left
+ *pOut++ = (short)samp2[1]; // right
+ *pOut++ = (short)samp1[0]; // left
+ *pOut++ = (short)samp1[1]; // right
+
+ // subtract the 2 samples in the header
+ count -= 2;
+
+ // this is a toggle to read nibbles, first nibble is high
+ int high = 1;
+
+ int error, sample = 0;
+
+ // now process the block
+ while ( count )
+ {
+ for ( i = 0; i < 2; i++ )
+ {
+ // read the error nibble from the input stream
+ if ( high )
+ {
+ sample = (unsigned char) (*pIn++);
+ // high nibble
+ error = sample >> 4;
+ // cache low nibble for next read
+ sample = sample & 0xf;
+ // Next read is from cache, not stream
+ high = 0;
+ }
+ else
+ {
+ // stored in previous read (low nibble)
+ error = sample;
+ // next read is from stream
+ high = 1;
+ }
+ // convert to signed with LUT
+ int errorSign = error_sign_lut[error];
+
+ // interpolate the new sample
+ int predSample = (samp1[i] * co1[i]) + (samp2[i] * co2[i]);
+ // coefficients are fixed point 8-bit, so shift back to 16-bit integer
+ predSample >>= 8;
+
+ // Add in current error estimate
+ predSample += (errorSign * delta[i]);
+
+ // Correct error estimate
+ delta[i] = (delta[i] * error_coefficients_lut[error]) >> 8;
+ // Clamp error estimate
+ if ( delta[i] < 16 )
+ delta[i] = 16;
+
+ // clamp
+ if ( predSample > 32767L )
+ predSample = 32767L;
+ else if ( predSample < -32768L )
+ predSample = -32768L;
+
+ // output
+ *pOut++ = (short)predSample;
+ // move samples over
+ samp2[i] = samp1[i];
+ samp1[i] = predSample;
+ }
+ count--;
+ }
+}
+
+
+bool CAudioMixerWaveADPCM::DecodeBlock( void )
+{
+ char tmpBlock[MAX_BLOCK_SIZE];
+ char *pData;
+
+ int available = m_pData->ReadSourceData( (void **) (&pData), m_offset, m_blockSize );
+ if ( available < m_blockSize )
+ {
+ int total = 0;
+ while ( available && total < m_blockSize )
+ {
+ memcpy( tmpBlock + total, pData, available );
+ total += available;
+ available = m_pData->ReadSourceData( (void **) (&pData), m_offset + total, m_blockSize - total );
+ }
+ pData = tmpBlock;
+ available = total;
+ }
+
+ Assert( m_blockSize > 0 );
+
+ // Current block number is based on starting offset
+ int blockNumber = m_offset / m_blockSize;
+ SetCurrentBlock( blockNumber );
+
+ if ( !available )
+ {
+ return false;
+ }
+
+ // advance the file pointer
+ m_offset += available;
+
+ int channelCount = NumChannels();
+
+ // this is sample pairs for stereo, samples for mono
+ m_sampleCount = m_pFormat->wSamplesPerBlock;
+
+ // short block?, fixup sample count (2 samples per byte, divided by number of channels per sample set)
+ m_sampleCount -= ((m_blockSize - available) * 2) / channelCount;
+
+ // new block, start at the first sample
+ m_samplePosition = 0;
+
+ // no need to subclass for different channel counts...
+ if ( channelCount == 1 )
+ {
+ DecompressBlockMono( m_pSamples, pData, m_sampleCount );
+ }
+ else
+ {
+ DecompressBlockStereo( m_pSamples, pData, m_sampleCount );
+ }
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : block -
+//-----------------------------------------------------------------------------
+void CAudioMixerWaveADPCM::SetCurrentBlock( int block )
+{
+ m_currentBlock = block;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CAudioMixerWaveADPCM::GetCurrentBlock( void ) const
+{
+ return m_currentBlock;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : samplePosition -
+// Output : int
+//-----------------------------------------------------------------------------
+int CAudioMixerWaveADPCM::GetBlockNumberForSample( int samplePosition )
+{
+ int blockNum = samplePosition / m_pFormat->wSamplesPerBlock;
+ return blockNum;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : samplePosition -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CAudioMixerWaveADPCM::IsSampleInCurrentBlock( int samplePosition )
+{
+ int currentBlock = GetCurrentBlock();
+
+ int startSample = currentBlock * m_pFormat->wSamplesPerBlock;
+ int endSample = startSample + m_pFormat->wSamplesPerBlock - 1;
+
+ if ( samplePosition >= startSample &&
+ samplePosition <= endSample )
+ {
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : blocknum -
+// Output : int
+//-----------------------------------------------------------------------------
+int CAudioMixerWaveADPCM::GetFirstSampleForBlock( int blocknum ) const
+{
+ return m_pFormat->wSamplesPerBlock * blocknum;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Read existing buffer or decompress a new block when necessary
+// Input : **pData - output data pointer
+// sampleCount - number of samples (or pairs)
+// Output : int - available samples (zero to stop decoding)
+//-----------------------------------------------------------------------------
+int CAudioMixerWaveADPCM::GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward /*= true*/ )
+{
+ int requestedBlock = GetBlockNumberForSample( samplePosition );
+ if ( requestedBlock != GetCurrentBlock() )
+ {
+ // Ran out of data!!!
+ if ( !SetSamplePosition( samplePosition ) )
+ return 0;
+ }
+
+ Assert( requestedBlock == GetCurrentBlock() );
+
+ if ( m_samplePosition >= m_sampleCount )
+ {
+ if ( !DecodeBlock() )
+ return 0;
+ }
+
+ if ( m_samplePosition < m_sampleCount )
+ {
+ *pData = (void *)(m_pSamples + m_samplePosition * NumChannels());
+ int available = m_sampleCount - m_samplePosition;
+ if ( available > sampleCount )
+ available = sampleCount;
+
+ m_samplePosition += available;
+ return available;
+ }
+
+ return 0;
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : position -
+//-----------------------------------------------------------------------------
+bool CAudioMixerWaveADPCM::SetSamplePosition( int position )
+{
+ position = max( 0, position );
+
+ CAudioMixerWave::SetSamplePosition( position );
+
+ int requestedBlock = GetBlockNumberForSample( position );
+ int firstSample = GetFirstSampleForBlock( requestedBlock );
+
+ if ( firstSample >= m_pData->Source().SampleCount() )
+ {
+ // Read past end of file!!!
+ return false;
+ }
+
+ int currentSample = ( position - firstSample );
+
+ if ( requestedBlock != GetCurrentBlock() )
+ {
+ // Rewind file to beginning of block
+ m_offset = requestedBlock * m_blockSize;
+ if ( !DecodeBlock() )
+ {
+ return false;
+ }
+ }
+
+ m_samplePosition = currentSample;
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Abstract factory function for ADPCM mixers
+// Input : *data - wave data access object
+// channels -
+// Output : CAudioMixer
+//-----------------------------------------------------------------------------
+CAudioMixer *CreateADPCMMixer( CWaveData *data )
+{
+ return new CAudioMixerWaveADPCM( data );
+}
diff --git a/utils/scenemanager/snd_wave_mixer_adpcm.h b/utils/scenemanager/snd_wave_mixer_adpcm.h
new file mode 100644
index 0000000..467ab5f
--- /dev/null
+++ b/utils/scenemanager/snd_wave_mixer_adpcm.h
@@ -0,0 +1,24 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SND_WAVE_MIXER_ADPCM_H
+#define SND_WAVE_MIXER_ADPCM_H
+#pragma once
+
+
+class CAudioMixer;
+class CWaveData;
+
+CAudioMixer *CreateADPCMMixer( CWaveData *data );
+
+#endif // SND_WAVE_MIXER_ADPCM_H
diff --git a/utils/scenemanager/snd_wave_mixer_private.h b/utils/scenemanager/snd_wave_mixer_private.h
new file mode 100644
index 0000000..ec01e1c
--- /dev/null
+++ b/utils/scenemanager/snd_wave_mixer_private.h
@@ -0,0 +1,94 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SND_WAVE_MIXER_PRIVATE_H
+#define SND_WAVE_MIXER_PRIVATE_H
+#pragma once
+
+#include "snd_audio_source.h"
+#include "snd_wave_mixer.h"
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Linear iterator over source data.
+// Keeps track of position in source, and maintains necessary buffers
+//-----------------------------------------------------------------------------
+class CWaveData
+{
+public:
+ virtual ~CWaveData( void ) {}
+ virtual CAudioSourceWave &Source( void ) = 0;
+ virtual int ReadSourceData( void **pData, int sampleIndex, int sampleCount, bool forward = true ) = 0;
+};
+
+class CAudioMixerWave : public CAudioMixer
+{
+public:
+ CAudioMixerWave( CWaveData *data );
+ virtual ~CAudioMixerWave( void );
+
+ virtual bool MixDataToDevice( IAudioDevice *pDevice, channel_t *pChannel, int startSample, int sampleCount, int outputRate, bool forward = true );
+ virtual void IncrementSamples( channel_t *pChannel, int startSample, int sampleCount,int outputRate, bool forward = true );
+ virtual bool SkipSamples( channel_t *pChannel, int startSample, int sampleCount,int outputRate, bool forward = true );
+ virtual void Mix( IAudioDevice *pDevice,
+ channel_t *pChannel,
+ void *pData,
+ int outputOffset,
+ int inputOffset,
+ fixedint fracRate,
+ int outCount,
+ int timecompress,
+ bool forward = true ) = 0;
+
+ virtual int GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward = true );
+
+ virtual CAudioSource *GetSource( void );
+
+ virtual int GetSamplePosition( void );
+
+ virtual bool SetSamplePosition( int position );
+ virtual void SetLoopPosition( int position );
+ virtual int GetStartPosition( void );
+
+ virtual bool GetActive( void );
+ virtual void SetActive( bool active );
+
+ virtual void SetModelIndex( int index );
+ virtual int GetModelIndex( void ) const;
+
+ virtual void SetDirection( bool forward );
+ virtual bool GetDirection( void ) const;
+
+ virtual void SetAutoDelete( bool autodelete );
+ virtual bool GetAutoDelete( void ) const;
+protected:
+ int m_sample;
+ int m_absoluteSample;
+ int m_startpos;
+ int m_loop;
+ int m_fracOffset;
+ CWaveData *m_pData;
+
+ int m_absoluteStartPos;
+
+ bool m_bActive;
+ // Associated playback model in faceposer
+ int m_nModelIndex;
+
+ bool m_bForward;
+
+ bool m_bAutoDelete;
+};
+
+
+#endif // SND_WAVE_MIXER_PRIVATE_H
diff --git a/utils/scenemanager/snd_wave_source.cpp b/utils/scenemanager/snd_wave_source.cpp
new file mode 100644
index 0000000..c11d5d2
--- /dev/null
+++ b/utils/scenemanager/snd_wave_source.cpp
@@ -0,0 +1,590 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <windows.h>
+#include "tier2/riff.h"
+#include "snd_wave_source.h"
+#include "snd_wave_mixer_private.h"
+#include "snd_audio_source.h"
+#include <mmsystem.h> // wave format
+#include <mmreg.h> // adpcm format
+#include "filesystem.h"
+#include "utlbuffer.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Implements the RIFF i/o interface on stdio
+//-----------------------------------------------------------------------------
+class StdIOReadBinary : public IFileReadBinary
+{
+public:
+ int open( const char *pFileName )
+ {
+ return (int)filesystem->Open( pFileName, "rb" );
+ }
+
+ int read( void *pOutput, int size, int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Read( pOutput, size, (FileHandle_t)file );
+ }
+
+ void seek( int file, int pos )
+ {
+ if ( !file )
+ return;
+
+ filesystem->Seek( (FileHandle_t)file, pos, FILESYSTEM_SEEK_HEAD );
+ }
+
+ unsigned int tell( int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Tell( (FileHandle_t)file );
+ }
+
+ unsigned int size( int file )
+ {
+ if ( !file )
+ return 0;
+
+ return filesystem->Size( (FileHandle_t)file );
+ }
+
+ void close( int file )
+ {
+ if ( !file )
+ return;
+
+ filesystem->Close( (FileHandle_t)file );
+ }
+};
+
+static StdIOReadBinary io;
+
+#define RIFF_WAVE MAKEID('W','A','V','E')
+#define WAVE_FMT MAKEID('f','m','t',' ')
+#define WAVE_DATA MAKEID('d','a','t','a')
+#define WAVE_FACT MAKEID('f','a','c','t')
+#define WAVE_CUE MAKEID('c','u','e',' ')
+
+void ChunkError( unsigned int id )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Init to empty wave
+//-----------------------------------------------------------------------------
+CAudioSourceWave::CAudioSourceWave( void )
+{
+ m_format = 0;
+ m_pHeader = NULL;
+ // no looping
+ m_loopStart = -1;
+ m_sampleSize = 1;
+ m_sampleCount = 0;
+}
+
+
+CAudioSourceWave::~CAudioSourceWave( void )
+{
+ // for non-standard waves, we store a copy of the header in RAM
+ delete[] m_pHeader;
+ // m_pWords points into m_pWordBuffer, no need to delete
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Init the wave data.
+// Input : *pHeaderBuffer - the RIFF fmt chunk
+// headerSize - size of that chunk
+//-----------------------------------------------------------------------------
+void CAudioSourceWave::Init( const char *pHeaderBuffer, int headerSize )
+{
+ const WAVEFORMATEX *pHeader = (const WAVEFORMATEX *)pHeaderBuffer;
+
+ // copy the relevant header data
+ m_format = pHeader->wFormatTag;
+ m_bits = pHeader->wBitsPerSample;
+ m_rate = pHeader->nSamplesPerSec;
+ m_channels = pHeader->nChannels;
+
+ m_sampleSize = (m_bits * m_channels) / 8;
+
+ // this can never be zero -- other functions divide by this.
+ // This should never happen, but avoid crashing
+ if ( m_sampleSize <= 0 )
+ m_sampleSize = 1;
+
+ // For non-standard waves (like ADPCM) store the header, it has some useful data
+ if ( m_format != WAVE_FORMAT_PCM )
+ {
+ m_pHeader = new char[headerSize];
+ memcpy( m_pHeader, pHeader, headerSize );
+ if ( m_format == WAVE_FORMAT_ADPCM )
+ {
+ // treat ADPCM sources as a file of bytes. They are decoded by the mixer
+ m_sampleSize = 1;
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : float
+//-----------------------------------------------------------------------------
+float CAudioSourceWave::TrueSampleSize( void )
+{
+ if ( m_format == WAVE_FORMAT_ADPCM )
+ {
+ return 0.5f;
+ }
+ return (float)m_sampleSize;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Total number of samples in this source
+// Output : int
+//-----------------------------------------------------------------------------
+int CAudioSourceWave::SampleCount( void )
+{
+ if ( m_format == WAVE_FORMAT_ADPCM )
+ {
+ ADPCMWAVEFORMAT *pFormat = (ADPCMWAVEFORMAT *)m_pHeader;
+ int blockSize = ((pFormat->wSamplesPerBlock - 2) * pFormat->wfx.nChannels ) / 2;
+ blockSize += 7 * pFormat->wfx.nChannels;
+
+ int blockCount = m_sampleCount / blockSize;
+ int blockRem = m_sampleCount % blockSize;
+
+ // total samples in complete blocks
+ int sampleCount = blockCount * pFormat->wSamplesPerBlock;
+
+ // add remaining in a short block
+ if ( blockRem )
+ {
+ sampleCount += pFormat->wSamplesPerBlock - (((blockSize - blockRem) * 2) / m_channels);
+ }
+ return sampleCount;
+ }
+ return m_sampleCount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Do any sample conversion
+// For 8 bit PCM, convert to signed because the mixing routine assumes this
+// Input : *pData - pointer to sample data
+// sampleCount - number of samples
+//-----------------------------------------------------------------------------
+void CAudioSourceWave::ConvertSamples( char *pData, int sampleCount )
+{
+ if ( m_format == WAVE_FORMAT_PCM )
+ {
+ if ( m_bits == 8 )
+ {
+ for ( int i = 0; i < sampleCount; i++ )
+ {
+ for ( int j = 0; j < m_channels; j++ )
+ {
+ *pData = (unsigned char)((int)((unsigned)*pData) - 128);
+ pData++;
+ }
+ }
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &walk -
+//-----------------------------------------------------------------------------
+void CAudioSourceWave::ParseSentence( IterateRIFF &walk )
+{
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.EnsureCapacity( walk.ChunkSize() );
+ walk.ChunkRead( buf.Base() );
+ buf.SeekPut( CUtlBuffer::SEEK_HEAD, walk.ChunkSize() );
+
+ m_Sentence.InitFromDataChunk( buf.Base(), buf.TellPut() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Parse base chunks
+// Input : &walk - riff file to parse
+// : chunkName - name of the chunk to parse
+//-----------------------------------------------------------------------------
+// UNDONE: Move parsing loop here and drop each chunk into a virtual function
+// instead of this being virtual.
+void CAudioSourceWave::ParseChunk( IterateRIFF &walk, int chunkName )
+{
+ switch( chunkName )
+ {
+ case WAVE_CUE:
+ {
+ m_loopStart = ParseCueChunk( walk );
+ }
+ break;
+ case WAVE_VALVEDATA:
+ {
+ ParseSentence( walk );
+ }
+ break;
+ // unknown/don't care
+ default:
+ {
+ ChunkError( walk.ChunkName() );
+ }
+ break;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : CSentence
+//-----------------------------------------------------------------------------
+CSentence *CAudioSourceWave::GetSentence( void )
+{
+ return &m_Sentence;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Bastardized construction routine. This is just to avoid complex
+// constructor functions so code can be shared more easily by sub-classes
+// Input : *pFormatBuffer - RIFF header
+// formatSize - header size
+// &walk - RIFF file
+//-----------------------------------------------------------------------------
+void CAudioSourceWave::Setup( const char *pFormatBuffer, int formatSize, IterateRIFF &walk )
+{
+ Init( pFormatBuffer, formatSize );
+
+ while ( walk.ChunkAvailable() )
+ {
+ ParseChunk( walk, walk.ChunkName() );
+ walk.ChunkNext();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Wave file that is completely in memory
+// UNDONE: Implement Lock/Unlock and caching
+//-----------------------------------------------------------------------------
+class CAudioSourceMemWave : public CAudioSourceWave
+{
+public:
+ CAudioSourceMemWave( void );
+ ~CAudioSourceMemWave( void );
+
+ // Create an instance (mixer) of this audio source
+ virtual CAudioMixer *CreateMixer( void );
+
+ virtual void ParseChunk( IterateRIFF &walk, int chunkName );
+ void ParseDataChunk( IterateRIFF &walk );
+
+ virtual int GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward = true );
+ virtual float GetRunningLength( void ) { return CAudioSourceWave::GetRunningLength(); };
+
+private:
+ char *m_pData; // wave data
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Iterator for wave data (this is to abstract streaming/buffering)
+//-----------------------------------------------------------------------------
+class CWaveDataMemory : public CWaveData
+{
+public:
+ CWaveDataMemory( CAudioSourceWave &source ) : m_source(source) {}
+ ~CWaveDataMemory( void ) {}
+ CAudioSourceWave &Source( void ) { return m_source; }
+
+ // this file is in memory, simply pass along the data request to the source
+ virtual int ReadSourceData( void **pData, int sampleIndex, int sampleCount, bool forward /*= true*/ )
+ {
+ return m_source.GetOutputData( pData, sampleIndex, sampleCount, forward );
+ }
+private:
+ CAudioSourceWave &m_source; // pointer to source
+};
+
+
+//-----------------------------------------------------------------------------
+// Purpose: NULL the wave data pointer (we haven't loaded yet)
+//-----------------------------------------------------------------------------
+CAudioSourceMemWave::CAudioSourceMemWave( void )
+{
+ m_pData = NULL;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Free any wave data we've allocated
+//-----------------------------------------------------------------------------
+CAudioSourceMemWave::~CAudioSourceMemWave( void )
+{
+ delete[] m_pData;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Creates a mixer and initializes it with an appropriate mixer
+//-----------------------------------------------------------------------------
+CAudioMixer *CAudioSourceMemWave::CreateMixer( void )
+{
+ return CreateWaveMixer( new CWaveDataMemory(*this), m_format, m_channels, m_bits );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: parse chunks with unique processing to in-memory waves
+// Input : &walk - RIFF file
+//-----------------------------------------------------------------------------
+void CAudioSourceMemWave::ParseChunk( IterateRIFF &walk, int chunkName )
+{
+ switch( chunkName )
+ {
+ // this is the audio data
+ case WAVE_DATA:
+ {
+ ParseDataChunk( walk );
+ }
+ return;
+ }
+
+ CAudioSourceWave::ParseChunk( walk, chunkName );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: reads the actual sample data and parses it
+// Input : &walk - RIFF file
+//-----------------------------------------------------------------------------
+void CAudioSourceMemWave::ParseDataChunk( IterateRIFF &walk )
+{
+ int size = walk.ChunkSize();
+
+ // create a buffer for the samples
+ m_pData = new char[size];
+
+ // load them into memory
+ walk.ChunkRead( m_pData );
+
+ if ( m_format == WAVE_FORMAT_PCM )
+ {
+ // number of samples loaded
+ m_sampleCount = size / m_sampleSize;
+
+ // some samples need to be converted
+ ConvertSamples( m_pData, m_sampleCount );
+ }
+ else if ( m_format == WAVE_FORMAT_ADPCM )
+ {
+ // The ADPCM mixers treat the wave source as a flat file of bytes.
+ m_sampleSize = 1;
+ // Since each "sample" is a byte (this is a flat file), the number of samples is the file size
+ m_sampleCount = size;
+
+ // file says 4, output is 16
+ m_bits = 16;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: parses loop information from a cue chunk
+// Input : &walk - RIFF iterator
+// Output : int loop start position
+//-----------------------------------------------------------------------------
+int CAudioSourceWave::ParseCueChunk( IterateRIFF &walk )
+{
+ // Cue chunk as specified by RIFF format
+ // see $/research/jay/sound/riffnew.htm
+ struct
+ {
+ unsigned int dwName;
+ unsigned int dwPosition;
+ unsigned int fccChunk;
+ unsigned int dwChunkStart;
+ unsigned int dwBlockStart;
+ unsigned int dwSampleOffset;
+ } cue_chunk;
+
+ int cueCount;
+
+ // assume that the cue chunk stored in the wave is the start of the loop
+ // assume only one cue chunk, UNDONE: Test this assumption here?
+ cueCount = walk.ChunkReadInt();
+
+ walk.ChunkReadPartial( &cue_chunk, sizeof(cue_chunk) );
+ return cue_chunk.dwSampleOffset;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: get the wave header
+//-----------------------------------------------------------------------------
+void *CAudioSourceWave::GetHeader( void )
+{
+ return m_pHeader;
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: wrap the position wrt looping
+// Input : samplePosition - absolute position
+// Output : int - looped position
+//-----------------------------------------------------------------------------
+int CAudioSourceWave::ConvertLoopedPosition( int samplePosition )
+{
+ // if the wave is looping and we're past the end of the sample
+ // convert to a position within the loop
+ // At the end of the loop, we return a short buffer, and subsequent call
+ // will loop back and get the rest of the buffer
+ if ( m_loopStart >= 0 )
+ {
+ if ( samplePosition >= m_sampleCount )
+ {
+ // size of loop
+ int loopSize = m_sampleCount - m_loopStart;
+ // subtract off starting bit of the wave
+ samplePosition -= m_loopStart;
+
+ if ( loopSize )
+ {
+ // "real" position in memory (mod off extra loops)
+ samplePosition = m_loopStart + (samplePosition % loopSize);
+ }
+ // ERROR? if no loopSize
+ }
+ }
+
+ return samplePosition;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : **pData - output pointer to samples
+// samplePosition - position (in samples not bytes)
+// sampleCount - number of samples (not bytes)
+// Output : int - number of samples available
+//-----------------------------------------------------------------------------
+int CAudioSourceMemWave::GetOutputData( void **pData, int samplePosition, int sampleCount, bool forward /*= true*/ )
+{
+ // handle position looping
+ samplePosition = ConvertLoopedPosition( samplePosition );
+
+ // how many samples are available (linearly not counting looping)
+ int availableSampleCount = m_sampleCount - samplePosition;
+ if ( !forward )
+ {
+ if ( samplePosition >= m_sampleCount )
+ {
+ availableSampleCount = 0;
+ }
+ else
+ {
+ availableSampleCount = samplePosition;
+ }
+ }
+
+ // may be asking for a sample out of range, clip at zero
+ if ( availableSampleCount < 0 )
+ availableSampleCount = 0;
+
+ // clip max output samples to max available
+ if ( sampleCount > availableSampleCount )
+ sampleCount = availableSampleCount;
+
+ // byte offset in sample database
+ samplePosition *= m_sampleSize;
+
+ // if we are returning some samples, store the pointer
+ if ( sampleCount )
+ {
+ *pData = m_pData + samplePosition;
+ }
+
+ return sampleCount;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a wave audio source (streaming or in memory)
+// Input : *pName - file name
+// streaming - if true, don't load, stream each instance
+// Output : CAudioSource * - a new source
+//-----------------------------------------------------------------------------
+// UNDONE : Pool these and check for duplicates?
+CAudioSource *CreateWave( const char *pName )
+{
+ char formatBuffer[1024];
+ InFileRIFF riff( pName, io );
+
+ // UNDONE: Don't use printf to handle errors
+ if ( riff.RIFFName() != RIFF_WAVE )
+ {
+ printf("Bad RIFF file type %s\n", pName );
+ return NULL;
+ }
+
+ // set up the iterator for the whole file (root RIFF is a chunk)
+ IterateRIFF walk( riff, riff.RIFFSize() );
+
+ int format = 0;
+ int formatSize = 0;
+
+ // This chunk must be first as it contains the wave's format
+ // break out when we've parsed it
+ while ( walk.ChunkAvailable() && format == 0 )
+ {
+ switch( walk.ChunkName() )
+ {
+ case WAVE_FMT:
+ {
+ if ( walk.ChunkSize() <= 1024 )
+ {
+ walk.ChunkRead( formatBuffer );
+ formatSize = walk.ChunkSize();
+ format = ((WAVEFORMATEX *)formatBuffer)->wFormatTag;
+ }
+ }
+ break;
+ default:
+ {
+ ChunkError( walk.ChunkName() );
+ }
+ break;
+ }
+ walk.ChunkNext();
+ }
+
+ // Not really a WAVE file or no format chunk, bail
+ if ( !format )
+ return NULL;
+
+ CAudioSourceWave *pWave;
+
+ // create the source from this file
+ pWave = new CAudioSourceMemWave();
+
+ // init the wave source
+ pWave->Setup( formatBuffer, formatSize, walk );
+
+ return pWave;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Wrapper for CreateWave()
+//-----------------------------------------------------------------------------
+CAudioSource *Audio_CreateMemoryWave( const char *pName )
+{
+ return CreateWave( pName );
+}
diff --git a/utils/scenemanager/snd_wave_source.h b/utils/scenemanager/snd_wave_source.h
new file mode 100644
index 0000000..cce5015
--- /dev/null
+++ b/utils/scenemanager/snd_wave_source.h
@@ -0,0 +1,77 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $Date: $
+//
+//-----------------------------------------------------------------------------
+// $Log: $
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef SND_WAVE_SOURCE_H
+#define SND_WAVE_SOURCE_H
+#pragma once
+
+#include "snd_audio_source.h"
+#include "sentence.h"
+
+class IterateRIFF;
+
+class CAudioSourceWave : public CAudioSource
+{
+public:
+ CAudioSourceWave( void );
+ ~CAudioSourceWave( void );
+
+ void Setup( const char *pFormat, int formatSize, IterateRIFF &walk );
+
+ virtual int SampleRate( void ) { return m_rate; }
+ inline int SampleSize( void ) { return m_sampleSize; }
+ virtual float TrueSampleSize( void );
+
+ void *GetHeader( void );
+
+ // Legacy
+ virtual void ParseChunk( IterateRIFF &walk, int chunkName );
+
+ virtual void ParseSentence( IterateRIFF &walk );
+
+ void ConvertSamples( char *pData, int sampleCount );
+ bool IsLooped( void ) { return (m_loopStart >= 0) ? true : false; }
+ bool IsStreaming( void ) { return false; }
+ int ConvertLoopedPosition( int samplePosition );
+
+ int SampleCount( void );
+
+ virtual float GetRunningLength( void )
+ {
+ if ( m_rate > 0.0 )
+ {
+ return (float)SampleCount() / m_rate;
+ }
+ return 0.0f; }
+
+ CSentence *GetSentence( void );
+
+protected:
+ // returns the loop start from a cue chunk
+ int ParseCueChunk( IterateRIFF &walk );
+ void Init( const char *pHeaderBuffer, int headerSize );
+
+ int m_bits;
+ int m_rate;
+ int m_channels;
+ int m_format;
+ int m_sampleSize;
+ int m_loopStart;
+ int m_sampleCount;
+
+private:
+ char *m_pHeader;
+ CSentence m_Sentence;
+};
+
+#endif // SND_WAVE_SOURCE_H
diff --git a/utils/scenemanager/sound.cpp b/utils/scenemanager/sound.cpp
new file mode 100644
index 0000000..fc12d0b
--- /dev/null
+++ b/utils/scenemanager/sound.cpp
@@ -0,0 +1,1182 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <mmsystem.h>
+#include <stdio.h>
+#include <math.h>
+#include "snd_audio_source.h"
+#include "AudioWaveOutput.h"
+#include "ISceneManagerSound.h"
+#include "utlvector.h"
+#include "filesystem.h"
+#include "sentence.h"
+
+typedef struct channel_s
+{
+ int leftvol;
+ int rightvol;
+ int rleftvol;
+ int rrightvol;
+ float pitch;
+} channel_t;
+
+#define INPUT_BUFFER_COUNT 32
+
+class CAudioWaveInput : public CAudioInput
+{
+public:
+ CAudioWaveInput( void );
+ ~CAudioWaveInput( void );
+
+ // Returns the current count of available samples
+ int SampleCount( void );
+
+ // returns the size of each sample in bytes
+ int SampleSize( void ) { return m_sampleSize; }
+
+ // returns the sampling rate of the data
+ int SampleRate( void ) { return m_sampleRate; }
+
+ // returns a pointer to the actual data
+ void *SampleData( void );
+
+ // release the available data (mark as done)
+ void SampleRelease( void );
+
+ // returns the mono/stereo status of this device (true if stereo)
+ bool IsStereo( void ) { return m_isStereo; }
+
+ // begin sampling
+ void Start( void );
+
+ // stop sampling
+ void Stop( void );
+
+ void WaveMessage( HWAVEIN hdevice, UINT uMsg, DWORD dwParam1, DWORD dwParam2 );
+
+private:
+ void OpenDevice( void );
+ bool ValidDevice( void ) { return m_deviceId >= 0; }
+ void ClearDevice( void ) { m_deviceId = (UINT)-1; }
+
+ // returns true if the new format is better
+ bool BetterFormat( DWORD dwNewFormat, DWORD dwOldFormat );
+
+ void InitReadyList( void );
+ void AddToReadyList( WAVEHDR *pBuffer );
+ void PopReadyList( void );
+
+ WAVEHDR *m_pReadyList;
+
+ int m_sampleSize;
+ int m_sampleRate;
+ bool m_isStereo;
+
+ UINT m_deviceId;
+ HWAVEIN m_deviceHandle;
+
+ WAVEHDR *m_buffers[ INPUT_BUFFER_COUNT ];
+};
+
+extern "C" void CALLBACK WaveData( HWAVEIN hwi, UINT uMsg, CAudioWaveInput *pAudio, DWORD dwParam1, DWORD dwParam2 );
+
+CAudioWaveInput::CAudioWaveInput( void )
+{
+ memset( m_buffers, 0, sizeof( m_buffers ) );
+ int deviceCount = (int)waveInGetNumDevs();
+ UINT deviceId = (UINT)-1;
+ DWORD deviceFormat = 0;
+
+ int i;
+ for ( i = 0; i < deviceCount; i++ )
+ {
+ WAVEINCAPS waveCaps;
+ MMRESULT errorCode = waveInGetDevCaps( (UINT)i, &waveCaps, sizeof(waveCaps) );
+ if ( errorCode == MMSYSERR_NOERROR )
+ {
+ // valid device
+ if ( BetterFormat( waveCaps.dwFormats, deviceFormat ) )
+ {
+ deviceId = i;
+ deviceFormat = waveCaps.dwFormats;
+ }
+ }
+ }
+
+ if ( !deviceFormat )
+ {
+ m_deviceId = (UINT)-1;
+ m_sampleSize = 0;
+ m_sampleRate = 0;
+ m_isStereo = false;
+ }
+ else
+ {
+ m_deviceId = deviceId;
+ m_sampleRate = 44100;
+ m_isStereo = false;
+ if ( deviceFormat & WAVE_FORMAT_4M16 )
+ {
+ m_sampleSize = 2;
+ }
+ else if ( deviceFormat & WAVE_FORMAT_4M08 )
+ {
+ m_sampleSize = 1;
+ }
+ else
+ {
+ // ERROR!
+ }
+
+ OpenDevice();
+ }
+
+ InitReadyList();
+}
+
+CAudioWaveInput::~CAudioWaveInput( void )
+{
+ if ( ValidDevice() )
+ {
+ Stop();
+ waveInReset( m_deviceHandle );
+ waveInClose( m_deviceHandle );
+ for ( int i = 0; i < INPUT_BUFFER_COUNT; i++ )
+ {
+ if ( m_buffers[i] )
+ {
+ waveInUnprepareHeader( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
+ delete[] m_buffers[i]->lpData;
+ delete m_buffers[i];
+ }
+ m_buffers[i] = NULL;
+ }
+ ClearDevice();
+ }
+}
+
+void CALLBACK WaveData( HWAVEIN hwi, UINT uMsg, CAudioWaveInput *pAudio, DWORD dwParam1, DWORD dwParam2 )
+{
+ if ( pAudio )
+ {
+ pAudio->WaveMessage( hwi, uMsg, dwParam1, dwParam2 );
+ }
+}
+
+void CAudioWaveInput::WaveMessage( HWAVEIN hdevice, UINT uMsg, DWORD dwParam1, DWORD dwParam2 )
+{
+ if ( hdevice != m_deviceHandle )
+ return;
+ switch( uMsg )
+ {
+ case WIM_DATA:
+ WAVEHDR *pHeader = (WAVEHDR *)dwParam1;
+ AddToReadyList( pHeader );
+ break;
+ }
+}
+
+void CAudioWaveInput::OpenDevice( void )
+{
+ if ( !ValidDevice() )
+ return;
+
+ WAVEFORMATEX format;
+
+ memset( &format, 0, sizeof(format) );
+ format.nAvgBytesPerSec = m_sampleRate * m_sampleSize;
+ format.nChannels = 1;
+ format.wBitsPerSample = m_sampleSize * 8;
+ format.nSamplesPerSec = m_sampleRate;
+ format.wFormatTag = WAVE_FORMAT_PCM;
+ format.nBlockAlign = m_sampleSize;
+
+ MMRESULT errorCode = waveInOpen( &m_deviceHandle, m_deviceId, &format, (DWORD)WaveData, (DWORD)this, CALLBACK_FUNCTION );
+ if ( errorCode == MMSYSERR_NOERROR )
+ {
+ // valid device opened
+ int bufferSize = m_sampleSize * m_sampleRate / INPUT_BUFFER_COUNT; // total of one second of data
+
+ // allocate buffers
+ for ( int i = 0; i < INPUT_BUFFER_COUNT; i++ )
+ {
+ m_buffers[i] = new WAVEHDR;
+ m_buffers[i]->lpData = new char[ bufferSize ];
+ m_buffers[i]->dwBufferLength = bufferSize;
+ m_buffers[i]->dwUser = 0;
+ m_buffers[i]->dwFlags = 0;
+
+ waveInPrepareHeader( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
+ waveInAddBuffer( m_deviceHandle, m_buffers[i], sizeof( *m_buffers[i] ) );
+ }
+ }
+ else
+ {
+ ClearDevice();
+ }
+}
+
+void CAudioWaveInput::Start( void )
+{
+ if ( !ValidDevice() )
+ return;
+
+ waveInStart( m_deviceHandle );
+}
+
+void CAudioWaveInput::Stop( void )
+{
+ if ( !ValidDevice() )
+ return;
+
+ waveInStop( m_deviceHandle );
+}
+
+void CAudioWaveInput::InitReadyList( void )
+{
+ m_pReadyList = NULL;
+}
+
+void CAudioWaveInput::AddToReadyList( WAVEHDR *pBuffer )
+{
+ WAVEHDR **pList = &m_pReadyList;
+
+ waveInUnprepareHeader( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
+ // insert at the tail of the list
+ while ( *pList )
+ {
+ pList = reinterpret_cast<WAVEHDR **>(&((*pList)->dwUser));
+ }
+ pBuffer->dwUser = NULL;
+ *pList = pBuffer;
+}
+
+
+void CAudioWaveInput::PopReadyList( void )
+{
+ if ( m_pReadyList )
+ {
+ WAVEHDR *pBuffer = m_pReadyList;
+ m_pReadyList = reinterpret_cast<WAVEHDR *>(m_pReadyList->dwUser);
+ waveInPrepareHeader( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
+ waveInAddBuffer( m_deviceHandle, pBuffer, sizeof(*pBuffer) );
+ }
+}
+
+
+
+#define WAVE_FORMAT_STEREO (WAVE_FORMAT_1S08|WAVE_FORMAT_1S16|WAVE_FORMAT_2S08|WAVE_FORMAT_2S16|WAVE_FORMAT_4S08|WAVE_FORMAT_4S16)
+#define WAVE_FORMATS_UNDERSTOOD (0xFFF)
+#define WAVE_FORMAT_11K (WAVE_FORMAT_1M08|WAVE_FORMAT_1M16)
+#define WAVE_FORMAT_22K (WAVE_FORMAT_2M08|WAVE_FORMAT_2M16)
+#define WAVE_FORMAT_44K (WAVE_FORMAT_4M08|WAVE_FORMAT_4M16)
+
+static int HighestBit( DWORD dwFlags )
+{
+ int i = 31;
+ while ( i )
+ {
+ if ( dwFlags & (1<<i) )
+ return i;
+ i--;
+ }
+
+ return 0;
+}
+
+bool CAudioWaveInput::BetterFormat( DWORD dwNewFormat, DWORD dwOldFormat )
+{
+ dwNewFormat &= WAVE_FORMATS_UNDERSTOOD & (~WAVE_FORMAT_STEREO);
+ dwOldFormat &= WAVE_FORMATS_UNDERSTOOD & (~WAVE_FORMAT_STEREO);
+
+ // our target format is 44.1KHz, mono, 16-bit
+ if ( HighestBit(dwOldFormat) >= HighestBit(dwNewFormat) )
+ return false;
+
+ return true;
+}
+
+
+int CAudioWaveInput::SampleCount( void )
+{
+ if ( !ValidDevice() )
+ return 0;
+
+ if ( m_pReadyList )
+ {
+ switch( SampleSize() )
+ {
+ case 2:
+ return m_pReadyList->dwBytesRecorded >> 1;
+ case 1:
+ return m_pReadyList->dwBytesRecorded;
+ default:
+ break;
+ }
+ }
+ return 0;
+}
+
+void *CAudioWaveInput::SampleData( void )
+{
+ if ( !ValidDevice() )
+ return NULL;
+
+ if ( m_pReadyList )
+ {
+ return m_pReadyList->lpData;
+ }
+
+ return NULL;
+}
+
+
+// release the available data (mark as done)
+void CAudioWaveInput::SampleRelease( void )
+{
+ PopReadyList();
+}
+
+
+// factory to create a suitable audio input for this system
+CAudioInput *CAudioInput::Create( void )
+{
+ // sound source is a singleton for now
+ static CAudioInput *pSource = NULL;
+
+ if ( !pSource )
+ {
+ pSource = new CAudioWaveInput;
+ }
+
+ return pSource;
+}
+
+void CAudioDeviceSWMix::Mix8Mono( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
+{
+ int sampleIndex = 0;
+ fixedint sampleFrac = inputOffset;
+
+ int fixup = 0;
+ int fixupstep = 1;
+
+ if ( !forward )
+ {
+ fixup = outCount - 1;
+ fixupstep = -1;
+ }
+
+ for ( int i = 0; i < outCount; i++, fixup += fixupstep )
+ {
+ int dest = max( outputOffset + fixup, 0 );
+
+ m_paintbuffer[ dest ].left += pChannel->leftvol * pData[sampleIndex];
+ m_paintbuffer[ dest ].right += pChannel->rightvol * pData[sampleIndex];
+ sampleFrac += rateScaleFix;
+ sampleIndex += FIX_INTPART(sampleFrac);
+ sampleFrac = FIX_FRACPART(sampleFrac);
+ }
+}
+
+
+void CAudioDeviceSWMix::Mix8Stereo( channel_t *pChannel, char *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
+{
+ int sampleIndex = 0;
+ fixedint sampleFrac = inputOffset;
+
+ int fixup = 0;
+ int fixupstep = 1;
+
+ if ( !forward )
+ {
+ fixup = outCount - 1;
+ fixupstep = -1;
+ }
+
+ for ( int i = 0; i < outCount; i++, fixup += fixupstep )
+ {
+ int dest = max( outputOffset + fixup, 0 );
+
+ m_paintbuffer[ dest ].left += pChannel->leftvol * pData[sampleIndex];
+ m_paintbuffer[ dest ].right += pChannel->rightvol * pData[sampleIndex+1];
+ sampleFrac += rateScaleFix;
+ sampleIndex += FIX_INTPART(sampleFrac)<<1;
+ sampleFrac = FIX_FRACPART(sampleFrac);
+ }
+}
+
+
+void CAudioDeviceSWMix::Mix16Mono( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
+{
+ int sampleIndex = 0;
+ fixedint sampleFrac = inputOffset;
+
+ int fixup = 0;
+ int fixupstep = 1;
+
+ if ( !forward )
+ {
+ fixup = outCount - 1;
+ fixupstep = -1;
+ }
+
+ for ( int i = 0; i < outCount; i++, fixup += fixupstep )
+ {
+ int dest = max( outputOffset + fixup, 0 );
+
+ m_paintbuffer[ dest ].left += (pChannel->leftvol * pData[sampleIndex])>>8;
+ m_paintbuffer[ dest ].right += (pChannel->rightvol * pData[sampleIndex])>>8;
+ sampleFrac += rateScaleFix;
+ sampleIndex += FIX_INTPART(sampleFrac);
+ sampleFrac = FIX_FRACPART(sampleFrac);
+ }
+}
+
+
+void CAudioDeviceSWMix::Mix16Stereo( channel_t *pChannel, short *pData, int outputOffset, int inputOffset, int rateScaleFix, int outCount, int timecompress, bool forward )
+{
+ int sampleIndex = 0;
+ fixedint sampleFrac = inputOffset;
+
+ int fixup = 0;
+ int fixupstep = 1;
+
+ if ( !forward )
+ {
+ fixup = outCount - 1;
+ fixupstep = -1;
+ }
+
+ for ( int i = 0; i < outCount; i++, fixup += fixupstep )
+ {
+ int dest = max( outputOffset + fixup, 0 );
+
+ m_paintbuffer[ dest ].left += (pChannel->leftvol * pData[sampleIndex])>>8;
+ m_paintbuffer[ dest ].right += (pChannel->rightvol * pData[sampleIndex+1])>>8;
+
+ sampleFrac += rateScaleFix;
+ sampleIndex += FIX_INTPART(sampleFrac)<<1;
+ sampleFrac = FIX_FRACPART(sampleFrac);
+ }
+}
+
+
+int CAudioDeviceSWMix::MaxSampleCount( void )
+{
+ return PAINTBUFFER_SIZE;
+}
+
+void CAudioDeviceSWMix::MixBegin( void )
+{
+ memset( m_paintbuffer, 0, sizeof(m_paintbuffer) );
+}
+
+void CAudioDeviceSWMix::TransferBufferStereo16( short *pOutput, int sampleCount )
+{
+ for ( int i = 0; i < sampleCount; i++ )
+ {
+ if ( m_paintbuffer[i].left > 32767 )
+ m_paintbuffer[i].left = 32767;
+ else if ( m_paintbuffer[i].left < -32768 )
+ m_paintbuffer[i].left = -32768;
+
+ if ( m_paintbuffer[i].right > 32767 )
+ m_paintbuffer[i].right = 32767;
+ else if ( m_paintbuffer[i].right < -32768 )
+ m_paintbuffer[i].right = -32768;
+
+ *pOutput++ = (short)m_paintbuffer[i].left;
+ *pOutput++ = (short)m_paintbuffer[i].right;
+ }
+}
+
+CAudioWaveOutput::CAudioWaveOutput( void )
+{
+ for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
+ {
+ CAudioBuffer *buffer = &m_buffers[ i ];
+ Assert( buffer );
+ buffer->hdr = NULL;
+ buffer->submitted = false;
+ buffer->submit_sample_count = false;
+ }
+
+ ClearDevice();
+ OpenDevice();
+
+ m_mixTime = -1;
+ m_sampleIndex = 0;
+ memset( m_sourceList, 0, sizeof(m_sourceList) );
+
+ m_nEstimatedSamplesAhead = (int)( ( float ) OUTPUT_SAMPLE_RATE / 10.0f );
+}
+
+void CAudioWaveOutput::RemoveMixerChannelReferences( CAudioMixer *mixer )
+{
+ for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
+ {
+ RemoveFromReferencedList( mixer, &m_buffers[ i ] );
+ }
+}
+
+void CAudioWaveOutput::AddToReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer )
+{
+ // Already in list
+ for ( int i = 0; i < buffer->m_Referenced.Size(); i++ )
+ {
+ if ( buffer->m_Referenced[ i ].mixer == mixer )
+ {
+ return;
+ }
+ }
+
+ // Just remove it
+ int idx = buffer->m_Referenced.AddToTail();
+
+ CAudioMixerState *state = &buffer->m_Referenced[ idx ];
+ state->mixer = mixer;
+ state->submit_mixer_sample = mixer->GetSamplePosition();
+
+}
+
+void CAudioWaveOutput::RemoveFromReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer )
+{
+ for ( int i = 0; i < buffer->m_Referenced.Size(); i++ )
+ {
+ if ( buffer->m_Referenced[ i ].mixer == mixer )
+ {
+ buffer->m_Referenced.Remove( i );
+ break;
+ }
+ }
+}
+
+bool CAudioWaveOutput::IsSoundInReferencedList( CAudioMixer *mixer, CAudioBuffer *buffer )
+{
+ for ( int i = 0; i < buffer->m_Referenced.Size(); i++ )
+ {
+ if ( buffer->m_Referenced[ i ].mixer == mixer )
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool CAudioWaveOutput::IsSourceReferencedByActiveBuffer( CAudioMixer *mixer )
+{
+ if ( !ValidDevice() )
+ return false;
+
+ CAudioBuffer *buffer;
+ for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
+ {
+ buffer = &m_buffers[ i ];
+ if ( !buffer->submitted )
+ continue;
+
+ if ( buffer->hdr->dwFlags & WHDR_DONE )
+ continue;
+
+ // See if it's referenced
+ if ( IsSoundInReferencedList( mixer, buffer ) )
+ return true;
+ }
+
+ return false;
+}
+
+CAudioWaveOutput::~CAudioWaveOutput( void )
+{
+ if ( ValidDevice() )
+ {
+ waveOutReset( m_deviceHandle );
+ for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
+ {
+ if ( m_buffers[i].hdr )
+ {
+ waveOutUnprepareHeader( m_deviceHandle, m_buffers[i].hdr, sizeof(*m_buffers[i].hdr) );
+ delete[] m_buffers[i].hdr->lpData;
+ delete m_buffers[i].hdr;
+ }
+ m_buffers[i].hdr = NULL;
+ m_buffers[i].submitted = false;
+ m_buffers[i].submit_sample_count = 0;
+ m_buffers[i].m_Referenced.Purge();
+ }
+ waveOutClose( m_deviceHandle );
+ ClearDevice();
+ }
+}
+
+
+
+CAudioBuffer *CAudioWaveOutput::GetEmptyBuffer( void )
+{
+ CAudioBuffer *pOutput = NULL;
+ if ( ValidDevice() )
+ {
+ for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
+ {
+ if ( !(m_buffers[ i ].submitted ) ||
+ m_buffers[i].hdr->dwFlags & WHDR_DONE )
+ {
+ pOutput = &m_buffers[i];
+ pOutput->submitted = true;
+ pOutput->m_Referenced.Purge();
+ break;
+ }
+ }
+ }
+
+ return pOutput;
+}
+
+void CAudioWaveOutput::SilenceBuffer( short *pSamples, int sampleCount )
+{
+ int i;
+
+ for ( i = 0; i < sampleCount; i++ )
+ {
+ // left
+ *pSamples++ = 0;
+ // right
+ *pSamples++ = 0;
+ }
+}
+
+void CAudioWaveOutput::Flush( void )
+{
+ waveOutReset( m_deviceHandle );
+}
+
+// mix a buffer up to time (time is absolute)
+void CAudioWaveOutput::Update( float time )
+{
+ channel_t channel;
+
+ channel.leftvol = 200;
+ channel.rightvol = 200;
+ channel.pitch = 1.0;
+
+ if ( !ValidDevice() )
+ return;
+
+ // reset the system
+ if ( m_mixTime < 0 || time < m_baseTime )
+ {
+ m_baseTime = time;
+ m_mixTime = 0;
+ }
+
+ // put time in our coordinate frame
+ time -= m_baseTime;
+
+ if ( time > m_mixTime )
+ {
+ CAudioBuffer *pBuffer = GetEmptyBuffer();
+
+ // no free buffers, mixing is ahead of the playback!
+ if ( !pBuffer || !pBuffer->hdr )
+ {
+ //Con_Printf( "out of buffers\n" );
+ return;
+ }
+
+ // UNDONE: These numbers are constants
+ // calc number of samples (2 channels * 2 bytes per sample)
+ int sampleCount = pBuffer->hdr->dwBufferLength >> 2;
+ //float oldTime = m_mixTime;
+
+ m_mixTime += sampleCount * (1.0f / OUTPUT_SAMPLE_RATE);
+
+ short *pSamples = reinterpret_cast<short *>(pBuffer->hdr->lpData);
+
+ SilenceBuffer( pSamples, sampleCount );
+
+ int tempCount = sampleCount;
+
+ while ( tempCount > 0 )
+ {
+ if ( tempCount > m_audioDevice.MaxSampleCount() )
+ sampleCount = m_audioDevice.MaxSampleCount();
+ else
+ sampleCount = tempCount;
+
+ m_audioDevice.MixBegin();
+ for ( int i = 0; i < MAX_CHANNELS; i++ )
+ {
+ CAudioMixer *pSource = m_sourceList[i];
+ if ( !pSource )
+ continue;
+
+ int currentsample = pSource->GetSamplePosition();
+ bool forward = pSource->GetDirection();
+
+ if ( pSource->GetActive() )
+ {
+ if ( !pSource->MixDataToDevice( &m_audioDevice, &channel, currentsample, sampleCount, SampleRate(), forward ) )
+ {
+ // Source becomes inactive when last submitted sample is finally
+ // submitted. But it lingers until it's no longer referenced
+ pSource->SetActive( false );
+ }
+ else
+ {
+ AddToReferencedList( pSource, pBuffer );
+ }
+ }
+ else
+ {
+ if ( !IsSourceReferencedByActiveBuffer( pSource ) )
+ {
+ if ( !pSource->GetAutoDelete() )
+ {
+ FreeChannel( i );
+ }
+ }
+ else
+ {
+ pSource->IncrementSamples( &channel, currentsample, sampleCount, SampleRate(), forward );
+ }
+ }
+
+ }
+
+ m_audioDevice.TransferBufferStereo16( pSamples, sampleCount );
+
+ m_sampleIndex += sampleCount;
+ tempCount -= sampleCount;
+ pSamples += sampleCount * 2;
+ }
+ // if the buffers aren't aligned on sample boundaries, this will hard-lock the machine!
+
+ pBuffer->submit_sample_count = GetOutputPosition();
+
+ waveOutWrite( m_deviceHandle, pBuffer->hdr, sizeof(*(pBuffer->hdr)) );
+ }
+}
+
+int CAudioWaveOutput::GetNumberofSamplesAhead( void )
+{
+ ComputeSampleAheadAmount();
+ return m_nEstimatedSamplesAhead;
+}
+
+float CAudioWaveOutput::GetAmountofTimeAhead( void )
+{
+ ComputeSampleAheadAmount();
+ return ( (float)m_nEstimatedSamplesAhead / (float)OUTPUT_SAMPLE_RATE );
+}
+
+// Find the most recent submitted sample that isn't flagged as whdr_done
+void CAudioWaveOutput::ComputeSampleAheadAmount( void )
+{
+ m_nEstimatedSamplesAhead = 0;
+
+ int newest_sample_index = -1;
+ int newest_sample_count = 0;
+
+ CAudioBuffer *buffer;
+
+ if ( ValidDevice() )
+ {
+
+ for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
+ {
+ buffer = &m_buffers[ i ];
+ if ( !buffer->submitted )
+ continue;
+
+ if ( buffer->hdr->dwFlags & WHDR_DONE )
+ continue;
+
+ if ( buffer->submit_sample_count > newest_sample_count )
+ {
+ newest_sample_index = i;
+ newest_sample_count = buffer->submit_sample_count;
+ }
+ }
+ }
+
+ if ( newest_sample_index == -1 )
+ return;
+
+
+ buffer = &m_buffers[ newest_sample_index ];
+ int currentPos = GetOutputPosition() ;
+ m_nEstimatedSamplesAhead = currentPos - buffer->submit_sample_count;
+}
+
+int CAudioWaveOutput::FindSourceIndex( CAudioMixer *pSource )
+{
+ for ( int i = 0; i < MAX_CHANNELS; i++ )
+ {
+ if ( pSource == m_sourceList[i] )
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+CAudioMixer *CAudioWaveOutput::GetMixerForSource( CAudioSource *source )
+{
+ for ( int i = 0; i < MAX_CHANNELS; i++ )
+ {
+ if ( !m_sourceList[i] )
+ continue;
+
+ if ( source == m_sourceList[i]->GetSource() )
+ {
+ return m_sourceList[i];
+ }
+ }
+ return NULL;
+}
+
+void CAudioWaveOutput::AddSource( CAudioMixer *pSource )
+{
+ int slot = 0;
+ for ( int i = 0; i < MAX_CHANNELS; i++ )
+ {
+ if ( !m_sourceList[i] )
+ {
+ slot = i;
+ break;
+ }
+ }
+
+ if ( m_sourceList[slot] )
+ {
+ FreeChannel( slot );
+ }
+ SetChannel( slot, pSource );
+
+ pSource->SetActive( true );
+}
+
+
+void CAudioWaveOutput::StopSounds( void )
+{
+ for ( int i = 0; i < MAX_CHANNELS; i++ )
+ {
+ if ( m_sourceList[i] )
+ {
+ FreeChannel( i );
+ }
+ }
+}
+
+
+void CAudioWaveOutput::SetChannel( int channelIndex, CAudioMixer *pSource )
+{
+ if ( channelIndex < 0 || channelIndex >= MAX_CHANNELS )
+ return;
+
+ m_sourceList[channelIndex] = pSource;
+}
+
+void CAudioWaveOutput::FreeChannel( int channelIndex )
+{
+ if ( channelIndex < 0 || channelIndex >= MAX_CHANNELS )
+ return;
+
+ if ( m_sourceList[channelIndex] )
+ {
+ RemoveMixerChannelReferences( m_sourceList[channelIndex] );
+
+ delete m_sourceList[channelIndex];
+ m_sourceList[channelIndex] = NULL;
+ }
+}
+
+int CAudioWaveOutput::GetOutputPosition( void )
+{
+ if ( !m_deviceHandle )
+ return 0;
+
+ MMTIME mmtime;
+ mmtime.wType = TIME_SAMPLES;
+ waveOutGetPosition( m_deviceHandle, &mmtime, sizeof( MMTIME ) );
+
+ // Convert time to sample count
+ return ( mmtime.u.sample );
+}
+
+void CAudioWaveOutput::OpenDevice( void )
+{
+ WAVEFORMATEX waveFormat;
+
+ memset( &waveFormat, 0, sizeof(waveFormat) );
+ // Select a PCM, 16-bit stereo playback device
+ waveFormat.cbSize = sizeof(waveFormat);
+ waveFormat.nAvgBytesPerSec = OUTPUT_SAMPLE_RATE * 2 * 2;
+ waveFormat.nBlockAlign = 2 * 2; // channels * sample size
+ waveFormat.nChannels = 2; // stereo
+ waveFormat.nSamplesPerSec = OUTPUT_SAMPLE_RATE;
+ waveFormat.wBitsPerSample = 16;
+ waveFormat.wFormatTag = WAVE_FORMAT_PCM;
+
+ MMRESULT errorCode = waveOutOpen( &m_deviceHandle, WAVE_MAPPER, &waveFormat, 0, 0, CALLBACK_NULL );
+ if ( errorCode == MMSYSERR_NOERROR )
+ {
+ int bufferSize = 4 * ( OUTPUT_SAMPLE_RATE / OUTPUT_BUFFER_COUNT ); // total of 1 second of data
+
+ // Got one!
+ for ( int i = 0; i < OUTPUT_BUFFER_COUNT; i++ )
+ {
+ m_buffers[i].hdr = new WAVEHDR;
+ m_buffers[i].hdr->lpData = new char[ bufferSize ];
+ long align = (long)m_buffers[i].hdr->lpData;
+ if ( align & 3 )
+ {
+ m_buffers[i].hdr->lpData = (char *) ( (align+3) &~3 );
+ }
+ m_buffers[i].hdr->dwBufferLength = bufferSize - (align&3);
+ m_buffers[i].hdr->dwFlags = 0;
+
+ if ( waveOutPrepareHeader( m_deviceHandle, m_buffers[i].hdr, sizeof(*m_buffers[i].hdr) ) != MMSYSERR_NOERROR )
+ {
+ ClearDevice();
+ return;
+ }
+ }
+ }
+ else
+ {
+ ClearDevice();
+ }
+}
+
+// factory to create a suitable audio output for this system
+CAudioOutput *CAudioOutput::Create( void )
+{
+ // sound device is a singleton for now
+ static CAudioOutput *pWaveOut = NULL;
+
+ if ( !pWaveOut )
+ {
+ pWaveOut = new CAudioWaveOutput;
+ }
+
+ return pWaveOut;
+}
+
+struct CSoundFile
+{
+ char filename[ 512 ];
+ CAudioSource *source;
+ long filetime;
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+class CSceneManagerSound : public ISceneManagerSound
+{
+public:
+ ~CSceneManagerSound( void );
+
+ void Init( void );
+ void Shutdown( void );
+ void Update( float dt );
+ void Flush( void );
+
+ CAudioSource *LoadSound( const char *wavfile );
+ void PlaySound( const char *wavfile, CAudioMixer **ppMixer );
+
+ void PlaySound( CAudioSource *source, CAudioMixer **ppMixer );
+ bool IsSoundPlaying( CAudioMixer *pMixer );
+ CAudioMixer *FindMixer( CAudioSource *source );
+
+ void StopAll( void );
+ void StopSound( CAudioMixer *mixer );
+
+ CAudioOuput *GetAudioOutput( void );
+
+ virtual CAudioSource *FindOrAddSound( const char *filename );
+
+private:
+
+ CAudioOutput *m_pAudio;
+
+ float m_flElapsedTime;
+
+ CUtlVector < CSoundFile > m_ActiveSounds;
+};
+
+static CSceneManagerSound g_FacePoserSound;
+
+ISceneManagerSound *sound = ( ISceneManagerSound * )&g_FacePoserSound;
+
+CSceneManagerSound::~CSceneManagerSound( void )
+{
+ OutputDebugString( va( "Removing %i sounds\n", m_ActiveSounds.Size() ) );
+ for ( int i = 0 ; i < m_ActiveSounds.Size(); i++ )
+ {
+ CSoundFile *p = &m_ActiveSounds[ i ];
+ OutputDebugString( va( "Removing sound: %s\n", p->filename ) );
+ delete p->source;
+ }
+
+ m_ActiveSounds.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+CAudioOuput *CSceneManagerSound::GetAudioOutput( void )
+{
+ return (CAudioOuput *)m_pAudio;
+}
+
+CAudioSource *CSceneManagerSound::FindOrAddSound( const char *filename )
+{
+ CSoundFile *s;
+
+ int i;
+ for ( i = 0; i < m_ActiveSounds.Size(); i++ )
+ {
+ s = &m_ActiveSounds[ i ];
+ Assert( s );
+ if ( !stricmp( s->filename, filename ) )
+ {
+ long filetime = filesystem->GetFileTime( filename );
+ if ( filetime != s->filetime )
+ {
+ Con_Printf( "Reloading sound %s\n", filename );
+ delete s->source;
+ s->source = LoadSound( filename );
+ s->filetime = filetime;
+ }
+ return s->source;
+ }
+ }
+
+ i = m_ActiveSounds.AddToTail();
+ s = &m_ActiveSounds[ i ];
+ strcpy( s->filename, filename );
+ s->source = LoadSound( filename );
+ s->filetime = filesystem->GetFileTime( filename );
+
+ return s->source;
+}
+
+void CSceneManagerSound::Init( void )
+{
+ m_flElapsedTime = 0.0f;
+ m_pAudio = CAudioOutput::Create();
+}
+
+void CSceneManagerSound::Shutdown( void )
+{
+}
+
+CAudioSource *CSceneManagerSound::LoadSound( const char *wavfile )
+{
+ if ( !m_pAudio )
+ return NULL;
+
+ CAudioSource *wave = AudioSource_Create( wavfile );
+ return wave;
+}
+
+void CSceneManagerSound::PlaySound( const char *wavfile, CAudioMixer **ppMixer )
+{
+ if ( m_pAudio )
+ {
+ CAudioSource *wave = FindOrAddSound( wavfile );
+ if ( !wave )
+ return;
+
+ CAudioMixer *pMixer = wave->CreateMixer();
+ if ( ppMixer )
+ {
+ *ppMixer = pMixer;
+ }
+ m_pAudio->AddSource( pMixer );
+ }
+}
+
+void CSceneManagerSound::PlaySound( CAudioSource *source, CAudioMixer **ppMixer )
+{
+ if ( ppMixer )
+ {
+ *ppMixer = NULL;
+ }
+
+ if ( m_pAudio )
+ {
+ CAudioMixer *mixer = source->CreateMixer();
+ if ( ppMixer )
+ {
+ *ppMixer = mixer;
+ }
+ m_pAudio->AddSource( mixer );
+ }
+}
+
+void CSceneManagerSound::Update( float dt )
+{
+ if ( m_pAudio )
+ {
+ m_pAudio->Update( m_flElapsedTime );
+ }
+
+ m_flElapsedTime += dt;
+}
+
+void CSceneManagerSound::Flush( void )
+{
+ if ( m_pAudio )
+ {
+ m_pAudio->Flush();
+ }
+}
+
+void CSceneManagerSound::StopAll( void )
+{
+ if ( m_pAudio )
+ {
+ m_pAudio->StopSounds();
+ }
+}
+
+void CSceneManagerSound::StopSound( CAudioMixer *mixer )
+{
+ int idx = m_pAudio->FindSourceIndex( mixer );
+ if ( idx != -1 )
+ {
+ m_pAudio->FreeChannel( idx );
+ }
+}
+
+bool CSceneManagerSound::IsSoundPlaying( CAudioMixer *pMixer )
+{
+ if ( !m_pAudio || !pMixer )
+ {
+ return false;
+ }
+
+ //
+ int index = m_pAudio->FindSourceIndex( pMixer );
+ if ( index != -1 )
+ return true;
+
+ return false;
+}
+
+CAudioMixer *CSceneManagerSound::FindMixer( CAudioSource *source )
+{
+ if ( !m_pAudio )
+ return NULL;
+
+ return m_pAudio->GetMixerForSource( source );
+}
diff --git a/utils/scenemanager/sound.h b/utils/scenemanager/sound.h
new file mode 100644
index 0000000..0199701
--- /dev/null
+++ b/utils/scenemanager/sound.h
@@ -0,0 +1,97 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#ifndef SOUND_H
+#define SOUND_H
+#pragma once
+
+class CAudioMixer;
+
+class CAudioInput
+{
+public:
+ // factory to create a suitable audio input for this system
+ static CAudioInput *Create( void );
+
+ // base class needs virtual destructor
+ virtual ~CAudioInput( void ) {}
+
+ // ------------------- interface ------------------------
+
+ // Returns the current count of available samples
+ virtual int SampleCount( void ) = 0;
+
+ // returns the size of each sample in bytes
+ virtual int SampleSize( void ) = 0;
+
+ // returns the sampling rate of the data
+ virtual int SampleRate( void ) = 0;
+
+ // returns a pointer to the available data
+ virtual void *SampleData( void ) = 0;
+
+ // release the available data (mark as done)
+ virtual void SampleRelease( void ) = 0;
+
+ // returns the mono/stereo status of this device (true if stereo)
+ virtual bool IsStereo( void ) = 0;
+
+ // begin sampling
+ virtual void Start( void ) = 0;
+
+ // stop sampling
+ virtual void Stop( void ) = 0;
+};
+
+class CAudioSource;
+
+class CAudioOutput
+{
+public:
+ // factory to create a suitable audio output for this system
+ static CAudioOutput *Create( void );
+
+ // base class needs virtual destructor
+ virtual ~CAudioOutput( void ) {}
+
+ // ------------------- interface ------------------------
+
+ // returns the size of each sample in bytes
+ virtual int SampleSize( void ) = 0;
+
+ // returns the sampling rate of the data
+ virtual int SampleRate( void ) = 0;
+
+ // returns the mono/stereo status of this device (true if stereo)
+ virtual bool IsStereo( void ) = 0;
+
+ // move up to time (time is absolute)
+ virtual void Update( float dt ) = 0;
+
+ virtual void Flush( void ) = 0;
+
+ // Hook up a filter to the input channel
+ virtual void AddSource( CAudioMixer *pSource ) = 0;
+
+ virtual void StopSounds( void ) = 0;
+
+ virtual void FreeChannel( int channel ) = 0;
+
+ virtual int FindSourceIndex( CAudioMixer *pSource ) = 0;
+
+ virtual float GetAmountofTimeAhead( void ) = 0;
+
+ virtual int GetNumberofSamplesAhead( void ) = 0;
+
+ virtual CAudioMixer *GetMixerForSource( CAudioSource *pDevice ) = 0;
+};
+
+
+int AudioResample( void *pInput, int inCount, int inSize, bool inStereo, int inRate,
+ void *pOutput, int outCount, int outSize, bool outStereo, int outRate );
+
+#endif // SOUND_H
diff --git a/utils/scenemanager/soundbrowser.cpp b/utils/scenemanager/soundbrowser.cpp
new file mode 100644
index 0000000..f81e01d
--- /dev/null
+++ b/utils/scenemanager/soundbrowser.cpp
@@ -0,0 +1,964 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "workspacebrowser.h"
+#include "workspace.h"
+#include "project.h"
+#include <windows.h>
+#include "resource.h"
+#include "project.h"
+#include "vcdfile.h"
+#include "soundentry.h"
+#include "scene.h"
+
+#include "workspacemanager.h"
+#include "soundbrowser.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "iscenemanagersound.h"
+#include "snd_wave_source.h"
+#include "cmdlib.h"
+#include "tabwindow.h"
+#include "soundproperties.h"
+#include "soundproperties_multiple.h"
+#include "wavebrowser.h"
+#include "wavefile.h"
+#include "inputproperties.h"
+#include "drawhelper.h"
+#include "utlbuffer.h"
+
+#define ENTRY_ALLSOUNDS "AllSounds"
+#define ENTRY_ALL_INDEX 0
+#define ENTRY_SEARCHRESULTS "Search results"
+#define ENTRY_SEARCH_INDEX 1
+
+enum
+{
+ // Controls
+ IDC_SB_LISTVIEW = 101,
+ IDC_SB_FILTERTAB,
+
+ // Messages
+ IDC_SB_PLAY = 1000,
+ IDC_SB_SOUNDPROPERTIES,
+ IDC_SB_SHOWINWAVEBROWSER,
+ IDC_SB_ADDSOUND,
+ IDC_SB_REMOVESOUND,
+ IDC_SB_GETSENTENCE,
+};
+
+enum
+{
+ COL_SOUND = 0,
+ COL_COUNT,
+ COL_WAV,
+ COL_SENTENCE,
+ COL_CHANNEL,
+ COL_VOLUME,
+ COL_SOUNDLEVEL,
+ COL_PITCH,
+ COL_SCRIPT,
+ COL_CC,
+};
+
+class CSoundList : public mxListView
+{
+public:
+ CSoundList( mxWindow *parent, int id = 0 )
+ : mxListView( parent, 0, 0, 0, 0, id )
+ {
+ // SendMessage ( (HWND)getHandle(), WM_SETFONT, (WPARAM) (HFONT) GetStockObject (ANSI_FIXED_FONT), MAKELPARAM (TRUE, 0));
+
+ //HWND wnd = (HWND)getHandle();
+ //DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ //style |= LVS_SORTASCENDING;
+ //SetWindowLong( wnd, GWL_STYLE, style );
+
+ //SceneManager_AddWindowStyle( this, LVS_SORTASCENDING );
+
+ // Add column headers
+ insertTextColumn( COL_SOUND, 200, "Sound" );
+ insertTextColumn( COL_COUNT, 20, "#" );
+ insertTextColumn( COL_WAV, 220, "WAV Filename" );
+ insertTextColumn( COL_SENTENCE, 300, "Sentence Text" );
+ insertTextColumn( COL_CHANNEL, 100, "Channel" );
+ insertTextColumn( COL_VOLUME, 100, "Volume" );
+ insertTextColumn( COL_SOUNDLEVEL, 120, "Soundlevel" );
+ insertTextColumn( COL_PITCH, 100, "Pitch" );
+ insertTextColumn( COL_SCRIPT, 150, "Script File" );
+ insertTextColumn( COL_CC, 300, "CC Text" );
+ }
+};
+
+class CSoundFilterTab : public CTabWindow
+{
+public:
+ typedef CTabWindow BaseClass;
+
+ CSoundFilterTab( mxWindow *parent, int x, int y, int w, int h, int id = 0, int style = 0 ) :
+ CTabWindow( parent, x, y, w, h, id, style )
+ {
+ SetInverted( true );
+ SetRowHeight( 20 );
+ }
+
+ virtual void ShowRightClickMenu( int mx, int my )
+ {
+ // Nothing
+ }
+
+ void Init( CUtlSymbolTable& table, CUtlVector< CUtlSymbol >& scripts )
+ {
+ add( ENTRY_ALLSOUNDS );
+ add( ENTRY_SEARCHRESULTS );
+
+ int c = scripts.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ CUtlSymbol& sym = scripts[ i ];
+ add( table.String( sym ) );
+ }
+ select( 0 );
+ }
+
+ void UpdatePrefixes()
+ {
+ int c = getItemCount();
+ // Skip All and search results
+ for ( int i = 2; i < c; i++ )
+ {
+ setPrefix( i, "" );
+
+ char const *script = getLabel( i );
+ if ( !script )
+ continue;
+
+ int scriptindex = g_pSoundEmitterSystem->FindSoundScript( va( "scripts/%s.txt", script ) );
+ if ( scriptindex < 0 )
+ continue;
+
+ if ( g_pSoundEmitterSystem->IsSoundScriptDirty( scriptindex ) )
+ {
+ setPrefix( i, "* " );
+ }
+ }
+
+ RecomputeLayout( w2() );
+ redraw();
+ }
+};
+
+
+class COptionsWindow : public mxWindow
+{
+ typedef mxWindow BaseClass;
+public:
+ enum
+ {
+ IDC_VOICE_ONLY = 1000,
+ IDC_PLAY_SOUND,
+ IDC_STOP_SOUNDS,
+ IDC_SEARCH,
+ };
+
+ COptionsWindow( CSoundBrowser *browser ) : BaseClass( browser, 0, 0, 0, 0 ), m_pBrowser( browser )
+ {
+ SceneManager_AddWindowStyle( this, WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
+
+ m_szSearchString[0]=0;
+
+ m_pChanVoiceOnly = new mxCheckBox( this, 0, 0, 0, 0, "CHAN_VOICE only", IDC_VOICE_ONLY );
+ m_pChanVoiceOnly->setChecked( true );
+
+ m_pPlay = new mxButton( this, 0, 0, 0, 0, "Play", IDC_PLAY_SOUND );
+
+ m_pStopSounds = new mxButton( this, 0, 0, 0, 0, "Stop Sounds", IDC_STOP_SOUNDS );
+
+ m_pSearch = new mxButton( this, 0, 0, 0, 0, "Search...", IDC_SEARCH );
+
+ m_pSearchString = new mxLabel( this, 0, 0, 0, 0, "" );
+ }
+
+ bool PaintBackground( void )
+ {
+ redraw();
+ return false;
+ }
+
+
+ virtual void redraw()
+ {
+ CDrawHelper drawHelper( this, GetSysColor( COLOR_BTNFACE ) );
+ }
+
+ virtual int handleEvent( mxEvent *event )
+ {
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Size:
+ {
+ iret = 1;
+
+ int split = 120;
+
+ int x = 1;
+
+ m_pPlay->setBounds( x, 1, split, h2() - 2 );
+
+ x += split + 10;
+
+ m_pStopSounds->setBounds( x, 1, split, h2()-2 );
+
+ x += split + 10;
+
+ m_pChanVoiceOnly->setBounds( x, 1, split, h2() - 2 );
+
+ x += split + 10;
+
+ m_pSearch->setBounds( x, 1, split, h2() - 2 );
+
+ x += split + 10;
+
+ m_pSearchString->setBounds( x, 2, split * 2, h2() - 4 );
+
+ x += split * 2 + 10;
+
+ }
+ break;
+ case mxEvent::Action:
+ {
+ switch ( event->action )
+ {
+ case IDC_STOP_SOUNDS:
+ {
+ iret = 1;
+ sound->StopAll();
+ }
+ break;
+ case IDC_PLAY_SOUND:
+ {
+ iret = 1;
+ m_pBrowser->OnPlay();
+ }
+ break;
+ case IDC_VOICE_ONLY:
+ {
+ iret = 1;
+ m_pBrowser->RepopulateTree();
+ };
+ break;
+ case IDC_SEARCH:
+ {
+ iret = 1;
+ OnSearch();
+ };
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ return iret;
+ }
+
+ bool IsChanVoiceOnly() const
+ {
+ return m_pChanVoiceOnly->isChecked();
+ }
+
+ char const *GetSearchString()
+ {
+ return m_szSearchString;
+ }
+
+ void OnSearch()
+ {
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Search" );
+ Q_strcpy( params.m_szPrompt, "Find:" );
+ Q_strcpy( params.m_szInputText, m_szSearchString );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ Q_strcpy( m_szSearchString, params.m_szInputText );
+
+ m_pSearchString->setLabel( va( "Search: '%s'", GetSearchString() ) );
+
+ m_pBrowser->OnSearch();
+ }
+
+private:
+
+ mxCheckBox *m_pChanVoiceOnly;
+ mxButton *m_pStopSounds;
+ mxButton *m_pPlay;
+ mxButton *m_pSearch;
+ mxLabel *m_pSearchString;
+
+ CSoundBrowser *m_pBrowser;
+
+ char m_szSearchString[ 256 ];
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+//-----------------------------------------------------------------------------
+CSoundBrowser::CSoundBrowser( mxWindow *parent, CWorkspaceManager *manager, int id ) :
+ BaseClass( parent, 0, 0, 0, 0, "Sound Browser", id )
+{
+ m_pManager = manager;
+
+ SceneManager_MakeToolWindow( this, false );
+
+ m_pListView = new CSoundList( this, IDC_SB_LISTVIEW );
+ m_pFilter = new CSoundFilterTab( this, 0, 0, 0, 0, IDC_SB_FILTERTAB );
+ m_pOptions = new COptionsWindow( this );
+
+ HIMAGELIST list = GetWorkspaceManager()->CreateImageList();
+
+ // Associate the image list with the tree-view control.
+ m_pListView->setImageList( (void *)list );
+
+ LoadAllSounds();
+
+ m_pFilter->select( 0 );
+ RepopulateTree();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSoundBrowser::OnDelete()
+{
+ RemoveAllSounds();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *event -
+// Output : int
+//-----------------------------------------------------------------------------
+int CSoundBrowser::handleEvent( mxEvent *event )
+{
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ {
+ iret = 0;
+ }
+ break;
+ case IDC_SB_FILTERTAB:
+ {
+ RepopulateTree();
+ }
+ break;
+ case IDC_SB_LISTVIEW:
+ {
+ bool rightmouse = ( event->flags == mxEvent::RightClicked ) ? true : false;
+ bool doubleclicked = ( event->flags == mxEvent::DoubleClicked ) ? true : false;
+
+ if ( rightmouse )
+ {
+ ShowContextMenu();
+ }
+ else if ( doubleclicked )
+ {
+ if ( m_pListView->getNumSelected() == 1 )
+ {
+ int index = m_pListView->getNextSelectedItem( -1 );
+ if ( index >= 0 )
+ {
+ CSoundEntry *se = (CSoundEntry *)m_pListView->getUserData( index, 0 );
+ if ( se )
+ {
+ se->Play();
+
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ if ( wb && se->GetWaveCount() > 0 )
+ {
+ CWaveFile *firstwave = se->GetWave( 0 );
+ Assert( firstwave );
+ if ( firstwave )
+ {
+ wb->JumpToItem( firstwave );
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ case IDC_SB_PLAY:
+ {
+ OnPlay();
+ }
+ break;
+ case IDC_SB_GETSENTENCE:
+ {
+ OnGetSentence();
+ }
+ break;
+ case IDC_SB_SOUNDPROPERTIES:
+ {
+ OnSoundProperties();
+ }
+ break;
+ case IDC_SB_SHOWINWAVEBROWSER:
+ {
+ OnShowInWaveBrowser();
+ }
+ break;
+ case IDC_SB_ADDSOUND:
+ {
+ OnAddSound();
+ }
+ break;
+ case IDC_SB_REMOVESOUND:
+ {
+ OnRemoveSound();
+ }
+ break;
+ }
+ }
+ break;
+ case mxEvent::Size:
+ {
+ int optionsh = 20;
+ int filterh = m_pFilter->GetBestHeight( w2() );
+
+ m_pOptions->setBounds( 0, 0, w2(), optionsh );
+ m_pListView->setBounds( 0, optionsh, w2(), h2() - filterh - optionsh );
+ m_pFilter->setBounds( 0, h2() - filterh, w2(), filterh );
+
+ GetWorkspaceManager()->SetWorkspaceDirty();
+
+ iret = 1;
+ }
+ break;
+ case mxEvent::Close:
+ {
+ iret = 1;
+ }
+ break;
+ }
+
+ return iret;
+}
+
+static bool NameLessFunc( CSoundEntry *const& name1, CSoundEntry *const& name2 )
+{
+ if ( Q_stricmp( name1->GetName(), name2->GetName() ) < 0 )
+ return true;
+ return false;
+}
+
+void CSoundBrowser::LoadAllSounds()
+{
+ RemoveAllSounds();
+
+ // int c = g_pSoundEmitterSystem->GetSoundCount();
+ int added = 0;
+
+ int i;
+ for ( i = g_pSoundEmitterSystem->First(); i != g_pSoundEmitterSystem->InvalidIndex(); i = g_pSoundEmitterSystem->Next( i ) )
+ {
+ char const *name = g_pSoundEmitterSystem->GetSoundName( i );
+ CSoundEntry *se = new CSoundEntry( NULL, name );
+ m_AllSounds.AddToTail( se );
+
+ char filebase [ 512 ];
+ Q_FileBase( g_pSoundEmitterSystem->GetSourceFileForSound( i ), filebase, sizeof( filebase ) );
+
+ // Add script file symbol
+ CUtlSymbol script_sym = m_ScriptTable.AddString( filebase );
+
+ if ( m_Scripts.Find( script_sym ) == m_Scripts.InvalidIndex() )
+ {
+ m_Scripts.AddToTail( script_sym );
+ }
+
+ ++added;
+
+ if ( !( added % 500 ) )
+ {
+ // Con_Printf( "CSoundBrowser: loaded %i sounds\n", added );
+ }
+ }
+
+ m_pFilter->Init( m_ScriptTable, m_Scripts );
+}
+
+void CSoundBrowser::RemoveAllSounds()
+{
+ int c = m_AllSounds.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ CSoundEntry *se = m_AllSounds[ i ];
+ delete se;
+ }
+
+ m_AllSounds.RemoveAll();
+ m_Scripts.RemoveAll();
+ m_CurrentSelection.RemoveAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CSoundBrowser::PopulateTree( bool voiceonly, char const *scriptonly )
+{
+ int i;
+
+ CUtlRBTree< CSoundEntry *, int > m_Sorted( 0, 0, NameLessFunc );
+
+ bool textsearch = false;
+ char const *texttofind = NULL;
+
+ if ( scriptonly )
+ {
+ if ( !Q_stricmp( scriptonly, ENTRY_ALLSOUNDS ) )
+ {
+ scriptonly = NULL;
+ }
+ else if ( !Q_stricmp( scriptonly, ENTRY_SEARCHRESULTS ) )
+ {
+ scriptonly = NULL;
+ textsearch = true;
+ texttofind = GetSearchString();
+ }
+ }
+
+ int c = m_AllSounds.Count();
+ for ( i = 0; i < c; i++ )
+ {
+ CSoundEntry *se = m_AllSounds[ i ];
+ char const *name = se->GetName();
+
+ CSoundParametersInternal *params = se->GetSoundParameters();
+ if ( !params )
+ continue;
+
+ if ( voiceonly && params->GetChannel() != CHAN_VOICE )
+ continue;
+
+ if ( scriptonly )
+ {
+ if ( Q_stricmp( scriptonly, se->GetScriptFile() ) )
+ continue;
+ }
+
+ if ( textsearch && texttofind )
+ {
+ bool keep = false;
+ if ( Q_stristr( name, texttofind ) )
+ {
+ keep = true;
+ }
+ else
+ {
+ int waveCount = se->GetWaveCount();
+ for ( int wave = 0; wave < waveCount; wave++ )
+ {
+ CWaveFile *w = se->GetWave( wave );
+ if ( !w )
+ continue;
+
+ char const *wavename = w->GetFileName();
+ if ( !wavename )
+ {
+ Assert( 0 );
+ continue;
+ }
+
+ if ( !Q_stristr( wavename, texttofind ) )
+ {
+ continue;
+ }
+
+ keep = true;
+ break;
+ }
+ }
+
+
+ if ( !keep )
+ {
+ continue;
+ }
+ }
+
+ m_Sorted.Insert( se );
+ }
+
+
+// Repopulate tree
+ m_pListView->removeAll();
+
+ int loadcount = 0;
+
+ m_pListView->setDrawingEnabled( false );
+
+ for ( i = m_Sorted.FirstInorder(); i != m_Sorted.InvalidIndex(); i = m_Sorted.NextInorder( i ) )
+ {
+ CSoundEntry *se = m_Sorted[ i ];
+ char const *name = se->GetName();
+ CSoundParametersInternal *params = se->GetSoundParameters();
+ if ( !params )
+ continue;
+
+ int slot = m_pListView->add( name );
+
+ m_pListView->setUserData( slot, COL_SOUND, (void *)se );
+
+ m_pListView->setImage( slot, COL_SOUND, se->GetIconIndex() );
+
+ int waveCount = params->NumSoundNames();
+
+ if ( waveCount >= 1 )
+ {
+ m_pListView->setLabel( slot, COL_COUNT, waveCount > 1 ? va( "%i", waveCount ) : "" );
+ m_pListView->setLabel( slot, COL_WAV, g_pSoundEmitterSystem->GetWaveName( params->GetSoundNames()[ 0 ].symbol ) );
+ }
+
+ m_pListView->setLabel( slot, COL_SENTENCE, se->GetSentenceText( 0 ) );
+
+ m_pListView->setLabel( slot, COL_CHANNEL, params->ChannelToString() );
+ m_pListView->setLabel( slot, COL_VOLUME, params->VolumeToString() );
+ m_pListView->setLabel( slot, COL_SOUNDLEVEL, params->SoundLevelToString() );
+ m_pListView->setLabel( slot, COL_PITCH, params->PitchToString() );
+
+ wchar_t buf[ 1024 ];
+ se->GetCCText( buf, 1024 );
+ m_pListView->setLabel( slot, COL_CC, buf );
+
+ char filebase [ 512 ];
+
+ int soundIndex = g_pSoundEmitterSystem->GetSoundIndex( name );
+
+ Q_FileBase( g_pSoundEmitterSystem->GetSourceFileForSound( soundIndex ), filebase, sizeof( filebase ) );
+
+ m_pListView->setLabel( slot, COL_SCRIPT, filebase );
+
+ ++loadcount;
+ }
+
+ m_pListView->setDrawingEnabled( true );
+
+ // Con_Printf( "CSoundBrowser: selected %i sounds\n", loadcount );
+}
+
+CWorkspaceManager *CSoundBrowser::GetManager()
+{
+ return m_pManager;
+}
+
+void CSoundBrowser::RepopulateTree()
+{
+ bool voiceonly = m_pOptions->IsChanVoiceOnly();
+
+ int slot = m_pFilter->getSelectedIndex();
+
+ if ( 0 >= slot )
+ {
+ PopulateTree( voiceonly, NULL );
+ }
+ else
+ {
+ PopulateTree( voiceonly, m_pFilter->getLabel( slot ) );
+ }
+
+ m_pFilter->UpdatePrefixes();
+}
+
+void CSoundBrowser::BuildSelectionList( CUtlVector< CSoundEntry * >& selected )
+{
+ selected.RemoveAll();
+
+ int idx = -1;
+ do
+ {
+ idx = m_pListView->getNextSelectedItem( idx );
+ if ( idx != -1 )
+ {
+ CSoundEntry *se = (CSoundEntry *)m_pListView->getUserData( idx, 0 );
+ if ( se )
+ {
+ selected.AddToTail( se );
+ }
+ }
+ } while ( idx != -1 );
+
+}
+
+void CSoundBrowser::ShowContextMenu( void )
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() <= 0 )
+ return;
+
+ POINT pt;
+ GetCursorPos( &pt );
+ ScreenToClient( (HWND)getHandle(), &pt );
+
+ // New scene, edit comments
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ if ( m_CurrentSelection.Count() == 1 )
+ {
+ pop->add ("&Play", IDC_SB_PLAY );
+ pop->addSeparator();
+ }
+
+ pop->add( "Refresh sentence data", IDC_SB_GETSENTENCE );
+
+ pop->add( "Add sound entry...", IDC_SB_ADDSOUND );
+ if ( m_CurrentSelection.Count() >= 1 )
+ {
+ pop->add( "Remove sound(s)", IDC_SB_REMOVESOUND );
+ }
+
+ pop->addSeparator();
+
+ pop->add( "Show in Wave Browser", IDC_SB_SHOWINWAVEBROWSER );
+
+ pop->add( "&Properties...", IDC_SB_SOUNDPROPERTIES );
+
+ pop->popup( this, pt.x, pt.y );
+}
+
+void CSoundBrowser::OnPlay()
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() == 1 )
+ {
+ CSoundEntry *se = m_CurrentSelection[ 0 ];
+ if ( se )
+ {
+ se->Play();
+ }
+ }
+}
+
+void CSoundBrowser::JumpToItem( CSoundEntry *se )
+{
+ char const *script = se->GetScriptFile();
+
+ bool voiceonly = m_pOptions->IsChanVoiceOnly();
+
+ if ( !script || !script[ 0 ] )
+ {
+ PopulateTree( voiceonly, NULL );
+ }
+ else
+ {
+ PopulateTree( voiceonly, script );
+ }
+
+ int idx = 0;
+ int c = m_pListView->getItemCount();
+ for ( ; idx < c; idx++ )
+ {
+ CSoundEntry *item = (CSoundEntry *)m_pListView->getUserData( idx, 0 );
+ if ( !Q_stricmp( item->GetName(), se->GetName() ) )
+ {
+ break;
+ }
+ }
+
+ if ( idx < c )
+ {
+ m_pListView->scrollToItem( idx );
+ }
+}
+
+void CSoundBrowser::OnSoundProperties()
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() < 1 )
+ {
+ Con_Printf( "No selection\n" );
+ return;
+ }
+
+ CSoundParams params;
+ memset( &params, 0, sizeof( params ) );
+
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Sound Properties" );
+
+ int c = m_CurrentSelection.Count();
+ for ( int i = 0 ; i < c; i++ )
+ {
+ CSoundEntry *entry = m_CurrentSelection[ i ];
+ if ( !entry )
+ continue;
+
+ params.items.AddToTail( entry );
+ }
+
+ if ( params.items.Count() > 1 )
+ {
+ SoundProperties_Multiple( &params );
+ }
+ else
+ {
+ SoundProperties( &params );
+ }
+}
+
+void CSoundBrowser::OnShowInWaveBrowser()
+{
+ if ( m_pListView->getNumSelected() == 1 )
+ {
+ int index = m_pListView->getNextSelectedItem( -1 );
+ if ( index >= 0 )
+ {
+ CSoundEntry *se = (CSoundEntry *)m_pListView->getUserData( index, 0 );
+ if ( se )
+ {
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ if ( wb && se->GetWaveCount() > 0 )
+ {
+ CWaveFile *firstwave = se->GetWave( 0 );
+ Assert( firstwave );
+ if ( firstwave )
+ {
+ wb->JumpToItem( firstwave );
+ }
+ }
+ }
+ }
+ }
+}
+
+void CSoundBrowser::OnSearch()
+{
+ m_pFilter->select( ENTRY_SEARCH_INDEX );
+ RepopulateTree();
+}
+
+char const *CSoundBrowser::GetSearchString()
+{
+ return m_pOptions->GetSearchString();
+}
+
+void CSoundBrowser::OnAddSound()
+{
+ CSoundParams params;
+ memset( &params, 0, sizeof( params ) );
+ params.addsound = true;
+
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "New Sound" );
+
+ if ( !SoundProperties( &params ) )
+ return;
+
+ if ( params.items.Count() == 1 )
+ {
+ CSoundEntry *newItem = params.items[ 0 ];
+ m_AllSounds.AddToTail( newItem );
+
+ int slot = g_pSoundEmitterSystem->GetSoundIndex( newItem->GetName() );
+ if ( g_pSoundEmitterSystem->IsValidIndex( slot ) )
+ {
+ CSoundParametersInternal *p = g_pSoundEmitterSystem->InternalGetParametersForSound( slot );
+ if ( p )
+ {
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ Assert( wb );
+
+ int waveCount = p->NumSoundNames();
+ for ( int wave = 0; wave < waveCount; wave++ )
+ {
+ char const *wavname = g_pSoundEmitterSystem->GetWaveName( p->GetSoundNames()[ wave ].symbol );
+ if ( wavname )
+ {
+ CWaveFile *wavefile = wb->FindEntry( wavname, true );
+ if ( wavefile )
+ {
+ newItem->AddWave( wavefile );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Repopulate things
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+void CSoundBrowser::OnRemoveSound()
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() < 1 )
+ {
+ Con_Printf( "No selection\n" );
+ return;
+ }
+
+ int c = m_CurrentSelection.Count();
+ for ( int i = c - 1; i >= 0 ; i-- )
+ {
+ CSoundEntry *se = m_CurrentSelection[ i ];
+ Assert( se );
+
+ // FIXME: See if still referenced by a vcd?
+
+ g_pSoundEmitterSystem->RemoveSound( se->GetName() );
+ m_AllSounds.FindAndRemove( se );
+ delete se;
+ }
+
+ // Repopulate things
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+void CSoundBrowser::OnGetSentence()
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() < 1 )
+ {
+ Con_Printf( "No selection\n" );
+ return;
+ }
+
+ int c = m_CurrentSelection.Count();
+ for ( int i = c - 1; i >= 0 ; i-- )
+ {
+ CSoundEntry *se = m_CurrentSelection[ i ];
+ Assert( se );
+
+ int c = se->GetWaveCount();
+ for ( int i = 0; i < c; ++i )
+ {
+ CWaveFile *wav = se->GetWave( i );
+ if ( !wav->HasLoadedSentenceInfo() )
+ {
+ wav->EnsureSentence();
+ }
+ }
+ }
+
+ // Repopulate things
+ GetWorkspaceManager()->RefreshBrowsers();
+}
diff --git a/utils/scenemanager/soundbrowser.h b/utils/scenemanager/soundbrowser.h
new file mode 100644
index 0000000..5b3b067
--- /dev/null
+++ b/utils/scenemanager/soundbrowser.h
@@ -0,0 +1,89 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SOUNDBROWSER_H
+#define SOUNDBROWSER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "mxtk/mxListView.h"
+#include "commctrl.h"
+#include "utlsymbol.h"
+
+class CWorkspace;
+class CProject;
+class CScene;
+class CVCDFile;
+class CSoundEntry;
+
+class CSoundList;
+class CWorkspaceManager;
+class CSoundFilterTab;
+class COptionsWindow;
+
+
+class CSoundBrowser : public mxWindow
+{
+ typedef mxWindow BaseClass;
+public:
+
+ CSoundBrowser( mxWindow *parent, CWorkspaceManager *manager, int id );
+
+ virtual int handleEvent( mxEvent *event );
+ virtual void OnDelete();
+
+ CWorkspaceManager *GetManager();
+
+ void RepopulateTree();
+
+ void BuildSelectionList( CUtlVector< CSoundEntry * >& selected );
+
+ void OnPlay();
+
+ void JumpToItem( CSoundEntry *se );
+
+ void OnSearch();
+
+private:
+
+ char const *GetSearchString();
+
+ void OnShowInWaveBrowser();
+ void OnSoundProperties();
+ void OnAddSound();
+ void OnRemoveSound();
+ void OnGetSentence();
+ void PopulateTree( bool voiceonly, char const *scriptonly );
+
+ void ShowContextMenu( void );
+
+ void LoadAllSounds();
+ void RemoveAllSounds();
+
+
+ CSoundList *m_pListView;
+
+ enum
+ {
+ NUM_BITMAPS = 8,
+ };
+
+ CWorkspaceManager *m_pManager;
+
+ CUtlVector< CSoundEntry * > m_AllSounds;
+ CUtlSymbolTable m_ScriptTable;
+
+ CUtlVector< CUtlSymbol > m_Scripts;
+
+ CSoundFilterTab *m_pFilter;
+ COptionsWindow *m_pOptions;
+
+ CUtlVector< CSoundEntry * > m_CurrentSelection;
+};
+
+
+#endif // SOUNDBROWSER_H
diff --git a/utils/scenemanager/soundentry.cpp b/utils/scenemanager/soundentry.cpp
new file mode 100644
index 0000000..fa2e0c9
--- /dev/null
+++ b/utils/scenemanager/soundentry.cpp
@@ -0,0 +1,334 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "soundentry.h"
+#include "sentence.h"
+#include "iscenemanagersound.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "snd_wave_source.h"
+#include "cmdlib.h"
+#include "workspacemanager.h"
+#include "vcdfile.h"
+#include "workspacebrowser.h"
+#include "wavefile.h"
+#include "wavebrowser.h"
+#include <vgui/ILocalize.h>
+#include "tier3/tier3.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CSoundEntry::CSoundEntry( CVCDFile *vcd, char const *name ) : m_pOwner( vcd )
+{
+ Q_memset( &m_Params, 0, sizeof( m_Params ) );
+
+ m_szScriptFile[ 0 ] = 0;
+
+ Q_strncpy( m_szName, name, sizeof( m_szName ) );
+
+ // Get name out of sound emitter system
+ char filebase [ 64 ];
+ int slot = g_pSoundEmitterSystem->GetSoundIndex( name );
+ if ( g_pSoundEmitterSystem->IsValidIndex( slot ) )
+ {
+ Q_FileBase( g_pSoundEmitterSystem->GetSourceFileForSound( slot ), filebase, sizeof( filebase ) );
+ Q_strncpy( m_szScriptFile, filebase, sizeof( m_szScriptFile ) );
+
+ // Look up and add the .wav files for the sound entry
+
+ CSoundParametersInternal *p = g_pSoundEmitterSystem->InternalGetParametersForSound( slot );
+ if ( p )
+ {
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ Assert( wb );
+
+ int waveCount = p->NumSoundNames();
+ for ( int wave = 0; wave < waveCount; wave++ )
+ {
+ char const *wavname = g_pSoundEmitterSystem->GetWaveName( p->GetSoundNames()[ wave ].symbol );
+ if ( wavname )
+ {
+ CWaveFile *wavefile = wb->FindEntry( wavname, false );
+ if ( wavefile )
+ {
+ AddWave( wavefile );
+ }
+ }
+ }
+ }
+ }
+}
+
+CSoundEntry::~CSoundEntry()
+{
+ m_Waves.RemoveAll();
+}
+
+CVCDFile *CSoundEntry::GetOwnerVCDFile()
+{
+ return m_pOwner;
+}
+
+int CSoundEntry::GetWaveCount() const
+{
+ return m_Waves.Count();
+}
+
+CWaveFile *CSoundEntry::GetWave( int index )
+{
+ if ( index < 0 || index >= m_Waves.Count() )
+ return NULL;
+ return m_Waves[ index ];
+}
+
+void CSoundEntry::ClearWaves()
+{
+ m_Waves.RemoveAll();
+}
+
+void CSoundEntry::AddWave( CWaveFile *wave )
+{
+ if ( m_Waves.Find( wave ) != m_Waves.InvalidIndex() )
+ return;
+
+ m_Waves.AddToTail( wave );
+}
+
+void CSoundEntry::RemoveWave( CWaveFile *wave )
+{
+ m_Waves.FindAndRemove( wave );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *wave -
+// Output : int
+//-----------------------------------------------------------------------------
+int CSoundEntry::FindWave( CWaveFile *wave )
+{
+ int idx = m_Waves.Find( wave );
+ if ( idx != m_Waves.InvalidIndex() )
+ return idx;
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+void CSoundEntry::SetName( char const *name )
+{
+ if ( !Q_stricmp( m_szName, name ) )
+ return;
+
+ Q_strncpy( m_szName, name, sizeof( m_szName ) );
+
+ // Get name out of sound emitter system
+ char filebase [ 64 ];
+ int slot = g_pSoundEmitterSystem->GetSoundIndex( name );
+ if ( g_pSoundEmitterSystem->IsValidIndex( slot ) )
+ {
+ Q_FileBase( g_pSoundEmitterSystem->GetSourceFileForSound( slot ), filebase, sizeof( filebase ) );
+ Q_strncpy( m_szScriptFile, filebase, sizeof( m_szScriptFile ) );
+ }
+}
+
+
+char const *CSoundEntry::GetName() const
+{
+ return m_szName;
+}
+
+void CSoundEntry::ValidateTree( mxTreeView *tree, mxTreeViewItem* parent )
+{
+ CUtlVector< mxTreeViewItem * > m_KnownItems;
+
+ int c = GetWaveCount();
+ CWaveFile *wave;
+ for ( int i = 0; i < c; i++ )
+ {
+ wave = GetWave( i );
+ if ( !wave )
+ continue;
+
+ char sz[ 256 ];
+ if ( wave->HasLoadedSentenceInfo() )
+ {
+ Q_snprintf( sz, sizeof( sz ), "\"%s\" : '%s'", wave->GetName(), wave->GetSentenceText() );
+ }
+ else
+ {
+ Q_snprintf( sz, sizeof( sz ), "\"%s\" : '%s'", wave->GetName(), "(loading...)" );
+ }
+
+ mxTreeViewItem *spot = wave->FindItem( tree, parent );
+ if ( !spot )
+ {
+ spot = tree->add( parent, sz );
+ }
+
+ m_KnownItems.AddToTail( spot );
+
+ wave->SetOrdinal( i );
+
+ tree->setLabel( spot, sz );
+
+ tree->setImages( spot, wave->GetIconIndex(), wave->GetIconIndex() );
+ tree->setUserData( spot, wave );
+
+ wave->ValidateTree( tree, spot );
+ }
+
+ mxTreeViewItem *start = tree->getFirstChild( parent );
+ while ( start )
+ {
+ mxTreeViewItem *next = tree->getNextChild( start );
+
+ if ( m_KnownItems.Find( start ) == m_KnownItems.InvalidIndex() )
+ {
+ tree->remove( start );
+ }
+
+ start = next;
+ }
+
+ tree->sortTree( parent, true, CWorkspaceBrowser::CompareFunc, 0 );
+}
+
+void CSoundEntry::Play()
+{
+ if ( m_Waves.Count() == 0 )
+ return;
+
+ m_nLastPlay = ( m_nLastPlay + 1 ) % m_Waves.Count();
+
+ CWaveFile *wave = GetWave( m_nLastPlay );
+ if ( !wave )
+ return;
+
+ wave->Play();
+}
+
+char const *CSoundEntry::GetScriptFile() const
+{
+ return m_szScriptFile;
+}
+
+void CSoundEntry::SetScriptFile( char const *scriptfile )
+{
+ char filebase [ 64 ];
+ int slot = g_pSoundEmitterSystem->GetSoundIndex( GetName() );
+ Q_FileBase( g_pSoundEmitterSystem->GetSourceFileForSound( slot ), filebase, sizeof( filebase ) );
+
+ if ( !Q_stricmp( GetScriptFile(), filebase ) )
+ return;
+
+ Q_strncpy( m_szScriptFile, filebase, sizeof( m_szScriptFile ) );
+}
+
+CSoundParametersInternal *CSoundEntry::GetSoundParameters()
+{
+ int soundindex = g_pSoundEmitterSystem->GetSoundIndex( GetName() );
+ if ( g_pSoundEmitterSystem->IsValidIndex( soundindex ) )
+ {
+ return g_pSoundEmitterSystem->InternalGetParametersForSound( soundindex );
+ }
+ return NULL;
+}
+
+bool CSoundEntry::IsCheckedOut() const
+{
+ // FIXME: This could use the wave state or the script state?
+ return false;
+}
+
+int CSoundEntry::GetIconIndex() const
+{
+ if ( IsCheckedOut() )
+ {
+ return IMAGE_SPEAK_CHECKEDOUT;
+ }
+ else
+ {
+ return IMAGE_SPEAK;
+ }
+}
+
+
+void CSoundEntry::Checkout(bool updatestateicons /*= true*/)
+{
+}
+
+void CSoundEntry::Checkin(bool updatestateicons /*= true*/)
+{
+}
+
+
+void CSoundEntry::MoveChildUp( ITreeItem *child )
+{
+}
+
+void CSoundEntry::MoveChildDown( ITreeItem *child )
+{
+}
+
+void CSoundEntry::SetDirty( bool dirty )
+{
+ if ( GetOwnerVCDFile() )
+ {
+ GetOwnerVCDFile()->SetDirty( dirty );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : wavindex -
+// Output : char const
+//-----------------------------------------------------------------------------
+char const *CSoundEntry::GetSentenceText( int wavindex )
+{
+ if ( !GetWaveCount() )
+ return "";
+
+ CWaveFile *w = GetWave( wavindex );
+ if ( w->HasLoadedSentenceInfo() )
+ {
+ return w->GetSentenceText();
+ }
+ else
+ {
+ return "(loading...)";
+ }
+}
+
+void CSoundEntry::GetCCText( wchar_t *out, int maxchars )
+{
+ out[ 0 ] = 0;
+
+ if ( !g_pVGuiLocalize )
+ return;
+
+ const wchar_t *str = g_pVGuiLocalize->Find( GetName() );
+ if ( !str )
+ return;
+
+ wcsncpy( out, str, maxchars );
+}
+
+
+bool CSoundEntry::IsChildFirst( ITreeItem *child )
+{
+ return false;
+}
+
+bool CSoundEntry::IsChildLast( ITreeItem *child )
+{
+ return false;
+} \ No newline at end of file
diff --git a/utils/scenemanager/soundentry.h b/utils/scenemanager/soundentry.h
new file mode 100644
index 0000000..aca3a4b
--- /dev/null
+++ b/utils/scenemanager/soundentry.h
@@ -0,0 +1,95 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SOUNDENTRY_H
+#define SOUNDENTRY_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "itreeitem.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "sentence.h"
+
+class CAudioSource;
+class CVCDFile;
+class CWaveFile;
+
+class CSoundEntry : public ITreeItem
+{
+public:
+ CSoundEntry( CVCDFile *vcd, char const *name );
+ ~CSoundEntry();
+
+ CVCDFile *GetOwnerVCDFile();
+
+ void SetName( char const *name );
+
+ char const *GetName() const;
+
+ int GetWaveCount() const;
+ CWaveFile *GetWave( int index );
+ void ClearWaves();
+ void AddWave( CWaveFile *wave );
+ void RemoveWave( CWaveFile *wave );
+ int FindWave( CWaveFile *wave );
+
+ void ValidateTree( mxTreeView *tree, mxTreeViewItem* parent );
+
+ virtual CWorkspace *GetWorkspace() { return NULL; }
+ virtual CProject *GetProject() { return NULL; }
+ virtual CScene *GetScene() { return NULL; }
+ virtual CVCDFile *GetVCDFile() { return NULL; }
+ virtual CSoundEntry *GetSoundEntry() { return this; }
+ virtual CWaveFile *GetWaveFile() { return NULL; }
+
+ void Play();
+
+ char const *GetScriptFile() const;
+ void SetScriptFile( char const *scriptfile );
+
+ char const *GetSentenceText( int wavindex );
+ void GetCCText( wchar_t *out, int maxchars );
+
+ CSoundParametersInternal *GetSoundParameters();
+
+ virtual void Checkout( bool updatestateicons = true );
+ virtual void Checkin( bool updatestateicons = true );
+
+ bool IsCheckedOut() const;
+ int GetIconIndex() const;
+
+
+ virtual void MoveChildUp( ITreeItem *child );
+ virtual void MoveChildDown( ITreeItem *child );
+
+ virtual void SetDirty( bool dirty );
+
+ virtual bool IsChildFirst( ITreeItem *child );
+ virtual bool IsChildLast( ITreeItem *child );
+
+private:
+
+ CSoundParameters m_Params;
+
+ enum
+ {
+ MAX_SOUND_NAME = 256,
+ MAX_SCRIPT_FILE = 64,
+ MAX_SOUND_FILENAME = 128,
+ };
+
+ char m_szName[ MAX_SOUND_NAME ];
+ char m_szScriptFile[ MAX_SCRIPT_FILE ];
+
+ CVCDFile *m_pOwner;
+
+ CUtlVector< CWaveFile * > m_Waves;
+
+ int m_nLastPlay;
+};
+
+#endif // SOUNDENTRY_H
diff --git a/utils/scenemanager/soundproperties.cpp b/utils/scenemanager/soundproperties.cpp
new file mode 100644
index 0000000..a2e8053
--- /dev/null
+++ b/utils/scenemanager/soundproperties.cpp
@@ -0,0 +1,616 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include <mxtk/mx.h>
+#include <stdio.h>
+#include "resource.h"
+#include "SoundProperties.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "soundentry.h"
+#include "cmdlib.h"
+#include "workspacemanager.h"
+#include "wavebrowser.h"
+#include "wavefile.h"
+#include "waveproperties.h"
+
+static CSoundParams g_Params;
+
+static void PopulateChannelList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_CHANNEL );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+ if ( p )
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->ChannelToString() );
+ }
+ else
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)"CHAN_VOICE" );
+ }
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_VOICE" );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_AUTO" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_WEAPON" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_ITEM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_BODY" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_STREAM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_STATIC" );
+}
+
+static void PopulateVolumeList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_VOLUME );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+
+ if ( p )
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->VolumeToString() );
+ }
+ else
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)"VOL_NORM" );
+ }
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"VOL_NORM" );
+}
+
+static void PopulateSoundlevelList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_SOUNDLEVEL );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+
+ if ( p )
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->SoundLevelToString() );
+ }
+ else
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)"SNDLVL_NORM" );
+ }
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_NORM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_NONE" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_IDLE" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_TALKING" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_STATIC" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_GUNFIRE" );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_25dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_30dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_35dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_40dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_45dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_50dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_55dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_60dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_65dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_70dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_75dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_80dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_85dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_90dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_95dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_100dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_105dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_120dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_130dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_140dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_150dB" );
+}
+
+static void PopulatePitchList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_PITCH );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+
+ if ( p )
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->PitchToString() );
+ }
+ else
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)"PITCH_NORM" );
+ }
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"PITCH_NORM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"PITCH_LOW" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"PITCH_HIGH" );
+}
+
+
+static void PopulateScriptList( HWND wnd, char const *curscript )
+{
+ HWND control = GetDlgItem( wnd, IDC_SOUNDSCRIPT );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+
+ if ( curscript )
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)curscript );
+ }
+
+ int c = g_pSoundEmitterSystem->GetNumSoundScripts();
+ for ( int i = 0; i < c; i++ )
+ {
+ // add text to combo box
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)g_pSoundEmitterSystem->GetSoundScriptName( i ) );
+
+ if ( !curscript && i == 0 )
+ {
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)g_pSoundEmitterSystem->GetSoundScriptName( i ) );
+ }
+ }
+}
+
+static bool WaveLessFunc( const char *const& name1, const char *const& name2 )
+{
+ if ( stricmp( name1, name2 ) < 0 )
+ return true;
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : wnd -
+// Output : static void
+//-----------------------------------------------------------------------------
+static void PopulateWaveList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_WAVELIST );
+ if ( !control )
+ return;
+
+ // Remove all
+ SendMessage( control, LB_RESETCONTENT, 0, 0 );
+
+ if ( !p )
+ return;
+
+ CUtlRBTree< char const *, int > m_SortedNames( 0, 0, WaveLessFunc );
+
+ int c = p->NumSoundNames();
+ for ( int i = 0; i < c; i++ )
+ {
+ char const *name = strdup( g_pSoundEmitterSystem->GetWaveName( p->GetSoundNames()[ i ].symbol ) );
+
+ m_SortedNames.Insert( name );
+ }
+
+ int j = m_SortedNames.FirstInorder();
+ while ( j != m_SortedNames.InvalidIndex() )
+ {
+ char const *name = m_SortedNames[ j ];
+ if ( name && name[ 0 ] )
+ {
+ SendMessage( control, LB_ADDSTRING, 0, (LPARAM)name );
+ }
+
+ delete name;
+
+ j = m_SortedNames.NextInorder( j );
+ }
+}
+
+static void PopulateWaveList_Available( HWND wnd )
+{
+ HWND control = GetDlgItem( wnd, IDC_WAVELIST_AVAILABLE );
+ if ( !control )
+ return;
+
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ if ( !wb )
+ {
+ Assert( 0 );
+ return;
+ }
+
+ CUtlRBTree< char const *, int > m_SortedNames( 0, 0, WaveLessFunc );
+
+ int c = wb->GetSoundCount();;
+ for ( int i = 0; i < c; i++ )
+ {
+ CWaveFile *entry = wb->GetSound( i );
+ if ( !entry )
+ continue;
+
+ char const *name = entry->GetName();
+ m_SortedNames.Insert( name );
+ }
+
+ // Remove all
+ SendMessage( control, LB_RESETCONTENT, 0, 0 );
+
+ int j = m_SortedNames.FirstInorder();
+ while ( j != m_SortedNames.InvalidIndex() )
+ {
+ char const *name = m_SortedNames[ j ];
+ if ( name && name[ 0 ] )
+ {
+ SendMessage( control, LB_ADDSTRING, 0, (LPARAM)name );
+ }
+
+ j = m_SortedNames.NextInorder( j );
+ }
+}
+
+static void SoundProperties_GetSelectedWaveList( HWND hwndDlg, HWND control, CUtlVector< int >& list )
+{
+ if ( !control )
+ return;
+
+ int count = SendMessage( control, LB_GETSELCOUNT, 0, 0 );
+ if ( count == LB_ERR )
+ return;
+
+ int *s = new int[ count ];
+
+ SendMessage( control, LB_GETSELITEMS, count, (LPARAM)s );
+
+ for ( int i = 0 ;i < count; i++ )
+ {
+ list.AddToTail( s[ i ] );
+ }
+
+ delete[] s;
+}
+
+static const char *SoundProperties_GetSelectedWave( HWND hwndDlg, HWND control, int *item = NULL )
+{
+ if ( item )
+ *item = -1;
+
+ if ( !control )
+ return NULL;
+
+ int selectedionindex = SendMessage( control, LB_GETCURSEL, 0, 0 );
+ if ( selectedionindex == LB_ERR )
+ return NULL;
+
+ static char itemtext[ 256 ];
+ SendMessage( control, LB_GETTEXT, selectedionindex, (LPARAM)itemtext );
+
+ if ( item )
+ {
+ *item = selectedionindex;
+ }
+
+ return itemtext;
+}
+
+static void SoundProperties_OnOK( HWND hwndDlg )
+{
+ CSoundParametersInternal outparams;
+
+ // Gather info and make changes
+ CSoundEntry *item = g_Params.items[ 0 ];
+
+ int soundindex = -1;
+ char const *script = NULL;
+
+ char outsoundname[ 256 ];
+ char outscriptfile[ 256 ];
+
+ GetDlgItemText( hwndDlg, IDC_SOUNDNAME, outsoundname, sizeof( outsoundname ) );
+ GetDlgItemText( hwndDlg, IDC_SOUNDSCRIPT, outscriptfile, sizeof( outscriptfile ) );
+
+ if ( !g_Params.addsound )
+ {
+ soundindex = g_pSoundEmitterSystem->GetSoundIndex( item->GetName() );
+ script = g_pSoundEmitterSystem->GetSourceFileForSound( soundindex );
+ }
+
+ char sz[ 128 ];
+ GetDlgItemText( hwndDlg, IDC_CHANNEL, sz, sizeof( sz ) );
+ outparams.ChannelFromString( sz );
+
+ GetDlgItemText( hwndDlg, IDC_VOLUME, sz, sizeof( sz ) );
+ outparams.VolumeFromString( sz );
+
+ GetDlgItemText( hwndDlg, IDC_SOUNDLEVEL, sz, sizeof( sz ) );
+ outparams.SoundLevelFromString( sz );
+
+ GetDlgItemText( hwndDlg, IDC_PITCH, sz, sizeof( sz ) );
+ outparams.PitchFromString( sz );
+
+ bool owneronly = SendMessage( GetDlgItem( hwndDlg, IDC_OWNERONLY ), BM_GETCHECK, 0, 0 ) == BST_CHECKED ? true : false;
+
+ outparams.SetOnlyPlayToOwner( owneronly );
+
+ // Retrieve wave list
+ int c = SendMessage( GetDlgItem( hwndDlg, IDC_WAVELIST ), LB_GETCOUNT, 0, 0 );
+
+ for ( int i = 0; i < c; i++ )
+ {
+ char wavename[ 256 ];
+ SendMessage( GetDlgItem( hwndDlg, IDC_WAVELIST ), LB_GETTEXT, i, (LPARAM)wavename );
+
+ CUtlSymbol sym = g_pSoundEmitterSystem->AddWaveName( wavename );
+ SoundFile sf;
+ sf.symbol = sym;
+ sf.gender = GENDER_NONE;
+ outparams.AddSoundName( sf );
+ }
+
+ if ( g_Params.addsound )
+ {
+ g_pSoundEmitterSystem->AddSound( outsoundname, outscriptfile, outparams );
+ }
+ else
+ {
+ // Update sound stuff
+ g_pSoundEmitterSystem->MoveSound( item->GetName(), outscriptfile );
+ item->SetScriptFile( outscriptfile );
+ g_pSoundEmitterSystem->UpdateSoundParameters( item->GetName(), outparams );
+ // Rename if necessary
+ g_pSoundEmitterSystem->RenameSound( item->GetName(), outsoundname );
+ }
+
+ // Apply changes
+ item->SetName( outsoundname );
+
+ // Repopulate things
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+// uMsg -
+// wParam -
+// lParam -
+// Output : static BOOL CALLBACK
+//-----------------------------------------------------------------------------
+static BOOL CALLBACK SoundPropertiesDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ g_Params.PositionSelf( hwndDlg );
+
+ CSoundEntry *item = NULL;
+
+ CSoundParametersInternal *p = NULL;
+ char const *script = NULL;
+
+ if ( g_Params.addsound )
+ {
+ Assert( g_Params.items.Count() == 0 );
+
+ CSoundEntry *entry = new CSoundEntry( NULL, "Unnamed" );
+ g_Params.items.AddToTail( entry );
+
+ item = item = g_Params.items[ 0 ];
+
+ SendMessage( GetDlgItem( hwndDlg, IDC_OWNERONLY ), BM_SETCHECK,
+ ( WPARAM )BST_UNCHECKED,
+ ( LPARAM )0 );
+
+ SetDlgItemText( hwndDlg, IDC_STATIC_SENTENCETEXT, "" );
+ SetDlgItemTextW( hwndDlg, IDC_STATIC_CLOSECAPTION, L"" );
+ }
+ else
+ {
+ item = g_Params.items[ 0 ];
+
+ int soundindex = g_pSoundEmitterSystem->GetSoundIndex( item->GetName() );
+
+ script = g_pSoundEmitterSystem->GetSourceFileForSound( soundindex );
+
+ p = g_pSoundEmitterSystem->InternalGetParametersForSound( soundindex );
+ Assert( p );
+
+ SendMessage( GetDlgItem( hwndDlg, IDC_OWNERONLY ), BM_SETCHECK,
+ ( WPARAM ) p->OnlyPlayToOwner() ? BST_CHECKED : BST_UNCHECKED,
+ ( LPARAM )0 );
+
+ SetDlgItemText( hwndDlg, IDC_STATIC_SENTENCETEXT, item->GetSentenceText( 0 ) );
+ wchar_t cctext[ 1024 ];
+ item->GetCCText( cctext, sizeof( cctext ) / sizeof( wchar_t ) );
+
+ SetDlgItemTextW( hwndDlg, IDC_STATIC_CLOSECAPTION, cctext );
+ }
+
+ PopulateChannelList( hwndDlg, p );
+ PopulateVolumeList( hwndDlg, p );
+ PopulateSoundlevelList( hwndDlg, p );
+ PopulatePitchList( hwndDlg, p );
+
+ PopulateWaveList( hwndDlg, p );
+
+ SetDlgItemText( hwndDlg, IDC_SOUNDNAME, item->GetName() );
+
+ PopulateScriptList( hwndDlg, script );
+
+ PopulateWaveList_Available( hwndDlg );
+
+ SetWindowText( hwndDlg, g_Params.m_szDialogTitle );
+
+ SetFocus( GetDlgItem( hwndDlg, IDC_SOUNDNAME ) );
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ SoundProperties_OnOK( hwndDlg );
+
+ EndDialog( hwndDlg, 1 );
+ }
+ break;
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ case IDC_WAVELIST:
+ {
+ if ( HIWORD(wParam) == LBN_SELCHANGE )
+ {
+ // Find selected item in wave list...
+ char const *wave = SoundProperties_GetSelectedWave( hwndDlg, GetDlgItem( hwndDlg, IDC_WAVELIST ) );
+ if ( wave )
+ {
+ // Look it up
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ if ( wb )
+ {
+ CWaveFile *wavefile = wb->FindEntry( wave, true );
+ if ( wavefile )
+ {
+ SetDlgItemText( hwndDlg, IDC_STATIC_SENTENCETEXT, wavefile->GetSentenceText() );
+ }
+ }
+ }
+ }
+ }
+ break;
+ case IDC_WAVEPROPERTIES:
+ {
+ // Find selected item in wave list...
+ char const *wave = SoundProperties_GetSelectedWave( hwndDlg, GetDlgItem( hwndDlg, IDC_WAVELIST ) );
+ if ( wave )
+ {
+ // Look it up
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ if ( wb )
+ {
+ CWaveFile *wavefile = wb->FindEntry( wave, true );
+ if ( wavefile )
+ {
+ CWaveParams wp;
+ memset( &wp, 0, sizeof( wp ) );
+
+ Q_snprintf( wp.m_szDialogTitle, sizeof( wp.m_szDialogTitle ), "Wave Properties" );
+
+ wp.items.AddToTail( wavefile );
+
+ WaveProperties( &wp );
+ }
+ }
+ }
+ }
+ break;
+ case IDC_REMOVEWAVE:
+ {
+ CUtlVector<int> selected;
+ SoundProperties_GetSelectedWaveList( hwndDlg, GetDlgItem( hwndDlg, IDC_WAVELIST ), selected );
+ int count = selected.Count();
+ if ( count >= 1 )
+ {
+ int i;
+ for ( i = 0; i < count; i++ )
+ {
+ char wavename[ 256 ];
+
+ SendMessage( GetDlgItem( hwndDlg, IDC_WAVELIST), LB_GETTEXT, selected[ i ], (LPARAM)wavename );
+
+ // Add it to global parameters, too
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ if ( wb )
+ {
+ CWaveFile *wavefile = wb->FindEntry( wavename, true );
+ if ( wavefile )
+ {
+ CSoundEntry *item = g_Params.items[ 0 ];
+ item->RemoveWave( wavefile );
+ }
+ }
+ }
+
+ for ( i = count - 1; i >= 0; i-- )
+ {
+ // Remove them from list
+ SendMessage( GetDlgItem( hwndDlg, IDC_WAVELIST), LB_DELETESTRING, selected[ i ], 0 );
+ }
+ }
+ }
+ break;
+ case IDC_ADDWAVE:
+ {
+ CUtlVector<int> selected;
+ SoundProperties_GetSelectedWaveList( hwndDlg, GetDlgItem( hwndDlg, IDC_WAVELIST_AVAILABLE ), selected );
+ int count = selected.Count();
+ if ( count >= 1 )
+ {
+ int i;
+ for ( i = 0; i < count; i++ )
+ {
+ char wavename[ 256 ];
+
+ // Get selection wave name
+ SendMessage( GetDlgItem( hwndDlg, IDC_WAVELIST_AVAILABLE), LB_GETTEXT, selected[ i ], (LPARAM)wavename );
+
+ // Add it to global parameters, too
+ CWaveBrowser *wb = GetWorkspaceManager()->GetWaveBrowser();
+ if ( wb )
+ {
+ CWaveFile *wavefile = wb->FindEntry( wavename, true );
+ if ( wavefile )
+ {
+ CSoundEntry *item = g_Params.items[ 0 ];
+ if ( item->FindWave( wavefile ) == -1 )
+ {
+ item->AddWave( wavefile );
+ // Add it to list
+ SendMessage( GetDlgItem( hwndDlg, IDC_WAVELIST ), LB_ADDSTRING, 0, (LPARAM)wavename );
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *view -
+// *actor -
+// Output : int
+//-----------------------------------------------------------------------------
+int SoundProperties( CSoundParams *params )
+{
+ g_Params = *params;
+
+ int retval = DialogBox( (HINSTANCE)GetModuleHandle( 0 ),
+ MAKEINTRESOURCE( IDD_SOUNDPROPERTIES ),
+ (HWND)GetWorkspaceManager()->getHandle(),
+ (DLGPROC)SoundPropertiesDialogProc );
+
+ *params = g_Params;
+
+ return retval;
+} \ No newline at end of file
diff --git a/utils/scenemanager/soundproperties.h b/utils/scenemanager/soundproperties.h
new file mode 100644
index 0000000..d342bf3
--- /dev/null
+++ b/utils/scenemanager/soundproperties.h
@@ -0,0 +1,44 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SOUNDPROPERTIES_H
+#define SOUNDPROPERTIES_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialogparams.h"
+
+class CSoundEntry;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+struct CSoundParams : public CBaseDialogParams
+{
+ bool addsound;
+
+ CSoundParams()
+ {
+ }
+
+ CSoundParams( const CSoundParams& src )
+ {
+ addsound = src.addsound;
+
+ int c = src.items.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ items.AddToTail( src.items[ i ] );
+ }
+ }
+
+ CUtlVector< CSoundEntry * > items;
+};
+
+int SoundProperties( CSoundParams *params );
+
+#endif // SOUNDPROPERTIES_H
diff --git a/utils/scenemanager/soundproperties_multiple.cpp b/utils/scenemanager/soundproperties_multiple.cpp
new file mode 100644
index 0000000..8d91d4d
--- /dev/null
+++ b/utils/scenemanager/soundproperties_multiple.cpp
@@ -0,0 +1,240 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include <mxtk/mx.h>
+#include <stdio.h>
+#include "resource.h"
+#include "SoundProperties_Multiple.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "soundentry.h"
+#include "cmdlib.h"
+#include "workspacemanager.h"
+#include "wavebrowser.h"
+#include "wavefile.h"
+#include "waveproperties.h"
+
+static CSoundParams g_Params;
+
+static void PopulateChannelList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_CHANNEL );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->ChannelToString() );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_VOICE" );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_AUTO" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_WEAPON" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_ITEM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_BODY" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_STREAM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"CHAN_STATIC" );
+}
+
+static void PopulateVolumeList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_VOLUME );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->VolumeToString() );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"VOL_NORM" );
+}
+
+static void PopulateSoundlevelList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_SOUNDLEVEL );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->SoundLevelToString() );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_NORM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_NONE" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_IDLE" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_TALKING" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_STATIC" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_GUNFIRE" );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_25dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_30dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_35dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_40dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_45dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_50dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_55dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_60dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_65dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_70dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_75dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_80dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_85dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_90dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_95dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_100dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_105dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_120dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_130dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_140dB" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"SNDLVL_150dB" );
+}
+
+static void PopulatePitchList( HWND wnd, CSoundParametersInternal *p )
+{
+ HWND control = GetDlgItem( wnd, IDC_PITCH );
+ if ( !control )
+ {
+ return;
+ }
+
+ SendMessage( control, CB_RESETCONTENT, 0, 0 );
+
+ SendMessage( control, WM_SETTEXT , 0, (LPARAM)p->PitchToString() );
+
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"PITCH_NORM" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"PITCH_LOW" );
+ SendMessage( control, CB_ADDSTRING, 0, (LPARAM)"PITCH_HIGH" );
+}
+
+static void SoundProperties_Multiple_OnOK( HWND hwndDlg )
+{
+ int c = g_Params.items.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ // Gather info and make changes
+ CSoundEntry *item = g_Params.items[ i ];
+ Assert( item );
+ if ( !item )
+ continue;
+
+ int idx = g_pSoundEmitterSystem->GetSoundIndex( item->GetName() );
+ if ( !g_pSoundEmitterSystem->IsValidIndex( idx ) )
+ {
+ continue;
+ }
+
+
+ CSoundParametersInternal *baseparams = g_pSoundEmitterSystem->InternalGetParametersForSound( idx );
+ if ( !baseparams )
+ return;
+
+ // Start with old settings
+ CSoundParametersInternal outparams;
+ outparams.CopyFrom( *baseparams );
+
+ char sz[ 128 ];
+ GetDlgItemText( hwndDlg, IDC_CHANNEL, sz, sizeof( sz ) );
+ outparams.ChannelFromString( sz );
+
+ GetDlgItemText( hwndDlg, IDC_VOLUME, sz, sizeof( sz ) );
+ outparams.VolumeFromString( sz );
+
+ GetDlgItemText( hwndDlg, IDC_SOUNDLEVEL, sz, sizeof( sz ) );
+ outparams.SoundLevelFromString( sz );
+
+ GetDlgItemText( hwndDlg, IDC_PITCH, sz, sizeof( sz ) );
+ outparams.PitchFromString( sz );
+
+ bool owneronly = SendMessage( GetDlgItem( hwndDlg, IDC_OWNERONLY ), BM_GETCHECK, 0, 0 ) == BST_CHECKED ? true : false;
+
+ outparams.SetOnlyPlayToOwner( owneronly );
+
+ g_pSoundEmitterSystem->UpdateSoundParameters( item->GetName(), outparams );
+ }
+
+ // Repopulate things
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+// uMsg -
+// wParam -
+// lParam -
+// Output : static BOOL CALLBACK
+//-----------------------------------------------------------------------------
+static BOOL CALLBACK SoundProperties_MultipleDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ g_Params.PositionSelf( hwndDlg );
+
+ CSoundEntry *entry = g_Params.items[ 0 ];
+ Assert( entry );
+
+ CSoundParametersInternal *p = entry->GetSoundParameters();
+ Assert( p );
+
+ SendMessage( GetDlgItem( hwndDlg, IDC_OWNERONLY ), BM_SETCHECK,
+ ( WPARAM ) p->OnlyPlayToOwner() ? BST_CHECKED : BST_UNCHECKED,
+ ( LPARAM )0 );
+
+ PopulateChannelList( hwndDlg, p );
+ PopulateVolumeList( hwndDlg, p );
+ PopulateSoundlevelList( hwndDlg, p );
+ PopulatePitchList( hwndDlg, p );
+
+ SetWindowText( hwndDlg, g_Params.m_szDialogTitle );
+
+ SetFocus( GetDlgItem( hwndDlg, IDC_CHANNEL ) );
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ SoundProperties_Multiple_OnOK( hwndDlg );
+
+ EndDialog( hwndDlg, 1 );
+ }
+ break;
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *view -
+// *actor -
+// Output : int
+//-----------------------------------------------------------------------------
+int SoundProperties_Multiple( CSoundParams *params )
+{
+ g_Params = *params;
+
+ int retval = DialogBox( (HINSTANCE)GetModuleHandle( 0 ),
+ MAKEINTRESOURCE( IDD_SOUNDPROPERTIES_MULTIPLE ),
+ (HWND)GetWorkspaceManager()->getHandle(),
+ (DLGPROC)SoundProperties_MultipleDialogProc );
+
+ *params = g_Params;
+
+ return retval;
+} \ No newline at end of file
diff --git a/utils/scenemanager/soundproperties_multiple.h b/utils/scenemanager/soundproperties_multiple.h
new file mode 100644
index 0000000..b82af30
--- /dev/null
+++ b/utils/scenemanager/soundproperties_multiple.h
@@ -0,0 +1,20 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef SOUNDPROPERTIES_MULTIPLE_H
+#define SOUNDPROPERTIES_MULTIPLE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialogparams.h"
+#include "soundproperties.h"
+
+class CSoundEntry;
+
+int SoundProperties_Multiple( CSoundParams *params );
+
+#endif // SOUNDPROPERTIES_MULTIPLE_H
diff --git a/utils/scenemanager/statuswindow.cpp b/utils/scenemanager/statuswindow.cpp
new file mode 100644
index 0000000..85acb40
--- /dev/null
+++ b/utils/scenemanager/statuswindow.cpp
@@ -0,0 +1,245 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "statuswindow.h"
+#include "drawhelper.h"
+
+CStatusWindow *g_pStatusWindow = NULL;
+
+#define STATUS_SCROLLBAR_SIZE 12
+#define STATUS_FONT_SIZE 10
+
+CStatusWindow::CStatusWindow(mxWindow *parent, int x, int y, int w, int h, const char *label /*= 0*/ )
+: mxWindow( parent, x, y, w, h, label ), m_pScrollbar(NULL)
+{
+ for ( int i = 0; i < MAX_TEXT_LINES; i++ )
+ {
+ m_rgTextLines[ i ].m_szText[ 0 ] = 0;
+ m_rgTextLines[ i ].r = CONSOLE_R;
+ m_rgTextLines[ i ].g = CONSOLE_G;
+ m_rgTextLines[ i ].b = CONSOLE_B;
+ m_rgTextLines[ i ].curtime = 0;
+ }
+ m_nCurrentLine = 0;
+
+ m_pScrollbar = new mxScrollbar( this, 0, 0, STATUS_SCROLLBAR_SIZE, 100, IDC_STATUS_SCROLL, mxScrollbar::Vertical );
+ m_pScrollbar->setRange( 0, 1000 );
+ m_pScrollbar->setPagesize( 100 );
+ g_pStatusWindow = this;
+}
+
+CStatusWindow::~CStatusWindow()
+{
+ g_pStatusWindow = NULL;
+}
+
+void CStatusWindow::redraw()
+{
+// if ( !ToolCanDraw() )
+// return;
+
+ if ( !m_pScrollbar )
+ return;
+
+ CDrawHelper helper( this, RGB( 0, 0, 0 ) );
+
+ RECT rc;
+ helper.GetClientRect( rc );
+
+ RECT rcText = rc;
+
+ int lineheight = ( STATUS_FONT_SIZE + 2 );
+
+ InflateRect( &rcText, -4, 0 );
+ rcText.bottom = h2() - 4;
+ rcText.top = rcText.bottom - lineheight;
+
+// int minval = m_pScrollbar->getMinValue();
+ int maxval = m_pScrollbar->getMaxValue();
+ int pagesize = m_pScrollbar->getPagesize();
+ int curval = m_pScrollbar->getValue();
+
+ int offset = ( maxval - pagesize ) - curval;
+ offset = ( offset + lineheight - 1 ) / lineheight;
+
+ offset = max( 0, offset );
+ //offset = 0;
+ //offset += 10;
+ //offset = max( 0, offset );
+
+ for ( int i = 0; i < MAX_TEXT_LINES - offset; i++ )
+ {
+ int rawline = m_nCurrentLine - i - 1;
+ if ( rawline <= 0 )
+ continue;
+
+ if ( rcText.bottom < 0 )
+ break;
+
+ int line = ( rawline - offset ) & TEXT_LINE_MASK;
+
+ COLORREF clr = RGB( m_rgTextLines[ line ].r, m_rgTextLines[ line ].g, m_rgTextLines[ line ].b );
+
+ char *ptext = m_rgTextLines[ line ].m_szText;
+
+ RECT rcTime = rcText;
+ rcTime.right = rcTime.left + 50;
+
+ char sz[ 32 ];
+ sprintf( sz, "%.3f", m_rgTextLines[ line ].curtime );
+
+ int len = helper.CalcTextWidth( "Arial", STATUS_FONT_SIZE, FW_NORMAL, sz );
+
+ rcTime.left = rcTime.right - len - 5;
+
+ helper.DrawColoredText( "Arial", STATUS_FONT_SIZE, FW_NORMAL, RGB( 255, 255, 150 ), rcTime, sz );
+
+ rcTime = rcText;
+ rcTime.left += 50;
+
+ helper.DrawColoredText( "Arial", STATUS_FONT_SIZE, FW_NORMAL, clr, rcTime, ptext );
+
+ OffsetRect( &rcText, 0, -lineheight );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CStatusWindow::PaintBackground( void )
+{
+ redraw();
+ return false;
+}
+
+void CStatusWindow::StatusPrint( int r, int g, int b, bool overwrite, const char *text )
+{
+ float curtime = (float)Plat_FloatTime();
+
+ char sz[32];
+ sprintf( sz, "%.3f ", curtime );
+
+ OutputDebugString( sz );
+ OutputDebugString( text );
+
+ char fixedtext[ 512 ];
+ char *in, *out;
+ in = (char *)text;
+ out = fixedtext;
+
+ int c = 0;
+ while ( *in && c < 511 )
+ {
+ if ( *in == '\n' || *in == '\r' )
+ {
+ in++;
+ }
+ else
+ {
+ *out++ = *in++;
+ c++;
+ }
+ }
+ *out = 0;
+
+ if ( overwrite )
+ {
+ m_nCurrentLine--;
+ }
+
+ int i = m_nCurrentLine & TEXT_LINE_MASK;
+
+ strncpy( m_rgTextLines[ i ].m_szText, fixedtext, 511 );
+ m_rgTextLines[ i ].m_szText[ 511 ] = 0;
+
+ m_rgTextLines[ i ].r = r;
+ m_rgTextLines[ i ].g = g;
+ m_rgTextLines[ i ].b = b;
+ m_rgTextLines[ i ].curtime = curtime;
+
+ m_nCurrentLine++;
+
+ if ( m_nCurrentLine <= MAX_TEXT_LINES )
+ {
+ PositionSliders( 0 );
+ }
+ m_pScrollbar->setValue( m_pScrollbar->getMaxValue() );
+
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : sboffset -
+//-----------------------------------------------------------------------------
+void CStatusWindow::PositionSliders( int sboffset )
+{
+ int lineheight = ( STATUS_FONT_SIZE + 2 );
+
+ int linesused = min( (int)MAX_TEXT_LINES, m_nCurrentLine );
+ linesused = max( linesused, 1 );
+
+ int trueh = h2();
+
+ int vpixelsneeded = max( linesused * lineheight, trueh );
+ m_pScrollbar->setVisible( linesused * lineheight > trueh );
+
+
+ m_pScrollbar->setPagesize( trueh );
+ m_pScrollbar->setRange( 0, vpixelsneeded );
+
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *event -
+// Output : int
+//-----------------------------------------------------------------------------
+int CStatusWindow::handleEvent( mxEvent *event )
+{
+ int iret = 0;
+
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Size:
+ {
+ m_pScrollbar->setBounds( w2() - STATUS_SCROLLBAR_SIZE, 0, STATUS_SCROLLBAR_SIZE, h2() );
+ PositionSliders( 0 );
+ m_pScrollbar->setValue( m_pScrollbar->getMaxValue() );
+ iret = 1;
+ }
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ iret = 0;
+ break;
+ case IDC_STATUS_SCROLL:
+ {
+ if ( event->event == mxEvent::Action &&
+ event->modifiers == SB_THUMBTRACK)
+ {
+ int offset = event->height;
+ m_pScrollbar->setValue( offset );
+ PositionSliders( offset );
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ return iret;
+}
diff --git a/utils/scenemanager/statuswindow.h b/utils/scenemanager/statuswindow.h
new file mode 100644
index 0000000..5e43bad
--- /dev/null
+++ b/utils/scenemanager/statuswindow.h
@@ -0,0 +1,57 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef STATUSWINDOW_H
+#define STATUSWINDOW_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class mxScrollbar;
+
+#define IDC_STATUS_SCROLL 1000
+
+class CStatusWindow : public mxWindow
+{
+public:
+ CStatusWindow (mxWindow *parent, int x, int y, int w, int h, const char *label = 0 );
+ ~CStatusWindow();
+
+ void StatusPrint( int r, int g, int b, bool overwrite, const char *text );
+
+ virtual void redraw();
+ virtual bool PaintBackground( void );
+
+ virtual int handleEvent( mxEvent *event );
+
+// virtual void Think( float dt );
+
+private:
+
+ void PositionSliders( int sboffset );
+
+ enum
+ {
+ MAX_TEXT_LINES = 1024,
+ TEXT_LINE_MASK = MAX_TEXT_LINES - 1,
+ };
+
+ struct TextLine
+ {
+ char m_szText[ 512 ];
+ int r, g, b;
+ float curtime;
+ };
+
+ TextLine m_rgTextLines[ MAX_TEXT_LINES ];
+ int m_nCurrentLine;
+
+ mxScrollbar *m_pScrollbar;
+};
+
+extern CStatusWindow *g_pStatusWindow;
+
+#endif // STATUSWINDOW_H
diff --git a/utils/scenemanager/tabwindow.cpp b/utils/scenemanager/tabwindow.cpp
new file mode 100644
index 0000000..03750a5
--- /dev/null
+++ b/utils/scenemanager/tabwindow.cpp
@@ -0,0 +1,484 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "tabwindow.h"
+#include "DrawHelper.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Constructor
+// Input : *parent -
+// x -
+// y -
+// w -
+// h -
+// id -
+// style -
+//-----------------------------------------------------------------------------
+CTabWindow::CTabWindow( mxWindow *parent, int x, int y, int w, int h, int id /*= 0*/, int style /*=0*/ )
+: mxWindow( parent, x, y, w, h, "", style )
+{
+ setId( id );
+
+ m_nSelected = -1;
+
+ m_nRowHeight = 20;
+ m_nRowsRequired = 1;
+
+ m_nTabWidth = 80;
+ m_nPixelDelta = 3;
+ m_bInverted = false;
+ m_bRightJustify = false;
+ SetColor( COLOR_BG, GetSysColor( COLOR_BTNFACE ) );
+ SetColor( COLOR_FG, GetSysColor( COLOR_INACTIVECAPTION ) );
+ SetColor( COLOR_FG_SELECTED, GetSysColor( COLOR_ACTIVECAPTION ) );
+ SetColor( COLOR_HILITE, GetSysColor( COLOR_3DSHADOW ) );
+ SetColor( COLOR_HILITE_SELECTED, GetSysColor( COLOR_3DHILIGHT ) );
+ SetColor( COLOR_TEXT, GetSysColor( COLOR_BTNTEXT ) );
+ SetColor( COLOR_TEXT_SELECTED, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
+
+ SceneManager_AddWindowStyle( this, WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : CTabWindow::~CTabWindow
+//-----------------------------------------------------------------------------
+CTabWindow::~CTabWindow ( void )
+{
+ removeAll();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : index -
+// clr -
+//-----------------------------------------------------------------------------
+void CTabWindow::SetColor( int index, COLORREF clr )
+{
+ if ( index < 0 || index >= NUM_COLORS )
+ return;
+
+ m_Colors[ index ] = clr;
+}
+
+void CTabWindow::SetInverted( bool invert )
+{
+ m_bInverted = invert;
+ RecomputeLayout( w2() );
+}
+
+void CTabWindow::SetRightJustify( bool rightjustify )
+{
+ m_bRightJustify = true;
+ RecomputeLayout( w2() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Tabs are sized to string content
+// Input : rcClient -
+// tabRect -
+// tabNum -
+//-----------------------------------------------------------------------------
+void CTabWindow::GetTabRect( const RECT& rcClient, RECT& tabRect, int tabNum )
+{
+ tabRect = m_Items[ tabNum ].rect;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : drawHelper -
+// rcClient -
+// tabnum -
+// selected -
+//-----------------------------------------------------------------------------
+void CTabWindow::DrawTab( CDrawHelper& drawHelper, RECT& rcClient, int tabnum, bool selected )
+{
+ RECT rcTab;
+
+ if ( tabnum < 0 || tabnum >= m_Items.Size() )
+ return;
+
+#if defined( _DEBUG )
+ CETItem *p = &m_Items[ tabnum ];
+ Assert( p );
+#endif
+
+ GetTabRect( rcClient, rcTab, tabnum );
+
+ COLORREF fgcolor = m_Colors[ selected ? COLOR_FG_SELECTED : COLOR_FG ];
+ COLORREF hilightcolor = m_Colors[ selected ? COLOR_HILITE_SELECTED : COLOR_HILITE ];
+ COLORREF text = m_Colors[ selected ? COLOR_TEXT_SELECTED : COLOR_TEXT ];
+
+ // Create a trapezoid/paralleogram
+ POINT region[4];
+ int cPoints = 4;
+
+ OffsetRect( &rcTab, 0, m_bInverted ? 1 : -1 );
+
+ if ( m_bInverted )
+ {
+ region[ 0 ].x = rcTab.left - m_nPixelDelta;
+ region[ 0 ].y = rcTab.top;
+
+ region[ 1 ].x = rcTab.right + m_nPixelDelta;
+ region[ 1 ].y = rcTab.top;
+
+ region[ 2 ].x = rcTab.right - m_nPixelDelta;
+ region[ 2 ].y = rcTab.bottom;
+
+ region[ 3 ].x = rcTab.left + m_nPixelDelta;
+ region[ 3 ].y = rcTab.bottom;
+ }
+ else
+ {
+ region[ 0 ].x = rcTab.left + m_nPixelDelta;
+ region[ 0 ].y = rcTab.top;
+
+ region[ 1 ].x = rcTab.right - m_nPixelDelta;
+ region[ 1 ].y = rcTab.top;
+
+ region[ 2 ].x = rcTab.right + m_nPixelDelta;
+ region[ 2 ].y = rcTab.bottom;
+
+ region[ 3 ].x = rcTab.left - m_nPixelDelta;
+ region[ 3 ].y = rcTab.bottom;
+ }
+
+ HDC dc = drawHelper.GrabDC();
+
+ HRGN rgn = CreatePolygonRgn( region, cPoints, ALTERNATE );
+
+ int oldPF = SetPolyFillMode( dc, ALTERNATE );
+
+ HBRUSH brBg = CreateSolidBrush( fgcolor );
+ HBRUSH brBorder = CreateSolidBrush( hilightcolor );
+ //HBRUSH brInset = CreateSolidBrush( fgcolor );
+
+ FillRgn( dc, rgn, brBg );
+ FrameRgn( dc, rgn, brBorder, 1, 1 );
+
+ SetPolyFillMode( dc, oldPF );
+
+ DeleteObject( rgn );
+
+ DeleteObject( brBg );
+ DeleteObject( brBorder );
+ //DeleteObject( brInset );
+
+ // Position label
+ InflateRect( &rcTab, -5, 0 );
+ OffsetRect( &rcTab, 2, 0 );
+
+ // Draw label
+ drawHelper.DrawColoredText( "Arial", 9, FW_NORMAL, text, rcTab, "%s%s", getPrefix( tabnum ), getLabel( tabnum ) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CTabWindow::redraw( void )
+{
+ CDrawHelper drawHelper( this, m_Colors[ COLOR_BG ] );
+
+ int liney = m_bInverted ? 1 : h2() - 2;
+
+ drawHelper.DrawColoredLine( m_Colors[ COLOR_HILITE ], PS_SOLID, 1, 0, liney, w(), liney );
+ RECT rc;
+ drawHelper.GetClientRect( rc );
+
+ // Draw non-selected first
+ for ( int i = 0 ; i < m_Items.Size(); i++ )
+ {
+ if ( i == m_nSelected )
+ continue;
+
+ DrawTab( drawHelper, rc, i );
+ }
+
+ // Draw selected last, so that it appears to pop to top of z order
+ if ( m_nSelected >= 0 && m_nSelected < m_Items.Size() )
+ {
+ DrawTab( drawHelper, rc, m_nSelected, true );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : mx -
+// my -
+// Output : int
+//-----------------------------------------------------------------------------
+int CTabWindow::GetItemUnderMouse( int mx, int my )
+{
+ RECT rcClient;
+ GetClientRect( (HWND)getHandle(), &rcClient );
+
+ for ( int i = 0; i < m_Items.Size() ; i++ )
+ {
+ RECT rcTab;
+ GetTabRect( rcClient, rcTab, i );
+
+ if ( mx < rcTab.left ||
+ mx > rcTab.right ||
+ my < rcTab.top ||
+ my > rcTab.bottom )
+ {
+ continue;
+ }
+ return i;
+ }
+
+ return -1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *event -
+// Output : int CTabWindow::handleEvent
+//-----------------------------------------------------------------------------
+int CTabWindow::handleEvent (mxEvent *event)
+{
+ int iret = 0;
+
+ switch ( event->event )
+ {
+ case mxEvent::MouseDown:
+ {
+ int item = GetItemUnderMouse( (short)event->x, (short)event->y );
+ if ( item != -1 )
+ {
+ m_nSelected = item;
+ redraw();
+
+ // Send CBN_SELCHANGE WM_COMMAND message to parent
+ HWND parent = (HWND)( getParent() ? getParent()->getHandle() : NULL );
+ if ( parent )
+ {
+ LPARAM lp;
+ WPARAM wp;
+
+ wp = MAKEWPARAM( getId(), CBN_SELCHANGE );
+ lp = (long)getHandle();
+
+ PostMessage( parent, WM_COMMAND, wp, lp );
+ }
+ iret = 1;
+ }
+
+ if ( event->buttons & mxEvent::MouseRightButton )
+ {
+ ShowRightClickMenu( (short)event->x, (short)event->y );
+ iret = 1;
+ }
+ }
+ break;
+ case mxEvent::Size:
+ {
+ RecomputeLayout( w2() );
+ }
+ break;
+ }
+ return iret;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Add string to table
+// Input : *item -
+//-----------------------------------------------------------------------------
+void CTabWindow::add( const char *item )
+{
+ m_Items.AddToTail();
+ CETItem *p = &m_Items[ m_Items.Size() - 1 ];
+ Assert( p );
+
+ Q_memset( &p->rect, 0, sizeof( p->rect) );
+
+ strcpy( p->m_szString, item );
+ p->m_szPrefix[ 0 ] = 0;
+ m_nSelected = min( m_nSelected, m_Items.Size() - 1 );
+ m_nSelected = max( m_nSelected, 0 );
+
+ RecomputeLayout( w2() );
+
+ redraw();
+}
+
+void CTabWindow::setPrefix( int item, char const *prefix )
+{
+ if ( item < 0 || item >= m_Items.Size() )
+ return;
+
+ strncpy( m_Items[ item ].m_szPrefix, prefix, sizeof( m_Items[ item ].m_szPrefix ) );
+// RecomputeLayout( w2() );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Change selected item
+// Input : index -
+//-----------------------------------------------------------------------------
+void CTabWindow::select( int index )
+{
+ if ( index < 0 || index >= m_Items.Size() )
+ return;
+
+ m_nSelected = index;
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Remove a string
+// Input : index -
+//-----------------------------------------------------------------------------
+void CTabWindow::remove( int index )
+{
+ if ( index < 0 || index >= m_Items.Size() )
+ return;
+
+ m_Items.Remove( index );
+
+ m_nSelected = min( m_nSelected, m_Items.Size() - 1 );
+ m_nSelected = max( m_nSelected, 0 );
+
+ RecomputeLayout( w2() );
+
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Clear out everything
+//-----------------------------------------------------------------------------
+void CTabWindow::removeAll()
+{
+ m_nSelected = -1;
+ m_Items.RemoveAll();
+
+ RecomputeLayout( w2() );
+
+ redraw();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CTabWindow::getItemCount () const
+{
+ return m_Items.Size();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CTabWindow::getSelectedIndex () const
+{
+ // Convert based on override index
+ return m_nSelected;
+}
+
+char const *CTabWindow::getLabel( int item )
+{
+ if ( item < 0 || item >= m_Items.Count() )
+ return "";
+
+ return m_Items[ item ].m_szString;
+}
+
+char const *CTabWindow::getPrefix( int item )
+{
+ if ( item < 0 || item >= m_Items.Count() )
+ return "";
+
+ return m_Items[ item ].m_szPrefix;
+}
+
+void CTabWindow::SetRowHeight( int rowheight )
+{
+ m_nRowHeight = rowheight;
+ RecomputeLayout( w2() );
+ redraw();
+}
+
+int CTabWindow::GetBestHeight( int width )
+{
+ return RecomputeLayout( width, false ) * m_nRowHeight;
+}
+
+
+int CTabWindow::RecomputeLayout( int windowWidth, bool dolayout /*=true*/ )
+{
+ // Draw non-selected first
+ int curedge = m_nPixelDelta + 1;
+ int curtop = 0;
+
+ if ( m_bRightJustify )
+ {
+ curedge = windowWidth - ( m_nPixelDelta + 1 ) - 5;
+ }
+
+ int startedge = curedge;
+
+ int currentrow = 0;
+
+ for ( int i = 0 ; i < m_Items.Size(); i++ )
+ {
+ CETItem *p = &m_Items[ i ];
+
+ RECT rc;
+
+ int textwidth = CDrawHelper::CalcTextWidth( "Arial", 9, FW_NORMAL, "%s%s", p->m_szPrefix, p->m_szString ) + 15;
+
+ if ( !m_bRightJustify )
+ {
+ // Starting column
+ if ( curedge + textwidth > windowWidth )
+ {
+ curedge = startedge;
+ curtop += m_nRowHeight;
+ currentrow++;
+ }
+
+ rc.left = curedge;
+ rc.right = curedge + textwidth;
+ rc.top = curtop + 2;
+ rc.bottom = curtop + m_nRowHeight;
+
+ curedge += textwidth;
+
+ p->rect = rc;
+ }
+ else
+ {
+ // Starting column
+ if ( curedge - textwidth < 0 )
+ {
+ curedge = startedge;
+ curtop += m_nRowHeight;
+ currentrow++;
+ }
+
+ rc.left = curedge - textwidth;
+ rc.right = curedge;
+ rc.top = curtop;
+ rc.bottom = curtop + m_nRowHeight - 2;
+
+ curedge -= textwidth;
+ }
+
+ if ( dolayout )
+ {
+ p->rect = rc;
+ }
+ }
+
+ if ( dolayout )
+ {
+ m_nRowsRequired = currentrow + 1;
+ }
+
+ return currentrow + 1;
+}
diff --git a/utils/scenemanager/tabwindow.h b/utils/scenemanager/tabwindow.h
new file mode 100644
index 0000000..aec100a
--- /dev/null
+++ b/utils/scenemanager/tabwindow.h
@@ -0,0 +1,103 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+
+#ifndef TABWINDOW_H
+#define TABWINDOW_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include <mxtk/mx.h>
+#include "utlvector.h"
+
+class CDrawHelper;
+
+//-----------------------------------------------------------------------------
+// Purpose: A custom tab control for handling expression class strings
+//-----------------------------------------------------------------------------
+class CTabWindow : public mxWindow
+{
+public:
+ enum
+ {
+ COLOR_BG = 0,
+ COLOR_FG,
+ COLOR_FG_SELECTED,
+ COLOR_HILITE,
+ COLOR_HILITE_SELECTED,
+ COLOR_TEXT,
+ COLOR_TEXT_SELECTED,
+
+ NUM_COLORS
+ };
+
+ CTabWindow( mxWindow *parent, int x, int y, int w, int h, int id = 0, int style = 0 );
+ virtual ~CTabWindow ( void );
+
+ virtual void redraw( void );
+ virtual int handleEvent (mxEvent *event);
+
+ // MANIPULATORS
+ virtual void add (const char *item);
+ virtual void select (int index);
+ virtual void remove (int index);
+ virtual void removeAll ();
+ virtual void setPrefix( int item, char const *prefix );
+
+ // ACCESSORS
+ virtual int getItemCount () const;
+ virtual int getSelectedIndex () const;
+
+ virtual char const *getLabel( int item );
+ virtual char const *getPrefix( int item );
+
+ virtual void ShowRightClickMenu( int mx, int my ) = 0;
+
+ void SetColor( int index, COLORREF clr );
+
+ void SetInverted( bool invert );
+ void SetRightJustify( bool rightjustify );
+
+ int GetBestHeight( int width );
+ void SetRowHeight( int rowheight );
+
+protected:
+ void GetTabRect( const RECT& rcClient, RECT& tabRect, int tabNum );
+ virtual void DrawTab( CDrawHelper& drawHelper, RECT& rcClient, int tabnum, bool selected = false );
+
+ int RecomputeLayout( int windowWidth, bool dolayout = true );
+
+ class CETItem
+ {
+ public:
+ enum
+ {
+ MAX_ET_STRING_LENGTH = 64
+ };
+
+ char m_szString[ MAX_ET_STRING_LENGTH ];
+ char m_szPrefix[ MAX_ET_STRING_LENGTH ];
+ RECT rect;
+ };
+
+ int GetItemUnderMouse( int mx, int my );
+
+ CUtlVector <CETItem> m_Items;
+ int m_nRowsRequired;
+
+ int m_nSelected;
+
+ int m_nTabWidth;
+ int m_nPixelDelta;
+ bool m_bInverted;
+ bool m_bRightJustify;
+
+ COLORREF m_Colors[ NUM_COLORS ];
+
+ int m_nRowHeight;
+};
+#endif // TABWINDOW_H
diff --git a/utils/scenemanager/vcd1.ico b/utils/scenemanager/vcd1.ico
new file mode 100644
index 0000000..249d061
--- /dev/null
+++ b/utils/scenemanager/vcd1.ico
Binary files differ
diff --git a/utils/scenemanager/vcdfile.cpp b/utils/scenemanager/vcdfile.cpp
new file mode 100644
index 0000000..4dccbe3
--- /dev/null
+++ b/utils/scenemanager/vcdfile.cpp
@@ -0,0 +1,284 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include "vcdfile.h"
+#include "soundentry.h"
+#include "choreoscene.h"
+#include "scriplib.h"
+#include "cmdlib.h"
+#include "iscenetokenprocessor.h"
+#include "choreoevent.h"
+#include "scene.h"
+#include "project.h"
+#include "workspacemanager.h"
+#include "workspacebrowser.h"
+
+//-----------------------------------------------------------------------------
+// Purpose: Helper to scene module for parsing the .vcd file
+//-----------------------------------------------------------------------------
+class CSceneTokenProcessor : public ISceneTokenProcessor
+{
+public:
+ const char *CurrentToken( void );
+ bool GetToken( bool crossline );
+ bool TokenAvailable( void );
+ void Error( const char *fmt, ... );
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : const
+//-----------------------------------------------------------------------------
+const char *CSceneTokenProcessor::CurrentToken( void )
+{
+ return token;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : crossline -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CSceneTokenProcessor::GetToken( bool crossline )
+{
+ return ::GetToken( crossline ) ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CSceneTokenProcessor::TokenAvailable( void )
+{
+ return ::TokenAvailable() ? true : false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *fmt -
+// ... -
+//-----------------------------------------------------------------------------
+void CSceneTokenProcessor::Error( const char *fmt, ... )
+{
+ char string[ 2048 ];
+ va_list argptr;
+ va_start( argptr, fmt );
+ vsprintf( string, fmt, argptr );
+ va_end( argptr );
+
+ Con_ColorPrintf( ERROR_R, ERROR_G, ERROR_B, string );
+ ::Error( string );
+}
+
+static CSceneTokenProcessor g_TokenProcessor;
+ISceneTokenProcessor *tokenprocessor = &g_TokenProcessor;
+
+CVCDFile::CVCDFile( CScene *scene, char const *filename ) : m_pOwner( scene )
+{
+ Q_strncpy( m_szName, filename, sizeof( m_szName ) );
+
+ m_pScene = LoadScene( filename );
+ LoadSoundsFromScene( m_pScene );
+
+ m_pszComments = NULL;
+}
+
+CVCDFile::~CVCDFile()
+{
+ while ( m_Sounds.Count() > 0 )
+ {
+ CSoundEntry *p = m_Sounds[ 0 ];
+ m_Sounds.Remove( 0 );
+ delete p;
+ }
+ delete[] m_pszComments;
+}
+
+CScene *CVCDFile::GetOwnerScene()
+{
+ return m_pOwner;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *filename -
+// Output : CChoreoScene
+//-----------------------------------------------------------------------------
+CChoreoScene *CVCDFile::LoadScene( char const *filename )
+{
+ if ( filesystem->FileExists( filename ) )
+ {
+ char fullpath[ 512 ];
+ filesystem->RelativePathToFullPath( filename, "GAME", fullpath, sizeof( fullpath ) );
+ LoadScriptFile( fullpath );
+ CChoreoScene *scene = ChoreoLoadScene( filename, this, &g_TokenProcessor, Con_Printf );
+ return scene;
+ }
+
+ return NULL;
+}
+
+void CVCDFile::LoadSoundsFromScene( CChoreoScene *scene )
+{
+ if ( !scene )
+ return;
+
+ CChoreoEvent *e;
+
+ int c = scene->GetNumEvents();
+ for ( int i = 0; i < c; i++ )
+ {
+ e = scene->GetEvent( i );
+ if ( !e )
+ continue;
+
+ if ( e->GetType() != CChoreoEvent::SPEAK )
+ continue;
+
+ CSoundEntry *se = new CSoundEntry( this, e->GetParameters() );
+ m_Sounds.AddToTail( se );
+ }
+}
+
+char const *CVCDFile::GetName() const
+{
+ return m_szName;
+}
+
+char const *CVCDFile::GetComments()
+{
+ return m_pszComments ? m_pszComments : "";
+}
+
+void CVCDFile::SetComments( char const *comments )
+{
+ delete[] m_pszComments;
+ m_pszComments = V_strdup( comments );
+
+ if ( GetOwnerScene() )
+ {
+ if ( GetOwnerScene()->GetOwnerProject() )
+ {
+ GetOwnerScene()->GetOwnerProject()->SetDirty( true );
+ }
+ }
+}
+
+int CVCDFile::GetSoundEntryCount() const
+{
+ return m_Sounds.Count();
+}
+
+CSoundEntry *CVCDFile::GetSoundEntry( int index )
+{
+ if ( index < 0 || index >= m_Sounds.Count() )
+ return NULL;
+ return m_Sounds[ index ];
+}
+
+void CVCDFile::ValidateTree( mxTreeView *tree, mxTreeViewItem* parent )
+{
+ CUtlVector< mxTreeViewItem * > m_KnownItems;
+
+ int c = GetSoundEntryCount();
+ CSoundEntry *sound;
+ for ( int i = 0; i < c; i++ )
+ {
+ sound = GetSoundEntry( i );
+ if ( !sound )
+ continue;
+
+ char sz[ 256 ];
+ Q_snprintf( sz, sizeof( sz ), "\"%s\" : script %s", sound->GetName(), sound->GetScriptFile() );
+
+ mxTreeViewItem *spot = sound->FindItem( tree, parent );
+ if ( !spot )
+ {
+ spot = tree->add( parent, sz );
+ }
+
+ m_KnownItems.AddToTail( spot );
+
+ sound->SetOrdinal( i );
+
+ tree->setLabel( spot, sz );
+
+ tree->setImages( spot, sound->GetIconIndex(), sound->GetIconIndex() );
+ tree->setUserData( spot, sound );
+
+ sound->ValidateTree( tree, spot );
+ }
+
+ mxTreeViewItem *start = tree->getFirstChild( parent );
+ while ( start )
+ {
+ mxTreeViewItem *next = tree->getNextChild( start );
+
+ if ( m_KnownItems.Find( start ) == m_KnownItems.InvalidIndex() )
+ {
+ tree->remove( start );
+ }
+
+ start = next;
+ }
+
+ tree->sortTree( parent, true, CWorkspaceBrowser::CompareFunc, 0 );
+}
+
+void CVCDFile::Checkout(bool updatestateicons /*= true*/)
+{
+ VSS_Checkout( GetName(), updatestateicons );
+}
+
+void CVCDFile::Checkin(bool updatestateicons /*= true*/)
+{
+ VSS_Checkin( GetName(), updatestateicons );
+}
+
+
+bool CVCDFile::IsCheckedOut() const
+{
+ return filesystem->IsFileWritable( GetName() );
+}
+
+int CVCDFile::GetIconIndex() const
+{
+ if ( IsCheckedOut() )
+ {
+ return IMAGE_VCD_CHECKEDOUT;
+ }
+ else
+ {
+ return IMAGE_VCD;
+ }
+}
+
+void CVCDFile::MoveChildUp( ITreeItem *child )
+{
+}
+
+void CVCDFile::MoveChildDown( ITreeItem *child )
+{
+}
+
+void CVCDFile::SetDirty( bool dirty )
+{
+ if ( GetOwnerScene() )
+ {
+ GetOwnerScene()->SetDirty( dirty );
+ }
+}
+
+
+bool CVCDFile::IsChildFirst( ITreeItem *child )
+{
+ return false;
+}
+
+bool CVCDFile::IsChildLast( ITreeItem *child )
+{
+ return false;
+}
diff --git a/utils/scenemanager/vcdfile.h b/utils/scenemanager/vcdfile.h
new file mode 100644
index 0000000..661f332
--- /dev/null
+++ b/utils/scenemanager/vcdfile.h
@@ -0,0 +1,90 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef VCDFILE_H
+#define VCDFILE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CSoundEntry;
+class CScene;
+
+#include "itreeitem.h"
+#include "ichoreoeventcallback.h"
+
+class CChoreoScene;
+
+class CVCDFile : public ITreeItem, public IChoreoEventCallback
+{
+public:
+ CVCDFile( CScene *scene, char const *filename );
+ ~CVCDFile();
+
+ CScene *GetOwnerScene();
+
+ char const *GetName() const;
+ char const *GetComments();
+ void SetComments( char const *comments );
+
+ int GetSoundEntryCount() const;
+ CSoundEntry *GetSoundEntry( int index );
+
+ void ValidateTree( mxTreeView *tree, mxTreeViewItem* parent );
+
+ // ITreeItem
+ virtual CWorkspace *GetWorkspace() { return NULL; }
+ virtual CProject *GetProject() { return NULL; }
+ virtual CScene *GetScene() { return NULL; }
+ virtual CVCDFile *GetVCDFile() { return this; }
+ virtual CSoundEntry *GetSoundEntry() { return NULL; }
+ virtual CWaveFile *GetWaveFile() { return NULL; }
+
+ // IChoreoEventCallback stubs
+ virtual void StartEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) {}
+ // Only called for events with HasEndTime() == true
+ virtual void EndEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) {}
+ // Called for events which have been started but aren't done yet
+ virtual void ProcessEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) {}
+ // Called for events that are part of a pause condition
+ virtual bool CheckEvent( float currenttime, CChoreoScene *scene, CChoreoEvent *event ) { return false; }
+
+ virtual void Checkout( bool updatestateicons = true );
+ virtual void Checkin( bool updatestateicons = true );
+
+ bool IsCheckedOut() const;
+ int GetIconIndex() const;
+
+ virtual void MoveChildUp( ITreeItem *child );
+ virtual void MoveChildDown( ITreeItem *child );
+
+ void SetDirty( bool dirty );
+
+ virtual bool IsChildFirst( ITreeItem *child );
+ virtual bool IsChildLast( ITreeItem *child );
+
+private:
+
+ CChoreoScene *LoadScene( char const *filename );
+
+ void LoadSoundsFromScene( CChoreoScene *scene );
+
+ enum
+ {
+ MAX_VCD_NAME = 128,
+ };
+
+ char m_szName[ MAX_VCD_NAME ];
+ char *m_pszComments;
+
+ CUtlVector< CSoundEntry * > m_Sounds;
+
+ CChoreoScene *m_pScene;
+
+ CScene *m_pOwner;
+};
+
+#endif // VCDFILE_H
diff --git a/utils/scenemanager/vssproperties.cpp b/utils/scenemanager/vssproperties.cpp
new file mode 100644
index 0000000..44d4473
--- /dev/null
+++ b/utils/scenemanager/vssproperties.cpp
@@ -0,0 +1,83 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include <mxtk/mx.h>
+#include <stdio.h>
+#include "resource.h"
+#include "VSSProperties.h"
+#include "workspacemanager.h"
+
+static CVSSParams g_Params;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+// uMsg -
+// wParam -
+// lParam -
+// Output : static BOOL CALLBACK
+//-----------------------------------------------------------------------------
+static BOOL CALLBACK VSSPropertiesDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ // Insert code here to put the string (to find and replace with)
+ // into the edit controls.
+ // ...
+ {
+ g_Params.PositionSelf( hwndDlg );
+
+ SetDlgItemText( hwndDlg, IDC_VSS_USERNAME, g_Params.m_szUserName );
+ SetDlgItemText( hwndDlg, IDC_VSS_PROJECT, g_Params.m_szProject );
+
+ SetWindowText( hwndDlg, g_Params.m_szDialogTitle );
+
+ SetFocus( GetDlgItem( hwndDlg, IDC_VSS_USERNAME ) );
+ SendMessage( GetDlgItem( hwndDlg, IDC_VSS_USERNAME ), EM_SETSEL, 0, MAKELONG(0, 0xffff) );
+
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ g_Params.m_szUserName[ 0 ] = 0;
+ g_Params.m_szProject[ 0 ] = 0;
+ GetDlgItemText( hwndDlg, IDC_VSS_USERNAME, g_Params.m_szUserName, sizeof( g_Params.m_szUserName ) );
+ GetDlgItemText( hwndDlg, IDC_VSS_PROJECT, g_Params.m_szProject, sizeof( g_Params.m_szProject ) );
+ EndDialog( hwndDlg, 1 );
+ break;
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ }
+ return TRUE;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *view -
+// *actor -
+// Output : int
+//-----------------------------------------------------------------------------
+int VSSProperties( CVSSParams *params )
+{
+ g_Params = *params;
+
+ int retval = DialogBox( (HINSTANCE)GetModuleHandle( 0 ),
+ MAKEINTRESOURCE( IDD_VSSPROPERTIES ),
+ (HWND)GetWorkspaceManager()->getHandle(),
+ (DLGPROC)VSSPropertiesDialogProc );
+
+ *params = g_Params;
+
+ return retval;
+} \ No newline at end of file
diff --git a/utils/scenemanager/vssproperties.h b/utils/scenemanager/vssproperties.h
new file mode 100644
index 0000000..534c800
--- /dev/null
+++ b/utils/scenemanager/vssproperties.h
@@ -0,0 +1,27 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef VSSPROPERTIES_H
+#define VSSPROPERTIES_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialogparams.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+struct CVSSParams : public CBaseDialogParams
+{
+ // Event descriptive name
+ char m_szUserName[ 256 ];
+ char m_szProject[ 256 ];
+};
+
+int VSSProperties( CVSSParams *params );
+
+#endif // VSSPROPERTIES_H
diff --git a/utils/scenemanager/wav1.ico b/utils/scenemanager/wav1.ico
new file mode 100644
index 0000000..d4ae51b
--- /dev/null
+++ b/utils/scenemanager/wav1.ico
Binary files differ
diff --git a/utils/scenemanager/wavebrowser.cpp b/utils/scenemanager/wavebrowser.cpp
new file mode 100644
index 0000000..1bc45f6
--- /dev/null
+++ b/utils/scenemanager/wavebrowser.cpp
@@ -0,0 +1,1066 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "workspacebrowser.h"
+#include "workspace.h"
+#include "project.h"
+#include <windows.h>
+#include "resource.h"
+#include "project.h"
+#include "vcdfile.h"
+#include "wavefile.h"
+#include "scene.h"
+
+#include "workspacemanager.h"
+#include "wavebrowser.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "iscenemanagersound.h"
+#include "snd_wave_source.h"
+#include "cmdlib.h"
+#include "tabwindow.h"
+#include "inputproperties.h"
+#include "waveproperties.h"
+#include "drawhelper.h"
+#include "ifileloader.h"
+#include "MultipleRequest.h"
+
+#include "soundchars.h"
+
+enum
+{
+ // Controls
+ IDC_SB_LISTVIEW = 101,
+ IDC_SB_FILETREE,
+
+ // Messages
+ IDC_SB_PLAY = 1000,
+ IDC_SB_CHECKOUT,
+ IDC_SB_CHECKIN,
+ IDC_SB_PROPERTIES,
+ IDC_SB_ENABLEVOICEDUCKING,
+ IDC_SB_DISABLEVOICEDUCKING,
+
+ IDC_SB_EXPORTSENTENCE,
+ IDC_SB_IMPORTSENTENCE,
+
+ IDC_SB_GETSENTENCE,
+};
+
+enum
+{
+ COL_WAV = 0,
+ COL_DUCKED,
+ COL_SENTENCE
+};
+
+class CWaveList : public mxListView
+{
+public:
+ CWaveList( mxWindow *parent, int id = 0 )
+ : mxListView( parent, 0, 0, 0, 0, id )
+ {
+ // SendMessage ( (HWND)getHandle(), WM_SETFONT, (WPARAM) (HFONT) GetStockObject (ANSI_FIXED_FONT), MAKELPARAM (TRUE, 0));
+
+ //HWND wnd = (HWND)getHandle();
+ //DWORD style = GetWindowLong( wnd, GWL_STYLE );
+ //style |= LVS_SORTASCENDING;
+ //SetWindowLong( wnd, GWL_STYLE, style );
+
+ //SceneManager_AddWindowStyle( this, LVS_SORTASCENDING );
+
+ // Add column headers
+ insertTextColumn( COL_WAV, 300, "WAV" );
+ insertTextColumn( COL_DUCKED, 50, "Ducked" );
+ insertTextColumn( COL_SENTENCE, 300, "Sentence Text" );
+ }
+};
+
+class CWaveFileTree : public mxTreeView
+{
+public:
+ CWaveFileTree( mxWindow *parent, int id = 0 ) : mxTreeView( parent, 0, 0, 0, 0, id ),
+ m_Paths( 0, 0, FileTreeLessFunc )
+ {
+ }
+
+ void Clear()
+ {
+ removeAll();
+ m_Paths.RemoveAll();
+ }
+
+ void FindOrAddSubdirectory( char const *subdir )
+ {
+ FileTreePath fp;
+ Q_strcpy( fp.path, subdir );
+
+ if ( m_Paths.Find( fp ) != m_Paths.InvalidIndex() )
+ return;
+
+ m_Paths.Insert( fp );
+ }
+
+ mxTreeViewItem *FindOrAddChildItem( mxTreeViewItem *parent, char const *child )
+ {
+ mxTreeViewItem *p = getFirstChild( parent );
+ if ( !p )
+ {
+ return add( parent, child );
+ }
+
+ while ( p )
+ {
+ if ( !Q_stricmp( getLabel( p ), child ) )
+ return p;
+
+ p = getNextChild( p );
+ }
+
+ return add( parent, child );
+ }
+
+ void _PopulateTree( int pathId, char const *path )
+ {
+ char sz[ 512 ];
+ Q_strcpy( sz, path );
+ char *p = sz;
+
+ // Start at root
+ mxTreeViewItem *cur = NULL;
+
+ // Tokenize path
+ while ( p && p[0] )
+ {
+ char *slash = Q_strstr( p, "/" );
+ if ( !slash )
+ {
+ slash = Q_strstr( p, "\\" );
+ }
+
+ char *check = p;
+
+ if ( slash )
+ {
+ *slash = 0;
+
+ // see if a child of current already exists with this name
+ p = slash + 1;
+ }
+ else
+ {
+ p = NULL;
+ }
+
+ Assert( check );
+
+ cur = FindOrAddChildItem( cur, check );
+ }
+
+ setUserData( cur, (void *)pathId );
+ }
+
+ char const *GetSelectedPath( void )
+ {
+ mxTreeViewItem *tvi = getSelectedItem();
+ int id = (int)getUserData( tvi );
+
+ if ( id < 0 || id >= m_Paths.Count() )
+ {
+ Assert( 0 );
+ return "";
+ }
+ return m_Paths[ id ].path;
+ }
+
+ void PopulateTree()
+ {
+ int i;
+ for ( i = m_Paths.FirstInorder(); i != m_Paths.InvalidIndex(); i = m_Paths.NextInorder( i ) )
+ {
+ _PopulateTree( i, m_Paths[ i ].path );
+ }
+
+ mxTreeViewItem *p = getFirstChild( NULL );
+ setOpen( p, true );
+ }
+
+ struct FileTreePath
+ {
+ char path[ MAX_PATH ];
+ };
+
+ static bool FileTreeLessFunc( const FileTreePath &lhs, const FileTreePath &rhs )
+ {
+ return Q_stricmp( lhs.path, rhs.path ) < 0;
+ }
+
+ CUtlRBTree< FileTreePath, int > m_Paths;
+};
+
+class CWaveOptionsWindow : public mxWindow
+{
+typedef mxWindow BaseClass;
+public:
+ enum
+ {
+ IDC_PLAY_SOUND = 1000,
+ IDC_STOP_SOUNDS,
+ IDC_SEARCH,
+ };
+
+ CWaveOptionsWindow( CWaveBrowser *browser ) : BaseClass( browser, 0, 0, 0, 0 ), m_pBrowser( browser )
+ {
+ SceneManager_AddWindowStyle( this, WS_CLIPSIBLINGS | WS_CLIPCHILDREN );
+
+ m_szSearchString[0]=0;
+
+ m_pPlay = new mxButton( this, 0, 0, 0, 0, "Play", IDC_PLAY_SOUND );
+
+ m_pStopSounds = new mxButton( this, 0, 0, 0, 0, "Stop Sounds", IDC_STOP_SOUNDS );
+
+ m_pSearch = new mxButton( this, 0, 0, 0, 0, "Search...", IDC_SEARCH );
+
+ m_pSearchString = new mxLabel( this, 0, 0, 0, 0, "" );
+
+ }
+
+ bool PaintBackground( void )
+ {
+ redraw();
+ return false;
+ }
+
+
+ virtual void redraw()
+ {
+ CDrawHelper drawHelper( this, GetSysColor( COLOR_BTNFACE ) );
+ }
+ virtual int handleEvent( mxEvent *event )
+ {
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Size:
+ {
+ iret = 1;
+
+ int split = 120;
+
+ int x = 1;
+
+ m_pPlay->setBounds( x, 1, split, h2() - 2 );
+
+ x += split + 10;
+
+ m_pStopSounds->setBounds( x, 1, split, h2()-2 );
+
+ x += split + 10;
+
+ m_pSearch->setBounds( x, 1, split, h2() - 2 );
+
+ x += split + 10;
+
+ m_pSearchString->setBounds( x, 2, split * 2, h2() - 4 );
+
+ x += split * 2 + 10;
+ }
+ break;
+ case mxEvent::Action:
+ {
+ switch ( event->action )
+ {
+ case IDC_STOP_SOUNDS:
+ {
+ iret = 1;
+ sound->StopAll();
+ }
+ break;
+ case IDC_PLAY_SOUND:
+ {
+ iret = 1;
+ m_pBrowser->OnPlay();
+ }
+ break;
+ case IDC_SEARCH:
+ {
+ iret = 1;
+ OnSearch();
+ };
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ }
+
+ return iret;
+ }
+
+ char const *GetSearchString()
+ {
+ return m_szSearchString;
+ }
+
+ void OnSearch()
+ {
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Search" );
+ Q_strcpy( params.m_szPrompt, "Find:" );
+ Q_strcpy( params.m_szInputText, m_szSearchString );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ Q_strcpy( m_szSearchString, params.m_szInputText );
+
+ m_pSearchString->setLabel( va( "Search: '%s'", GetSearchString() ) );
+
+ m_pBrowser->OnSearch();
+ }
+
+private:
+
+ mxButton *m_pStopSounds;
+ mxButton *m_pPlay;
+ mxButton *m_pSearch;
+ mxLabel *m_pSearchString;
+
+ CWaveBrowser *m_pBrowser;
+
+ char m_szSearchString[ 256 ];
+};
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+//-----------------------------------------------------------------------------
+CWaveBrowser::CWaveBrowser( mxWindow *parent, CWorkspaceManager *manager, int id ) :
+ BaseClass( parent, 0, 0, 0, 0, "Wave Browser", id )
+{
+ m_pManager = manager;
+
+ SceneManager_MakeToolWindow( this, false );
+
+ m_pListView = new CWaveList( this, IDC_SB_LISTVIEW );
+ m_pOptions = new CWaveOptionsWindow( this );
+ m_pFileTree = new CWaveFileTree( this, IDC_SB_FILETREE );
+
+ HIMAGELIST list = GetWorkspaceManager()->CreateImageList();
+
+ // Associate the image list with the tree-view control.
+ m_pListView->setImageList( (void *)list );
+
+ LoadAllSounds();
+
+ PopulateTree( NULL );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWaveBrowser::OnDelete()
+{
+ RemoveAllSounds();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *event -
+// Output : int
+//-----------------------------------------------------------------------------
+int CWaveBrowser::handleEvent( mxEvent *event )
+{
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ {
+ iret = 0;
+ }
+ break;
+ case IDC_SB_LISTVIEW:
+ {
+ bool rightmouse = ( event->flags == mxEvent::RightClicked ) ? true : false;
+ bool doubleclicked = ( event->flags == mxEvent::DoubleClicked ) ? true : false;
+
+ if ( rightmouse )
+ {
+ ShowContextMenu();
+ }
+ else if ( doubleclicked )
+ {
+ if ( m_pListView->getNumSelected() == 1 )
+ {
+ int index = m_pListView->getNextSelectedItem( -1 );
+ if ( index >= 0 )
+ {
+ CWaveFile *wav = (CWaveFile *)m_pListView->getUserData( index, 0 );
+ if ( wav )
+ {
+ wav->Play();
+ }
+ }
+ }
+ }
+ }
+ break;
+ case IDC_SB_FILETREE:
+ {
+ PopulateTree( m_pFileTree->GetSelectedPath() );
+ }
+ break;
+ case IDC_SB_PLAY:
+ {
+ OnPlay();
+ }
+ break;
+ case IDC_SB_GETSENTENCE:
+ {
+ OnGetSentence();
+ }
+ break;
+ case IDC_SB_PROPERTIES:
+ {
+ OnWaveProperties();
+ }
+ break;
+ case IDC_SB_CHECKOUT:
+ {
+ OnCheckout();
+ }
+ break;
+ case IDC_SB_CHECKIN:
+ {
+ OnCheckin();
+ }
+ break;
+ case IDC_SB_ENABLEVOICEDUCKING:
+ {
+ OnEnableVoiceDucking();
+ }
+ break;
+ case IDC_SB_DISABLEVOICEDUCKING:
+ {
+ OnDisableVoiceDucking();
+ }
+ break;
+ case IDC_SB_IMPORTSENTENCE:
+ {
+ OnImportSentence();
+ }
+ break;
+ case IDC_SB_EXPORTSENTENCE:
+ {
+ OnExportSentence();
+ }
+ break;
+ }
+ }
+ break;
+ case mxEvent::Size:
+ {
+ int optionsh = 20;
+
+ m_pOptions->setBounds( 0, 0, w2(), optionsh );
+
+ int filetreewidth = 175;
+
+ m_pFileTree->setBounds( 0, optionsh, filetreewidth, h2() - optionsh );
+ m_pListView->setBounds( filetreewidth, optionsh, w2() - filetreewidth, h2() - optionsh );
+
+ GetWorkspaceManager()->SetWorkspaceDirty();
+
+ iret = 1;
+ }
+ break;
+ case mxEvent::Close:
+ {
+ iret = 1;
+ }
+ break;
+ }
+
+ return iret;
+}
+
+static bool NameLessFunc( CWaveFile *const& name1, CWaveFile *const& name2 )
+{
+ if ( Q_stricmp( name1->GetName(), name2->GetName() ) < 0 )
+ return true;
+ return false;
+}
+
+#define SOUND_PREFIX_LEN 6
+//-----------------------------------------------------------------------------
+// Finds all .wav files in a particular directory
+//-----------------------------------------------------------------------------
+bool CWaveBrowser::LoadWaveFilesInDirectory( CUtlDict< CWaveFile *, int >& soundlist, char const* pDirectoryName, int nDirectoryNameLen )
+{
+ Assert( Q_strnicmp( pDirectoryName, "sound", 5 ) == 0 );
+
+ char *pWildCard;
+ pWildCard = ( char * )stackalloc( nDirectoryNameLen + 7 );
+ Q_snprintf( pWildCard, nDirectoryNameLen + 7, "%s/*.wav", pDirectoryName );
+
+ if ( !filesystem )
+ {
+ return false;
+ }
+
+ FileFindHandle_t findHandle;
+ const char *pFileName = filesystem->FindFirst( pWildCard, &findHandle );
+ while( pFileName )
+ {
+ if( !filesystem->FindIsDirectory( findHandle ) )
+ {
+ // Strip off the 'sound/' part of the name.
+ char *pFileNameWithPath;
+ int nAllocSize = nDirectoryNameLen + Q_strlen(pFileName) + 2;
+ pFileNameWithPath = (char *)stackalloc( nAllocSize );
+ Q_snprintf( pFileNameWithPath, nAllocSize, "%s/%s", &pDirectoryName[SOUND_PREFIX_LEN], pFileName );
+ Q_strnlwr( pFileNameWithPath, nAllocSize );
+
+ CWaveFile *wav = new CWaveFile( NULL, NULL, pFileNameWithPath );
+ soundlist.Insert( pFileNameWithPath, wav );
+
+ /*
+ if ( !(soundlist.Count() % 500 ) )
+ {
+ Con_Printf( "CWaveBrowser: loaded %i sounds\n", soundlist.Count() );
+ }
+ */
+ }
+ pFileName = filesystem->FindNext( findHandle );
+ }
+
+ m_pFileTree->FindOrAddSubdirectory( &pDirectoryName[ SOUND_PREFIX_LEN ] );
+
+ filesystem->FindClose( findHandle );
+ return true;
+}
+
+bool CWaveBrowser::InitDirectoryRecursive( CUtlDict< CWaveFile *, int >& soundlist, char const* pDirectoryName )
+{
+ // Compute directory name length
+ int nDirectoryNameLen = Q_strlen( pDirectoryName );
+
+ if (!LoadWaveFilesInDirectory( soundlist, pDirectoryName, nDirectoryNameLen ) )
+ return false;
+
+ char *pWildCard = ( char * )stackalloc( nDirectoryNameLen + 4 );
+ strcpy(pWildCard, pDirectoryName);
+ strcat(pWildCard, "/*.");
+ int nPathStrLen = nDirectoryNameLen + 1;
+
+ FileFindHandle_t findHandle;
+ const char *pFileName = filesystem->FindFirst( pWildCard, &findHandle );
+ while( pFileName )
+ {
+ if ((pFileName[0] != '.') || (pFileName[1] != '.' && pFileName[1] != 0))
+ {
+ if( filesystem->FindIsDirectory( findHandle ) )
+ {
+ int fileNameStrLen = Q_strlen( pFileName );
+ char *pFileNameWithPath = ( char * )stackalloc( nPathStrLen + fileNameStrLen + 1 );
+ memcpy( pFileNameWithPath, pWildCard, nPathStrLen );
+ pFileNameWithPath[nPathStrLen] = '\0';
+ strcat( pFileNameWithPath, pFileName );
+
+ if (!InitDirectoryRecursive( soundlist, pFileNameWithPath ))
+ return false;
+ }
+ }
+ pFileName = filesystem->FindNext( findHandle );
+ }
+
+ return true;
+}
+
+void CWaveBrowser::LoadAllSounds()
+{
+ RemoveAllSounds();
+
+ InitDirectoryRecursive( m_AllSounds, "sound" );
+ // InitDirectoryRecursive( m_AllSounds, "sound/npc" );
+
+ int c = m_AllSounds.Count();
+ CUtlVector< CWaveFile * > list;
+ for ( int i = 0; i < c; i++ )
+ {
+ CWaveFile *wav = m_AllSounds[ i ];
+ list.AddToTail( wav );
+ }
+
+
+ fileloader->AddWaveFilesToThread( list );
+
+
+ m_pFileTree->PopulateTree();
+}
+
+void CWaveBrowser::RemoveAllSounds()
+{
+ int c = m_AllSounds.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ CWaveFile *wav = m_AllSounds[ i ];
+ delete wav;
+ }
+
+ m_AllSounds.RemoveAll();
+ m_Scripts.RemoveAll();
+ m_CurrentSelection.RemoveAll();
+
+ m_pFileTree->Clear();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWaveBrowser::PopulateTree( char const *subdirectory, bool textsearch /*= false*/ )
+{
+ int i;
+
+ CUtlRBTree< CWaveFile *, int > m_Sorted( 0, 0, NameLessFunc );
+
+ bool check_load_sentence_data = false;
+
+ char const *texttofind = NULL;
+
+ if ( textsearch )
+ {
+ subdirectory = NULL;
+ texttofind = GetSearchString();
+ }
+
+ int len = 0;
+ if ( subdirectory )
+ {
+ len = Q_strlen( subdirectory );
+ check_load_sentence_data = Q_strstr( subdirectory, "/" ) ? true : false;
+ }
+
+ int c = m_AllSounds.Count();
+ for ( i = 0; i < c; i++ )
+ {
+ CWaveFile *wav = m_AllSounds[ i ];
+ char const *name = wav->GetName();
+
+ if ( subdirectory )
+ {
+ if ( Q_strnicmp( subdirectory, wav->GetName(), len ) )
+ continue;
+ }
+
+ if ( textsearch && texttofind )
+ {
+ if ( !Q_stristr( name, texttofind ) )
+ continue;
+ }
+
+ m_Sorted.Insert( wav );
+ }
+
+ char prevSelectedName[ 512 ];
+ prevSelectedName[ 0 ] = 0;
+ if ( m_pListView->getNumSelected() == 1 )
+ {
+ int selectedItem = m_pListView->getNextSelectedItem( 0 );
+ if ( selectedItem >= 0 )
+ {
+ // Grab wave name of previously selected item
+ Q_strcpy( prevSelectedName, m_pListView->getLabel( selectedItem, 0 ) );
+ }
+ }
+
+// Repopulate tree
+ m_pListView->removeAll();
+
+ int loadcount = 0;
+
+ m_pListView->setDrawingEnabled( false );
+
+ int selectedSlot = -1;
+
+ for ( i = m_Sorted.FirstInorder(); i != m_Sorted.InvalidIndex(); i = m_Sorted.NextInorder( i ) )
+ {
+ CWaveFile *wav = m_Sorted[ i ];
+ char const *name = wav->GetName();
+
+ int slot = m_pListView->add( name );
+
+ if ( !Q_stricmp( prevSelectedName, name ) )
+ {
+ selectedSlot = slot;
+ }
+
+ m_pListView->setImage( slot, COL_WAV, wav->GetIconIndex() );
+ m_pListView->setUserData( slot, COL_WAV, (void *)wav );
+
+ if ( wav->HasLoadedSentenceInfo() )
+ {
+ m_pListView->setLabel( slot, COL_DUCKED, wav->GetVoiceDuck() ? "yes" : "no" );
+ m_pListView->setLabel( slot, COL_SENTENCE, wav->GetSentenceText() );
+ }
+ else
+ {
+ m_pListView->setLabel( slot, COL_SENTENCE, "(loading...)" );
+ }
+
+ ++loadcount;
+ }
+
+ m_pListView->setDrawingEnabled( true );
+
+ if ( selectedSlot != -1 )
+ {
+ m_pListView->setSelected( selectedSlot, true );
+ m_pListView->scrollToItem( selectedSlot );
+ }
+
+ // Con_Printf( "CWaveBrowser: selected %i sounds\n", loadcount );
+}
+
+CWorkspaceManager *CWaveBrowser::GetManager()
+{
+ return m_pManager;
+}
+
+void CWaveBrowser::RepopulateTree()
+{
+ PopulateTree( m_pFileTree->GetSelectedPath() );
+}
+
+void CWaveBrowser::BuildSelectionList( CUtlVector< CWaveFile * >& selected )
+{
+ selected.RemoveAll();
+
+ int idx = -1;
+ do
+ {
+ idx = m_pListView->getNextSelectedItem( idx );
+ if ( idx != -1 )
+ {
+ CWaveFile *wav = (CWaveFile *)m_pListView->getUserData( idx, 0 );
+ if ( wav )
+ {
+ selected.AddToTail( wav );
+ }
+ }
+ } while ( idx != -1 );
+
+}
+
+void CWaveBrowser::ShowContextMenu( void )
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() <= 0 )
+ return;
+
+ POINT pt;
+ GetCursorPos( &pt );
+ ScreenToClient( (HWND)getHandle(), &pt );
+
+ // New scene, edit comments
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ if ( m_CurrentSelection.Count() == 1 )
+ {
+ pop->add ("&Play", IDC_SB_PLAY );
+ pop->add( "Properties...", IDC_SB_PROPERTIES );
+ pop->addSeparator();
+ }
+ else
+ {
+ pop->add( "Enable Voice Ducking", IDC_SB_ENABLEVOICEDUCKING );
+ pop->add( "Disable Voice Ducking", IDC_SB_DISABLEVOICEDUCKING );
+ pop->addSeparator();
+ }
+
+ pop->add( "Refresh sentence data", IDC_SB_GETSENTENCE );
+ pop->add( "Import Sentence Data", IDC_SB_IMPORTSENTENCE );
+ pop->add( "Export Sentence Data", IDC_SB_EXPORTSENTENCE );
+
+ pop->addSeparator();
+
+ pop->add( "Check out", IDC_SB_CHECKOUT );
+ pop->add( "Check in", IDC_SB_CHECKIN );
+
+ pop->popup( this, pt.x, pt.y );
+}
+
+void CWaveBrowser::OnPlay()
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() == 1 )
+ {
+ CWaveFile *wav = m_CurrentSelection[ 0 ];
+ if ( wav )
+ {
+ wav->Play();
+ }
+ }
+}
+
+void CWaveBrowser::OnCheckout()
+{
+ BuildSelectionList( m_CurrentSelection );
+ int c = m_CurrentSelection.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ CWaveFile *wav = m_CurrentSelection[ i ];
+ Assert( wav );
+
+ wav->Checkout( false );
+ }
+
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+void CWaveBrowser::OnCheckin()
+{
+ BuildSelectionList( m_CurrentSelection );
+ int c = m_CurrentSelection.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ CWaveFile *wav = m_CurrentSelection[ i ];
+ Assert( wav );
+
+ wav->Checkin( false );
+ }
+
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+void SplitFileName( char const *in, char *path, int maxpath, char *filename, int maxfilename );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *se -
+//-----------------------------------------------------------------------------
+void CWaveBrowser::JumpToItem( CWaveFile *wav )
+{
+
+ char path[ 256 ];
+ char filename[ 256 ];
+
+ SplitFileName( wav->GetFileName(), path, sizeof( path ), filename, sizeof( filename ) );
+
+ char *usepath = path + Q_strlen( "/sound/" );
+ PopulateTree( usepath );
+
+ int idx = 0;
+ int c = m_pListView->getItemCount();
+ for ( ; idx < c; idx++ )
+ {
+ CWaveFile *item = (CWaveFile *)m_pListView->getUserData( idx, 0 );
+ if ( !Q_stricmp( item->GetFileName(), wav->GetFileName() ) )
+ {
+ break;
+ }
+ }
+
+ if ( idx < c )
+ {
+ m_pListView->scrollToItem( idx );
+ }
+}
+
+CWaveFile *CWaveBrowser::FindEntry( char const *wavname, bool jump /*= false*/ )
+{
+ int idx = m_AllSounds.Find( PSkipSoundChars( wavname ) );
+ if ( idx != m_AllSounds.InvalidIndex() )
+ {
+ CWaveFile *wav = m_AllSounds[ idx ];
+#if defined( _DEBUG )
+ char const *name = wav->GetName();
+ NOTE_UNUSED( name );
+#endif
+
+ if ( jump )
+ {
+ JumpToItem( wav );
+ }
+
+ return wav;
+ }
+
+ return NULL;
+}
+
+void CWaveBrowser::OnWaveProperties()
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() != 1 )
+ {
+ Con_Printf( "Can only apply properties to one item at a time (FOR NOW)\n" );
+ return;
+ }
+
+ CWaveFile *entry = m_CurrentSelection[ 0 ];
+ if ( !entry )
+ return;
+
+ CWaveParams params;
+ memset( &params, 0, sizeof( params ) );
+
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Wave Properties" );
+
+ params.items.AddToTail( entry );
+
+ if ( !WaveProperties( &params ) )
+ return;
+}
+
+
+int CWaveBrowser::GetSoundCount() const
+{
+ return m_AllSounds.Count();
+}
+
+CWaveFile *CWaveBrowser::GetSound( int index )
+{
+ if ( index < 0 || index >= m_AllSounds.Count() )
+ return NULL;
+
+ return m_AllSounds[ index ];
+}
+
+
+void CWaveBrowser::OnSearch()
+{
+ PopulateTree( GetSearchString(), true );
+}
+
+char const *CWaveBrowser::GetSearchString()
+{
+ return m_pOptions->GetSearchString();
+}
+
+
+void CWaveBrowser::OnEnableVoiceDucking()
+{
+ BuildSelectionList( m_CurrentSelection );
+ int count = m_CurrentSelection.Count();
+ if ( count < 1 )
+ return;
+
+ MultipleRequestChangeContext();
+
+ for ( int i = 0; i < count; i++ )
+ {
+ CWaveFile *item = m_CurrentSelection[ i ];
+ if ( !item->GetVoiceDuck() )
+ {
+ item->SetVoiceDuck( true );
+ }
+ }
+
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+void CWaveBrowser::OnDisableVoiceDucking()
+{
+ BuildSelectionList( m_CurrentSelection );
+ int count = m_CurrentSelection.Count();
+ if ( count < 1 )
+ return;
+
+ MultipleRequestChangeContext();
+
+ for ( int i = 0; i < count; i++ )
+ {
+ CWaveFile *item = m_CurrentSelection[ i ];
+ if ( item->GetVoiceDuck() )
+ {
+ item->SetVoiceDuck( false );
+ }
+ }
+
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+void CWaveBrowser::OnImportSentence()
+{
+ BuildSelectionList( m_CurrentSelection );
+ int count = m_CurrentSelection.Count();
+ if ( count < 1 )
+ return;
+
+ MultipleRequestChangeContext();
+
+ for ( int i = 0; i < count; i++ )
+ {
+ CWaveFile *item = m_CurrentSelection[ i ];
+
+ char relative[ 512 ];
+ item->GetPhonemeExportFile( relative, sizeof( relative ) );
+ if ( filesystem->FileExists( relative ) )
+ {
+ item->ImportValveDataChunk( relative );
+ }
+ }
+
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+void CWaveBrowser::OnExportSentence()
+{
+ BuildSelectionList( m_CurrentSelection );
+ int count = m_CurrentSelection.Count();
+ if ( count < 1 )
+ return;
+
+ for ( int i = 0; i < count; i++ )
+ {
+ CWaveFile *item = m_CurrentSelection[ i ];
+
+ char relative[ 512 ];
+ item->GetPhonemeExportFile( relative, sizeof( relative ) );
+ if ( filesystem->FileExists( relative ) )
+ {
+ filesystem->RemoveFile( relative );
+ }
+
+ item->ExportValveDataChunk( relative );
+ }
+}
+
+
+void CWaveBrowser::OnGetSentence()
+{
+ BuildSelectionList( m_CurrentSelection );
+ if ( m_CurrentSelection.Count() < 1 )
+ {
+ Con_Printf( "No selection\n" );
+ return;
+ }
+
+ int c = m_CurrentSelection.Count();
+ for ( int i = c - 1; i >= 0 ; i-- )
+ {
+ CWaveFile *wav = m_CurrentSelection[ i ];
+ if ( !wav->HasLoadedSentenceInfo() )
+ {
+ wav->EnsureSentence();
+ }
+ }
+
+ // Repopulate things
+ GetWorkspaceManager()->RefreshBrowsers();
+} \ No newline at end of file
diff --git a/utils/scenemanager/wavebrowser.h b/utils/scenemanager/wavebrowser.h
new file mode 100644
index 0000000..b21f7e9
--- /dev/null
+++ b/utils/scenemanager/wavebrowser.h
@@ -0,0 +1,102 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WAVEBROWSER_H
+#define WAVEBROWSER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "mxtk/mxListView.h"
+#include "commctrl.h"
+#include "utldict.h"
+
+class CWorkspace;
+class CProject;
+class CScene;
+class CVCDFile;
+class CWaveFile;
+
+class CWaveList;
+class CWorkspaceManager;
+class CWaveFilterTab;
+class CWaveOptionsWindow;
+class CWaveFileTree;
+
+class CWaveBrowser : public mxWindow
+{
+ typedef mxWindow BaseClass;
+public:
+
+ CWaveBrowser( mxWindow *parent, CWorkspaceManager *manager, int id );
+
+ virtual int handleEvent( mxEvent *event );
+ virtual void OnDelete();
+
+ CWorkspaceManager *GetManager();
+
+ void RepopulateTree();
+
+ void BuildSelectionList( CUtlVector< CWaveFile * >& selected );
+
+ void OnPlay();
+
+ void JumpToItem( CWaveFile *wav );
+
+ CWaveFile *FindEntry( char const *wavname, bool jump = false );
+
+
+ int GetSoundCount() const;
+ CWaveFile *GetSound( int index );
+
+ void OnSearch();
+
+private:
+
+ char const *GetSearchString();
+
+ bool LoadWaveFilesInDirectory( CUtlDict< CWaveFile *, int >& soundlist, char const* pDirectoryName, int nDirectoryNameLen );
+ bool InitDirectoryRecursive( CUtlDict< CWaveFile *, int >& soundlist, char const* pDirectoryName );
+
+ void OnWaveProperties();
+ void OnEnableVoiceDucking();
+ void OnDisableVoiceDucking();
+ void OnCheckout();
+ void OnCheckin();
+
+ void OnImportSentence();
+ void OnExportSentence();
+
+ void OnGetSentence();
+
+ void PopulateTree( char const *subdirectory, bool textsearch = false );
+
+ void ShowContextMenu( void );
+
+ void LoadAllSounds();
+ void RemoveAllSounds();
+
+ CWaveList *m_pListView;
+
+ enum
+ {
+ NUM_BITMAPS = 6,
+ };
+
+ CWorkspaceManager *m_pManager;
+
+ CUtlDict< CWaveFile *, int > m_AllSounds;
+ CUtlSymbolTable m_ScriptTable;
+
+ CUtlVector< CUtlSymbol > m_Scripts;
+
+ CWaveOptionsWindow *m_pOptions;
+ CWaveFileTree *m_pFileTree;
+
+ CUtlVector< CWaveFile * > m_CurrentSelection;
+};
+
+#endif // WAVEBROWSER_H
diff --git a/utils/scenemanager/wavefile.cpp b/utils/scenemanager/wavefile.cpp
new file mode 100644
index 0000000..96d4ded
--- /dev/null
+++ b/utils/scenemanager/wavefile.cpp
@@ -0,0 +1,379 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "wavefile.h"
+#include "sentence.h"
+#include "iscenemanagersound.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "snd_wave_source.h"
+#include "cmdlib.h"
+#include "workspacemanager.h"
+#include "vcdfile.h"
+#include "workspacebrowser.h"
+#include "multiplerequest.h"
+#include "UtlBuffer.h"
+#include "scenemanager_tools.h"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+CWaveFile::CWaveFile( CVCDFile *vcd, CSoundEntry *se, char const *filename )
+ : m_pOwner( vcd ), m_pOwnerSE( se )
+{
+ m_bSentenceLoaded = false;
+
+ m_Sentence.Reset();
+
+ Q_strncpy( m_szName, filename, sizeof( m_szName ) );
+
+ m_pWaveFile = NULL;
+
+ Q_snprintf( m_szFileName, sizeof( m_szFileName ), "sound/%s", filename );
+}
+
+CWaveFile::~CWaveFile()
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : int
+//-----------------------------------------------------------------------------
+int CWaveFile::GetLanguageId()
+{
+ return GetWorkspaceManager()->GetLanguageId();
+}
+
+void CWaveFile::EnsureSentence()
+{
+ if ( m_bSentenceLoaded )
+ return;
+
+ m_bSentenceLoaded = true;
+
+ if ( m_szFileName[ 0 ] )
+ {
+ SceneManager_LoadSentenceFromWavFile( m_szFileName, m_Sentence );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CWaveFile::HasLoadedSentenceInfo() const
+{
+ return m_bSentenceLoaded;
+}
+
+
+CVCDFile *CWaveFile::GetOwnerVCDFile()
+{
+ return m_pOwner;
+}
+
+CSoundEntry *CWaveFile::GetOwnerSoundEntry()
+{
+ return m_pOwnerSE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *name -
+//-----------------------------------------------------------------------------
+void CWaveFile::SetName( char const *filename )
+{
+ if ( !Q_stricmp( m_szName, filename ) )
+ return;
+
+ Q_strncpy( m_szName, filename, sizeof( m_szName ) );
+
+ Q_snprintf( m_szFileName, sizeof( m_szFileName ), "sound/%s", filename );
+
+ if ( m_szFileName[ 0 ] )
+ {
+ SceneManager_LoadSentenceFromWavFile( m_szFileName, m_Sentence );
+ m_bSentenceLoaded = true;
+ }
+}
+
+char const *CWaveFile::GetName() const
+{
+ return m_szName;
+}
+
+char const *CWaveFile::GetFileName() const
+{
+ return m_szFileName;
+}
+
+char const *CWaveFile::GetSentenceText()
+{
+ EnsureSentence();
+ return m_Sentence.GetText();
+}
+
+void CWaveFile::SetSentenceText( char const *newText )
+{
+ EnsureSentence();
+ if ( !Q_stricmp( GetSentenceText(), newText ) )
+ return;
+
+ if ( !IsCheckedOut() )
+ {
+ int retval = MultipleRequest( va( "Check out '%s'?", GetFileName() ) );
+ if ( retval != 0 )
+ return;
+
+ VSS_Checkout( GetFileName() );
+ }
+
+ m_Sentence.SetText( newText );
+
+ SceneManager_SaveSentenceToWavFile( GetFileName(), m_Sentence );
+}
+
+void CWaveFile::ValidateTree( mxTreeView *tree, mxTreeViewItem* parent )
+{
+}
+
+void CWaveFile::Play()
+{
+ if ( !m_pWaveFile )
+ {
+ m_pWaveFile = sound->FindOrAddSound( m_szFileName );
+ }
+
+ if ( !m_pWaveFile )
+ {
+ Con_Printf( "Can't play '%s', no wave file loaded\n", GetFileName() );
+ return;
+ }
+
+ Con_Printf( "Playing '%s' : '%s'\n", GetFileName(), GetSentenceText() );
+
+ CAudioMixer *temp;
+ sound->PlaySound( m_pWaveFile, &temp );
+}
+
+bool CWaveFile::GetVoiceDuck()
+{
+ EnsureSentence();
+ return m_Sentence.GetVoiceDuck();
+}
+
+void CWaveFile::SetVoiceDuck( bool duck )
+{
+ EnsureSentence();
+ if ( GetVoiceDuck() == duck )
+ return;
+
+ m_Sentence.SetVoiceDuck( duck );
+
+ if ( !IsCheckedOut() )
+ {
+ int retval = MultipleRequest( va( "Check out '%s'?", GetFileName() ) );
+ if ( retval != 0 )
+ return;
+
+ VSS_Checkout( GetFileName() );
+ }
+
+ SceneManager_SaveSentenceToWavFile( GetFileName(), m_Sentence );
+}
+
+void CWaveFile::ToggleVoiceDucking()
+{
+ EnsureSentence();
+ m_Sentence.SetVoiceDuck( !m_Sentence.GetVoiceDuck() );
+
+ if ( !IsCheckedOut() )
+ {
+ int retval = MultipleRequest( va( "Check out '%s'?", GetFileName() ) );
+ if ( retval != 0 )
+ return;
+
+ VSS_Checkout( GetFileName() );
+ }
+
+ SceneManager_SaveSentenceToWavFile( GetFileName(), m_Sentence );
+}
+
+bool CWaveFile::IsCheckedOut() const
+{
+ return filesystem->IsFileWritable( GetFileName() );
+}
+
+int CWaveFile::GetIconIndex() const
+{
+ if ( IsCheckedOut() )
+ {
+ return IMAGE_WAV_CHECKEDOUT;
+ }
+ else
+ {
+ return IMAGE_WAV;
+ }
+}
+
+
+void CWaveFile::Checkout(bool updatestateicons /*= true*/)
+{
+ VSS_Checkout( GetFileName(), updatestateicons );
+}
+
+void CWaveFile::Checkin(bool updatestateicons /*= true*/)
+{
+ VSS_Checkin( GetFileName(), updatestateicons );
+}
+
+
+void CWaveFile::MoveChildUp( ITreeItem *child )
+{
+}
+
+void CWaveFile::MoveChildDown( ITreeItem *child )
+{
+}
+
+void CWaveFile::SetDirty( bool dirty )
+{
+ if ( GetOwnerVCDFile() )
+ {
+ GetOwnerVCDFile()->SetDirty( dirty );
+ }
+}
+
+bool CWaveFile::IsChildFirst( ITreeItem *child )
+{
+ return false;
+}
+
+bool CWaveFile::IsChildLast( ITreeItem *child )
+{
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : sentence -
+//-----------------------------------------------------------------------------
+void CWaveFile::SetThreadLoadedSentence( CSentence& sentence )
+{
+ if ( m_bSentenceLoaded )
+ return;
+
+ m_bSentenceLoaded = true;
+ m_Sentence = sentence;
+}
+
+#define WORD_DATA_EXTENSION ".txt"
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *tempfile -
+//-----------------------------------------------------------------------------
+void CWaveFile::ExportValveDataChunk( char const *tempfile )
+{
+ EnsureSentence();
+
+ if ( m_Sentence.m_Words.Count() <= 0 )
+ {
+ Con_ColorPrintf( ERROR_R, ERROR_G, ERROR_B, "CWaveFile::ExportValveDataChunk: Sentence has no word data\n" );
+ return;
+ }
+
+ SafeCreatePath( va( "%s%s", SceneManager_GetGameDirectory(), (char *)tempfile ) );
+
+ FileHandle_t fh = filesystem->Open( tempfile, "wb" );
+ if ( !fh )
+ {
+ Con_ColorPrintf( ERROR_R, ERROR_G, ERROR_B, "CWaveFile::ExportValveDataChunk: Unable to write to %s (read-only?)\n", tempfile );
+ return;
+ }
+ else
+ {
+ // Buffer and dump data
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ m_Sentence.SaveToBuffer( buf );
+
+ filesystem->Write( buf.Base(), buf.TellPut(), fh );
+ filesystem->Close(fh);
+
+ Con_Printf( "Exported %i words to %s\n", m_Sentence.m_Words.Count(), tempfile );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *tempfile -
+//-----------------------------------------------------------------------------
+void CWaveFile::ImportValveDataChunk( char const *tempfile )
+{
+ EnsureSentence();
+
+ FileHandle_t fh = filesystem->Open( tempfile, "rb" );
+ if ( !fh )
+ {
+ Con_ColorPrintf( ERROR_R, ERROR_G, ERROR_B, "CWaveFile::ImportValveDataChunk: Unable to read from %s\n", tempfile );
+ return;
+ }
+
+ int len = filesystem->Size( fh );
+ if ( len <= 4 )
+ {
+ Con_ColorPrintf( ERROR_R, ERROR_G, ERROR_B, "CWaveFile::ImportValveDataChunk: File %s has length 0\n", tempfile );
+ return;
+ }
+
+ CSentence newSentence;
+
+ unsigned char *buf = new unsigned char[ len + 1 ];
+
+ filesystem->Read( buf, len, fh );
+ filesystem->Close( fh );
+
+ newSentence.InitFromDataChunk( (void *)( buf ), len );
+
+ delete[] buf;
+
+ // See if we can write it out...
+ if ( !IsCheckedOut() )
+ {
+ int retval = MultipleRequest( va( "Check out '%s'?", GetFileName() ) );
+ if ( retval != 0 )
+ return;
+
+ VSS_Checkout( GetFileName() );
+ }
+
+ if ( !IsCheckedOut() )
+ {
+ MakeFileWriteable( GetFileName() );
+ Con_Printf( "Unable to check out %s, forcing it to be writable instead!\n", GetFileName() );
+ }
+
+ Con_Printf( "Imported %i words from %s\n", newSentence.m_Words.Count(), tempfile );
+
+ m_Sentence = newSentence;
+
+ SceneManager_SaveSentenceToWavFile( GetFileName(), m_Sentence );
+}
+
+void CWaveFile::GetPhonemeExportFile( char *path, int maxlen )
+{
+ char relative[ 512 ];
+ strcpy( relative, GetFileName() );
+ Q_StripExtension( relative, relative, sizeof( relative ) );
+ Q_DefaultExtension( relative, WORD_DATA_EXTENSION, sizeof( relative ) );
+
+ Q_snprintf( path, maxlen, "phonemes/%s", relative );
+ Q_FixSlashes( path );
+}
+
diff --git a/utils/scenemanager/wavefile.h b/utils/scenemanager/wavefile.h
new file mode 100644
index 0000000..d9f3c19
--- /dev/null
+++ b/utils/scenemanager/wavefile.h
@@ -0,0 +1,103 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WAVEFILE_H
+#define WAVEFILE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "itreeitem.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "sentence.h"
+
+class CSoundEntry;
+class CAudioSource;
+class CVCDFile;
+
+class CWaveFile : public ITreeItem
+{
+public:
+ // One or both may be valid
+ CWaveFile( CVCDFile *vcd, CSoundEntry *se, char const *filename );
+
+ ~CWaveFile();
+
+ static int GetLanguageId();
+
+ CVCDFile *GetOwnerVCDFile();
+ CSoundEntry *GetOwnerSoundEntry();
+
+ void SetName( char const *filename );
+
+ char const *GetName() const;
+ char const *GetFileName() const;
+
+ char const *GetSentenceText();
+ void SetSentenceText( char const *newText );
+
+ void ValidateTree( mxTreeView *tree, mxTreeViewItem* parent );
+
+ bool HasLoadedSentenceInfo() const;
+ void EnsureSentence();
+
+
+ virtual CWorkspace *GetWorkspace() { return NULL; }
+ virtual CProject *GetProject() { return NULL; }
+ virtual CScene *GetScene() { return NULL; }
+ virtual CVCDFile *GetVCDFile() { return NULL; }
+ virtual CSoundEntry *GetSoundEntry() { return NULL; }
+ virtual CWaveFile *GetWaveFile() { return this; }
+
+ void Play();
+
+ bool GetVoiceDuck();
+ void SetVoiceDuck( bool duck );
+ void ToggleVoiceDucking();
+
+ virtual void Checkout( bool updatestateicons = true );
+ virtual void Checkin( bool updatestateicons = true );
+
+ bool IsCheckedOut() const;
+ int GetIconIndex() const;
+
+ virtual void MoveChildUp( ITreeItem *child );
+ virtual void MoveChildDown( ITreeItem *child );
+
+ virtual void SetDirty( bool dirty );
+
+ virtual bool IsChildFirst( ITreeItem *child );
+ virtual bool IsChildLast( ITreeItem *child );
+
+ void SetThreadLoadedSentence( CSentence& sentence );
+
+ void ExportValveDataChunk( char const *tempfile );
+ void ImportValveDataChunk( char const *tempfile );
+
+ void GetPhonemeExportFile( char *path, int maxlen );
+
+private:
+
+ CAudioSource *m_pWaveFile;
+ CSentence m_Sentence;
+
+ enum
+ {
+ MAX_SOUND_NAME = 256,
+ MAX_SCRIPT_FILE = 64,
+ MAX_SOUND_FILENAME = 128,
+ };
+
+ char m_szName[ MAX_SOUND_FILENAME ];
+ char m_szFileName[ MAX_SOUND_FILENAME ];
+
+ CVCDFile *m_pOwner;
+ CSoundEntry *m_pOwnerSE;
+
+ bool m_bSentenceLoaded;
+};
+
+#endif // WAVEFILE_H
diff --git a/utils/scenemanager/waveproperties.cpp b/utils/scenemanager/waveproperties.cpp
new file mode 100644
index 0000000..7dc34f2
--- /dev/null
+++ b/utils/scenemanager/waveproperties.cpp
@@ -0,0 +1,193 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include <mxtk/mx.h>
+#include <stdio.h>
+#include "resource.h"
+#include "WaveProperties.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "soundentry.h"
+#include "cmdlib.h"
+#include "workspacemanager.h"
+#include "wavebrowser.h"
+#include "wavefile.h"
+#include "multiplerequest.h"
+
+static CWaveParams g_Params;
+
+static bool WaveLessFunc( const char *const& name1, const char *const& name2 )
+{
+ if ( stricmp( name1, name2 ) < 0 )
+ return true;
+ return false;
+}
+
+static void WaveProperties_OnOK( HWND hwndDlg )
+{
+ // Gather info and make changes
+ CWaveFile *item = g_Params.items[ 0 ];
+ char sentencetext[ 512 ];
+
+ GetDlgItemText( hwndDlg, IDC_SENTENCETEXT, sentencetext, sizeof( sentencetext ) );
+
+ bool voiceduck = SendMessage( GetDlgItem( hwndDlg, IDC_VOICEDUCK ), BM_GETCHECK, 0, 0 ) == BST_CHECKED ? true : false;
+
+ MultipleRequestChangeContext();
+
+ // Update ducking on wav files
+ item->SetVoiceDuck( voiceduck );
+ item->SetSentenceText( sentencetext );
+
+ // Repopulate things
+ GetWorkspaceManager()->RefreshBrowsers();
+}
+
+char *Q_stristr_slash( char const *pStr, char const *pSearch );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+//-----------------------------------------------------------------------------
+static void WaveProperties_ExportSentence()
+{
+ int c = g_Params.items.Count();
+ if ( c <= 0 )
+ return;
+
+ MultipleRequestChangeContext();
+
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ CWaveFile *item = g_Params.items[ i ];
+ Assert( item );
+
+ char relative[ 512 ];
+ item->GetPhonemeExportFile( relative, sizeof( relative ) );
+ if ( filesystem->FileExists( relative ) )
+ {
+ int retval = MultipleRequest( va( "Overwrite '%s'?", relative ) );
+ if ( retval != 0 )
+ continue;
+
+ filesystem->RemoveFile( relative );
+ }
+
+ item->ExportValveDataChunk( relative );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+//-----------------------------------------------------------------------------
+static void WaveProperties_ImportSentence()
+{
+ int c = g_Params.items.Count();
+ if ( c <= 0 )
+ return;
+
+ int i;
+ for ( i = 0; i < c; i++ )
+ {
+ CWaveFile *item = g_Params.items[ i ];
+ Assert( item );
+
+ char relative[ 512 ];
+ item->GetPhonemeExportFile( relative, sizeof( relative ) );
+ if ( filesystem->FileExists( relative ) )
+ {
+ item->ImportValveDataChunk( relative );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+// Output : static
+//-----------------------------------------------------------------------------
+static void WaveProperties_InitSentenceData( HWND hwndDlg )
+{
+ CWaveFile *item = g_Params.items[ 0 ];
+
+ SetDlgItemText( hwndDlg, IDC_WAVENAME, item->GetName() );
+ SetDlgItemText( hwndDlg, IDC_SENTENCETEXT, item->GetSentenceText() );
+
+ SendMessage( GetDlgItem( hwndDlg, IDC_VOICEDUCK ), BM_SETCHECK,
+ ( WPARAM ) item->GetVoiceDuck() ? BST_CHECKED : BST_UNCHECKED,
+ ( LPARAM )0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : hwndDlg -
+// uMsg -
+// wParam -
+// lParam -
+// Output : static BOOL CALLBACK
+//-----------------------------------------------------------------------------
+static BOOL CALLBACK WavePropertiesDialogProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
+{
+ switch(uMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ g_Params.PositionSelf( hwndDlg );
+
+ WaveProperties_InitSentenceData( hwndDlg );
+
+ SetWindowText( hwndDlg, g_Params.m_szDialogTitle );
+
+ SetFocus( GetDlgItem( hwndDlg, IDC_WAVENAME ) );
+ }
+ return FALSE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ WaveProperties_OnOK( hwndDlg );
+
+ EndDialog( hwndDlg, 1 );
+ }
+ break;
+ case IDCANCEL:
+ EndDialog( hwndDlg, 0 );
+ break;
+ case IDC_EXPORTSENTENCE:
+ WaveProperties_ExportSentence();
+ break;
+ case IDC_IMPORTSENTENCE:
+ WaveProperties_ImportSentence();
+ WaveProperties_InitSentenceData( hwndDlg );
+ break;
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *view -
+// *actor -
+// Output : int
+//-----------------------------------------------------------------------------
+int WaveProperties( CWaveParams *params )
+{
+ g_Params = *params;
+
+ int retval = DialogBox( (HINSTANCE)GetModuleHandle( 0 ),
+ MAKEINTRESOURCE( IDD_WAVEPROPERTIES ),
+ (HWND)GetWorkspaceManager()->getHandle(),
+ (DLGPROC)WavePropertiesDialogProc );
+
+ *params = g_Params;
+
+ return retval;
+} \ No newline at end of file
diff --git a/utils/scenemanager/waveproperties.h b/utils/scenemanager/waveproperties.h
new file mode 100644
index 0000000..5c661bf
--- /dev/null
+++ b/utils/scenemanager/waveproperties.h
@@ -0,0 +1,41 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WAVEPROPERTIES_H
+#define WAVEPROPERTIES_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "basedialogparams.h"
+
+class CWaveFile;
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+struct CWaveParams : public CBaseDialogParams
+{
+ CWaveParams()
+ {
+ }
+
+ CWaveParams( const CWaveParams& src )
+ {
+ int c = src.items.Count();
+ for ( int i = 0; i < c; i++ )
+ {
+ items.AddToTail( src.items[ i ] );
+ }
+ }
+
+ CUtlVector< CWaveFile * > items;
+};
+
+int WaveProperties( CWaveParams *params );
+
+
+#endif // WAVEPROPERTIES_H
diff --git a/utils/scenemanager/workspac.ico b/utils/scenemanager/workspac.ico
new file mode 100644
index 0000000..b3e4e4a
--- /dev/null
+++ b/utils/scenemanager/workspac.ico
Binary files differ
diff --git a/utils/scenemanager/workspace.cpp b/utils/scenemanager/workspace.cpp
new file mode 100644
index 0000000..04792a5
--- /dev/null
+++ b/utils/scenemanager/workspace.cpp
@@ -0,0 +1,473 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+#include "cbase.h"
+#include "workspace.h"
+#include <KeyValues.h>
+#include "project.h"
+#include "vstdlib/random.h"
+#include "cmdlib.h"
+#include "FileSystem_Tools.h"
+#include "utlbuffer.h"
+#include "workspacemanager.h"
+#include "workspacebrowser.h"
+#include "soundbrowser.h"
+#include "wavebrowser.h"
+
+CWorkspace::CWorkspace( char const *filename )
+{
+ m_szVSSUserName[ 0 ] = 0;
+ m_szVSSProject[ 0 ] = 0;
+
+ Q_strncpy( m_szFile, filename, sizeof( m_szFile ) );
+ // By default, name is the same as the filename
+ Q_FileBase( m_szFile, m_szName, sizeof( m_szName ) );
+ m_bDirty = false;
+ LoadFromFile();
+}
+
+CWorkspace::~CWorkspace()
+{
+ while ( m_Projects.Count() > 0 )
+ {
+ CProject *p = m_Projects[ 0 ];
+ m_Projects.Remove( 0 );
+ delete p;
+ }
+}
+
+char const *CWorkspace::GetName() const
+{
+ return m_szName;
+}
+
+bool CWorkspace::IsDirty( void ) const
+{
+ int c = GetProjectCount();
+ for ( int i = 0; i < c; i++ )
+ {
+ CProject *p = GetProject( i );
+ Assert( p );
+ if ( p->IsDirty() )
+ return true;
+ }
+
+ return m_bDirty;
+}
+
+void CWorkspace::SetDirty( bool dirty )
+{
+ m_bDirty = dirty;
+}
+
+int CWorkspace::GetProjectCount() const
+{
+ return m_Projects.Count();
+}
+
+CProject *CWorkspace::GetProject( int index ) const
+{
+ if ( index < 0 || index >= m_Projects.Count() )
+ return NULL;
+ return m_Projects[ index ];
+}
+
+void CWorkspace::RemoveProject( CProject *project )
+{
+ if ( m_Projects.Find( project ) == m_Projects.InvalidIndex() )
+ return;
+
+ m_Projects.FindAndRemove( project );
+ SetDirty( true );
+}
+
+
+void CWorkspace::AddProject( CProject *project )
+{
+ SetDirty( true );
+
+ Assert( m_Projects.Find( project ) == m_Projects.InvalidIndex() );
+
+ m_Projects.AddToTail( project );
+}
+
+CProject *CWorkspace::FindProjectFile( char const *filename ) const
+{
+ int c = GetProjectCount();
+ for ( int i = 0 ; i < c; i++ )
+ {
+ CProject *p = GetProject( i );
+ Assert( p );
+ if ( !Q_stricmp( p->GetFileName(), filename ) )
+ return p;
+ }
+ return NULL;
+}
+
+void CWorkspace::LoadFromFile()
+{
+ KeyValues *kv = new KeyValues( m_szName );
+ if ( kv->LoadFromFile( filesystem, m_szFile ) )
+ {
+ for ( KeyValues *proj = kv->GetFirstSubKey(); proj; proj = proj->GetNextKey() )
+ {
+ // Add named projects
+ if ( !Q_stricmp( proj->GetName(), "project" ) )
+ {
+ bool expanded = false;
+ char filename[ 256 ];
+ filename[0] = 0;
+
+ for ( KeyValues *sub = proj->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
+ {
+ if ( !Q_stricmp( sub->GetName(), "file" ) )
+ {
+ Q_strcpy( filename, sub->GetString() );
+ continue;
+ }
+ else if ( !Q_stricmp( sub->GetName(), "expanded" ) )
+ {
+ expanded = sub->GetInt() ? true : false;
+ continue;
+ }
+ else
+ {
+ Assert( 0 );
+ }
+ }
+
+ CProject *p = new CProject( this, filename );
+ p->SetExpanded( expanded );
+ p->SetDirty( false );
+ m_Projects.AddToTail( p );
+
+ continue;
+ }
+ else if ( !Q_stricmp( proj->GetName(), "vss_username" ) )
+ {
+ SetVSSUserName( proj->GetString() );
+
+ Con_Printf( "VSS User: '%s'\n", GetVSSUserName() );
+ continue;
+ }
+ else if ( !Q_stricmp( proj->GetName(), "vss_project" ) )
+ {
+ SetVSSProject( proj->GetString() );
+
+ Con_Printf( "VSS Project: '%s'\n", GetVSSProject() );
+ continue;
+ }
+ else if ( !Q_stricmp( proj->GetName(), "window" ) )
+ {
+ SetDirty( true );
+
+ char const *windowname = proj->GetString( "windowname", "" );
+ if ( !Q_stricmp( windowname, "workspace" ) )
+ {
+ SceneManager_LoadWindowPositions( proj, GetWorkspaceManager()->GetBrowser() );
+ continue;
+ }
+ else if ( !Q_stricmp( windowname, "soundbrowser" ) )
+ {
+ SceneManager_LoadWindowPositions( proj, GetWorkspaceManager()->GetSoundBrowser() );
+ continue;
+ }
+ else if ( !Q_stricmp( windowname, "wavebrowser" ) )
+ {
+ SceneManager_LoadWindowPositions( proj, GetWorkspaceManager()->GetWaveBrowser() );
+ continue;
+ }
+ else if ( !Q_stricmp( windowname, "main" ) )
+ {
+ SceneManager_LoadWindowPositions( proj, GetWorkspaceManager() );
+ continue;
+ }
+ else
+ {
+ Assert( 0 );
+ }
+ }
+
+ Assert( 0 );
+ }
+ }
+ kv->deleteThis();
+}
+
+static void SaveWindowPositions( CUtlBuffer& buf, char const *windowname, mxWindow *wnd )
+{
+ buf.Printf( "\t\"window\"\n" );
+ buf.Printf( "\t{\n" );
+ buf.Printf( "\t\twindowname\t\"%s\"\n", windowname );
+
+ SceneManager_SaveWindowPositions( buf, 2, wnd );
+
+ buf.Printf( "\t}\n" );
+}
+
+void CWorkspace::SaveToFile()
+{
+ SetDirty( false );
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "%s\n{\n", GetName() );
+
+ // walk projects
+ int c = GetProjectCount();
+ for ( int i = 0; i < c; i++ )
+ {
+ CProject *p = GetProject( i );
+ Assert( p );
+
+ buf.Printf( "\t\"project\"\n" );
+ buf.Printf( "\t{\n" );
+ buf.Printf( "\t\t\"expanded\"\t\"%i\"\n", p->IsExpanded() );
+ buf.Printf( "\t\t\"file\"\t\"%s\"\n", p->GetFileName() );
+ buf.Printf( "\t}\n" );
+
+ p->SaveChanges();
+ }
+
+ buf.Printf( "\t\"vss_username\"\t\"%s\"\n", GetVSSUserName() );
+ buf.Printf( "\t\"vss_project\"\t\"%s\"\n", GetVSSProject() );
+
+ // Save window positions
+ SaveWindowPositions( buf, "main", GetWorkspaceManager() );
+
+ SaveWindowPositions( buf, "workspace", GetWorkspaceManager()->GetBrowser() );
+ SaveWindowPositions( buf, "soundbrowser", GetWorkspaceManager()->GetSoundBrowser() );
+ SaveWindowPositions( buf, "wavebrowser", GetWorkspaceManager()->GetWaveBrowser() );
+
+ buf.Printf( "}\n" );
+
+ if ( filesystem->FileExists( m_szFile ) && !filesystem->IsFileWritable( m_szFile ) )
+ {
+ int retval = mxMessageBox( NULL, va( "Check out '%s'?", m_szFile ), g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval != 0 )
+ return;
+
+ VSS_Checkout( m_szFile );
+
+ if ( !filesystem->IsFileWritable( m_szFile ) )
+ {
+ mxMessageBox( NULL, va( "Unable to check out'%s'!!!", m_szFile ), g_appTitle, MX_MB_OK );
+ return;
+ }
+ }
+
+ // Write it out baby
+ FileHandle_t fh = filesystem->Open( m_szFile, "wt" );
+ if (fh)
+ {
+ filesystem->Write( buf.Base(), buf.TellPut(), fh );
+ filesystem->Close(fh);
+ }
+ else
+ {
+ Con_Printf( "CWorkspace::SaveToFile: Unable to write file %s!!!\n", m_szFile );
+ }
+}
+
+void CWorkspace::SaveChanges()
+{
+ if ( !IsDirty() )
+ return;
+
+ SaveToFile();
+}
+
+
+void CWorkspace::ValidateTree( mxTreeView *tree, mxTreeViewItem *parent )
+{
+ CUtlVector< mxTreeViewItem * > m_KnownItems;
+
+ int c = GetProjectCount();
+ CProject *proj;
+ for ( int i = 0; i < c; i++ )
+ {
+ proj = GetProject( i );
+ if ( !proj )
+ continue;
+
+ char sz[ 256 ];
+ if ( proj->GetComments() && proj->GetComments()[0] )
+ {
+ Q_snprintf( sz, sizeof( sz ), "%s : %s", proj->GetName(), proj->GetComments() );
+ }
+ else
+ {
+ Q_strncpy( sz, proj->GetName(), sizeof( sz ) );
+ }
+
+ mxTreeViewItem *spot = proj->FindItem( tree, parent );
+ if ( !spot )
+ {
+ spot = tree->add( parent, sz );
+ }
+
+ m_KnownItems.AddToTail( spot );
+
+ proj->SetOrdinal ( i );
+
+ tree->setLabel( spot, sz );
+
+ tree->setImages( spot, proj->GetIconIndex(), proj->GetIconIndex() );
+ tree->setUserData( spot, proj );
+ //tree->setOpen( spot, proj->IsExpanded() );
+
+ proj->ValidateTree( tree, spot );
+ }
+
+ // Now check for dangling items
+ mxTreeViewItem *start = tree->getFirstChild( parent );
+ while ( start )
+ {
+ mxTreeViewItem *next = tree->getNextChild( start );
+
+ if ( m_KnownItems.Find( start ) == m_KnownItems.InvalidIndex() )
+ {
+ tree->remove( start );
+ }
+
+ start = next;
+ }
+
+ tree->sortTree( parent, true, CWorkspaceBrowser::CompareFunc, 0 );
+}
+
+bool CWorkspace::CanClose( void )
+{
+ if ( !IsDirty() )
+ return true;
+
+ int retval = mxMessageBox( NULL, va( "Save changes to workspace '%s'?", GetName() ), g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval == 2 )
+ return false;
+
+ if ( retval == 0 )
+ {
+ SaveChanges();
+ }
+
+ return true;
+}
+
+char const *CWorkspace::GetVSSUserName() const
+{
+ return m_szVSSUserName;
+}
+
+char const *CWorkspace::GetVSSProject() const
+{
+ return m_szVSSProject;
+}
+
+void CWorkspace::SetVSSUserName( char const *username )
+{
+ Q_strncpy( m_szVSSUserName, username, sizeof( m_szVSSUserName ) );
+}
+
+void CWorkspace::SetVSSProject( char const *projectname )
+{
+ Q_strncpy( m_szVSSProject, projectname, sizeof( m_szVSSProject ) );
+ while ( Q_strlen( m_szVSSProject ) > 0 )
+ {
+ if ( m_szVSSProject[ Q_strlen( m_szVSSProject ) - 1 ] == '/' ||
+ m_szVSSProject[ Q_strlen( m_szVSSProject ) - 1 ] == '\\' )
+ {
+ m_szVSSProject[ Q_strlen( m_szVSSProject ) - 1 ] = 0;
+ }
+ else
+ {
+ break;
+ }
+ }
+}
+
+void CWorkspace::Checkout( bool updatestateicons /*= true*/ )
+{
+ VSS_Checkout( GetFileName(), updatestateicons );
+}
+
+void CWorkspace::Checkin(bool updatestateicons /*= true*/)
+{
+ VSS_Checkin( GetFileName(), updatestateicons );
+}
+
+bool CWorkspace::IsCheckedOut() const
+{
+ return filesystem->IsFileWritable( GetFileName() );
+}
+
+int CWorkspace::GetIconIndex() const
+{
+ if ( IsCheckedOut() )
+ {
+ return IMAGE_WORKSPACE_CHECKEDOUT;
+ }
+ else
+ {
+ return IMAGE_WORKSPACE;
+ }
+}
+
+void CWorkspace::MoveChildUp( ITreeItem *child )
+{
+ int c = GetProjectCount();
+ for ( int i = 1; i < c; i++ )
+ {
+ CProject *p = GetProject( i );
+ if ( p != child )
+ continue;
+
+ CProject *prev = GetProject( i - 1 );
+ // Swap
+ m_Projects[ i - 1 ] = p;
+ m_Projects[ i ] = prev;
+ return;
+ }
+}
+
+void CWorkspace::MoveChildDown( ITreeItem *child )
+{
+ int c = GetProjectCount();
+ for ( int i = 0; i < c - 1; i++ )
+ {
+ CProject *p = GetProject( i );
+ if ( p != child )
+ continue;
+
+ CProject *next = GetProject( i + 1 );
+ // Swap
+ m_Projects[ i ] = next;
+ m_Projects[ i + 1 ] = p;
+ return;
+ }
+}
+
+bool CWorkspace::IsChildFirst( ITreeItem *child )
+{
+ int idx = m_Projects.Find( (CProject *)child );
+ if ( idx == m_Projects.InvalidIndex() )
+ return false;
+
+ if ( idx != 0 )
+ return false;
+
+ return true;
+}
+
+bool CWorkspace::IsChildLast( ITreeItem *child )
+{
+ int idx = m_Projects.Find( (CProject *)child );
+ if ( idx == m_Projects.InvalidIndex() )
+ return false;
+
+ if ( idx != m_Projects.Count() - 1 )
+ return false;
+
+ return true;
+} \ No newline at end of file
diff --git a/utils/scenemanager/workspace.h b/utils/scenemanager/workspace.h
new file mode 100644
index 0000000..0c8675e
--- /dev/null
+++ b/utils/scenemanager/workspace.h
@@ -0,0 +1,90 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WORKSPACE_H
+#define WORKSPACE_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CProject;
+class mxTreeView;
+
+#include "itreeitem.h"
+
+class CWorkspace : public ITreeItem
+{
+public:
+ CWorkspace( char const *filename );
+ ~CWorkspace();
+
+ char const *GetName() const;
+ char const *GetFileName() const { return m_szFile; }
+
+ bool IsDirty( void ) const;
+ void SetDirty( bool dirty );
+
+ int GetProjectCount() const;
+ CProject *GetProject( int index ) const;
+ void AddProject( CProject *project );
+ CProject *FindProjectFile( char const *filename ) const;
+ void RemoveProject( CProject *project );
+
+ void ValidateTree( mxTreeView *tree, mxTreeViewItem *parent );
+
+ bool CanClose( void );
+
+ void SaveChanges();
+
+ virtual CWorkspace *GetWorkspace() { return this; }
+ virtual CProject *GetProject() { return NULL; }
+ virtual CScene *GetScene() { return NULL; }
+ virtual CVCDFile *GetVCDFile() { return NULL; }
+ virtual CSoundEntry *GetSoundEntry() { return NULL; }
+ virtual CWaveFile *GetWaveFile() { return NULL; }
+
+
+ char const *GetVSSUserName() const;
+ char const *GetVSSProject() const;
+
+ void SetVSSUserName( char const *username );
+ void SetVSSProject( char const *projectname );
+
+ virtual void Checkout( bool updatestateicons = true );
+ virtual void Checkin( bool updatestateicons = true );
+
+ bool IsCheckedOut() const;
+ int GetIconIndex() const;
+
+ virtual void MoveChildUp( ITreeItem *item );
+ virtual void MoveChildDown( ITreeItem *item );
+
+ virtual bool IsChildFirst( ITreeItem *child );
+ virtual bool IsChildLast( ITreeItem *child );
+
+private:
+
+ void LoadFromFile();
+ void SaveToFile();
+
+ enum
+ {
+ MAX_WORKSPACE_NAME = 128,
+ MAX_WORKSPACE_FILENAME = 256
+ };
+
+ char m_szName[ MAX_WORKSPACE_NAME ];
+ char m_szFile[ MAX_WORKSPACE_FILENAME ];
+
+ char m_szVSSUserName[ MAX_WORKSPACE_NAME ];
+ char m_szVSSProject[ MAX_WORKSPACE_NAME ];
+
+ bool m_bDirty;
+
+ CUtlVector< CProject * > m_Projects;
+};
+
+#endif // WORKSPACE_H
diff --git a/utils/scenemanager/workspacebrowser.cpp b/utils/scenemanager/workspacebrowser.cpp
new file mode 100644
index 0000000..31775e9
--- /dev/null
+++ b/utils/scenemanager/workspacebrowser.cpp
@@ -0,0 +1,258 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#include "cbase.h"
+#include "workspacebrowser.h"
+#include "workspace.h"
+#include "project.h"
+#include <windows.h>
+#include "resource.h"
+#include "project.h"
+#include "vcdfile.h"
+#include "soundentry.h"
+#include "scene.h"
+#include "workspacemanager.h"
+
+enum
+{
+ IDC_WSB_TREE = 101,
+};
+
+class CBrowserTree : public mxTreeView
+{
+public:
+ CBrowserTree( mxWindow *parent, int id = 0 )
+ : mxTreeView( parent, 0, 0, 0, 0, id )
+ {
+ // SendMessage ( (HWND)getHandle(), WM_SETFONT, (WPARAM) (HFONT) GetStockObject (ANSI_FIXED_FONT), MAKELPARAM (TRUE, 0));
+ }
+};
+
+int CALLBACK CWorkspaceBrowser::CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ ITreeItem const *item1 = (ITreeItem *)lParam1;
+ ITreeItem const *item2 = (ITreeItem *)lParam2;
+
+ Assert( item1 && item2 );
+
+ if ( item1->GetOrdinal() < item2->GetOrdinal() )
+ return -1;
+ else if ( item1->GetOrdinal() > item2->GetOrdinal() )
+ return 1;
+
+ // Ok, just compare pointers... sigh
+ return ( item1 < item2 ) ? -1 : 1;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *parent -
+//-----------------------------------------------------------------------------
+CWorkspaceBrowser::CWorkspaceBrowser( mxWindow *parent, CWorkspaceManager *manager, int id ) :
+ BaseClass( parent, 0, 0, 0, 0, "Workspace Browser", id )
+{
+ m_pManager = manager;
+
+ SceneManager_MakeToolWindow( this, false );
+
+ m_pLastSelected = NULL;
+
+ m_pCurrentWorkspace = NULL;
+ m_pTree = new CBrowserTree( this, IDC_WSB_TREE );
+
+ HIMAGELIST list = GetWorkspaceManager()->CreateImageList();
+
+ // Associate the image list with the tree-view control.
+ m_pTree->setImageList( (void *)list );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *event -
+// Output : int
+//-----------------------------------------------------------------------------
+int CWorkspaceBrowser::handleEvent( mxEvent *event )
+{
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Action:
+ {
+ switch ( event->action )
+ {
+ default:
+ break;
+ case IDC_WSB_TREE:
+ {
+ iret = 1;
+
+ bool rightmouse = ( event->flags == mxEvent::RightClicked ) ? true : false;
+ bool doubleclicked = ( event->flags == mxEvent::DoubleClicked ) ? true : false;
+
+ OnTreeItemSelected( event->x, event->y, rightmouse, doubleclicked );
+ }
+ break;
+ }
+ }
+ break;
+ case mxEvent::Size:
+ {
+ m_pTree->setBounds( 0, 0, w2(), h2() );
+
+ GetWorkspaceManager()->SetWorkspaceDirty();
+
+ iret = 1;
+ }
+ break;
+ case mxEvent::Close:
+ {
+ iret = 1;
+ }
+ break;
+ }
+
+ return iret;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : CWorkspace
+//-----------------------------------------------------------------------------
+CWorkspace *CWorkspaceBrowser::GetWorkspace()
+{
+ return m_pCurrentWorkspace;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceBrowser::PopulateTree()
+{
+ m_pLastSelected = NULL;
+
+ CWorkspace *w = m_pCurrentWorkspace;
+
+ if ( !w )
+ return;
+
+ // Add root element
+ char sz[ 128 ];
+ if ( w->GetProjectCount() == 1 )
+ {
+ Q_snprintf( sz, sizeof( sz ), "Workspace '%s': %i project", w->GetName(), w->GetProjectCount() );
+ }
+ else
+ {
+ Q_snprintf( sz, sizeof( sz ), "Workspace '%s': %i projects", w->GetName(), w->GetProjectCount() );
+ }
+
+
+ mxTreeViewItem *root = w->FindItem( m_pTree, NULL );
+ if ( !root )
+ {
+ root = m_pTree->add( NULL, sz );
+ }
+
+ // Reset the label
+ m_pTree->setLabel( root, sz );
+
+ m_pTree->setImages( root, w->GetIconIndex(), w->GetIconIndex() );
+ m_pTree->setUserData( root, w );
+
+ w->ValidateTree( m_pTree, root );
+
+ m_pTree->setOpen( root, true );
+
+ m_pTree->sortTree( root, true, CompareFunc, 0 );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *w -
+//-----------------------------------------------------------------------------
+void CWorkspaceBrowser::SetWorkspace( CWorkspace *w )
+{
+ m_pCurrentWorkspace = w;
+
+ PopulateTree();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *project -
+//-----------------------------------------------------------------------------
+void CWorkspaceBrowser::AddProject( CProject *project )
+{
+ if ( !m_pCurrentWorkspace )
+ return;
+
+ m_pCurrentWorkspace->AddProject( project );
+
+ PopulateTree();
+}
+
+ITreeItem *CWorkspaceBrowser::GetSelectedItem()
+{
+ return m_pLastSelected;
+}
+
+CWorkspaceManager *CWorkspaceBrowser::GetManager()
+{
+ return m_pManager;
+}
+
+void CWorkspaceBrowser::OnTreeItemSelected( int x, int y, bool rightmouse, bool doubleclick )
+{
+ mxTreeViewItem *item = m_pTree->getSelectedItem();
+ if ( !item )
+ {
+ Con_Printf( "No item selected\n" );
+ return;
+ }
+
+ ITreeItem *p = (ITreeItem *)m_pTree->getUserData( item );
+ if ( !p )
+ {
+ Con_Printf( "No userdata for item\n" );
+ return;
+ }
+
+ m_pLastSelected = p;
+
+ GetManager()->UpdateMenus();
+
+ if ( p->GetSoundEntry() || p->GetWaveFile() )
+ {
+ GetManager()->OnSoundShowInBrowsers();
+ }
+
+ if ( !rightmouse )
+ {
+ if ( doubleclick )
+ {
+ GetManager()->OnDoubleClicked( GetSelectedItem() );
+ }
+ return;
+ }
+
+ POINT pt;
+ GetCursorPos( &pt );
+
+ ScreenToClient( (HWND)GetManager()->getHandle(), &pt );
+
+ GetManager()->ShowContextMenu( pt.x, pt.y, GetSelectedItem() );
+}
+
+void CWorkspaceBrowser::JumpTo( ITreeItem *item )
+{
+ mxTreeViewItem *found = item->FindItem( m_pTree, NULL, true );
+ if ( found )
+ {
+ m_pTree->scrollTo( found );
+ }
+} \ No newline at end of file
diff --git a/utils/scenemanager/workspacebrowser.h b/utils/scenemanager/workspacebrowser.h
new file mode 100644
index 0000000..a99a311
--- /dev/null
+++ b/utils/scenemanager/workspacebrowser.h
@@ -0,0 +1,67 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WORKSPACEBROWSER_H
+#define WORKSPACEBROWSER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+#include "mxtk/mxTreeView.h"
+#include "commctrl.h"
+
+class CWorkspace;
+class CProject;
+class CScene;
+class CVCDFile;
+class CSoundEntry;
+
+class CBrowserTree;
+class ITreeItem;
+class CWorkspaceManager;
+
+class CWorkspaceBrowser : public mxWindow
+{
+ typedef mxWindow BaseClass;
+public:
+
+ CWorkspaceBrowser( mxWindow *parent, CWorkspaceManager *manager, int id );
+
+ CWorkspace *GetWorkspace();
+ void SetWorkspace( CWorkspace *w );
+ void AddProject( CProject *project );
+
+ virtual int handleEvent( mxEvent *event );
+
+ ITreeItem *GetSelectedItem();
+
+ void PopulateTree();
+
+ static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort);
+
+
+ void JumpTo( ITreeItem *item );
+
+private:
+
+ CWorkspaceManager *GetManager();
+
+ void OnTreeItemSelected( int x, int y, bool rightmouse, bool doubleclick );
+
+ CWorkspace *m_pCurrentWorkspace;
+
+ CBrowserTree *m_pTree;
+
+ enum
+ {
+ NUM_BITMAPS = 12,
+ };
+
+ ITreeItem *m_pLastSelected;
+ CWorkspaceManager *m_pManager;
+};
+
+#endif // WORKSPACEBROWSER_H
diff --git a/utils/scenemanager/workspacemanager.cpp b/utils/scenemanager/workspacemanager.cpp
new file mode 100644
index 0000000..c866f04
--- /dev/null
+++ b/utils/scenemanager/workspacemanager.cpp
@@ -0,0 +1,2004 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $NoKeywords: $
+//
+//=============================================================================//
+#include "cbase.h"
+#include "workspacemanager.h"
+#include "workspacebrowser.h"
+#include "workspace.h"
+#include "statuswindow.h"
+#include "SoundEmitterSystem/isoundemittersystembase.h"
+#include "drawhelper.h"
+#include "InputProperties.h"
+#include "filesystem.h"
+#include "cmdlib.h"
+#include "project.h"
+#include "scene.h"
+#include <KeyValues.h>
+#include "utlbuffer.h"
+#include "iscenemanagersound.h"
+#include "soundentry.h"
+#include "vcdfile.h"
+#include "soundbrowser.h"
+#include "wavebrowser.h"
+#include "VSSProperties.h"
+#include "resource.h"
+#include "soundproperties.h"
+#include "waveproperties.h"
+#include "wavefile.h"
+#include "ifileloader.h"
+#include "MultipleRequest.h"
+#include <vgui/ILocalize.h>
+#include "tier3/tier3.h"
+
+char g_appTitle[] = "Source Engine SceneManager";
+static char g_appTitleFmt[] = "%s - SceneManager Workspace (%s)";
+static char g_appTitleFmtModified[] = "%s * - SceneManager Workspace (%s)";
+
+#define RECENT_FILES_FILE "scenemanager.rf"
+
+enum
+{
+ // Menu options
+ IDC_WSM_FILE_EXIT = 1000,
+
+ IDC_WSM_FILE_WS_NEW,
+ IDC_WSM_FILE_WS_OPEN,
+ IDC_WSM_FILE_WS_CLOSE,
+ IDC_WSM_FILE_WS_SAVE,
+
+ IDC_WSM_FILE_WS_REFRESH,
+
+ IDC_WSM_FILE_WS_VSSPROPERTIES,
+ IDC_WSM_FILE_WS_CHECKOUT,
+ IDC_WSM_FILE_WS_CHECKIN,
+
+ IDC_WSM_FILE_SCENE_NEW, // + prompt for add to active project
+
+ IDC_WSM_PROJECT_PRJ_NEW, // + Prompt for add to workspace
+
+ IDC_WSM_PROJECT_PRJ_INSERT,
+ IDC_WSM_PROJECT_PRJ_REMOVE,
+ IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS,
+
+ IDC_WSM_PROJECT_SCENE_NEW,
+ IDC_WSM_SCENE_REMOVE,
+
+ IDC_WSM_SOUNDENTRY_PLAY,
+ IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK,
+ IDC_WSM_SOUNDENTRY_EDITTEXT,
+ IDC_WSM_SOUNDENTRY_SHOWINBROWSERS,
+ IDC_WSM_SOUNDENTRY_PROPERTIES,
+
+ IDC_WSM_SCENE_VCD_ADD,
+ IDC_WSM_SCENE_VCD_REMOVE,
+ IDC_WSM_SCENE_EDIT_COMMENTS,
+
+ IDC_WSM_VCD_EDIT_COMMENTS,
+
+ IDC_WSM_SELECTION_CHECKOUT,
+ IDC_WSM_SELECTION_CHECKIN,
+
+ IDC_WSM_SELECTION_MOVEUP,
+ IDC_WSM_SELECTION_MOVEDOWN,
+
+ IDC_WSM_WAVEFILE_PROPERTIES,
+
+ // Controls
+ IDC_WS_BROWSER,
+ IDC_WS_SOUNDBROWSER,
+ IDC_WS_WAVEBROWSER,
+
+ // These should be the final entriex
+ IDC_WSM_FILE_RECENT_WORKSPACE_START = 1500,
+ IDC_WSM_FILE_RECENT_WORKSPACE_END = 1510,
+
+ IDC_WSM_OPTIONS_LANGUAGESTART = 1600,
+ IDC_WSM_OPTIONS_LANGUAGEEND = 1600 + CC_NUM_LANGUAGES,
+};
+
+static CWorkspaceManager *g_pManager = NULL;
+CWorkspaceManager *GetWorkspaceManager()
+{
+ Assert( g_pManager );
+ return g_pManager;
+}
+
+class CWorkspaceWorkArea : public mxWindow
+{
+public:
+ CWorkspaceWorkArea( mxWindow *parent )
+ : mxWindow( parent, 0, 0, 0, 0, "" )
+ {
+ SceneManager_AddWindowStyle( this, WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
+ }
+
+ virtual void redraw()
+ {
+ CDrawHelper helper( this, RGB( 200, 200, 200 ) );
+ }
+};
+
+CWorkspaceManager::CWorkspaceManager()
+ : mxWindow (0, 0, 0, 0, 0, g_appTitle, mxWindow::Normal)
+{
+ m_lEnglishCaptionsFileChangeTime = -1L;
+ m_nLanguageId = CC_ENGLISH;
+
+ g_pManager = this;
+
+ g_pStatusWindow = new CStatusWindow( this, 0, 0, 1024, 150, "" );
+ g_pStatusWindow->setVisible( true );
+
+ m_pWorkArea = new CWorkspaceWorkArea( this );
+
+ Con_Printf( "Initializing\n" );
+
+ Con_Printf( "CSoundEmitterSystemBase::Init()\n" );
+
+ m_nRecentMenuItems = 0;
+
+ // create menu stuff
+ m_pMenuBar = new mxMenuBar (this);
+ m_pFileMenu = new mxMenu ();
+ m_pProjectMenu = new mxMenu ();
+ m_pOptionsMenu = new mxMenu();
+
+ {
+ m_pMenuCloseCaptionLanguages = new mxMenu();
+
+ for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
+ {
+ int id = IDC_WSM_OPTIONS_LANGUAGESTART + i;
+ m_pMenuCloseCaptionLanguages->add( CSentence::NameForLanguage( i ), id );
+ }
+ // Check the first item
+ m_pMenuCloseCaptionLanguages->setChecked( IDC_WSM_OPTIONS_LANGUAGESTART + CC_ENGLISH, true );
+ m_pOptionsMenu->addMenu( "CC Language", m_pMenuCloseCaptionLanguages );
+
+ }
+
+ m_pMenuBar->addMenu ("File", m_pFileMenu );
+ m_pMenuBar->addMenu( "Project", m_pProjectMenu );
+ m_pMenuBar->addMenu ( "Options", m_pOptionsMenu );
+
+ CreateFileMenu( m_pFileMenu );
+ CreateProjectMenu( m_pProjectMenu );
+
+ setMenuBar ( m_pMenuBar );
+
+ Con_Printf( "Creating browser\n" );
+
+ m_pBrowser = new CWorkspaceBrowser( m_pWorkArea, this, IDC_WS_BROWSER );
+
+ m_pSoundBrowser = NULL;
+ m_pWaveBrowser = NULL;
+
+ int w = 1280;
+ setBounds (10, 10, w, 960);
+
+ setVisible (true);
+
+ Con_Printf( "Creating wave browser\n" );
+
+ m_pWaveBrowser = new CWaveBrowser( m_pWorkArea, this, IDC_WS_WAVEBROWSER );
+
+ Con_Printf( "Creating sound browser\n" );
+
+ m_pSoundBrowser = new CSoundBrowser( m_pWorkArea, this, IDC_WS_SOUNDBROWSER );
+
+ GetBrowser()->SetWorkspace( NULL );
+
+ // See if command line requested workspace
+
+ // Default layout
+ PerformLayout( true );
+
+ LoadRecentFilesMenuFromDisk();
+}
+
+CWorkspaceManager::~CWorkspaceManager()
+{
+}
+
+bool CWorkspaceManager::Closing()
+{
+ Con_Printf( "Checking for sound script changes...\n" );
+
+ MultipleRequestChangeContext();
+
+ // Save any changed sound script files
+ int c = g_pSoundEmitterSystem->GetNumSoundScripts();
+ for ( int i = 0; i < c; i++ )
+ {
+ if ( !g_pSoundEmitterSystem->IsSoundScriptDirty( i ) )
+ continue;
+
+ char const *scriptname = g_pSoundEmitterSystem->GetSoundScriptName( i );
+ if ( !scriptname )
+ continue;
+
+ Assert( filesystem->FileExists( scriptname ) );
+
+ bool save = true;
+
+ if ( filesystem->FileExists( scriptname ) )
+ {
+ if ( !filesystem->IsFileWritable( scriptname ) )
+ {
+ int retval = MultipleRequest( va( "Check out '%s'?", scriptname ));
+ // Cancel
+ if ( retval == 2 )
+ return false;
+
+ if ( retval == 0 )
+ {
+ VSS_Checkout( scriptname );
+
+ if ( !filesystem->IsFileWritable( scriptname ) )
+ {
+ mxMessageBox( NULL, va( "Aborting shutdown, %s, not writable!!", scriptname ), g_appTitle, MX_MB_OK );
+ return false;
+ }
+ }
+ else if ( retval == 1 )
+ {
+ // Don't save
+ save = false;
+ }
+ }
+
+ if ( filesystem->IsFileWritable( scriptname ) )
+ {
+ int retval = mxMessageBox( NULL, va( "Save changes to out '%s'?", scriptname ), g_appTitle, MX_MB_YESNOCANCEL );
+ // Cancel
+ if ( retval == 2 )
+ return false;
+
+ if ( retval == 0 )
+ {
+ if ( !filesystem->IsFileWritable( scriptname ) )
+ {
+ mxMessageBox( NULL, va( "Aborting shutdown, %s, not writable!!", scriptname ), g_appTitle, MX_MB_OK );
+ return false;
+ }
+ }
+ else if ( retval == 1 )
+ {
+ // Skip changes!!!
+ save = false;
+ }
+ }
+ }
+
+ // Try and save it
+ if ( !save )
+ continue;
+
+ g_pSoundEmitterSystem->SaveChangesToSoundScript( i );
+ }
+
+ return CloseWorkspace();
+}
+
+void CWorkspaceManager::OnDelete()
+{
+ SaveRecentFilesMenuToDisk();
+}
+
+void CWorkspaceManager::CreateFileMenu( mxMenu *m )
+{
+ m->add ("&New Workspace", IDC_WSM_FILE_WS_NEW );
+ m->addSeparator();
+ m->add ("Open &Workspace...", IDC_WSM_FILE_WS_OPEN );
+ m->add ("Sa&ve Workspace", IDC_WSM_FILE_WS_SAVE );
+ m->add ("Close Wor&kspace", IDC_WSM_FILE_WS_CLOSE );
+ m->addSeparator();
+ m->add ("&Create New Scene...", IDC_WSM_FILE_SCENE_NEW );
+ m->addSeparator();
+
+ m->add( "V&SS Properties...", IDC_WSM_FILE_WS_VSSPROPERTIES );
+ m->addSeparator();
+
+ m->add( "Refresh\tF5", IDC_WSM_FILE_WS_REFRESH );
+
+ m->addSeparator();
+
+ m_pRecentFileMenu = new mxMenu ();
+ m->addMenu ("Recent Files", m_pRecentFileMenu);
+
+ m->addSeparator();
+ m->add ("E&xit", IDC_WSM_FILE_EXIT );
+}
+
+void CWorkspaceManager::UpdateMenus()
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+
+ bool hasworkspace = ws != NULL ? true : false;
+ //bool workspacedirty = ws && ws->IsDirty() ? true : false;
+ bool hasproject = item && item->GetProject() ? true : false;
+
+ m_pMenuBar->setEnabled( IDC_WSM_FILE_WS_SAVE, true );
+ m_pMenuBar->setEnabled( IDC_WSM_FILE_WS_CLOSE, hasworkspace );
+
+
+ if ( hasproject )
+ {
+ m_pMenuBar->modify( IDC_WSM_FILE_SCENE_NEW, IDC_WSM_FILE_SCENE_NEW, va( "&Create Scene in '%s'", item->GetProject()->GetName() ) );
+ }
+ else
+ {
+ m_pMenuBar->modify( IDC_WSM_FILE_SCENE_NEW, IDC_WSM_FILE_SCENE_NEW, "&Create New Scene..." );
+ }
+ m_pMenuBar->setEnabled( IDC_WSM_FILE_SCENE_NEW, hasproject );
+
+}
+
+void CWorkspaceManager::CreateProjectMenu( mxMenu *m )
+{
+ m->add ("Create New Project...", IDC_WSM_PROJECT_PRJ_NEW );
+ m->addSeparator();
+ m->add ("Insert Project...", IDC_WSM_PROJECT_PRJ_INSERT );
+ m->add ("Remove Project...", IDC_WSM_PROJECT_PRJ_REMOVE );
+ m->addSeparator();
+ m->add ("Properties...", IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS );
+}
+
+CWorkspaceBrowser *CWorkspaceManager::GetBrowser()
+{
+ return m_pBrowser;
+}
+
+CSoundBrowser *CWorkspaceManager::GetSoundBrowser()
+{
+ return m_pSoundBrowser;
+}
+
+CWaveBrowser *CWorkspaceManager::GetWaveBrowser()
+{
+ return m_pWaveBrowser;
+}
+
+int CWorkspaceManager::GetMaxRecentFiles() const
+{
+ return IDC_WSM_FILE_RECENT_WORKSPACE_END - IDC_WSM_FILE_RECENT_WORKSPACE_START;
+}
+
+#define MAX_FPS 250.0f
+#define MIN_TIMESTEP ( 1.0f / MAX_FPS )
+
+double realtime = 0.0f;
+
+void CWorkspaceManager::Think( float dt )
+{
+ sound->Update( dt );
+ int c = fileloader->ProcessCompleted();
+ if ( c > 0 )
+ {
+ RefreshBrowsers();
+ Con_Printf( "Thread loaded %i sounds\n", c );
+ }
+}
+
+void CWorkspaceManager::Frame( void )
+{
+ static bool recursion_guard = false;
+
+ static double prev = 0.0;
+ double curr = (double) mx::getTickCount () / 1000.0;
+ double dt = ( curr - prev );
+
+ if ( recursion_guard )
+ return;
+
+ recursion_guard = true;
+
+ // clamp to MAX_FPS
+ if ( dt >= 0.0 && dt < MIN_TIMESTEP )
+ {
+ Sleep( max( 0, (int)( ( MIN_TIMESTEP - dt ) * 1000.0f ) ) );
+
+ recursion_guard = false;
+ return;
+ }
+
+ if ( prev != 0.0 )
+ {
+ dt = min( 0.1, dt );
+
+ Think( dt );
+
+ realtime += dt;
+ }
+
+ prev = curr;
+
+ recursion_guard = false;
+}
+
+int CWorkspaceManager::handleEvent( mxEvent *event )
+{
+ int iret = 0;
+ switch ( event->event )
+ {
+ default:
+ break;
+ case mxEvent::Activate:
+ {
+ if (event->action)
+ {
+ mx::setIdleWindow( this );
+ // Force reload of localization data
+ OnChangeLanguage( GetLanguageId(), true );
+ }
+ else
+ {
+ mx::setIdleWindow( 0 );
+ }
+ iret = 1;
+ }
+ break;
+ case mxEvent::Idle:
+ {
+ iret = 1;
+ Frame();
+ }
+ break;
+ case mxEvent::KeyUp:
+ {
+ if ( event->key == VK_F5 )
+ {
+ RefreshBrowsers();
+ }
+ }
+ break;
+ case mxEvent::Action:
+ {
+ iret = 1;
+ switch ( event->action )
+ {
+ default:
+ {
+ if ( event->action >= IDC_WSM_FILE_RECENT_WORKSPACE_START &&
+ event->action < IDC_WSM_FILE_RECENT_WORKSPACE_END )
+ {
+ OnRecentWorkspace( event->action - IDC_WSM_FILE_RECENT_WORKSPACE_START );
+ }
+ else if ( event->action >= IDC_WSM_OPTIONS_LANGUAGESTART &&
+ event->action < IDC_WSM_OPTIONS_LANGUAGEEND )
+ {
+ OnChangeLanguage( event->action - IDC_WSM_OPTIONS_LANGUAGESTART );
+ }
+ else
+ {
+ iret = 0;
+ }
+ }
+ break;
+ case IDC_WSM_FILE_EXIT:
+ {
+ mx::quit();
+ }
+ break;
+ case IDC_WSM_FILE_WS_REFRESH:
+ {
+ RefreshBrowsers();
+ }
+ break;
+ case IDC_WSM_FILE_WS_NEW:
+ {
+ OnNewWorkspace();
+ }
+ break;
+ case IDC_WSM_FILE_WS_OPEN:
+ {
+ OnOpenWorkspace();
+ }
+ break;
+ case IDC_WSM_FILE_WS_CLOSE:
+ {
+ OnCloseWorkspace();
+ }
+ break;
+ case IDC_WSM_FILE_WS_SAVE:
+ {
+ OnSaveWorkspace();
+ }
+ break;
+ case IDC_WSM_FILE_WS_VSSPROPERTIES:
+ {
+ OnChangeVSSProperites();
+ }
+ break;
+ case IDC_WSM_FILE_WS_CHECKOUT:
+ {
+ OnCheckoutWorkspace();
+ }
+ break;
+ case IDC_WSM_FILE_WS_CHECKIN:
+ {
+ OnCheckinWorkspace();
+ }
+ break;
+ case IDC_WSM_PROJECT_PRJ_NEW:
+ {
+ OnNewProject();
+ }
+ break;
+ case IDC_WSM_PROJECT_PRJ_INSERT:
+ {
+ OnInsertProject();
+ }
+ break;
+ case IDC_WSM_PROJECT_PRJ_REMOVE:
+ {
+ OnRemoveProject();
+ }
+ break;
+ case IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS:
+ {
+ OnModifyProjectComments();
+ }
+ break;
+ case IDC_WSM_PROJECT_SCENE_NEW:
+ {
+ OnNewScene();
+ }
+ break;
+ case IDC_WSM_SOUNDENTRY_PLAY:
+ {
+ OnSoundPlay();
+ }
+ break;
+ case IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK:
+ {
+ OnSoundToggleVoiceDuck();
+ }
+ break;
+ case IDC_WSM_SOUNDENTRY_EDITTEXT:
+ {
+ OnSoundEditText();
+ }
+ break;
+ case IDC_WSM_SOUNDENTRY_PROPERTIES:
+ {
+ OnSoundProperties();
+ }
+ break;
+ case IDC_WSM_SCENE_VCD_ADD:
+ {
+ OnSceneAddVCD();
+ }
+ break;
+ case IDC_WSM_SCENE_VCD_REMOVE:
+ {
+ OnSceneRemoveVCD();
+ }
+ break;
+ case IDC_WSM_SCENE_EDIT_COMMENTS:
+ {
+ OnModifySceneComments();
+ }
+ break;
+ case IDC_WSM_VCD_EDIT_COMMENTS:
+ {
+ OnModifyVCDComments();
+ }
+ break;
+ case IDC_WSM_SCENE_REMOVE:
+ {
+ OnRemoveScene();
+ }
+ break;
+ case IDC_WSM_SOUNDENTRY_SHOWINBROWSERS:
+ {
+ OnSoundShowInBrowsers();
+ }
+ break;
+ case IDC_WSM_SELECTION_CHECKOUT:
+ {
+ OnCheckout();
+ }
+ break;
+ case IDC_WSM_SELECTION_CHECKIN:
+ {
+ OnCheckin();
+ }
+ break;
+ case IDC_WSM_SELECTION_MOVEUP:
+ {
+ OnMoveUp();
+ }
+ break;
+ case IDC_WSM_SELECTION_MOVEDOWN:
+ {
+ OnMoveDown();
+ }
+ break;
+ case IDC_WSM_WAVEFILE_PROPERTIES:
+ {
+ OnWaveProperties();
+ }
+ break;
+ }
+ }
+ break;
+ case mxEvent::Size:
+ {
+ iret = 1;
+ PerformLayout( false );
+ }
+ break;
+ }
+
+ return iret;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::PerformLayout( bool movebrowsers )
+{
+ int width = w2();
+ int height = h2();
+
+ int statush = 100;
+ m_pWorkArea->setBounds( 0, 0, width, height - statush );
+ if ( movebrowsers )
+ {
+ GetBrowser()->setBounds( 0, 0, m_pWorkArea->w2(), m_pWorkArea->h2() / 3 );
+ if ( GetSoundBrowser() )
+ {
+ GetSoundBrowser()->setBounds( 0, m_pWorkArea->h2() / 3, m_pWorkArea->w2(), m_pWorkArea->h2() / 3 );
+ }
+ if ( GetWaveBrowser() )
+ {
+ GetWaveBrowser()->setBounds( 0, 2 * m_pWorkArea->h2() / 3, m_pWorkArea->w2(), m_pWorkArea->h2() / 3 );
+ }
+ }
+
+ g_pStatusWindow->setBounds( 0, height - statush, width, statush );
+
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool CWorkspaceManager::CloseWorkspace()
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( !ws )
+ return true;
+
+ if ( !ws->CanClose() )
+ return false;
+
+ delete ws;
+
+ SetWorkspace( NULL );
+
+ return true;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnUpdateTitle( void )
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+
+ char szTitle[ 256 ];
+ if ( ws )
+ {
+ char const *fmt = g_appTitleFmt;
+ if ( ws->IsDirty() )
+ {
+ fmt = g_appTitleFmtModified;
+ }
+ Q_snprintf( szTitle, sizeof( szTitle ), fmt, ws->GetName(), CSentence::NameForLanguage( m_nLanguageId ) );
+ }
+ else
+ {
+ Q_snprintf( szTitle, sizeof( szTitle ), g_appTitle );
+ }
+
+ setLabel( szTitle );
+
+ UpdateMenus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : *ws -
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::SetWorkspace( CWorkspace *ws )
+{
+ GetBrowser()->SetWorkspace( ws );
+
+ OnUpdateTitle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnNewWorkspace()
+{
+ // Show file io
+ const char *fullpath = mxGetSaveFileName(
+ 0,
+ ".",
+ "*.vsw" );
+
+ if ( !fullpath || !fullpath[ 0 ] )
+ return;
+
+ // Strip game directory and slash
+ char workspace_name[ 512 ];
+ filesystem->FullPathToRelativePath( fullpath, workspace_name, sizeof( workspace_name ) );
+
+ Q_StripExtension( workspace_name, workspace_name, sizeof( workspace_name ) );
+ Q_DefaultExtension( workspace_name, ".vsw", sizeof( workspace_name ) );
+
+ if ( filesystem->FileExists( workspace_name ) )
+ {
+ Con_Printf( "%s exists already!\n", workspace_name );
+ Assert( 0 );
+ return;
+ }
+
+ LoadWorkspace( workspace_name );
+}
+
+void CWorkspaceManager::AddFileToRecentWorkspaceList( char const *filename )
+{
+ int i;
+ int c = m_RecentFiles.Count();
+
+ for ( i = 0; i < c; i++ )
+ {
+ if (!Q_stricmp( m_RecentFiles[i].filename, filename ))
+ break;
+ }
+
+ // swap existing recent file
+ if ( i < c )
+ {
+ RecentFile rf = m_RecentFiles[0];
+ m_RecentFiles[ 0 ] = m_RecentFiles[ i ];
+ m_RecentFiles[ i ] = rf;
+ }
+ // insert recent file
+ else
+ {
+ RecentFile rf;
+ Q_strcpy( rf.filename, filename );
+
+ m_RecentFiles.AddToHead( rf );
+ }
+
+ while( m_RecentFiles.Count() > GetMaxRecentFiles() )
+ {
+ m_RecentFiles.Remove( m_RecentFiles.Count() - 1 );
+ }
+
+ UpdateRecentFilesMenu();
+}
+
+void CWorkspaceManager::LoadRecentFilesMenuFromDisk()
+{
+ KeyValues *kv = new KeyValues( "recentfiles" );
+ if ( kv->LoadFromFile( filesystem, RECENT_FILES_FILE ) )
+ {
+ for ( KeyValues *sub = kv->GetFirstSubKey(); sub; sub = sub->GetNextKey() )
+ {
+ RecentFile rf;
+ Q_strncpy( rf.filename, sub->GetString(), sizeof( rf ) );
+ m_RecentFiles.AddToTail( rf );
+ }
+ }
+ kv->deleteThis();
+
+ UpdateRecentFilesMenu();
+}
+
+void CWorkspaceManager::AutoLoad( char const *workspace )
+{
+ if ( workspace )
+ {
+ LoadWorkspace( workspace );
+ }
+ else
+ {
+ if ( m_RecentFiles.Count() > 0 )
+ {
+ LoadWorkspace( m_RecentFiles[ 0 ].filename );
+ }
+ }
+}
+
+void CWorkspaceManager::SaveRecentFilesMenuToDisk()
+{
+ int i;
+ int c = m_RecentFiles.Count();
+
+ CUtlBuffer buf( 0, 0, CUtlBuffer::TEXT_BUFFER );
+
+ buf.Printf( "recentfiles\n{\n" );
+
+ for ( i = 0; i < c; i++ )
+ {
+ buf.Printf( "\t\"%i\"\t\"%s\"\n", i + 1, m_RecentFiles[ i ].filename );
+ }
+
+ buf.Printf( "}\n" );
+
+ char const *recentfiles = RECENT_FILES_FILE;
+
+ // Write it out baby
+ FileHandle_t fh = filesystem->Open( recentfiles, "wt" );
+ if (fh)
+ {
+ filesystem->Write( buf.Base(), buf.TellPut(), fh );
+ filesystem->Close(fh);
+ }
+ else
+ {
+ Con_Printf( "CWorkspace::SaveRecentFilesMenuToDisk: Unable to write file %s!!!\n", recentfiles );
+ }
+}
+
+void CWorkspaceManager::UpdateRecentFilesMenu()
+{
+ int c = m_RecentFiles.Count();
+
+ while ( c > m_nRecentMenuItems )
+ {
+ m_pRecentFileMenu->add( "(empty)", IDC_WSM_FILE_RECENT_WORKSPACE_START + m_nRecentMenuItems++ );
+ }
+
+ for (int i = 0; i < c; i++)
+ {
+ m_pMenuBar->modify (IDC_WSM_FILE_RECENT_WORKSPACE_START + i, IDC_WSM_FILE_RECENT_WORKSPACE_START + i, m_RecentFiles[i].filename );
+ }
+}
+
+void CWorkspaceManager::LoadWorkspace( char const *filename )
+{
+ if ( !CloseWorkspace() )
+ return;
+
+ Con_Printf( "Loading workspace %s\n", filename );
+
+ CWorkspace *wks = new CWorkspace( filename );
+ SetWorkspace( wks );
+
+ AddFileToRecentWorkspaceList( filename );
+
+ OnUpdateTitle();
+
+ UpdateMenus();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnOpenWorkspace()
+{
+ // Show file io
+ const char *fullpath = mxGetOpenFileName(
+ 0,
+ ".",
+ "*.vsw" );
+
+ if ( !fullpath || !fullpath[ 0 ] )
+ return;
+
+ // Strip game directory and slash
+ char workspace_name[ 512 ];
+ filesystem->FullPathToRelativePath( fullpath, workspace_name, sizeof( workspace_name ) );
+
+ LoadWorkspace( workspace_name );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnCloseWorkspace()
+{
+ if ( !CloseWorkspace() )
+ return;
+
+ Con_Printf( "Closed workspace\n" );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnSaveWorkspace()
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( ws )
+ {
+ ws->SaveChanges();
+
+ OnUpdateTitle();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnNewProject()
+{
+ Con_Printf( "OnNewProject()\n" );
+
+ // Show file io
+ const char *fullpath = mxGetSaveFileName(
+ 0,
+ ".",
+ "*.vsp" );
+
+ if ( !fullpath || !fullpath[ 0 ] )
+ return;
+
+ // Strip game directory and slash
+ char project_name[ 512 ];
+ filesystem->FullPathToRelativePath( fullpath, project_name, sizeof( project_name ) );
+
+ Q_StripExtension( project_name, project_name, sizeof( project_name ) );
+ Q_DefaultExtension( project_name, ".vsp", sizeof( project_name ) );
+
+ if ( filesystem->FileExists( project_name ) )
+ {
+ Con_Printf( "%s exists already!\n", project_name );
+ Assert( 0 );
+ return;
+ }
+
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ // Create one on the fly
+ char workspace_name[ 512 ];
+ Q_StripExtension( project_name, workspace_name, sizeof( workspace_name ) );
+ Q_DefaultExtension( workspace_name, ".vsw", sizeof( workspace_name ) );
+
+ if ( !filesystem->FileExists( workspace_name ) )
+ {
+ int retval = mxMessageBox( NULL, va( "Automatically create workspace %s?", workspace_name ), g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval != 0 )
+ {
+ Con_Printf( "Canceling project creation\n" );
+ return;
+ }
+ }
+ else
+ {
+ Con_Printf( "Found workspace '%s', automatically loading...\n", workspace_name );
+ }
+
+ LoadWorkspace( workspace_name );
+
+ ws = GetBrowser()->GetWorkspace();
+ }
+
+ if ( ws && ws->FindProjectFile( project_name ) )
+ {
+ Con_Printf( "Project %s already exists in workspace\n", project_name );
+ return;
+ }
+
+ // Create a new project and add it into current workspace
+ CProject *proj = new CProject( ws, project_name );
+ Assert( proj );
+ Assert( ws );
+
+ if ( ws )
+ {
+ GetBrowser()->AddProject( proj );
+ }
+
+ OnUpdateTitle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnInsertProject()
+{
+ Con_Printf( "OnInsertProject()\n" );
+
+ // Show file io
+ const char *fullpath = mxGetOpenFileName(
+ 0,
+ ".",
+ "*.vsp" );
+
+ if ( !fullpath || !fullpath[ 0 ] )
+ return;
+
+ // Strip game directory and slash
+ char project_name[ 512 ];
+ filesystem->FullPathToRelativePath( fullpath, project_name, sizeof( project_name ) );
+
+ Q_StripExtension( project_name, project_name, sizeof( project_name ) );
+ Q_DefaultExtension( project_name, ".vsp", sizeof( project_name ) );
+
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ // Create one on the fly
+ char workspace_name[ 512 ];
+ Q_StripExtension( project_name, workspace_name, sizeof( workspace_name ) );
+ Q_DefaultExtension( workspace_name, ".vsw", sizeof( workspace_name ) );
+
+ if ( !filesystem->FileExists( workspace_name ) )
+ {
+ int retval = mxMessageBox( NULL, va( "Automatically create workspace %s?", workspace_name ), g_appTitle, MX_MB_YESNOCANCEL );
+ if ( retval != 0 )
+ {
+ Con_Printf( "Canceling project creation\n" );
+ return;
+ }
+ }
+ else
+ {
+ Con_Printf( "Found workspace '%s', automatically loading...\n", workspace_name );
+ }
+
+ LoadWorkspace( workspace_name );
+
+ ws = GetBrowser()->GetWorkspace();
+ }
+
+ if ( ws && ws->FindProjectFile( project_name ) )
+ {
+ Con_Printf( "Project %s already exists in workspace\n", project_name );
+ return;
+ }
+
+ // Create a new project and add it into current workspace
+ CProject *proj = new CProject( ws, project_name );
+ Assert( proj );
+ Assert( ws );
+
+ if ( ws )
+ {
+ GetBrowser()->AddProject( proj );
+ }
+
+ OnUpdateTitle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnRemoveProject()
+{
+ Con_Printf( "OnRemoveProject()\n" );
+
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CProject *project = item->GetProject();
+ if ( !project )
+ {
+ Con_Printf( "Can't remove project, item is not a project\n" );
+ return;
+ }
+
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ Con_Printf( "Can't remove project '%s', no current workspace?!\n",
+ project->GetName() );
+ return;
+ }
+
+ ws->RemoveProject( project );
+ Con_Printf( "Removed project '%s'\n", project->GetName() );
+ delete project;
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::OnRemoveScene()
+{
+ Con_Printf( "OnRemoveScene()\n" );
+
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CScene *scene = item->GetScene();
+ if ( !scene )
+ {
+ Con_Printf( "Can't remove scene, item is not a scene\n" );
+ return;
+ }
+
+ CProject *project = scene->GetOwnerProject();
+ if ( !project )
+ {
+ Con_Printf( "Can't remove scene '%s', no current owner project?!\n",
+ scene->GetName() );
+ return;
+ }
+
+ project->RemoveScene( scene );
+ Con_Printf( "Removed scene '%s'\n", scene->GetName() );
+ delete scene;
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::OnNewScene()
+{
+ Con_Printf( "OnNewScene()\n" );
+
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CProject *project = item->GetProject();
+ if ( !project )
+ {
+ Con_Printf( "Can't add new scene, selected item is not a project\n" );
+ return;
+ }
+
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Create scene in '%s'", project->GetName() );
+ Q_strcpy( params.m_szPrompt, "Scene Name:" );
+ Q_strcpy( params.m_szInputText, "" );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ if ( !params.m_szInputText[ 0 ] )
+ {
+ Con_Printf( "You must name the scene!\n" );
+ return;
+ }
+
+ CScene *scene = new CScene( project, params.m_szInputText );
+ Assert( scene );
+
+ project->AddScene( scene );
+
+ Con_Printf( "Added scene '%s' to project '%s'\n", scene->GetName(),
+ project->GetName() );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnModifyProjectComments()
+{
+ Con_Printf( "OnModifyProjectComments()\n" );
+
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CProject *project = item->GetProject();
+ if ( !project )
+ {
+ Con_Printf( "Can't modify comments, item is not a project\n" );
+ return;
+ }
+
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit comments for '%s'", project->GetName() );
+ Q_strcpy( params.m_szPrompt, "Comments:" );
+ Q_strncpy( params.m_szInputText, project->GetComments(), sizeof( params.m_szInputText ) );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ if ( !Q_strcmp( params.m_szInputText, project->GetComments() ) )
+ return;
+
+ project->SetComments( params.m_szInputText );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : index -
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnRecentWorkspace( int index )
+{
+ if ( index < 0 || index >= m_RecentFiles.Count() )
+ return;
+
+ LoadWorkspace( m_RecentFiles[ index ].filename );
+}
+
+int CWorkspaceManager::GetLanguageId() const
+{
+ return m_nLanguageId;
+}
+
+void CWorkspaceManager::OnChangeLanguage( int lang_index, bool force /* = false */ )
+{
+ bool changed = m_nLanguageId != lang_index;
+ m_nLanguageId = lang_index;
+
+ if ( changed || force )
+ {
+ // Update the menu
+ for ( int i = 0; i < CC_NUM_LANGUAGES; i++ )
+ {
+ int id = IDC_WSM_OPTIONS_LANGUAGESTART + i;
+ m_pMenuCloseCaptionLanguages->setChecked( id, i == m_nLanguageId );
+ }
+
+ bool filechanged = false;
+
+ char const *suffix = CSentence::NameForLanguage( lang_index );
+ if ( Q_stricmp( suffix, "unknown_language" ) )
+ {
+ char fn[ MAX_PATH ];
+ Q_snprintf( fn, sizeof( fn ), "resource/closecaption_%s.txt", suffix );
+
+ long filetimestamp = filesystem->GetFileTime( fn );
+
+
+ if ( filesystem->FileExists( fn ) )
+ {
+ if ( m_lEnglishCaptionsFileChangeTime != filetimestamp )
+ {
+ filechanged = true;
+ m_lEnglishCaptionsFileChangeTime = filetimestamp;
+ //Con_Printf( "Reloading close caption data from '%s'\n", fn );
+ g_pVGuiLocalize->RemoveAll();
+ g_pVGuiLocalize->AddFile( fn );
+ }
+ }
+ else
+ {
+ Con_Printf( "CWorkspaceManager::OnChangeLanguage Warning, can't find localization file %s\n", fn );
+ }
+ }
+
+ if ( !force || filechanged )
+ {
+ // Update all text for items.
+ RefreshBrowsers();
+
+ OnUpdateTitle();
+ }
+ }
+}
+
+void CWorkspaceManager::OnDoubleClicked( ITreeItem *item )
+{
+ CSoundEntry *s = item->GetSoundEntry();
+ if ( s )
+ {
+ s->Play();
+ return;
+ }
+}
+
+void CWorkspaceManager::OnSoundPlay()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( item->GetSoundEntry() )
+ {
+ item->GetSoundEntry()->Play();
+ }
+ else if ( item->GetWaveFile() )
+ {
+ item->GetWaveFile()->Play();
+ }
+}
+
+void CWorkspaceManager::OnSoundToggleVoiceDuck()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( item->GetWaveFile() )
+ {
+ item->GetWaveFile()->ToggleVoiceDucking();
+ }
+}
+
+void CWorkspaceManager::OnSoundEditText()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CWaveFile *s = item->GetWaveFile();
+ if ( !s )
+ return;
+
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit text of '%s'", s->GetName() );
+ Q_strcpy( params.m_szPrompt, "Sentence text:" );
+ V_strcpy_safe( params.m_szInputText, s->GetSentenceText() );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ if ( !Q_stricmp( params.m_szInputText, s->GetSentenceText() ) )
+ {
+ return;
+ }
+
+ s->SetSentenceText( params.m_szInputText );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+// Scene entries
+void CWorkspaceManager::OnSceneAddVCD()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CScene *scene = item->GetScene();
+ if ( !scene )
+ return;
+
+ // Show file io
+ const char *fullpath = mxGetOpenFileName(
+ 0,
+ ".",
+ "*.vcd" );
+
+ if ( !fullpath || !fullpath[ 0 ] )
+ return;
+
+ // Strip game directory and slash
+ char vcd_name[ 512 ];
+ filesystem->FullPathToRelativePath( fullpath, vcd_name, sizeof( vcd_name ) );
+
+ Q_StripExtension( vcd_name, vcd_name, sizeof( vcd_name ) );
+ Q_DefaultExtension( vcd_name, ".vcd", sizeof( vcd_name ) );
+
+ if ( scene->FindVCD( vcd_name ) )
+ {
+ Con_Printf( "File '%s' is already in scene '%s'\n", vcd_name, scene->GetName() );
+ return;
+ }
+
+ CVCDFile *vcd = new CVCDFile( scene, vcd_name );
+
+ scene->AddVCD( vcd );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::OnModifySceneComments()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CScene *scene = item->GetScene();
+ if ( !scene )
+ return;
+
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit comments for '%s'", scene->GetName() );
+ Q_strcpy( params.m_szPrompt, "Comments:" );
+ Q_strncpy( params.m_szInputText, scene->GetComments(), sizeof( params.m_szInputText ) );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ if ( !Q_strcmp( params.m_szInputText, scene->GetComments() ) )
+ return;
+
+ scene->SetComments( params.m_szInputText );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::OnModifyVCDComments()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CVCDFile *file = item->GetVCDFile();
+ if ( !file )
+ return;
+
+ CInputParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Edit comments for '%s'", file->GetName() );
+ Q_strcpy( params.m_szPrompt, "Comments:" );
+ Q_strncpy( params.m_szInputText, file->GetComments(), sizeof( params.m_szInputText ) );
+
+ if ( !InputProperties( &params ) )
+ return;
+
+ if ( !Q_strcmp( params.m_szInputText, file->GetComments() ) )
+ return;
+
+ file->SetComments( params.m_szInputText );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::OnSceneRemoveVCD()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CVCDFile *file = item->GetVCDFile();
+ if ( !file )
+ return;
+
+ CScene *scene = file->GetOwnerScene();
+ if ( !scene )
+ return;
+
+ scene->RemoveVCD( file );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::ShowContextMenu( int x, int y, ITreeItem *p )
+{
+ CWorkspace *w = p->GetWorkspace();
+ if ( w )
+ {
+ ShowContextMenu_Workspace( x, y, w );
+ return;
+ }
+
+ CProject *proj = p->GetProject();
+ if ( proj )
+ {
+ ShowContextMenu_Project( x, y, proj );
+ return;
+ }
+
+ CScene *scene = p->GetScene();
+ if ( scene )
+ {
+ ShowContextMenu_Scene( x, y, scene );
+ return;
+ }
+
+ CVCDFile *vcd = p->GetVCDFile();
+ if ( vcd )
+ {
+ ShowContextMenu_VCD( x, y, vcd );
+ return;
+ }
+
+ CSoundEntry *sound = p->GetSoundEntry();
+ if ( sound )
+ {
+ ShowContextMenu_SoundEntry( x, y, sound );
+ return;
+ }
+
+ CWaveFile *wave = p->GetWaveFile();
+ if ( wave )
+ {
+ ShowContextMenu_WaveFile( x, y, wave );
+ return;
+ }
+
+ Con_Printf( "unknown tree item type\n" );
+ Assert( 0 );
+}
+
+void CWorkspaceManager::ShowContextMenu_Workspace( int x, int y, CWorkspace *ws )
+{
+ if ( !ws )
+ return;
+
+ // New project and insert project
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ pop->add ("Create New Project...", IDC_WSM_PROJECT_PRJ_NEW );
+ pop->add ("Insert Project...", IDC_WSM_PROJECT_PRJ_INSERT );
+ pop->addSeparator();
+ pop->add( "VSS Properties...", IDC_WSM_FILE_WS_VSSPROPERTIES );
+
+ if ( !filesystem->IsFileWritable( ws->GetFileName() ) )
+ {
+ pop->add( va( "Checkout '%s'", ws->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
+ }
+ else
+ {
+ pop->add( va( "Checkin '%s'", ws->GetName() ), IDC_WSM_SELECTION_CHECKIN );
+ }
+
+ pop->popup( this, x, y );
+}
+
+void CWorkspaceManager::ShowContextMenu_Project( int x, int y, CProject *project )
+{
+ // New scene, edit comments
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ pop->add ("Create New Scene...", IDC_WSM_PROJECT_SCENE_NEW );
+ pop->addSeparator();
+ pop->add ("Remove Project...", IDC_WSM_PROJECT_PRJ_REMOVE );
+ pop->addSeparator();
+ pop->add( "Edit comments...", IDC_WSM_PROJECT_PRJ_MODIFYCOMMENTS );
+ if ( !project->IsFirstChild() || !project->IsLastChild() )
+ {
+ pop->addSeparator();
+ if( !project->IsFirstChild() )
+ {
+ pop->add( va( "Move '%s' Up", project->GetName() ), IDC_WSM_SELECTION_MOVEUP );
+ }
+ if( !project->IsLastChild() )
+ {
+ pop->add( va( "Move '%s' Down", project->GetName() ), IDC_WSM_SELECTION_MOVEDOWN );
+ }
+ }
+ pop->addSeparator();
+
+ if ( !filesystem->IsFileWritable( project->GetFileName() ) )
+ {
+ pop->add( va( "Checkout '%s'", project->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
+ }
+ else
+ {
+ pop->add( va( "Checkin '%s'", project->GetName() ), IDC_WSM_SELECTION_CHECKIN );
+ }
+
+ pop->popup( this, x, y );
+}
+
+void CWorkspaceManager::ShowContextMenu_Scene( int x, int y, CScene *scene )
+{
+ // New scene, edit comments
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ pop->add( va( "Add VCD to '%s'...", scene->GetName() ), IDC_WSM_SCENE_VCD_ADD );
+ pop->addSeparator();
+ pop->add ("Remove Scene", IDC_WSM_SCENE_REMOVE );
+ pop->addSeparator();
+ pop->add( va( "Edit comments..." ), IDC_WSM_SCENE_EDIT_COMMENTS );
+ if ( !scene->IsFirstChild() || !scene->IsLastChild() )
+ {
+ pop->addSeparator();
+ if( !scene->IsFirstChild() )
+ {
+ pop->add( va( "Move '%s' Up", scene->GetName() ), IDC_WSM_SELECTION_MOVEUP );
+ }
+ if( !scene->IsLastChild() )
+ {
+ pop->add( va( "Move '%s' Down", scene->GetName() ), IDC_WSM_SELECTION_MOVEDOWN );
+ }
+ }
+
+ pop->popup( this, x, y );
+}
+
+void CWorkspaceManager::ShowContextMenu_VCD( int x, int y, CVCDFile *vcd )
+{
+ // New scene, edit comments
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ pop->add( va( "Remove VCD" ), IDC_WSM_SCENE_VCD_REMOVE );
+ pop->addSeparator();
+ pop->add( va( "Edit comments..." ), IDC_WSM_VCD_EDIT_COMMENTS );
+ if ( !vcd->IsFirstChild() || !vcd->IsLastChild() )
+ {
+ pop->addSeparator();
+ if( !vcd->IsFirstChild() )
+ {
+ pop->add( va( "Move '%s' Up", vcd->GetName() ), IDC_WSM_SELECTION_MOVEUP );
+ }
+ if( !vcd->IsLastChild() )
+ {
+ pop->add( va( "Move '%s' Down", vcd->GetName() ), IDC_WSM_SELECTION_MOVEDOWN );
+ }
+ }
+ pop->addSeparator();
+ if ( !filesystem->IsFileWritable( vcd->GetName() ) )
+ {
+ pop->add( va( "Checkout '%s'", vcd->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
+ }
+ else
+ {
+ pop->add( va( "Checkin '%s'", vcd->GetName() ), IDC_WSM_SELECTION_CHECKIN );
+ }
+
+ pop->popup( this, x, y );
+}
+
+void CWorkspaceManager::ShowContextMenu_SoundEntry( int x, int y, CSoundEntry *entry )
+{
+ // New scene, edit comments
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ pop->add ("&Play", IDC_WSM_SOUNDENTRY_PLAY );
+ // pop->add( "&Jump To", IDC_WSM_SOUNDENTRY_SHOWINBROWSERS );
+ pop->addSeparator();
+
+ pop->add( "Properties...", IDC_WSM_SOUNDENTRY_PROPERTIES );
+
+ pop->popup( this, x, y );
+}
+
+void CWorkspaceManager::ShowContextMenu_WaveFile( int x, int y, CWaveFile *entry )
+{
+ // New scene, edit comments
+ mxPopupMenu *pop = new mxPopupMenu();
+
+ pop->add ("&Play", IDC_WSM_SOUNDENTRY_PLAY );
+ // pop->add( "&Jump To", IDC_WSM_SOUNDENTRY_SHOWINBROWSERS );
+
+ if ( entry->GetVoiceDuck() )
+ {
+ pop->add ("Disable &voice duck", IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK );
+ }
+ else
+ {
+ pop->add ("Enable &voice duck", IDC_WSM_SOUNDENTRY_TOGGLEVOICEDUCK );
+ }
+ pop->add( "&Edit sentence text...", IDC_WSM_SOUNDENTRY_EDITTEXT );
+ pop->addSeparator();
+ if ( !filesystem->IsFileWritable( entry->GetFileName() ) )
+ {
+ pop->add( va( "Checkout '%s'", entry->GetName() ), IDC_WSM_SELECTION_CHECKOUT );
+ }
+ else
+ {
+ pop->add( va( "Checkin '%s'", entry->GetName() ), IDC_WSM_SELECTION_CHECKIN );
+ }
+ pop->addSeparator();
+ pop->add( "Properties...", IDC_WSM_WAVEFILE_PROPERTIES );
+
+ pop->popup( this, x, y );
+}
+
+
+void CWorkspaceManager::OnChangeVSSProperites()
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ return;
+ }
+
+ CVSSParams params;
+ memset( &params, 0, sizeof( params ) );
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "VSS Properites" );
+ V_strcpy_safe( params.m_szUserName, ws->GetVSSUserName() );
+ V_strcpy_safe( params.m_szProject, ws->GetVSSProject() );
+
+ if ( !VSSProperties( &params ) )
+ return;
+
+ if ( !params.m_szUserName[ 0 ] )
+ {
+ Con_Printf( "You must enter a user name\n" );
+ return;
+ }
+
+ if ( !params.m_szProject[ 0 ] )
+ {
+ Con_Printf( "You must enter a project name\n" );
+ return;
+ }
+
+ ws->SetVSSUserName( params.m_szUserName );
+ ws->SetVSSProject( params.m_szProject );
+
+ ws->SetDirty( true );
+
+ Con_Printf( "VSS user = '%s', project = '%s'\n",
+ ws->GetVSSUserName(), ws->GetVSSProject() );
+}
+
+void CWorkspaceManager::OnCheckoutWorkspace()
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ return;
+ }
+
+ ws->Checkout();
+}
+
+void CWorkspaceManager::OnCheckinWorkspace()
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( !ws )
+ {
+ return;
+ }
+
+ ws->Checkin();
+}
+
+
+#define CX_ICON 16
+#define CY_ICON 16
+
+HIMAGELIST CWorkspaceManager::CreateImageList()
+{
+ HIMAGELIST list;
+
+ list = ImageList_Create( CX_ICON, CY_ICON,
+ FALSE, NUM_IMAGES, 0 );
+
+ // Load the icon resources, and add the icons to the image list.
+ HICON hicon;
+ int slot;
+#if defined( DBGFLAG_ASSERT )
+ int c = 0;
+#endif
+
+ hicon = LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WORKSPACE));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon( GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WORKSPACE_CHECKEDOUT));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_PROJECT));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_PROJECT_CHECKEDOUT));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SCENE));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+// hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SCENE_CHECKEDOUT));
+// slot = ImageList_AddIcon(list, hicon);
+// Assert( slot == c++ );
+// DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_VCD));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_VCD_CHECKEDOUT ));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WAV));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_WAV_CHECKEDOUT));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SPEAK));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ hicon = LoadIcon(GetModuleHandle( 0 ), MAKEINTRESOURCE(IDI_SPEAK_CHECKEDOUT));
+ slot = ImageList_AddIcon(list, hicon);
+ Assert( slot == c++ );
+ DeleteObject( hicon );
+
+ return list;
+}
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::RefreshBrowsers()
+{
+ if ( GetBrowser() )
+ {
+ GetBrowser()->PopulateTree();
+ }
+
+ if ( GetSoundBrowser() )
+ {
+ GetSoundBrowser()->RepopulateTree();
+ }
+
+ if ( GetWaveBrowser() )
+ {
+ GetWaveBrowser()->RepopulateTree();
+ }
+}
+
+void CWorkspaceManager::OnSoundShowInBrowsers()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CSoundEntry *se = item->GetSoundEntry();
+ if ( se )
+ {
+ GetSoundBrowser()->JumpToItem( se );
+ return;
+ }
+
+ CWaveFile *wave = item->GetWaveFile();
+ if ( wave )
+ {
+ GetWaveBrowser()->JumpToItem( wave );
+ if ( wave->GetOwnerSoundEntry() )
+ {
+ GetSoundBrowser()->JumpToItem( wave->GetOwnerSoundEntry() );
+ }
+ }
+}
+
+void CWorkspaceManager::OnCheckout()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ item->Checkout();
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::OnCheckin()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ item->Checkin();
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+}
+
+void CWorkspaceManager::OnMoveUp()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ ITreeItem *parent = item->GetParentItem();
+ if ( !parent )
+ return;
+
+ parent->MoveChildUp( item );
+
+ parent->SetDirty( true );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+
+ GetBrowser()->JumpTo( item );
+}
+
+void CWorkspaceManager::OnMoveDown()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ ITreeItem *parent = item->GetParentItem();
+ if ( !parent )
+ return;
+
+ parent->MoveChildDown( item );
+
+ parent->SetDirty( true );
+
+ GetBrowser()->PopulateTree();
+
+ OnUpdateTitle();
+
+ GetBrowser()->JumpTo( item );
+}
+
+void CWorkspaceManager::SetWorkspaceDirty()
+{
+ CWorkspace *ws = GetBrowser()->GetWorkspace();
+ if ( ws )
+ {
+ ws->SetDirty( true );
+ }
+ OnUpdateTitle();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnSoundProperties()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CSoundEntry *entry = item->GetSoundEntry();
+ if ( !entry )
+ return;
+
+ CSoundParams params;
+ memset( &params, 0, sizeof( params ) );
+
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Sound Properties" );
+
+ params.items.AddToTail( entry );
+
+ SoundProperties( &params );
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void CWorkspaceManager::OnWaveProperties()
+{
+ ITreeItem *item = GetBrowser()->GetSelectedItem();
+ if ( !item )
+ return;
+
+ CWaveFile *wave = item->GetWaveFile();
+ if ( !wave )
+ return;
+
+ CWaveParams params;
+ memset( &params, 0, sizeof( params ) );
+
+ Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Wave Properties" );
+
+ params.items.AddToTail( wave );
+
+ WaveProperties( &params );
+}
diff --git a/utils/scenemanager/workspacemanager.h b/utils/scenemanager/workspacemanager.h
new file mode 100644
index 0000000..e7c5eb0
--- /dev/null
+++ b/utils/scenemanager/workspacemanager.h
@@ -0,0 +1,184 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+//=============================================================================//
+
+#ifndef WORKSPACEMANAGER_H
+#define WORKSPACEMANAGER_H
+#ifdef _WIN32
+#pragma once
+#endif
+
+class CWorkspaceBrowser;
+class CWorkspaceWorkArea;
+class CWorkspace;
+class CProject;
+class CScene;
+class CVCDFile;
+class CSoundEntry;
+class ITreeItem;
+class CSoundBrowser;
+class CWaveBrowser;
+class CWaveFile;
+
+struct _IMAGELIST;
+typedef struct _IMAGELIST NEAR* HIMAGELIST;
+
+enum
+{
+ IMAGE_WORKSPACE = 0,
+ IMAGE_WORKSPACE_CHECKEDOUT,
+ IMAGE_PROJECT,
+ IMAGE_PROJECT_CHECKEDOUT,
+ IMAGE_SCENE,
+// IMAGE_SCENE_CHECKEDOUT,
+ IMAGE_VCD,
+ IMAGE_VCD_CHECKEDOUT,
+ IMAGE_WAV,
+ IMAGE_WAV_CHECKEDOUT,
+ IMAGE_SPEAK,
+ IMAGE_SPEAK_CHECKEDOUT,
+
+ NUM_IMAGES,
+};
+
+class CWorkspaceManager : public mxWindow
+{
+public:
+ CWorkspaceManager();
+ ~CWorkspaceManager();
+
+ virtual int handleEvent( mxEvent *event );
+
+ CWorkspaceBrowser *GetBrowser();
+ CSoundBrowser *GetSoundBrowser();
+ CWaveBrowser *GetWaveBrowser();
+ void LoadWorkspace( char const *filename );
+
+ void AutoLoad( char const *workspace );
+
+ void ShowContextMenu( int x, int y, ITreeItem *item );
+ void OnDoubleClicked( ITreeItem *item );
+
+ void UpdateMenus();
+
+ virtual bool Closing();
+
+ HIMAGELIST CreateImageList();
+
+ void RefreshBrowsers();
+
+ void OnSoundShowInBrowsers();
+
+ void SetWorkspaceDirty();
+
+ int GetLanguageId() const;
+
+private:
+
+ void PerformLayout( bool movebrowsers );
+
+ void Think( float dt );
+ void Frame( void );
+
+ virtual void OnDelete();
+
+ void SetWorkspace( CWorkspace *ws );
+ void OnUpdateTitle( void );
+
+ void CreateFileMenu( mxMenu *m );
+ void CreateProjectMenu( mxMenu *m );
+
+ int GetMaxRecentFiles( void ) const;
+
+// Workspace message handlers
+ void OnNewWorkspace();
+ void OnOpenWorkspace();
+ void OnCloseWorkspace();
+ void OnSaveWorkspace();
+
+ void OnChangeVSSProperites();
+
+ void OnCheckoutWorkspace();
+ void OnCheckinWorkspace();
+
+// Project message handlers
+ void OnNewProject();
+ void OnInsertProject();
+ void OnRemoveProject();
+ void OnModifyProjectComments();
+
+// Scene message handlers
+ void OnNewScene();
+ void OnModifySceneComments();
+ void OnRemoveScene();
+
+// Sound entry handlers
+ void OnSoundPlay();
+ void OnSoundToggleVoiceDuck();
+ void OnSoundEditText();
+
+ void OnSoundProperties();
+ void OnWaveProperties();
+
+ void OnCheckout();
+ void OnCheckin();
+
+ void OnMoveUp();
+ void OnMoveDown();
+
+ //void OnSoundCheckOut();
+ //void OnSoundCheckIn();
+
+// Scene entries
+ void OnSceneAddVCD();
+ void OnSceneRemoveVCD();
+ void OnModifyVCDComments();
+
+ void OnRecentWorkspace( int index );
+ void OnChangeLanguage( int lang_index, bool force = false );
+ void AddFileToRecentWorkspaceList( char const *filename );
+ void UpdateRecentFilesMenu();
+
+ void LoadRecentFilesMenuFromDisk();
+ void SaveRecentFilesMenuToDisk();
+
+
+ bool CloseWorkspace();
+
+ void ShowContextMenu_Workspace( int x, int y, CWorkspace *ws );
+ void ShowContextMenu_Project( int x, int y, CProject *project );
+ void ShowContextMenu_Scene( int x, int y, CScene *scene );
+ void ShowContextMenu_VCD( int x, int y, CVCDFile *vcd );
+ void ShowContextMenu_SoundEntry( int x, int y, CSoundEntry *entry );
+ void ShowContextMenu_WaveFile( int x, int y, CWaveFile *entry );
+
+ mxMenuBar *m_pMenuBar;
+
+ mxMenu *m_pFileMenu;
+ mxMenu *m_pRecentFileMenu;
+ int m_nRecentMenuItems;
+ mxMenu *m_pProjectMenu;
+ mxMenu *m_pOptionsMenu;
+ mxMenu *m_pMenuCloseCaptionLanguages;
+
+ CWorkspaceWorkArea *m_pWorkArea;
+
+ CWorkspaceBrowser *m_pBrowser;
+ CSoundBrowser *m_pSoundBrowser;
+ CWaveBrowser *m_pWaveBrowser;
+
+ struct RecentFile
+ {
+ char filename[ 256 ];
+ };
+
+ CUtlVector< RecentFile > m_RecentFiles;
+ int m_nLanguageId;
+ long m_lEnglishCaptionsFileChangeTime;
+};
+
+CWorkspaceManager *GetWorkspaceManager();
+
+#endif // WORKSPACEMANAGER_H