diff --git a/src/audio/audio.c b/src/audio/audio.c index f9bd65f4..9d56986d 100644 --- a/src/audio/audio.c +++ b/src/audio/audio.c @@ -2,11 +2,18 @@ #include "loaders/source.h" #include "util.h" #include +#include static AudioState state; static LPALCRESETDEVICESOFT alcResetDeviceSOFT; +static void cross(float ux, float uy, float uz, float vx, float vy, float vz, float* x, float* y, float* z) { + *x = uy * vz - uz * vy; + *y = ux * vz - uz * vx; + *z = ux * vy - uy * vx; +} + void lovrAudioInit() { ALCdevice* device = alcOpenDevice(NULL); if (!device) { @@ -65,15 +72,23 @@ void lovrAudioAdd(Source* source) { } } -void lovrAudioGetOrientation(float* fx, float* fy, float* fz, float* ux, float* uy, float* uz) { +void lovrAudioGetOrientation(float* angle, float* ax, float* ay, float* az) { float v[6]; alGetListenerfv(AL_ORIENTATION, v); - *fx = v[0]; - *fy = v[1]; - *fz = v[2]; - *ux = v[3]; - *uy = v[4]; - *uz = v[5]; + float cx, cy, cz; + cross(v[0], v[1], v[2], v[3], v[4], v[5], &cx, &cy, &cz); + float w = 1 + v[0] * v[3] + v[1] * v[4] + v[2] * v[5]; + *angle = 2 * acos(w); + float s = sqrt(1 - w * w); + if (w < .001) { + *ax = cx; + *ay = cy; + *az = cz; + } else { + *ax = cx / s; + *ay = cy / s; + *az = cz / s; + } } void lovrAudioGetPosition(float* x, float* y, float* z) { @@ -113,7 +128,47 @@ void lovrAudioRewind() { } } -void lovrAudioSetOrientation(float fx, float fy, float fz, float ux, float uy, float uz) { +// Help +void lovrAudioSetOrientation(float angle, float ax, float ay, float az) { + + // Quaternion + float cos2 = cos(angle / 2.f); + float sin2 = sin(angle / 2.f); + float qx = sin2 * ax; + float qy = sin2 * ay; + float qz = sin2 * az; + float s = cos2; + + float vx, vy, vz, qdotv, qdotq, a, b, c, cx, cy, cz; + + // Forward + vx = 0; + vy = 0; + vz = -1; + qdotv = qx * vx + qy * vy + qz * vz; + qdotq = qx * qx + qy * qy + qz * qz; + a = 2 * qdotv; + b = s * s - qdotq; + c = 2 * s; + cross(qx, qy, qz, vx, vy, vz, &cx, &cy, &cz); + float fx = a * qx + b * vx + c * cx; + float fy = a * qy + b * vy + c * cy; + float fz = a * qz + b * vz + c * cz; + + // Up + vx = 0; + vy = 1; + vz = 0; + qdotv = qx * vx + qy * vy + qz * vz; + qdotq = qx * qx + qy * qy + qz * qz; + a = 2 * qdotv; + b = s * s - qdotq; + c = 2 * s; + cross(qx, qy, qz, vx, vy, vz, &cx, &cy, &cz); + float ux = a * qx + b * vx + c * cx; + float uy = a * qy + b * vy + c * cy; + float uz = a * qz + b * vz + c * cz; + ALfloat orientation[6] = { fx, fy, fz, ux, uy, uz }; alListenerfv(AL_ORIENTATION, orientation); } diff --git a/src/audio/audio.h b/src/audio/audio.h index be0f3199..d7a43b9b 100644 --- a/src/audio/audio.h +++ b/src/audio/audio.h @@ -19,14 +19,14 @@ void lovrAudioInit(); void lovrAudioDestroy(); void lovrAudioUpdate(); void lovrAudioAdd(Source* source); -void lovrAudioGetOrientation(float* fx, float* fy, float* fz, float* ux, float* uy, float* uz); +void lovrAudioGetOrientation(float* angle, float* ax, float* ay, float* az); void lovrAudioGetPosition(float* x, float* y, float* z); float lovrAudioGetVolume(); int lovrAudioHas(Source* source); void lovrAudioPause(); void lovrAudioResume(); void lovrAudioRewind(); -void lovrAudioSetOrientation(float fx, float fy, float fz, float ux, float uy, float uz); +void lovrAudioSetOrientation(float angle, float ax, float ay, float az); void lovrAudioSetPosition(float x, float y, float z); void lovrAudioSetVolume(float volume); void lovrAudioStop(); diff --git a/src/lovr.c b/src/lovr.c index 0123868f..e343e9cd 100644 --- a/src/lovr.c +++ b/src/lovr.c @@ -65,7 +65,7 @@ void lovrInit(lua_State* L, int argc, char** argv) { luax_preloadmodule(L, "lovr.timer", l_lovrTimerInit); // Bootstrap - char buffer[2048]; + char buffer[4096]; snprintf(buffer, sizeof(buffer), "%s", "local conf = { " " modules = { " @@ -122,7 +122,13 @@ void lovrInit(lua_State* L, int argc, char** argv) { " lovr.handlers[name](a, b, c, d) " " end " " local dt = lovr.timer.step() " - " if lovr.audio then lovr.audio.update(dt) end " + " if lovr.audio then " + " lovr.audio.update() " + " if lovr.headset and lovr.headset.isPresent() then " + " lovr.audio.setPosition(lovr.headset.getPosition()) " + " lovr.audio.setOrientation(lovr.headset.getOrientation()) " + " end " + " end " " if lovr.update then lovr.update(dt) end " " lovr.graphics.clear() " " lovr.graphics.origin() " diff --git a/src/lovr/audio.c b/src/lovr/audio.c index 0d9cb2f5..c795690b 100644 --- a/src/lovr/audio.c +++ b/src/lovr/audio.c @@ -40,15 +40,13 @@ int l_lovrAudioUpdate(lua_State* L) { } int l_lovrAudioGetOrientation(lua_State* L) { - float fx, fy, fz, ux, uy, uz; - lovrAudioGetOrientation(&fx, &fy, &fz, &ux, &uy, &uz); - lua_pushnumber(L, fx); - lua_pushnumber(L, fy); - lua_pushnumber(L, fz); - lua_pushnumber(L, ux); - lua_pushnumber(L, uy); - lua_pushnumber(L, uz); - return 6; + float angle, ax, ay, az; + lovrAudioGetOrientation(&angle, &ax, &ay, &az); + lua_pushnumber(L, angle); + lua_pushnumber(L, ax); + lua_pushnumber(L, ay); + lua_pushnumber(L, az); + return 4; } int l_lovrAudioGetPosition(lua_State* L) { @@ -98,13 +96,11 @@ int l_lovrAudioRewind(lua_State* L) { } int l_lovrAudioSetOrientation(lua_State* L) { - float fx = luaL_checknumber(L, 1); - float fy = luaL_checknumber(L, 2); - float fz = luaL_checknumber(L, 3); - float ux = luaL_checknumber(L, 4); - float uy = luaL_checknumber(L, 5); - float uz = luaL_checknumber(L, 6); - lovrAudioSetOrientation(fx, fy, fz, ux, uy, uz); + float angle = luaL_checknumber(L, 1); + float ax = luaL_checknumber(L, 2); + float ay = luaL_checknumber(L, 3); + float az = luaL_checknumber(L, 4); + lovrAudioSetOrientation(angle, ax, ay, az); return 0; }