diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /utils/scenemanager | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'utils/scenemanager')
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 Binary files differnew file mode 100644 index 0000000..c7d9da9 --- /dev/null +++ b/utils/scenemanager/ico00001.ico diff --git a/utils/scenemanager/ico00002.ico b/utils/scenemanager/ico00002.ico Binary files differnew file mode 100644 index 0000000..ad48cbf --- /dev/null +++ b/utils/scenemanager/ico00002.ico diff --git a/utils/scenemanager/ico00003.ico b/utils/scenemanager/ico00003.ico Binary files differnew file mode 100644 index 0000000..b61e1b1 --- /dev/null +++ b/utils/scenemanager/ico00003.ico diff --git a/utils/scenemanager/ico00004.ico b/utils/scenemanager/ico00004.ico Binary files differnew file mode 100644 index 0000000..ff2e77c --- /dev/null +++ b/utils/scenemanager/ico00004.ico diff --git a/utils/scenemanager/ico00005.ico b/utils/scenemanager/ico00005.ico Binary files differnew file mode 100644 index 0000000..1fa01d2 --- /dev/null +++ b/utils/scenemanager/ico00005.ico diff --git a/utils/scenemanager/ico00006.ico b/utils/scenemanager/ico00006.ico Binary files differnew file mode 100644 index 0000000..b27f13f --- /dev/null +++ b/utils/scenemanager/ico00006.ico diff --git a/utils/scenemanager/ico00007.ico b/utils/scenemanager/ico00007.ico Binary files differnew file mode 100644 index 0000000..35868d9 --- /dev/null +++ b/utils/scenemanager/ico00007.ico diff --git a/utils/scenemanager/icon1.ico b/utils/scenemanager/icon1.ico Binary files differnew file mode 100644 index 0000000..8251647 --- /dev/null +++ b/utils/scenemanager/icon1.ico 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( ¶ms, 0, sizeof( params ) ); + Q_strcpy( params.m_szDialogTitle, g_appTitle ); + Q_strncpy( params.m_szPrompt, prompt, sizeof( params.m_szPrompt ) ); + + return _MultipleRequest( ¶ms ); +}
\ 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 Binary files differnew file mode 100644 index 0000000..3e2b5c5 --- /dev/null +++ b/utils/scenemanager/project1.ico 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 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( ¶ms ); + } + else + { + SoundProperties( ¶ms ); + } +} + +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( ¶ms, 0, sizeof( params ) ); + params.addsound = true; + + Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "New Sound" ); + + if ( !SoundProperties( ¶ms ) ) + 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 Binary files differnew file mode 100644 index 0000000..249d061 --- /dev/null +++ b/utils/scenemanager/vcd1.ico 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 Binary files differnew file mode 100644 index 0000000..d4ae51b --- /dev/null +++ b/utils/scenemanager/wav1.ico 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 0, sizeof( params ) ); + + Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Wave Properties" ); + + params.items.AddToTail( entry ); + + if ( !WaveProperties( ¶ms ) ) + 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 Binary files differnew file mode 100644 index 0000000..b3e4e4a --- /dev/null +++ b/utils/scenemanager/workspac.ico 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 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( ¶ms ) ) + 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( ¶ms, 0, sizeof( params ) ); + + Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Sound Properties" ); + + params.items.AddToTail( entry ); + + SoundProperties( ¶ms ); +} + + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void CWorkspaceManager::OnWaveProperties() +{ + ITreeItem *item = GetBrowser()->GetSelectedItem(); + if ( !item ) + return; + + CWaveFile *wave = item->GetWaveFile(); + if ( !wave ) + return; + + CWaveParams params; + memset( ¶ms, 0, sizeof( params ) ); + + Q_snprintf( params.m_szDialogTitle, sizeof( params.m_szDialogTitle ), "Wave Properties" ); + + params.items.AddToTail( wave ); + + WaveProperties( ¶ms ); +} 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 |