mirror of
https://github.com/AquariaOSE/Aquaria.git
synced 2025-06-07 17:11:56 +00:00
Do all sound decoding in *one* background thread, instead of one thread per decoder.
This commit is contained in:
parent
6ffb668668
commit
f953f2b5ab
4 changed files with 333 additions and 73 deletions
|
@ -42,6 +42,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "ogg/ogg.h"
|
#include "ogg/ogg.h"
|
||||||
#include "vorbis/vorbisfile.h"
|
#include "vorbis/vorbisfile.h"
|
||||||
|
|
||||||
|
#include "MT.h"
|
||||||
|
|
||||||
#ifndef _DEBUG
|
#ifndef _DEBUG
|
||||||
//#define _DEBUG 1
|
//#define _DEBUG 1
|
||||||
#endif
|
#endif
|
||||||
|
@ -79,7 +81,13 @@ public:
|
||||||
static int mem_seek(void *datasource, ogg_int64_t offset, int whence);
|
static int mem_seek(void *datasource, ogg_int64_t offset, int whence);
|
||||||
static long mem_tell(void *datasource);
|
static long mem_tell(void *datasource);
|
||||||
|
|
||||||
|
static void startDecoderThread();
|
||||||
|
static void stopDecoderThread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void _stop();
|
||||||
|
|
||||||
// Decoding loop, run in a separate thread (if threads are available).
|
// Decoding loop, run in a separate thread (if threads are available).
|
||||||
static void decode_loop(OggDecoder *this_);
|
static void decode_loop(OggDecoder *this_);
|
||||||
|
|
||||||
|
@ -107,19 +115,27 @@ private:
|
||||||
ALenum format;
|
ALenum format;
|
||||||
int freq;
|
int freq;
|
||||||
|
|
||||||
#ifdef BBGE_BUILD_SDL
|
bool thread; // true if played by background thread
|
||||||
SDL_Thread *thread;
|
|
||||||
#else
|
|
||||||
#warning Threads not supported, music may cut out on area changes!
|
|
||||||
// ... because the stream runs out of decoded data while the area is
|
|
||||||
// still loading, so OpenAL aborts playback.
|
|
||||||
#endif
|
|
||||||
volatile bool stop_thread;
|
|
||||||
|
|
||||||
bool playing;
|
bool playing;
|
||||||
bool loop;
|
bool loop;
|
||||||
bool eof; // End of file _or_ unrecoverable error encountered
|
bool eof; // End of file _or_ unrecoverable error encountered
|
||||||
|
bool stopped; // true if enqueued deletion
|
||||||
unsigned int samples_done; // Number of samples played and dequeued
|
unsigned int samples_done; // Number of samples played and dequeued
|
||||||
|
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
static SDL_Thread *decoderThread;
|
||||||
|
static LockedQueue<OggDecoder*> decoderQ;
|
||||||
|
static volatile bool stop_thread;
|
||||||
|
static std::list<OggDecoder*> decoderList; // used by decoder thread only
|
||||||
|
|
||||||
|
#else
|
||||||
|
#warning Threads not supported, music may cut out on area changes!
|
||||||
|
// ... because the stream runs out of decoded data while the area is
|
||||||
|
// still loading, so OpenAL aborts playback.
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void detachDecoder(OggDecoder *);
|
||||||
};
|
};
|
||||||
|
|
||||||
// File I/O callback set (OV_CALLBACKS_NOCLOSE from libvorbis 1.2.0).
|
// File I/O callback set (OV_CALLBACKS_NOCLOSE from libvorbis 1.2.0).
|
||||||
|
@ -155,6 +171,88 @@ static const ov_callbacks ogg_memory_callbacks = {
|
||||||
OggDecoder::mem_tell
|
OggDecoder::mem_tell
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_Thread *OggDecoder::decoderThread = NULL;
|
||||||
|
LockedQueue<OggDecoder*> OggDecoder::decoderQ;
|
||||||
|
volatile bool OggDecoder::stop_thread;
|
||||||
|
std::list<OggDecoder*> OggDecoder::decoderList;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void OggDecoder::startDecoderThread()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
stop_thread = false;
|
||||||
|
decoderThread = SDL_CreateThread((int (*)(void *))decode_loop, NULL);
|
||||||
|
if (!decoderThread)
|
||||||
|
{
|
||||||
|
debugLog("Failed to create Ogg Vorbis decode thread: "
|
||||||
|
+ std::string(SDL_GetError()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OggDecoder::stopDecoderThread()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
if (decoderThread)
|
||||||
|
{
|
||||||
|
stop_thread = true;
|
||||||
|
debugLog("Waiting for decoder thread to exit...");
|
||||||
|
SDL_WaitThread(decoderThread, NULL);
|
||||||
|
decoderThread = NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OggDecoder::detachDecoder(OggDecoder *ogg)
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
if(decoderThread)
|
||||||
|
{
|
||||||
|
ogg->thread = true;
|
||||||
|
decoderQ.push(ogg);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void OggDecoder::decode_loop(OggDecoder *this_)
|
||||||
|
{
|
||||||
|
while (!this_->stop_thread)
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_Delay(10);
|
||||||
|
#endif
|
||||||
|
// Transfer decoder to this background thread
|
||||||
|
OggDecoder *ogg;
|
||||||
|
while(decoderQ.pop(ogg))
|
||||||
|
decoderList.push_back(ogg);
|
||||||
|
|
||||||
|
for(std::list<OggDecoder*>::iterator it = decoderList.begin(); it != decoderList.end(); )
|
||||||
|
{
|
||||||
|
ogg = *it;
|
||||||
|
if (ogg->playing)
|
||||||
|
{
|
||||||
|
int processed = 0;
|
||||||
|
alGetSourcei(ogg->source, AL_BUFFERS_PROCESSED, &processed);
|
||||||
|
for (int i = 0; i < processed; i++)
|
||||||
|
{
|
||||||
|
ogg->samples_done += BUFFER_LENGTH;
|
||||||
|
ALuint buffer = 0;
|
||||||
|
alSourceUnqueueBuffers(ogg->source, 1, &buffer);
|
||||||
|
if (buffer)
|
||||||
|
ogg->queue(buffer);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
delete ogg;
|
||||||
|
decoderList.erase(it++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
OggDecoder::OggDecoder(FILE *fp)
|
OggDecoder::OggDecoder(FILE *fp)
|
||||||
{
|
{
|
||||||
|
@ -167,14 +265,12 @@ OggDecoder::OggDecoder(FILE *fp)
|
||||||
this->data = NULL;
|
this->data = NULL;
|
||||||
this->data_size = 0;
|
this->data_size = 0;
|
||||||
this->data_pos = 0;
|
this->data_pos = 0;
|
||||||
#ifdef BBGE_BUILD_SDL
|
this->thread = false;
|
||||||
this->thread = NULL;
|
|
||||||
#endif
|
|
||||||
this->stop_thread = true;
|
|
||||||
this->playing = false;
|
this->playing = false;
|
||||||
this->loop = false;
|
this->loop = false;
|
||||||
this->eof = false;
|
this->eof = false;
|
||||||
this->samples_done = 0;
|
this->samples_done = 0;
|
||||||
|
this->stopped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OggDecoder::OggDecoder(const void *data, long data_size)
|
OggDecoder::OggDecoder(const void *data, long data_size)
|
||||||
|
@ -188,20 +284,17 @@ OggDecoder::OggDecoder(const void *data, long data_size)
|
||||||
this->data = (const char *)data;
|
this->data = (const char *)data;
|
||||||
this->data_size = data_size;
|
this->data_size = data_size;
|
||||||
this->data_pos = 0;
|
this->data_pos = 0;
|
||||||
#ifdef BBGE_BUILD_SDL
|
this->thread = false;
|
||||||
this->thread = NULL;
|
|
||||||
#endif
|
|
||||||
this->stop_thread = true;
|
|
||||||
this->playing = false;
|
this->playing = false;
|
||||||
this->loop = false;
|
this->loop = false;
|
||||||
this->eof = false;
|
this->eof = false;
|
||||||
this->samples_done = 0;
|
this->samples_done = 0;
|
||||||
|
this->stopped = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
OggDecoder::~OggDecoder()
|
OggDecoder::~OggDecoder()
|
||||||
{
|
{
|
||||||
if (playing)
|
_stop();
|
||||||
stop();
|
|
||||||
|
|
||||||
for (int i = 0; i < NUM_BUFFERS; i++)
|
for (int i = 0; i < NUM_BUFFERS; i++)
|
||||||
{
|
{
|
||||||
|
@ -280,27 +373,15 @@ bool OggDecoder::start(ALuint source, bool loop)
|
||||||
for (int i = 0; i < NUM_BUFFERS; i++)
|
for (int i = 0; i < NUM_BUFFERS; i++)
|
||||||
queue(buffers[i]);
|
queue(buffers[i]);
|
||||||
|
|
||||||
#ifdef BBGE_BUILD_SDL
|
detachDecoder(this);
|
||||||
stop_thread = false;
|
|
||||||
thread = SDL_CreateThread((int (*)(void *))decode_loop, this);
|
|
||||||
if (!thread)
|
|
||||||
{
|
|
||||||
debugLog("Failed to create Ogg Vorbis decode thread: "
|
|
||||||
+ std::string(SDL_GetError()));
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OggDecoder::update()
|
void OggDecoder::update()
|
||||||
{
|
{
|
||||||
if (!playing)
|
if (!playing || thread)
|
||||||
return;
|
return;
|
||||||
#ifdef BBGE_BUILD_SDL
|
|
||||||
if (thread)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int processed = 0;
|
int processed = 0;
|
||||||
alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
|
alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed);
|
||||||
|
@ -315,17 +396,18 @@ void OggDecoder::update()
|
||||||
|
|
||||||
void OggDecoder::stop()
|
void OggDecoder::stop()
|
||||||
{
|
{
|
||||||
if (!playing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
#ifdef BBGE_BUILD_SDL
|
|
||||||
if (thread)
|
if (thread)
|
||||||
{
|
playing = false; // The background thread will take care of deletion then.
|
||||||
stop_thread = true;
|
else
|
||||||
SDL_WaitThread(thread, NULL);
|
delete this;
|
||||||
thread = NULL;
|
}
|
||||||
}
|
|
||||||
#endif
|
void OggDecoder::_stop()
|
||||||
|
{
|
||||||
|
playing = false;
|
||||||
|
|
||||||
|
if (stopped)
|
||||||
|
return;
|
||||||
|
|
||||||
ov_clear(&vf);
|
ov_clear(&vf);
|
||||||
|
|
||||||
|
@ -342,6 +424,7 @@ void OggDecoder::stop()
|
||||||
alDeleteBuffers(1, &buffers[i]);
|
alDeleteBuffers(1, &buffers[i]);
|
||||||
buffers[i] = 0;
|
buffers[i] = 0;
|
||||||
}
|
}
|
||||||
|
stopped = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
double OggDecoder::position()
|
double OggDecoder::position()
|
||||||
|
@ -352,27 +435,6 @@ double OggDecoder::position()
|
||||||
return (double)samples_played / (double)freq;
|
return (double)samples_played / (double)freq;
|
||||||
}
|
}
|
||||||
|
|
||||||
void OggDecoder::decode_loop(OggDecoder *this_)
|
|
||||||
{
|
|
||||||
while (!this_->stop_thread)
|
|
||||||
{
|
|
||||||
#ifdef BBGE_BUILD_SDL
|
|
||||||
SDL_Delay(10);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int processed = 0;
|
|
||||||
alGetSourcei(this_->source, AL_BUFFERS_PROCESSED, &processed);
|
|
||||||
for (int i = 0; i < processed; i++)
|
|
||||||
{
|
|
||||||
this_->samples_done += BUFFER_LENGTH;
|
|
||||||
ALuint buffer = 0;
|
|
||||||
alSourceUnqueueBuffers(this_->source, 1, &buffer);
|
|
||||||
if (buffer)
|
|
||||||
this_->queue(buffer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if (defined(BBGE_BUILD_SDL) && (SDL_BYTEORDER == SDL_BIG_ENDIAN))
|
#if (defined(BBGE_BUILD_SDL) && (SDL_BYTEORDER == SDL_BIG_ENDIAN))
|
||||||
#define BBGE_BIGENDIAN 1
|
#define BBGE_BIGENDIAN 1
|
||||||
#else
|
#else
|
||||||
|
@ -675,16 +737,16 @@ void OpenALChannel::setGroupVolume(const float _volume)
|
||||||
bool OpenALChannel::start(OpenALSound *sound)
|
bool OpenALChannel::start(OpenALSound *sound)
|
||||||
{
|
{
|
||||||
if (decoder)
|
if (decoder)
|
||||||
delete decoder;
|
delete decoder;
|
||||||
if (sound->getFile())
|
if (sound->getFile())
|
||||||
decoder = new OggDecoder(sound->getFile());
|
decoder = new OggDecoder(sound->getFile());
|
||||||
else
|
else
|
||||||
decoder = new OggDecoder(sound->getData(), sound->getSize());
|
decoder = new OggDecoder(sound->getData(), sound->getSize());
|
||||||
if (!decoder->start(sid, sound->isLooping()))
|
if (!decoder->start(sid, sound->isLooping()))
|
||||||
{
|
{
|
||||||
delete decoder;
|
delete decoder;
|
||||||
decoder = NULL;
|
decoder = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -693,8 +755,8 @@ void OpenALChannel::update()
|
||||||
{
|
{
|
||||||
if (inuse)
|
if (inuse)
|
||||||
{
|
{
|
||||||
if (decoder)
|
if (decoder)
|
||||||
decoder->update();
|
decoder->update();
|
||||||
ALint state = 0;
|
ALint state = 0;
|
||||||
alGetSourceiv(sid, AL_SOURCE_STATE, &state);
|
alGetSourceiv(sid, AL_SOURCE_STATE, &state);
|
||||||
SANITY_CHECK_OPENAL_CALL();
|
SANITY_CHECK_OPENAL_CALL();
|
||||||
|
@ -967,8 +1029,8 @@ FMOD_RESULT OpenALChannel::stop()
|
||||||
{
|
{
|
||||||
if (decoder)
|
if (decoder)
|
||||||
{
|
{
|
||||||
delete decoder;
|
decoder->stop();
|
||||||
decoder = NULL;
|
decoder = NULL;
|
||||||
}
|
}
|
||||||
alSourceStop(sid);
|
alSourceStop(sid);
|
||||||
SANITY_CHECK_OPENAL_CALL();
|
SANITY_CHECK_OPENAL_CALL();
|
||||||
|
@ -1248,6 +1310,9 @@ FMOD_RESULT OpenALSystem::init(int maxchannels, const FMOD_INITFLAGS flags, cons
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Using " << num_channels << " sound channels.";
|
ss << "Using " << num_channels << " sound channels.";
|
||||||
debugLog(ss.str());
|
debugLog(ss.str());
|
||||||
|
|
||||||
|
OggDecoder::startDecoderThread();
|
||||||
|
|
||||||
return FMOD_OK;
|
return FMOD_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1301,6 +1366,8 @@ FMOD_RESULT OpenALSystem::playSound(FMOD_CHANNELINDEX channelid, Sound *_sound,
|
||||||
ALBRIDGE(System,release,(),())
|
ALBRIDGE(System,release,(),())
|
||||||
FMOD_RESULT OpenALSystem::release()
|
FMOD_RESULT OpenALSystem::release()
|
||||||
{
|
{
|
||||||
|
OggDecoder::stopDecoderThread();
|
||||||
|
|
||||||
ALCcontext *ctx = alcGetCurrentContext();
|
ALCcontext *ctx = alcGetCurrentContext();
|
||||||
if (ctx)
|
if (ctx)
|
||||||
{
|
{
|
||||||
|
|
75
BBGE/MT.cpp
Normal file
75
BBGE/MT.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
#include "MT.h"
|
||||||
|
#include "Base.h"
|
||||||
|
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
|
||||||
|
// --------- Lockable ----------
|
||||||
|
|
||||||
|
Lockable::Lockable()
|
||||||
|
: _mtx(NULL)
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
_mtx = SDL_CreateMutex();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Lockable::~Lockable()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_DestroyMutex((SDL_mutex*)_mtx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lockable::lock()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_LockMutex((SDL_mutex*)_mtx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Lockable::unlock()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_UnlockMutex((SDL_mutex*)_mtx);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// --------- Waitable ----------
|
||||||
|
|
||||||
|
Waitable::Waitable()
|
||||||
|
: _cond(NULL)
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
_cond = SDL_CreateCond();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
Waitable::~Waitable()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_DestroyCond((SDL_cond*)_cond);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Waitable::wait()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_CondWait((SDL_cond*)_cond, (SDL_mutex*)mutex());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Waitable::signal()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_CondSignal((SDL_cond*)_cond);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void Waitable::broadcast()
|
||||||
|
{
|
||||||
|
#ifdef BBGE_BUILD_SDL
|
||||||
|
SDL_CondBroadcast((SDL_cond*)_cond);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BBGE_BUILD_SDL
|
117
BBGE/MT.h
Normal file
117
BBGE/MT.h
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
#ifndef BBGE_MT_H
|
||||||
|
#define BBGE_MT_H
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <queue>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
class Lockable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Lockable();
|
||||||
|
virtual ~Lockable();
|
||||||
|
void lock();
|
||||||
|
void unlock();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
inline void *mutex() { return _mtx; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *_mtx;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Waitable : public Lockable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Waitable();
|
||||||
|
virtual ~Waitable();
|
||||||
|
void wait(); // releases the associated lock while waiting
|
||||||
|
void signal(); // signal a single waiting thread
|
||||||
|
void broadcast(); // signal all waiting threads
|
||||||
|
|
||||||
|
private:
|
||||||
|
void *_cond;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MTGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
MTGuard(Lockable& x) : _obj(&x) { _obj->lock(); }
|
||||||
|
MTGuard(Lockable* x) : _obj(x) { _obj->lock(); }
|
||||||
|
~MTGuard() { _obj->unlock(); }
|
||||||
|
Lockable *_obj;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class BlockingQueue : public Waitable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void push(const T& e)
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
_q.push(e);
|
||||||
|
unlock();
|
||||||
|
signal();
|
||||||
|
}
|
||||||
|
bool pop(T& e) // blocks if empty
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
while(_q.empty())
|
||||||
|
wait();
|
||||||
|
e = _q.front();
|
||||||
|
_q.pop();
|
||||||
|
unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::queue<T> _q;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class LockedQueue : public Lockable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void push(const T& e)
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
_q.push(e);
|
||||||
|
unlock();
|
||||||
|
}
|
||||||
|
bool pop(T& e) // continues if empty
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
if(_q.empty())
|
||||||
|
{
|
||||||
|
unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
e = _q.front();
|
||||||
|
_q.pop();
|
||||||
|
unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bool empty()
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
bool e = _q.empty();
|
||||||
|
unlock();
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
bool popIfPossible(T& e)
|
||||||
|
{
|
||||||
|
lock();
|
||||||
|
if(!_q.empty())
|
||||||
|
{
|
||||||
|
e = _q.front();
|
||||||
|
_q.pop();
|
||||||
|
unlock();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
unlock();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::queue<T> _q;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -382,6 +382,7 @@ SET(BBGE_SRCS
|
||||||
${BBGEDIR}/Joystick.cpp
|
${BBGEDIR}/Joystick.cpp
|
||||||
${BBGEDIR}/LensFlare.cpp
|
${BBGEDIR}/LensFlare.cpp
|
||||||
${BBGEDIR}/Math.cpp
|
${BBGEDIR}/Math.cpp
|
||||||
|
${BBGEDIR}/MT.cpp
|
||||||
${BBGEDIR}/ParticleEffect.cpp
|
${BBGEDIR}/ParticleEffect.cpp
|
||||||
${BBGEDIR}/ParticleManager.cpp
|
${BBGEDIR}/ParticleManager.cpp
|
||||||
${BBGEDIR}/Particles.cpp
|
${BBGEDIR}/Particles.cpp
|
||||||
|
|
Loading…
Add table
Reference in a new issue