+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "Quaternions.h"
+#include "openal_wrapper.h"
+#include "Sounds.h"
+
+// NOTE:
+// FMOD uses a Left Handed Coordinate system, OpenAL uses a Right Handed
+// one...so we just need to flip the sign on the Z axis when appropriate.
+
+#define DYNAMIC_LOAD_OPENAL 0
+
+#if DYNAMIC_LOAD_OPENAL
+
+#include <dlfcn.h>
+
+#define AL_FUNC(t,ret,fn,params,call,rt) \
+ extern "C" { \
+ static ret ALAPIENTRY (*p##fn) params = NULL; \
+ ret ALAPIENTRY fn params { rt p##fn call; } \
+ }
+#include "alstubs.h"
+#undef AL_FUNC
+
+static void *aldlhandle = NULL;
+
+static bool lookup_alsym(const char *funcname, void **func, const char *libname)
+{
+ if (!aldlhandle)
+ return false;
+
+ *func = dlsym(aldlhandle, funcname);
+ if (*func == NULL) {
+ fprintf(stderr, "Failed to find OpenAL symbol \"%s\" in \"%s\"\n",
+ funcname, libname);
+ return false;
+ }
+ return true;
+}
+
+static void unload_alsyms(void)
+{
+#define AL_FUNC(t,ret,fn,params,call,rt) p##fn = NULL;
+#include "alstubs.h"
+#undef AL_FUNC
+ if (aldlhandle) {
+ dlclose(aldlhandle);
+ aldlhandle = NULL;
+ }
+}
+
+static bool lookup_all_alsyms(const char *libname)
+{
+ if (!aldlhandle) {
+ if ( (aldlhandle = dlopen(libname, RTLD_GLOBAL | RTLD_NOW)) == NULL )
+ return false;
+ }
+
+ bool retval = true;
+#define AL_FUNC(t,ret,fn,params,call,rt) \
+ if (!lookup_alsym(#fn, (void **) &p##fn, libname)) retval = false;
+#include "alstubs.h"
+#undef AL_FUNC
+
+ if (!retval)
+ unload_alsyms();
+
+ return retval;
+}
+#else
+#define lookup_all_alsyms(x) (true)
+#define unload_alsyms()
+#endif
+
+typedef struct {
+ ALuint sid;
+ OPENAL_SAMPLE *sample;
+ bool startpaused;
+ float position[3];
+} OPENAL_Channels;
+
+typedef struct OPENAL_SAMPLE {
+ char *name;
+ ALuint bid; // buffer id.
+ int mode;
+ int is2d;
+} OPENAL_SAMPLE;
+
+static size_t num_channels = 0;
+static OPENAL_Channels *impl_channels = NULL;
+static bool initialized = false;
+static float listener_position[3];
+
+static void set_channel_position(const int channel, const float x,
+ const float y, const float z)
+{
+ OPENAL_Channels *chan = &impl_channels[channel];
+
+ chan->position[0] = x;
+ chan->position[1] = y;
+ chan->position[2] = z;
+
+ OPENAL_SAMPLE *sptr = chan->sample;
+ if (sptr == NULL)
+ return;
+
+ const ALuint sid = chan->sid;
+ const bool no_attenuate = sptr->is2d;
+
+ if (no_attenuate) {
+ alSourcei(sid, AL_SOURCE_RELATIVE, AL_TRUE);
+ alSource3f(sid, AL_POSITION, 0.0f, 0.0f, 0.0f);
+ } else {
+ alSourcei(sid, AL_SOURCE_RELATIVE, AL_FALSE);
+ alSource3f(sid, AL_POSITION, x, y, z);
+ }
+}
+
+
+AL_API void OPENAL_3D_Listener_SetAttributes(const float *pos, const float *vel, float fx, float fy, float fz, float tx, float ty, float tz)
+{
+ if (!initialized)
+ return;
+ if (pos != NULL) {
+ alListener3f(AL_POSITION, pos[0], pos[1], -pos[2]);
+ listener_position[0] = pos[0];
+ listener_position[1] = pos[1];
+ listener_position[2] = -pos[2];
+ }
+
+ ALfloat vec[6] = { fx, fy, -fz, tz, ty, -tz };
+ alListenerfv(AL_ORIENTATION, vec);
+
+ // we ignore velocity, since doppler's broken in the Linux AL at the moment...
+
+ // adjust existing positions...
+ for (int i = 0; i < num_channels; i++) {
+ const float *p = impl_channels[i].position;
+ set_channel_position(i, p[0], p[1], p[2]);
+ }
+}
+
+AL_API signed char OPENAL_3D_SetAttributes(int channel, const float *pos, const float *vel)
+{
+ if (!initialized)
+ return false;
+ if ((channel < 0) || (channel >= num_channels))
+ return false;
+
+ if (pos != NULL)
+ set_channel_position(channel, pos[0], pos[1], -pos[2]);