mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-07 17:29:36 +00:00
1
This commit is contained in:
@@ -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 );
|
||||
}
|
||||
Reference in New Issue
Block a user