mirror of
https://github.com/tribes2/engine.git
synced 2026-01-19 19:24:45 +00:00
867 lines
22 KiB
C++
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
|