engine/platformLinux/lokiOpenAL.cc
2024-01-07 04:36:33 +00:00

867 lines
22 KiB
C++

//-----------------------------------------------------------------------------
// V12 Engine
//
// Copyright (c) 2001 GarageGames.Com
// Portions Copyright (c) 2001 by Sierra Online, Inc.
//-----------------------------------------------------------------------------
#ifdef DEDICATED
// Stubs for the dedicated server
bool bindOpenALFunctions(void)
{
return false;
}
void unbindOpenALFunctions(void)
{
return;
}
#else
// Code for the Linux client
#include <dlfcn.h>
#include "engine/console/console.h"
#include "engine/core/fileio.h"
#include "engine/core/tVector.h"
#include "engine/platformWIN32/platformAL.h"
// For the MP3 playback support
#include "SDL.h"
#include "smpeg.h"
static void *hinstOpenAL = NULL;
// declare DLL loaded OpenAL functions
#define AL_FUNCTION(fn_return,fn_name,fn_args) fn_return (*OpenAL_##fn_name)fn_args = NULL;
#define AL_EXT_FUNCTION(ext_name,fn_return,fn_name,fn_args) fn_return (*OpenAL_##fn_name)fn_args = NULL;
// An API change in OpenAL 1.0 - the context creation takes a device handle
AL_FUNCTION(ALCdevice *, alcOpenDevice, ( const ALubyte *tokstr ));
AL_FUNCTION(ALvoid, alcCloseDevice, ( ALCdevice *dev ));
AL_FUNCTION(ALvoid, alDistanceModel, ( ALenum distanceModel ));
ALvoid* (*OpenAL10_alcCreateContext)( struct _AL_device *dev, ALint* attrlist ) = NULL;
#include "lib/openal/win32/openALFn.h"
// Loki functions: ---------------------------------------------------------
// Used by alutInit() and alutExit() for device context handling
static void *context_id;
static ALCdevice *dev;
typedef struct fakeCallbackPair_s {
U32 sid;
void (*proc)(U32, bool);
} fakeCallbackPair_t;
static Vector< fakeCallbackPair_t > fakeCallbackFake(__FILE__, __LINE__);
void alxFakeCallbackUpdate( void )
{
fakeCallbackPair_t pi;
ALuint state;
int i;
i = fakeCallbackFake.size();
while( i-- ) {
pi = fakeCallbackFake.last();
fakeCallbackFake.pop_back();
state = AL_INITIAL;
alGetSourcei( pi.sid, AL_SOURCE_STATE, &state );
if( state == AL_STOPPED )
{
Con::printf( "Calling callback for %d", pi.sid);
pi.proc( pi.sid, false );
} else {
fakeCallbackFake.push_front( pi );
}
}
}
// Code for MP3 playback support
static SMPEG *mpeg = NULL;
#define MAX_MPEG_READ 512
static ALint MP3_Callback(ALuint sid,
ALuint bid,
ALshort *outdata,
ALenum format,
ALint freq,
ALint samples)
{
int bytesRequested = samples * sizeof( ALshort );
int bytesPlayed;
int i;
if(samples > MAX_MPEG_READ) {
int first, second;
first = MP3_Callback(sid, bid, outdata, format, freq, MAX_MPEG_READ);
second = MP3_Callback(sid, bid, outdata + MAX_MPEG_READ, format, freq, samples - MAX_MPEG_READ);
return first + second;
}
if( SMPEG_status(mpeg) != SMPEG_PLAYING ) {
SMPEG_play( mpeg );
}
memset( outdata, 0, bytesRequested );
bytesPlayed = SMPEG_playAudio( mpeg, (ALubyte *) outdata, bytesRequested );
bytesPlayed /= sizeof( ALshort );
if(bytesPlayed < samples) {
SMPEG_stop( mpeg );
SMPEG_rewind( mpeg );
return bytesPlayed;
}
return samples;
}
ALboolean alutLoadMP3_LOKI(ALuint bid, ALvoid *data, ALint size)
{
void (*alBufferDataWithCallback)(ALuint bid,
int (*Callback)(ALuint, ALuint, ALshort *, ALenum, ALint, ALint));
SDL_AudioSpec spec;
alBufferDataWithCallback = (void (*)(ALuint bid,
int (*Callback)(ALuint, ALuint, ALshort *, ALenum, ALint, ALint)))
alGetProcAddress((ALubyte *) "alBufferDataWithCallback_LOKI");
if(alBufferDataWithCallback == NULL) {
Con::errorf(ConsoleLogEntry::General, "Need alBufferDataWithCallback()");
return AL_FALSE;
}
if ( mpeg != NULL ) {
SMPEG_stop(mpeg);
SMPEG_delete(mpeg);
}
mpeg = SMPEG_new_data( data, size, NULL, 0 );
if ( mpeg == NULL ) {
Con::errorf( ConsoleLogEntry::General, "Unable to allocate MP3 data");
return AL_FALSE;
}
SMPEG_wantedSpec( mpeg, &spec );
spec.freq = Con::getIntVariable( "$pref::Audio::frequency", 22050 );
spec.format = AUDIO_S16;
/* implicitly multichannel */
alBufferi_EXT( bid, AL_CHANNELS, spec.channels );
SMPEG_actualSpec( mpeg, &spec );
SMPEG_enableaudio( mpeg, 1 );
SMPEG_enablevideo( mpeg, 0 ); /* sanity check */
alBufferDataWithCallback(bid, MP3_Callback);
return AL_TRUE;
}
// AL functions
ALvoid loki_alEnable( ALenum capability )
{
OpenAL_alEnable( capability );
}
ALvoid loki_alDisable( ALenum capability )
{
OpenAL_alDisable( capability );
}
ALboolean loki_alIsEnabled( ALenum capability )
{
return OpenAL_alIsEnabled( capability );
}
ALvoid loki_alHint( ALenum target, ALenum mode )
{
OpenAL_alHint( target, mode );
}
ALboolean loki_alGetBoolean( ALenum param )
{
return OpenAL_alGetBoolean( param );
}
ALint loki_alGetInteger( ALenum param )
{
return OpenAL_alGetInteger( param );
}
ALfloat loki_alGetFloat( ALenum param )
{
return OpenAL_alGetFloat( param );
}
ALdouble loki_alGetDouble( ALenum param )
{
return OpenAL_alGetDouble( param );
}
ALvoid loki_alGetBooleanv( ALenum param, ALboolean* data )
{
OpenAL_alGetBooleanv( param, data );
}
ALvoid loki_alGetIntegerv( ALenum param, ALint* data )
{
OpenAL_alGetIntegerv( param, data );
}
ALvoid loki_alGetFloatv( ALenum param, ALfloat* data )
{
OpenAL_alGetFloatv( param, data );
}
ALvoid loki_alGetDoublev( ALenum param, ALdouble* data )
{
OpenAL_alGetDoublev( param, data );
}
const ALubyte* loki_alGetString( ALenum param )
{
const ALubyte* string;
switch (param) {
case AL_EXTENSIONS:
string = "AL_EXT_DYNAMIX";
break;
default:
string = OpenAL_alGetString( param );
break;
}
return string;
}
ALenum loki_alGetError( ALvoid )
{
ALenum error;
error = AL_NO_ERROR;
error += OpenAL_alGetError( );
error += OpenAL_alcGetError( );
return error;
}
ALboolean loki_alIsExtensionPresent( const ALubyte* fname )
{
ALboolean value;
if ( dStrcmp(fname, "AL_EXT_DYNAMIX") == 0 ) {
value = true;
} else {
value = OpenAL_alIsExtensionPresent( fname );
}
return value;
}
ALvoid* loki_alGetProcAddress( const ALubyte* fname )
{
return OpenAL_alGetProcAddress( fname );
}
ALenum loki_alGetEnumValue( const ALubyte* ename )
{
return OpenAL_alGetEnumValue( ename );
}
ALvoid loki_alListenerf( ALenum pname, ALfloat param )
{
OpenAL_alListenerf( pname, param );
}
ALvoid loki_alListener3f( ALenum pname, ALfloat param1, ALfloat param2, ALfloat param3 )
{
OpenAL_alListener3f( pname, param1, param2, param3 );
}
ALvoid loki_alListenerfv( ALenum pname, ALfloat* param )
{
OpenAL_alListenerfv( pname, param );
}
ALvoid loki_alGetListeneri( ALenum pname, ALint* value )
{
OpenAL_alGetListeneri( pname, value );
}
ALvoid loki_alGetListenerf( ALenum pname, ALfloat* values )
{
OpenAL_alGetListenerf( pname, values );
}
ALvoid loki_alGetListenerfv( ALenum pname, ALfloat* values )
{
OpenAL_alGetListenerfv( pname, values );
}
ALvoid loki_alGenSources( ALsizei n, ALuint* sources )
{
OpenAL_alGenSources( n, sources );
}
ALvoid loki_alDeleteSources( ALsizei n, ALuint* sources )
{
OpenAL_alDeleteSources( n, sources );
}
ALboolean loki_alIsSource( ALuint sid )
{
return OpenAL_alIsSource( sid );
}
ALvoid loki_alSourcei( ALuint sid, ALenum param, ALint value )
{
switch (param) {
case AL_STREAMING:
case AL_ENV_SAMPLE_DIRECT_EXT:
case AL_ENV_SAMPLE_DIRECT_HF_EXT:
case AL_ENV_SAMPLE_ROOM_EXT:
case AL_ENV_SAMPLE_ROOM_HF_EXT:
case AL_ENV_SAMPLE_OUTSIDE_VOLUME_HF_EXT:
case AL_ENV_SAMPLE_FLAGS_EXT:
// Not yet supported
break;
case AL_SOURCE_AMBIENT:
// Special case, emulated by positioning relative sources
if ( value ) {
alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE);
alSource3f(sid, AL_POSITION, 0.0, 0.0, 0.0);
} else {
alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE);
}
break;
default:
// Pass through to OpenAL 1.0
OpenAL_alSourcei( sid, param, value );
break;
}
}
ALvoid loki_alSourcef( ALuint sid, ALenum param, ALfloat value )
{
switch (param) {
case AL_PAN:
case AL_ENV_SAMPLE_REVERB_MIX_EXT:
case AL_ENV_SAMPLE_OBSTRUCTION_EXT:
case AL_ENV_SAMPLE_OBSTRUCTION_LF_RATIO_EXT:
case AL_ENV_SAMPLE_OCCLUSION_EXT:
case AL_ENV_SAMPLE_OCCLUSION_ROOM_RATIO_EXT:
case AL_ENV_SAMPLE_ROOM_ROLLOFF_EXT:
case AL_ENV_SAMPLE_AIR_ABSORPTION_EXT:
// Not yet supported
break;
default:
// Pass through to OpenAL 1.0
OpenAL_alSourcef( sid, param, value );
break;
}
}
ALvoid loki_alSource3f( ALuint sid, ALenum param, ALfloat v1, ALfloat v2, ALfloat v3 )
{
OpenAL_alSource3f( sid, param, v1, v2, v3 );
}
ALvoid loki_alSourcefv( ALuint sid, ALenum param, ALfloat* values )
{
OpenAL_alSourcefv( sid, param, values );
}
ALvoid loki_alGetSourcei( ALuint sid, ALenum pname, ALint* value )
{
switch (pname) {
case AL_SOURCE_AMBIENT:
// Special case, emulated by positioning relative sources
alGetSourcei(sid, AL_SOURCE_RELATIVE, value);
break;
default:
// Pass through to OpenAL 1.0
OpenAL_alGetSourcei( sid, pname, value );
break;
}
}
ALvoid loki_alGetSourcef( ALuint sid, ALenum pname, ALfloat* value )
{
OpenAL_alGetSourcef( sid, pname, value );
}
ALvoid loki_alGetSourcefv( ALuint sid, ALenum pname, ALfloat* values )
{
OpenAL_alGetSourcefv( sid, pname, values );
}
ALvoid loki_alSourcePlayv( ALuint ns, ALuint* ids )
{
OpenAL_alSourcePlayv( ns, ids );
}
ALvoid loki_alSourceStopv( ALuint ns, ALuint* ids )
{
OpenAL_alSourceStopv( ns, ids );
}
ALvoid loki_alSourcePlay( ALuint sid )
{
OpenAL_alSourcePlay( sid );
}
ALvoid loki_alSourcePause( ALuint sid )
{
OpenAL_alSourcePause( sid );
}
ALvoid loki_alSourceStop( ALuint sid )
{
OpenAL_alSourceStop( sid );
}
ALvoid loki_alGenBuffers( ALsizei n, ALuint* samples )
{
OpenAL_alGenBuffers( n, samples );
}
ALvoid loki_alDeleteBuffers( ALsizei n, ALuint* samples )
{
OpenAL_alDeleteBuffers( n, samples );
}
ALboolean loki_alIsBuffer( ALuint buffer )
{
return OpenAL_alIsBuffer( buffer );
}
ALvoid loki_alBufferData( ALuint buffer, ALenum format, ALvoid* data, ALsizei size, ALsizei freq )
{
OpenAL_alBufferData( buffer, format, data, size, freq );
}
ALsizei loki_alBufferAppendData( ALuint buffer, ALenum format, ALvoid* data, ALsizei size, ALsizei freq )
{
return OpenAL_alBufferAppendData( buffer, format, data, size, freq );
}
ALvoid loki_alGetBufferi( ALuint buffer, ALenum param, ALint* value )
{
OpenAL_alGetBufferi( buffer, param, value );
}
ALvoid loki_alGetBufferf( ALuint buffer, ALenum param, ALfloat* value )
{
OpenAL_alGetBufferf( buffer, param, value );
}
// ALC functions
ALvoid* loki_alcCreateContext( ALint* attrlist )
{
return OpenAL10_alcCreateContext( dev, attrlist );
}
ALCenum loki_alcMakeContextCurrent( ALvoid* context )
{
return OpenAL_alcMakeContextCurrent( context );
}
ALvoid* loki_alcUpdateContext( ALvoid* context )
{
return OpenAL_alcUpdateContext( context );
}
ALCenum loki_alcDestroyContext( ALvoid* context )
{
return OpenAL_alcDestroyContext( context );
}
ALCenum loki_alcGetError( ALvoid )
{
return OpenAL_alcGetError( );
}
const ALubyte * loki_alcGetErrorString( ALvoid )
{
return OpenAL_alcGetErrorString( );
}
ALvoid* loki_alcGetCurrentContext( ALvoid )
{
return OpenAL_alcGetCurrentContext( );
}
// ALUT functions
void loki_alutInit( int* argc, char** argv )
{
char devstr_buf[1024];
const char *devstr;
const char *paren;
int refresh, frequency;
ALint attrlist[5];
// Get some basic configuration variables
refresh = Con::getIntVariable( "$pref::Audio::refresh", 15 );
frequency = Con::getIntVariable( "$pref::Audio::frequency", 22050 );
// Open the audio device
devstr = Con::getVariable("$pref::OpenAL::driver");
if ( devstr && ((paren=strrchr(devstr, ')')) != NULL) ) {
// Make sure a sane sampling rate is specified
if ( strstr(devstr, "sampling-rate") == NULL ) {
strcpy(devstr_buf, devstr);
sprintf(&devstr_buf[paren-devstr],
" (sampling-rate %d ))", frequency);
devstr = devstr_buf;
}
} else {
sprintf(devstr_buf, "'( (sampling-rate %d ))", frequency);
devstr = devstr_buf;
}
dev = OpenAL_alcOpenDevice( (const ALubyte *) devstr );
if( dev == NULL ) {
Con::errorf( ConsoleLogEntry::General, "Audio device open failed..." );
return;
}
attrlist[0] = ALC_FREQUENCY;
attrlist[1] = frequency;
attrlist[2] = ALC_REFRESH;
attrlist[3] = refresh;
attrlist[4] = 0;
context_id = alcCreateContext( attrlist );
if( context_id == NULL ) {
Con::errorf( ConsoleLogEntry::General, "Audio context creation failed, exiting..." );
Platform::forceShutdown( 1 );
return;
}
alcMakeContextCurrent( context_id );
// Set the distance attenuation model
OpenAL_alDistanceModel(AL_INVERSE_DISTANCE_CLAMPED);
}
void loki_alutExit( ALvoid )
{
if( context_id != NULL ) {
alcDestroyContext( context_id );
OpenAL_alcCloseDevice( dev );
context_id = NULL;
}
}
ALboolean loki_alutLoadWAV( const char* fname, ALvoid** data, ALsizei* format, ALsizei* size, ALsizei* bits, ALsizei* freq )
{
return OpenAL_alutLoadWAV( fname, data, format, size, bits, freq );
}
// Extensions
ALvoid loki_alGenEnvironmentIASIG( ALsizei n, ALuint* environs )
{
OpenAL_alGenEnvironmentIASIG( n, environs );
}
ALvoid loki_alDeleteEnvironmentIASIG( ALsizei n, ALuint* environs )
{
OpenAL_alDeleteEnvironmentIASIG( n, environs );
}
ALboolean loki_alIsEnvironmentIASIG( ALuint environment )
{
return OpenAL_alIsEnvironmentIASIG( environment );
}
ALvoid loki_alEnvironmentiIASIG( ALuint eid, ALenum param, ALint value )
{
OpenAL_alEnvironmentiIASIG( eid, param, value );
}
ALboolean loki_alBufferi_EXT( ALuint buffer, ALenum pname, ALint value )
{
ALboolean status;
alGetError();
switch (pname) {
case AL_BUFFER_KEEP_RESIDENT:
status = false;
break;
default:
OpenAL_alBufferi_EXT( buffer, pname, value );
status = (alGetError() == AL_NO_ERROR);
break;
}
return status;
}
ALboolean loki_alBufferSyncData_EXT( ALuint buffer, ALenum format, ALvoid* data, ALsizei size, ALsizei freq )
{
ALboolean status;
// alBufferData doesn't return a value,
// so clear the error setting, execute,
// and check again.
alGetError( );
alBufferData(buffer, format, data, size, freq);
if( alGetError( ) == AL_NO_ERROR ) {
// let AL manage the memory
dFree( data );
status = true;
} else {
status = false;
}
return status;
}
ALboolean loki_alBufferStreamFile_EXT( ALuint buffer, const ALubyte* filename )
{
File file;
file.open( (const char*) filename, File::Read );
if( file.getStatus( ) != File::Ok ) {
return AL_FALSE;
}
U32 size = file.getSize( );
char* data = (char*) dMalloc( size );
if( data == NULL ) {
// technically, 'file' will go out of scope and
// close itself, but still...
file.close( );
return AL_FALSE;
}
file.read( size, data );
if( file.getStatus( ) != File::Ok ) {
file.close( );
dFree( data );
return AL_FALSE;
}
U32 ext = dStrlen( filename );
ext -= 3;
ext = ( ext >= 0 ) ? ext : 0;
ALuint ok = AL_FALSE;
if( dStrnicmp( &filename[ ext ], "mp3", 3 ) != 0 ) {
alGetError();
alBufferData( buffer, AL_FORMAT_WAVE_EXT, data, size, 0 );
ok = (alGetError() == AL_NO_ERROR);
} else {
ok = alutLoadMP3_LOKI( buffer, data, size );
}
dFree( data );
file.close( );
if( ok == AL_FALSE ) {
Con::warnf( ConsoleLogEntry::General,
"could not buffer and convert %s", filename );
return AL_FALSE;
}
return AL_TRUE;
}
ALboolean loki_alSourceCallback_EXT( ALuint source, ALvoid* callback )
{
fakeCallbackPair_t pusher;
if( alIsSource( source ) == AL_FALSE) {
Con::errorf(ConsoleLogEntry::General,
"alSourceCallback_EXT: %d not a source id", source );
return;
}
pusher.sid = source;
pusher.proc = callback;
fakeCallbackFake.push_back( pusher );
}
ALvoid loki_alSourceResetEnvironment_EXT( ALuint source )
{
return; // Nothing we can do here yet...
}
ALboolean loki_alContexti_EXT( ALenum pname, ALint value )
{
return false;
}
ALboolean loki_alGetContexti_EXT( ALenum pname, ALint* value )
{
ALboolean status;
status = false;
if( value ) {
switch( pname ) {
case ALC_PROVIDER:
*value = 0;
status = true;
break;
case ALC_PROVIDER_COUNT:
*value = 1;
status = true;
break;
case ALC_SPEAKER:
*value = 0;
status = true;
break;
case ALC_SPEAKER_COUNT:
*value = 1;
status = true;
break;
case ALC_BUFFER_MEMORY_USAGE:
*value = 0;
status = true;
break;
case ALC_BUFFER_MEMORY_SIZE:
*value = 1 << 16;
status = true;
break;
case ALC_BUFFER_MEMORY_COUNT:
*value = 0;
status = true;
break;
case ALC_BUFFER_COUNT:
*value = 0;
status = true;
break;
default:
// error
break;
}
}
return status;
}
ALboolean loki_alGetContextstr_EXT( ALenum pname, ALuint idx, ALubyte** value )
{
ALboolean status;
status = false;
if( value ) {
switch( pname ) {
case ALC_PROVIDER_NAME:
*value = "Loki Software, Inc.";
status = true;
break;
case ALC_SPEAKER_NAME:
*value = "Stereo, 2-Speaker";
status = true;
break;
default:
// error
break;
}
}
return status;
}
ALboolean loki_alCaptureInit_EXT( ALenum format, ALuint rate, ALsizei bufferSize )
{
return OpenAL_alCaptureInit_EXT( format, rate, bufferSize );
}
ALboolean loki_alCaptureDestroy_EXT( ALvoid )
{
return OpenAL_alCaptureDestroy_EXT( );
}
ALboolean loki_alCaptureStart_EXT( ALvoid )
{
return OpenAL_alCaptureStart_EXT( );
}
ALboolean loki_alCaptureStop_EXT( ALvoid )
{
return OpenAL_alCaptureStop_EXT( );
}
ALsizei loki_alCaptureGetData_EXT( ALvoid* data, ALsizei n, ALenum format, ALuint rate )
{
return OpenAL_alCaptureGetData_EXT( data, n, format, rate );
}
ALvoid loki_alEnvironmentfIASIG( ALuint eid, ALenum param, ALfloat value )
{
return; // Nothing we can do here yet...
}
ALvoid loki_alGetEnvironmentiIASIG_EXT( ALuint eid, ALenum param, ALint * value )
{
return; // Nothing we can do here yet...
}
ALvoid loki_alGetEnvironmentfIASIG_EXT( ALuint eid, ALenum param, ALfloat * value )
{
return; // Nothing we can do here yet...
}
// DLL's: ------------------------------------------------------------------
static bool findExtension( const char* name )
{
bool result = false;
if (alGetString != NULL)
{
result = dStrstr( (const char*)alGetString(AL_EXTENSIONS), name) != NULL;
}
return result;
}
static bool bindFunction( void *&fnAddress, const char *name )
{
fnAddress = dlsym( hinstOpenAL, name );
#ifdef DEBUG_OPENAL
if( !fnAddress ) {
Con::errorf(ConsoleLogEntry::General, " Missing OpenAL function '%s'", name);
}
#endif
return (fnAddress != NULL);
}
static void bindExtension( void *&fnAddress, const char *name, bool &supported )
{
if (supported)
{
bindFunction(fnAddress, name);
#if 0
if (fnAddress == NULL)
supported = false;
#endif
}
else
fnAddress = NULL;
}
static bool bindDLLFunctions()
{
bool result = true;
/* It's okay if the following functions are not found:
alGetBoolean()
alGetInteger()
alGetFloat()
alGetDouble()
alcUpdateContext()
alcGetErrorString()
*/
#define AL_EXTENSION(ext_name) \
gDoesSupport_##ext_name = findExtension(#ext_name);
#define AL_FUNCTION(fn_return,fn_name,fn_args) \
{ const char *name = #fn_name; \
/* Do some renaming of functions to match OpenAL 1.0 API */ \
if ( dStrcmp(name, "alGetListeneri") == 0 ) \
name = "alGetListeneriv"; \
else \
if ( dStrcmp(name, "alGetListenerf") == 0 ) \
name = "alGetListenerfv"; \
else \
if ( dStrcmp(name, "alGetSourcei") == 0 ) \
name = "alGetSourceiv"; \
else \
if ( dStrcmp(name, "alGetSourcef") == 0 ) \
name = "alGetSourcefv"; \
else \
if ( dStrcmp(name, "alBufferi_EXT") == 0 ) \
name = "alBufferi_LOKI"; \
result &= bindFunction( *(void**)&OpenAL_##fn_name, name); \
}
#define AL_EXT_FUNCTION(ext_name,fn_return,fn_name,fn_args) \
{ const char *name = #fn_name; \
/* Do some renaming of functions to match OpenAL 1.0 API */ \
if ( dStrcmp(name, "alBufferi_EXT") == 0 ) \
name = "alBufferi_LOKI"; \
bindExtension( *(void**)&OpenAL_##fn_name, name, gDoesSupport_##ext_name); \
}
AL_FUNCTION(ALCdevice *, alcOpenDevice, ( const ALubyte *tokstr ));
AL_FUNCTION(ALvoid, alcCloseDevice, ( ALCdevice *dev ));
AL_FUNCTION(ALvoid, alDistanceModel, ( ALenum distanceModel ));
result &= bindFunction( *(void**)&OpenAL10_alcCreateContext, "alcCreateContext");
#include "lib/openal/win32/openALFn.h"
return result;
}
bool bindOpenALFunctions(void)
{
hinstOpenAL = dlopen( "./libopenal.so.0", RTLD_NOW );
if(hinstOpenAL == NULL)
{
return false;
}
// Set the Loki OpenAL function pointers (needed for extension loading)
#define AL_EXTENSION(ext_name) gDoesSupport_##ext_name = false;
#define AL_FUNCTION(fn_return,fn_name,fn_parms) fn_name = loki_##fn_name;
#define AL_EXT_FUNCTION(ext_name,fn_return,fn_name,fn_args) fn_name = loki_##fn_name;
#include "lib/openal/win32/openALFn.h"
// Load the real OpenAL functions from the shared library
bindDLLFunctions();
// Yay, we're done!
return true;
}
void unbindOpenALFunctions(void)
{
if (hinstOpenAL)
dlclose(hinstOpenAL);
hinstOpenAL = NULL;
}
#endif // DEDICATED