diff --git a/CMakeLists.txt b/CMakeLists.txt index 5182f434..5e2cbfcf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -201,7 +201,7 @@ endif() if(NOT EMSCRIPTEN) set(BUILD_SHARED ON CACHE BOOL "") set(BUILD_UNIVERSAL OFF CACHE BOOL "") - include_directories(deps/openvr/headers) + include_directories(deps/openvr/headers) include_directories(deps/openvr/src) include_directories(deps/openvr/src/vrcommon) add_subdirectory(deps/openvr openvr_api) @@ -251,6 +251,7 @@ set(LOVR_SRC src/graphics/shader.c src/graphics/shaders.c src/graphics/texture.c + src/headset/fake.c src/headset/headset.c src/lib/glad/glad.c src/lib/lua-cjson/fpconv.c @@ -281,9 +282,9 @@ set(LOVR_SRC ) if(EMSCRIPTEN) - set(LOVR_HEADSET src/headset/webvr.c) + set(LOVR_SRC ${LOVR_SRC} src/headset/webvr.c) else() - set(LOVR_HEADSET src/headset/openvr.c) + set(LOVR_SRC ${LOVR_SRC} src/headset/openvr.c) endif() if(WIN32) @@ -294,7 +295,7 @@ if(WIN32) endif() include_directories(${CMAKE_CURRENT_SOURCE_DIR}/src) -add_executable(lovr ${LOVR_SRC} ${LOVR_HEADSET}) +add_executable(lovr ${LOVR_SRC}) target_link_libraries(lovr ${LOVR_ASSIMP} ${LOVR_ENET} diff --git a/src/api/headset.c b/src/api/headset.c index 0a0b0cab..009fbde1 100644 --- a/src/api/headset.c +++ b/src/api/headset.c @@ -64,6 +64,14 @@ int l_lovrHeadsetInit(lua_State* L) { map_set(&HeadsetTypes, "vive", HEADSET_VIVE); map_set(&HeadsetTypes, "rift", HEADSET_RIFT); +#if 0 + // not needed yet, but if we expose driver selection to lua... + map_init(&HeadsetDrivers); + map_set(&HeadsetDrivers, "unknown", HEADSET_DRIVER_FAKE); + map_set(&HeadsetDrivers, "openvr", HEADSET_DRIVER_OPENVR); + map_set(&HeadsetDrivers, "webvr", HEADSET_DRIVER_WEBVR); +#endif + lovrHeadsetInit(); headsetRenderData.ref = LUA_NOREF; @@ -252,6 +260,11 @@ int l_lovrHeadsetRenderTo(lua_State* L) { return 0; } +int l_lovrHeadsetUpdate(lua_State* L) { + float dt = luaL_checknumber(L, 1); + lovrHeadsetUpdate(dt); + return 0; +} const luaL_Reg lovrHeadset[] = { { "isPresent", l_lovrHeadsetIsPresent }, { "getType", l_lovrHeadsetGetType }, @@ -275,5 +288,6 @@ const luaL_Reg lovrHeadset[] = { { "getControllers", l_lovrHeadsetGetControllers }, { "getControllerCount", l_lovrHeadsetGetControllerCount }, { "renderTo", l_lovrHeadsetRenderTo }, + { "update", l_lovrHeadsetUpdate }, { NULL, NULL } }; diff --git a/src/data/boot.lua b/src/data/boot.lua index defdd9bc..1aabe6a4 100644 --- a/src/data/boot.lua +++ b/src/data/boot.lua @@ -186,6 +186,9 @@ function lovr.step() lovr.handlers[name](a, b, c, d) end local dt = lovr.timer.step() + if lovr.headset then + lovr.headset.update(dt) + end if lovr.audio then lovr.audio.update() if lovr.headset and lovr.headset.isPresent() then diff --git a/src/data/boot.lua.h b/src/data/boot.lua.h index 72b740fd..6d98636a 100644 --- a/src/data/boot.lua.h +++ b/src/data/boot.lua.h @@ -437,80 +437,84 @@ unsigned char boot_lua[] = { 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x74, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a, 0x20, - 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, - 0x69, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, - 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, - 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x72, - 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x69, 0x73, 0x50, - 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, - 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, - 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x4f, 0x72, - 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, - 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, - 0x65, 0x74, 0x4f, 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, - 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, - 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, - 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, - 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, - 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x56, 0x65, - 0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, - 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x56, - 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, - 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, - 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, - 0x74, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, - 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, - 0x73, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, - 0x2e, 0x63, 0x6c, 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, - 0x63, 0x73, 0x2e, 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, - 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, - 0x64, 0x72, 0x61, 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, - 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, - 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, - 0x2e, 0x69, 0x73, 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, - 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x65, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, - 0x65, 0x74, 0x2e, 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, - 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64, 0x65, - 0x72, 0x43, 0x61, 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x29, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x48, - 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, - 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, - 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x20, - 0x20, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, - 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, - 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, - 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, - 0x6d, 0x65, 0x72, 0x2e, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x28, 0x2e, 0x30, - 0x30, 0x31, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, - 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, - 0x75, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, - 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, - 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, - 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, - 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, - 0x20, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, - 0x3d, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, - 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x78, 0x69, - 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, - 0x6e, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, - 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, - 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, - 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, - 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x27, 0x29, 0x20, - 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, - 0x72, 0x65, 0x28, 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x27, 0x29, 0x0a, 0x65, - 0x6e, 0x64, 0x0a + 0x65, 0x74, 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, + 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, + 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x20, + 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, + 0x72, 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, + 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, + 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, + 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x69, 0x73, 0x50, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, + 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x4f, 0x72, 0x69, 0x65, 0x6e, + 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, + 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x4f, + 0x72, 0x69, 0x65, 0x6e, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, + 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, + 0x2e, 0x61, 0x75, 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x50, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, + 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x50, + 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x61, 0x75, + 0x64, 0x69, 0x6f, 0x2e, 0x73, 0x65, 0x74, 0x56, 0x65, 0x6c, 0x6f, 0x63, + 0x69, 0x74, 0x79, 0x28, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x65, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x65, 0x6c, 0x6f, + 0x63, 0x69, 0x74, 0x79, 0x28, 0x29, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, + 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x75, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, + 0x2e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x28, 0x64, 0x74, 0x29, 0x20, + 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, + 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x20, 0x74, + 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, + 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x63, 0x6c, + 0x65, 0x61, 0x72, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, + 0x76, 0x72, 0x2e, 0x67, 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, + 0x6f, 0x72, 0x69, 0x67, 0x69, 0x6e, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x64, 0x72, 0x61, + 0x77, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x65, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, + 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, 0x69, 0x73, + 0x50, 0x72, 0x65, 0x73, 0x65, 0x6e, 0x74, 0x28, 0x29, 0x20, 0x74, 0x68, + 0x65, 0x6e, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, + 0x6f, 0x76, 0x72, 0x2e, 0x68, 0x65, 0x61, 0x64, 0x73, 0x65, 0x74, 0x2e, + 0x72, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x54, 0x6f, 0x28, 0x68, 0x65, 0x61, + 0x64, 0x73, 0x65, 0x74, 0x52, 0x65, 0x6e, 0x64, 0x65, 0x72, 0x43, 0x61, + 0x6c, 0x6c, 0x62, 0x61, 0x63, 0x6b, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x65, 0x6c, 0x73, 0x65, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x65, 0x61, 0x64, + 0x73, 0x65, 0x74, 0x4f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x28, 0x29, 0x0a, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, + 0x2e, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x65, 0x6e, + 0x64, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x67, + 0x72, 0x61, 0x70, 0x68, 0x69, 0x63, 0x73, 0x2e, 0x70, 0x72, 0x65, 0x73, + 0x65, 0x6e, 0x74, 0x28, 0x29, 0x0a, 0x20, 0x20, 0x65, 0x6e, 0x64, 0x0a, + 0x20, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x74, 0x69, 0x6d, 0x65, 0x72, + 0x2e, 0x73, 0x6c, 0x65, 0x65, 0x70, 0x28, 0x2e, 0x30, 0x30, 0x31, 0x29, + 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, 0x72, 0x75, 0x6e, 0x28, + 0x29, 0x0a, 0x20, 0x20, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x72, 0x2e, + 0x6c, 0x6f, 0x61, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, + 0x76, 0x72, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x28, 0x29, 0x20, 0x65, 0x6e, + 0x64, 0x0a, 0x20, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, + 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x6c, + 0x6f, 0x76, 0x72, 0x2e, 0x73, 0x74, 0x65, 0x70, 0x28, 0x29, 0x0a, 0x20, + 0x20, 0x20, 0x20, 0x69, 0x66, 0x20, 0x65, 0x78, 0x69, 0x74, 0x20, 0x74, + 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, + 0x78, 0x69, 0x74, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x20, 0x20, 0x65, 0x6e, + 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, 0x0a, 0x69, 0x66, 0x20, 0x6c, 0x6f, + 0x76, 0x72, 0x2e, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x2e, 0x69, 0x73, 0x46, 0x69, 0x6c, 0x65, 0x28, 0x27, 0x6d, 0x61, + 0x69, 0x6e, 0x2e, 0x6c, 0x75, 0x61, 0x27, 0x29, 0x20, 0x74, 0x68, 0x65, + 0x6e, 0x0a, 0x20, 0x20, 0x72, 0x65, 0x71, 0x75, 0x69, 0x72, 0x65, 0x28, + 0x27, 0x6d, 0x61, 0x69, 0x6e, 0x27, 0x29, 0x0a, 0x65, 0x6e, 0x64, 0x0a }; -unsigned int boot_lua_len = 6147; +unsigned int boot_lua_len = 6204; diff --git a/src/graphics/graphics.c b/src/graphics/graphics.c index 6d478252..e0ba2a05 100644 --- a/src/graphics/graphics.c +++ b/src/graphics/graphics.c @@ -1047,3 +1047,8 @@ void lovrGraphicsBindIndexBuffer(uint32_t indexBuffer) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer); } } + +GLFWwindow* lovrGraphicsGetWindow() { + return state.window; +} + diff --git a/src/graphics/graphics.h b/src/graphics/graphics.h index 3bfacac8..da32a9db 100644 --- a/src/graphics/graphics.h +++ b/src/graphics/graphics.h @@ -182,3 +182,5 @@ void lovrGraphicsUseProgram(uint32_t program); void lovrGraphicsBindVertexArray(uint32_t vao); void lovrGraphicsBindVertexBuffer(uint32_t vbo); void lovrGraphicsBindIndexBuffer(uint32_t ibo); +GLFWwindow* lovrGraphicsGetWindow(); + diff --git a/src/headset/fake.c b/src/headset/fake.c new file mode 100644 index 00000000..29839c78 --- /dev/null +++ b/src/headset/fake.c @@ -0,0 +1,481 @@ +#include "event/event.h" +#include "graphics/graphics.h" +#include "math/mat4.h" +#include "math/vec3.h" +#include "math/quat.h" +#include "util.h" +#define _USE_MATH_DEFINES +#include +#include +#include +#include + + +// implements a fake headset, with mouselook and keyboard-driven movement. +// for use when a real headset isn't available. + +typedef struct { + int isInitialized; + HeadsetType type; + + vec_controller_t controllers; + + float clipNear; + float clipFar; + float FOV; + + float vel[3]; + float pos[3]; + + double yaw; + double pitch; + + float orientation[4]; // derived from pitch and yaw + + float projection[16]; // projection matrix + + float transform[16]; + + // keep track of currently hooked window, if any + GLFWwindow* hookedWindow; + + int mouselook; + double prevCursorX; + double prevCursorY; + + +} FakeHeadsetState; + +static FakeHeadsetState state; + + +// fwd declarations +static void fakePoll(); + +/* + * callback handlers + */ + +static void enableMouselook(GLFWwindow* window) { + if (window) { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + glfwGetCursorPos(window, &state.prevCursorX, &state.prevCursorY); + } + // track the intent for mouselook, even if no window yet. One might come along ;-) + state.mouselook = 1; +} + +static void disableMouselook(GLFWwindow* window) { + if(window) { + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + state.mouselook = 0; +} + +static void cursor_enter_callback( GLFWwindow *window, int entered) { + if (entered) { + if( !state.mouselook) { + enableMouselook(window); + } + } +} + + +static void window_focus_callback(GLFWwindow* window, int focused) { + if (!focused) { + disableMouselook(window); + } +} + +static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { + if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) { + disableMouselook(window); + } +} + +static void cursor_position_callback(GLFWwindow* window, double xpos, double ypos) +{ + if (!state.mouselook) { + return; + } + double dx = xpos - state.prevCursorX; + double dy = ypos - state.prevCursorY; + state.prevCursorX = xpos; + state.prevCursorY = ypos; + + const double k = 0.01; + const double l = 0.01; + + state.yaw -= dx*k; + state.pitch -= dy*l; + + if (state.pitch < -M_PI/2.0) { + state.pitch = -M_PI/2.0; + } + if (state.pitch > M_PI/2.0) { + state.pitch = M_PI/2.0; + } + +} + +static void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) +{ + if (!state.mouselook) { + if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) { + enableMouselook(window); + } + } +} + +// headset can start up without a window, so we poll window existance here +static void check_window_existance() +{ + GLFWwindow *window = lovrGraphicsGetWindow(); + + if (window == state.hookedWindow) { + // no change + return; + } + + state.hookedWindow = window; + // window might be coming or going. + // If it's coming we'll install our event hooks. + // If it's going, it's already gone, so no way to uninstall our hooks. + if( window ) { + glfwSetCursorEnterCallback(window, cursor_enter_callback); + glfwSetMouseButtonCallback(window, mouse_button_callback); + glfwSetCursorPosCallback(window, cursor_position_callback); + glfwSetWindowFocusCallback(window, window_focus_callback); + glfwSetKeyCallback(window, key_callback); + + // can now actually do mouselook! + if (state.mouselook ) { + enableMouselook(window); + } else { + disableMouselook(window); + } + } +} + + + +/* + * headset implementation fns + */ + + +static int fakeIsAvailable() +{ + return 1; +} + + +static void fakeInit() { + + state.clipNear = 0.1f; + state.clipFar = 100.f; + state.FOV = 67.0f * M_PI / 100.0f; + // TODO: aspect here too? + + mat4_identity(state.transform); + + state.pitch = 0.0; + state.yaw = 0.0; + quat_set( state.orientation, 0,0,0,1); + + vec3_set( state.vel, 0,0,0); + vec3_set( state.pos, 0,0,0); + + // set up controller(s) + vec_init(&state.controllers); + Controller* controller = lovrAlloc(sizeof(Controller), lovrControllerDestroy); + controller->id = state.controllers.length; + vec_push(&state.controllers, controller); + + lovrEventAddPump(fakePoll); + + state.mouselook = 1; + state.hookedWindow = NULL; + state.isInitialized = 1; + +} + + +static void fakeDestroy() { + int i; + Controller *controller; + state.isInitialized = 0; + + // TODO: unhook lovrEventAddPump ? + + // would be polite to unhook gracefully, but we're likely + // being called after glfw is already lone gone... + // not a big deal in practice. +#if 0 + GLFWwindow *window = lovrGraphicsGetWindow(); + if( window && window ==state.hookedWindow) { + glfwSetKeyCallback(window, NULL); + glfwSetWindowFocusCallback(window, NULL); + glfwSetCursorPosCallback(window, NULL); + glfwSetMouseButtonCallback(window, NULL); + glfwSetCursorEnterCallback(window, NULL); + state.hookedWindow = NULL; + } +#endif + + vec_foreach(&state.controllers, controller, i) { + lovrRelease(&controller->ref); + } + vec_deinit(&state.controllers); +} + +static void fakePoll() { +} + +static int fakeIsPresent() { + return 1; +} + +static HeadsetType fakeGetType() { + return HEADSET_FAKE; +} + +static HeadsetOrigin fakeGetOriginType() { + return ORIGIN_HEAD; // seated + //return ORIGIN_FLOOR; // standing +} + +static int fakeIsMirrored() { + return 0; +} + +static void fakeSetMirrored(int mirror) { +} + +static void fakeGetDisplayDimensions(int* width, int* height) { + GLFWwindow* window = lovrGraphicsGetWindow(); + if(window) { + glfwGetWindowSize(window,width,height); + } +} + + +static void fakeGetClipDistance(float* clipNear, float* clipFar) { + *clipNear = state.clipNear; + *clipFar = state.clipFar; +} + +static void fakeSetClipDistance(float clipNear, float clipFar) { + state.clipNear = clipNear; + state.clipFar = clipFar; + +} + +static float fakeGetBoundsWidth() { + return 0.0f; +} + +static float fakeGetBoundsDepth() { + return 0.0f; +} + +static void fakeGetBoundsGeometry(float* geometry) { + memset(geometry, 0, 12 * sizeof(float)); +} + +static void fakeGetPosition(float* x, float* y, float* z) { + // TODO: sit->stand transform? + *x = state.pos[0]; + *y = state.pos[1]; + *z = state.pos[2]; +} + +static void fakeGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { + fakeGetPosition(x,y,z); +} + +static void fakeGetOrientation(float* angle, float* x, float* y, float* z) { + float q[4]; + quat_fromMat4(q, state.transform); + quat_getAngleAxis(q, angle, x, y, z); +} + +static void fakeGetVelocity(float* x, float* y, float* z) { + // TODO: sit->stand transform? + *x = state.vel[0]; + *y = state.vel[1]; + *z = state.vel[2]; +} + +static void fakeGetAngularVelocity(float* x, float* y, float* z) { +#if 0 + float v[3]; + emscripten_vr_get_angular_velocity(&v[0], &v[1], &v[2]); + mat4_transformDirection(emscripten_vr_get_sitting_to_standing_matrix(), v); + *x = v[0]; + *y = v[1]; + *z = v[2]; +#endif +// TODO +} + + + + +static vec_controller_t* fakeGetControllers() { + return &state.controllers; +} + +static int fakeControllerIsPresent(Controller* controller) { + return 1; +} + +static ControllerHand fakeControllerGetHand(Controller* controller) { + return HAND_UNKNOWN; +} + +static void fakeControllerGetPosition(Controller* controller, float* x, float* y, float* z) { + // for now, locked to headset + fakeGetPosition(x,y,z); +} + +static void fakeControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) { + // for now, locked to headset + float q[4]; + quat_fromMat4(q, state.transform); + quat_getAngleAxis(q, angle, x, y, z); +} + + +static float fakeControllerGetAxis(Controller* controller, ControllerAxis axis) { + return 0.0f; +} + +static int fakeControllerIsDown(Controller* controller, ControllerButton button) { + GLFWwindow* window = lovrGraphicsGetWindow(); + if(!window) { + return 0; + } + int b = glfwGetMouseButton( window, GLFW_MOUSE_BUTTON_LEFT); + return (b == GLFW_PRESS) ? CONTROLLER_BUTTON_TRIGGER : 0; +} + +static int fakeControllerIsTouched(Controller* controller, ControllerButton button) { + return 0; +} + +static void fakeControllerVibrate(Controller* controller, float duration, float power) { +} + +static ModelData* fakeControllerNewModelData(Controller* controller) { + return NULL; +} + + +static void fakeRenderTo(headsetRenderCallback callback, void* userdata) { +// float head[16], transform[16], projection[16]; + + // TODO: Head transform + // TODO: Eye transform + // Projection + + int w,h; + GLFWwindow* window = lovrGraphicsGetWindow(); + if(!window) { + return; + } + + glfwGetWindowSize(window, &w, &h); + + float transform[16]; + mat4_perspective(state.projection, state.clipNear, state.clipFar, 67 * M_PI / 180.0, (float)w/h); + + // render + lovrGraphicsPush(); + float inv[16]; + mat4_set(inv,state.transform); + mat4_invert(inv); + lovrGraphicsMatrixTransform(MATRIX_VIEW, inv); + + lovrGraphicsSetProjection(state.projection); + lovrGraphicsClear(1, 1); + callback(EYE_LEFT, userdata); + lovrGraphicsPop(); +} + + +static void fakeUpdate(float dt) +{ + float k = 4.0f; + check_window_existance(); + GLFWwindow* w = lovrGraphicsGetWindow(); + if(!w) { + return; + } + float v[3] = {0.0f,0.0f,0.0f}; + if (glfwGetKey(w, GLFW_KEY_W)==GLFW_PRESS || glfwGetKey(w, GLFW_KEY_UP)==GLFW_PRESS) { + v[2] = -k; + } + if (glfwGetKey(w, GLFW_KEY_S)==GLFW_PRESS || glfwGetKey(w, GLFW_KEY_DOWN)==GLFW_PRESS) { + v[2] = k; + } + if (glfwGetKey(w, GLFW_KEY_A)==GLFW_PRESS || glfwGetKey(w, GLFW_KEY_LEFT)==GLFW_PRESS) { + v[0] = -k; + } + if (glfwGetKey(w, GLFW_KEY_D)==GLFW_PRESS || glfwGetKey(w, GLFW_KEY_RIGHT)==GLFW_PRESS) { + v[0] = k; + } + if (glfwGetKey(w, GLFW_KEY_Q) == GLFW_PRESS) { + v[1] = k; + } + if (glfwGetKey(w, GLFW_KEY_E) == GLFW_PRESS) { + v[1] = -k; + } + + // move + vec3_scale(v,dt); + mat4_transformDirection(state.transform, v); + vec3_add(state.pos, v); + + // update transform + mat4_identity(state.transform); + mat4_translate(state.transform, state.pos[0], state.pos[1], state.pos[2]); + mat4_rotate(state.transform, state.yaw, 0,1,0); + mat4_rotate(state.transform, state.pitch, 1,0,0); +} + +HeadsetInterface lovrHeadsetFakeDriver = { + fakeIsAvailable, + fakeInit, + fakeDestroy, + fakePoll, + fakeIsPresent, + fakeGetType, + fakeGetOriginType, + fakeIsMirrored, + fakeSetMirrored, + fakeGetDisplayDimensions, + fakeGetClipDistance, + fakeSetClipDistance, + fakeGetBoundsWidth, + fakeGetBoundsDepth, + fakeGetBoundsGeometry, + fakeGetPosition, + fakeGetEyePosition, + fakeGetOrientation, + fakeGetVelocity, + fakeGetAngularVelocity, + fakeGetControllers, + fakeControllerIsPresent, + fakeControllerGetHand, + fakeControllerGetPosition, + fakeControllerGetOrientation, + fakeControllerGetAxis, + fakeControllerIsDown, + fakeControllerIsTouched, + fakeControllerVibrate, + fakeControllerNewModelData, + fakeRenderTo, + fakeUpdate, +}; + diff --git a/src/headset/headset.c b/src/headset/headset.c index ec9d8e85..4d960e76 100644 --- a/src/headset/headset.c +++ b/src/headset/headset.c @@ -5,3 +5,238 @@ void lovrControllerDestroy(const Ref* ref) { Controller* controller = containerof(ref, Controller); free(controller); } + + +static HeadsetInterface* headset = NULL; + + +void lovrHeadsetInit() { + // assert(headset==NULL) + // TODO: should expose driver selection to lua, so conf can express a preference? + +#if EMSCRIPTEN + HeadsetInterface* drivers[] = { &lovrHeadsetWebVRDriver, &lovrHeadsetFakeDriver, NULL }; +#else + HeadsetInterface* drivers[] = { &lovrHeadsetOpenVRDriver, &lovrHeadsetFakeDriver, NULL }; +#endif + int i; + for (i=0; drivers[i]; ++i ) { + if (drivers[i]->isAvailable()) { + headset = drivers[i]; + break; + } + } + + if( headset) { + headset->init(); + atexit(lovrHeadsetDestroy); + } +} + + +void lovrHeadsetDestroy() { + if (headset) { + headset->destroy(); + headset = NULL; + } +} + +void lovrHeadsetPoll() { + headset->poll(); +} + +int lovrHeadsetIsPresent() { + return headset ? headset->isPresent() : 0; +} + +HeadsetType lovrHeadsetGetType() { + return headset ? headset->getType() : HEADSET_UNKNOWN; +} + +HeadsetOrigin lovrHeadsetGetOriginType() { + return headset ? headset->getOriginType() : ORIGIN_HEAD; +} + +int lovrHeadsetIsMirrored() { + return headset ? headset->isMirrored() : 0; +} + +void lovrHeadsetSetMirrored(int mirror) { + if (headset) { + headset->setMirrored(mirror); + } +} + +void lovrHeadsetGetDisplayDimensions(int* width, int* height) { + if (!headset) { + *width = *height = 0; + return; + } + + headset->getDisplayDimensions(width, height); +} + +void lovrHeadsetGetClipDistance(float* near, float* far) { + if (!headset) { + *near = *far = 0.f; + return; + } + headset->getClipDistance(near, far); +} + +void lovrHeadsetSetClipDistance(float near, float far) { + if (headset) { + headset->setClipDistance(near, far); + } +} + +float lovrHeadsetGetBoundsWidth() { + return headset ? headset->getBoundsWidth() : 0.0f; +} + +float lovrHeadsetGetBoundsDepth() { + return headset ? headset->getBoundsDepth() : 0.0f; +} + +void lovrHeadsetGetBoundsGeometry(float* geometry) { + if (!headset) { + *geometry = 0.f; + return; + } + + headset->getBoundsGeometry(geometry); +} + + +void lovrHeadsetGetPosition(float* x, float* y, float* z) { + if (!headset) { + *x = *y = *z = 0.f; + return; + } + + headset->getPosition(x, y, z); +} + +void lovrHeadsetGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { + if (!headset) { + *x = *y = *z = 0.f; + return; + } + + headset->getEyePosition(eye,x, y, z); +} + +void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float* z) { + if (!headset) { + *angle = *x = *y = *z = 0.f; + return; + } + + headset->getOrientation(angle,x,y,z); +} + +void lovrHeadsetGetVelocity(float* x, float* y, float* z) { + if (!headset) { + *x = *y = *z = 0.f; + return; + } + + headset->getVelocity(x,y,z); +} + +void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) { + if (!headset) { + *x = *y = *z = 0.f; + return; + } + + headset->getAngularVelocity(x,y,z); +} + +vec_controller_t* lovrHeadsetGetControllers() { + if (!headset) { + return NULL; + } + + return headset->getControllers(); +} + +int lovrHeadsetControllerIsPresent(Controller* controller) { + if (!headset || !controller) { + return 0; + } + + return headset->controllerIsPresent(controller); +} + +ControllerHand lovrHeadsetControllerGetHand(Controller* controller) { + return headset ? headset->controllerGetHand(controller) : HAND_UNKNOWN; +} + +void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y, float* z) { + if (!headset || !controller) { + *x = *y = *z = 0.f; + return; + } + + headset->controllerGetPosition(controller, x, y, z); +} + +void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) { + if (!headset || !controller) { + *angle = *x = *y = *z = 0.f; + return; + } + + headset->controllerGetOrientation(controller, angle, x, y, z); +} + +float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) { + if (!headset || !controller) { + return 0.f; + } + + return headset->controllerGetAxis(controller, axis); +} + +int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button) { + if (!headset || !controller) { + return 0; + } + + return headset->controllerIsDown(controller, button); +} + +int lovrHeadsetControllerIsTouched(Controller* controller, ControllerButton button) { + return (headset && controller) ? headset->controllerIsTouched(controller,button) : 0; +} + +void lovrHeadsetControllerVibrate(Controller* controller, float duration, float power) { + if (!headset || !controller) { + return; + } + + headset->controllerVibrate(controller, duration, power); +} + +ModelData* lovrHeadsetControllerNewModelData(Controller* controller) +{ + if( headset && controller) { + return headset->controllerNewModelData(controller); + } else { + return NULL; + } +} + + +void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) { + if (headset) { + headset->renderTo(callback, userdata); + } +} + +void lovrHeadsetUpdate(float dt) { + if(headset) { + headset->update(dt); + } +} diff --git a/src/headset/headset.h b/src/headset/headset.h index 7365a16e..6b211630 100644 --- a/src/headset/headset.h +++ b/src/headset/headset.h @@ -18,7 +18,8 @@ typedef enum { typedef enum { HEADSET_UNKNOWN, HEADSET_VIVE, - HEADSET_RIFT + HEADSET_RIFT, + HEADSET_FAKE } HeadsetType; typedef enum { @@ -56,6 +57,48 @@ typedef struct { typedef vec_t(Controller*) vec_controller_t; typedef void (*headsetRenderCallback)(HeadsetEye eye, void* userdata); + +typedef struct { + int (*isAvailable)(); + void (*init)(); + void (*destroy)(); + void (*poll)(); + int (*isPresent)(); + HeadsetType (*getType)(); + HeadsetOrigin (*getOriginType)(); + int (*isMirrored)(); + void (*setMirrored)(int mirror); + void (*getDisplayDimensions)(int* width, int* height); + void (*getClipDistance)(float* clipNear, float* clipFar); + void (*setClipDistance)(float clipNear, float clipFar); + float (*getBoundsWidth)(); + float (*getBoundsDepth)(); + void (*getBoundsGeometry)(float* geometry); + void (*getPosition)(float* x, float* y, float* z); + void (*getEyePosition)(HeadsetEye eye, float* x, float* y, float* z); + void (*getOrientation)(float* angle, float* x, float* y, float* z); + void (*getVelocity)(float* x, float* y, float* z); + void (*getAngularVelocity)(float* x, float* y, float* z); + vec_controller_t* (*getControllers)(); + int (*controllerIsPresent)(Controller* controller); + ControllerHand (*controllerGetHand)(Controller* controller); + void (*controllerGetPosition)(Controller* controller, float* x, float* y, float* z); + void (*controllerGetOrientation)(Controller* controller, float* angle, float* x, float* y, float* z); + float (*controllerGetAxis)(Controller* controller, ControllerAxis axis); + int (*controllerIsDown)(Controller* controller, ControllerButton button); + int (*controllerIsTouched)(Controller* controller, ControllerButton button); + void (*controllerVibrate)(Controller* controller, float duration, float power); + ModelData* (*controllerNewModelData)(Controller* controller); + void (*renderTo)(headsetRenderCallback callback, void* userdata); + void (*update)(float dt); +} HeadsetInterface; + + +// headset implementations +extern HeadsetInterface lovrHeadsetOpenVRDriver; +extern HeadsetInterface lovrHeadsetFakeDriver; + + void lovrHeadsetInit(); void lovrHeadsetDestroy(); void lovrHeadsetPoll(); @@ -65,8 +108,8 @@ HeadsetOrigin lovrHeadsetGetOriginType(); int lovrHeadsetIsMirrored(); void lovrHeadsetSetMirrored(int mirror); void lovrHeadsetGetDisplayDimensions(int* width, int* height); -void lovrHeadsetGetClipDistance(float* near, float* far); -void lovrHeadsetSetClipDistance(float near, float far); +void lovrHeadsetGetClipDistance(float* clipNear, float* clipFar); +void lovrHeadsetSetClipDistance(float clipNear, float clipFar); float lovrHeadsetGetBoundsWidth(); float lovrHeadsetGetBoundsDepth(); void lovrHeadsetGetBoundsGeometry(float* geometry); @@ -86,5 +129,7 @@ int lovrHeadsetControllerIsTouched(Controller* controller, ControllerButton butt void lovrHeadsetControllerVibrate(Controller* controller, float duration, float power); ModelData* lovrHeadsetControllerNewModelData(Controller* controller); void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata); +void lovrHeadsetUpdate(float dt); + void lovrControllerDestroy(const Ref* ref); diff --git a/src/headset/openvr.c b/src/headset/openvr.c index ec2c9650..6b41feaf 100644 --- a/src/headset/openvr.c +++ b/src/headset/openvr.c @@ -1,15 +1,72 @@ -#include "headset/openvr.h" #include "event/event.h" #include "graphics/graphics.h" #include "math/mat4.h" #include "math/quat.h" #include "util.h" +#include "graphics/texture.h" +#include #include #include #include +#include + +// From openvr_capi.h +extern intptr_t VR_InitInternal(EVRInitError *peError, EVRApplicationType eType); +extern bool VR_IsHmdPresent(); +extern intptr_t VR_GetGenericInterface(const char* pchInterfaceVersion, EVRInitError* peError); +extern bool VR_IsRuntimeInstalled(); + +static void openvrDestroy(); +static void openvrPoll(); +static void openvrRefreshControllers(); +static ControllerHand openvrControllerGetHand(Controller* controller); +static Controller* openvrAddController(unsigned int deviceIndex); +static ControllerHand openvrControllerGetHand(Controller* controller); + + + + +typedef struct { + int isInitialized; + int isRendering; + int isMirrored; + + struct VR_IVRSystem_FnTable* system; + struct VR_IVRCompositor_FnTable* compositor; + struct VR_IVRChaperone_FnTable* chaperone; + struct VR_IVRRenderModels_FnTable* renderModels; + + unsigned int headsetIndex; + HeadsetType type; + + TrackedDevicePose_t renderPoses[16]; + RenderModel_t* deviceModels[16]; + RenderModel_TextureMap_t* deviceTextures[16]; + + vec_controller_t controllers; + + float clipNear; + float clipFar; + + uint32_t renderWidth; + uint32_t renderHeight; + float refreshRate; + float vsyncToPhotons; + + Texture* texture; +} HeadsetState; static HeadsetState state; + +static int openvrIsAvailable() { + if (VR_IsHmdPresent() && VR_IsRuntimeInstalled()) { + return 1; + } else { + return 0; + } +} + static ControllerButton getButton(uint32_t button, ControllerHand hand) { switch (state.type) { case HEADSET_RIFT: @@ -88,7 +145,7 @@ static TrackedDevicePose_t getPose(unsigned int deviceIndex) { return poses[deviceIndex]; } -void lovrHeadsetInit() { +static void openvrInit() { state.isInitialized = 0; state.isRendering = 0; state.isMirrored = 1; @@ -101,7 +158,7 @@ void lovrHeadsetInit() { } if (!VR_IsHmdPresent() || !VR_IsRuntimeInstalled()) { - lovrHeadsetDestroy(); + openvrDestroy(); return; } @@ -109,7 +166,7 @@ void lovrHeadsetInit() { VR_InitInternal(&vrError, EVRApplicationType_VRApplication_Scene); if (vrError != EVRInitError_VRInitError_None) { - lovrHeadsetDestroy(); + openvrDestroy(); return; } @@ -118,28 +175,28 @@ void lovrHeadsetInit() { sprintf(buffer, "FnTable:%s", IVRSystem_Version); state.system = (struct VR_IVRSystem_FnTable*) VR_GetGenericInterface(buffer, &vrError); if (vrError != EVRInitError_VRInitError_None || !state.system) { - lovrHeadsetDestroy(); + openvrDestroy(); return; } sprintf(buffer, "FnTable:%s", IVRCompositor_Version); state.compositor = (struct VR_IVRCompositor_FnTable*) VR_GetGenericInterface(buffer, &vrError); if (vrError != EVRInitError_VRInitError_None || !state.compositor) { - lovrHeadsetDestroy(); + openvrDestroy(); return; } sprintf(buffer, "FnTable:%s", IVRChaperone_Version); state.chaperone = (struct VR_IVRChaperone_FnTable*) VR_GetGenericInterface(buffer, &vrError); if (vrError != EVRInitError_VRInitError_None || !state.chaperone) { - lovrHeadsetDestroy(); + openvrDestroy(); return; } sprintf(buffer, "FnTable:%s", IVRRenderModels_Version); state.renderModels = (struct VR_IVRRenderModels_FnTable*) VR_GetGenericInterface(buffer, &vrError); if (vrError != EVRInitError_VRInitError_None || !state.renderModels) { - lovrHeadsetDestroy(); + openvrDestroy(); return; } @@ -160,12 +217,11 @@ void lovrHeadsetInit() { state.clipNear = 0.1f; state.clipFar = 30.f; - lovrHeadsetRefreshControllers(); - lovrEventAddPump(lovrHeadsetPoll); - atexit(lovrHeadsetDestroy); + openvrRefreshControllers(); + lovrEventAddPump(openvrPoll); } -void lovrHeadsetDestroy() { +static void openvrDestroy() { state.isInitialized = 0; if (state.texture) { lovrRelease(&state.texture->ref); @@ -184,7 +240,7 @@ void lovrHeadsetDestroy() { vec_deinit(&state.controllers); } -void lovrHeadsetPoll() { +static void openvrPoll() { if (!state.isInitialized) return; struct VREvent_t vrEvent; while (state.system->PollNextEvent(&vrEvent, sizeof(vrEvent))) { @@ -192,7 +248,7 @@ void lovrHeadsetPoll() { case EVREventType_VREvent_TrackedDeviceActivated: case EVREventType_VREvent_TrackedDeviceDeactivated: case EVREventType_VREvent_TrackedDeviceRoleChanged: { - lovrHeadsetRefreshControllers(); + openvrRefreshControllers(); break; } @@ -203,7 +259,7 @@ void lovrHeadsetPoll() { int i; vec_foreach(&state.controllers, controller, i) { if (controller->id == vrEvent.trackedDeviceIndex) { - ControllerHand hand = lovrHeadsetControllerGetHand(controller); + ControllerHand hand = openvrControllerGetHand(controller); Event event; if (isPress) { event.type = EVENT_CONTROLLER_PRESSED; @@ -233,15 +289,15 @@ void lovrHeadsetPoll() { } } -int lovrHeadsetIsPresent() { +static int openvrIsPresent() { return state.isInitialized && state.system->IsTrackedDeviceConnected(state.headsetIndex); } -HeadsetType lovrHeadsetGetType() { +static HeadsetType openvrGetType() { return state.type; } -HeadsetOrigin lovrHeadsetGetOriginType() { +static HeadsetOrigin openvrGetOriginType() { if (!state.isInitialized) { return ORIGIN_HEAD; } @@ -253,15 +309,15 @@ HeadsetOrigin lovrHeadsetGetOriginType() { } } -int lovrHeadsetIsMirrored() { +static int openvrIsMirrored() { return state.isMirrored; } -void lovrHeadsetSetMirrored(int mirror) { +static void openvrSetMirrored(int mirror) { state.isMirrored = mirror; } -void lovrHeadsetGetDisplayDimensions(int* width, int* height) { +static void openvrGetDisplayDimensions(int* width, int* height) { if (!state.isInitialized) { *width = *height = 0; } else { @@ -270,7 +326,7 @@ void lovrHeadsetGetDisplayDimensions(int* width, int* height) { } } -void lovrHeadsetGetClipDistance(float* near, float* far) { +static void openvrGetClipDistance(float* near, float* far) { if (!state.isInitialized) { *near = *far = 0.f; } else { @@ -279,27 +335,27 @@ void lovrHeadsetGetClipDistance(float* near, float* far) { } } -void lovrHeadsetSetClipDistance(float near, float far) { +static void openvrSetClipDistance(float near, float far) { if (!state.isInitialized) return; state.clipNear = near; state.clipFar = far; } -float lovrHeadsetGetBoundsWidth() { +static float openvrGetBoundsWidth() { if (!state.isInitialized) return 0.f; float width; state.chaperone->GetPlayAreaSize(&width, NULL); return width; } -float lovrHeadsetGetBoundsDepth() { +static float openvrGetBoundsDepth() { if (!state.isInitialized) return 0.f; float depth; state.chaperone->GetPlayAreaSize(NULL, &depth); return depth; } -void lovrHeadsetGetBoundsGeometry(float* geometry) { +static void openvrGetBoundsGeometry(float* geometry) { if (!state.isInitialized) { memset(geometry, 0, 12 * sizeof(float)); } else { @@ -313,7 +369,7 @@ void lovrHeadsetGetBoundsGeometry(float* geometry) { } } -void lovrHeadsetGetPosition(float* x, float* y, float* z) { +static void openvrGetPosition(float* x, float* y, float* z) { if (!state.isInitialized) { *x = *y = *z = 0.f; return; @@ -331,7 +387,7 @@ void lovrHeadsetGetPosition(float* x, float* y, float* z) { *z = pose.mDeviceToAbsoluteTracking.m[2][3]; } -void lovrHeadsetGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { +static void openvrGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { if (!state.isInitialized) { *x = *y = *z = 0.f; return; @@ -356,7 +412,7 @@ void lovrHeadsetGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { *z = transform[14]; } -void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float *z) { +static void openvrGetOrientation(float* angle, float* x, float* y, float *z) { if (!state.isInitialized) { *angle = *x = *y = *z = 0.f; return; @@ -375,7 +431,7 @@ void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float *z) { quat_getAngleAxis(rotation, angle, x, y, z); } -void lovrHeadsetGetVelocity(float* x, float* y, float* z) { +static void openvrGetVelocity(float* x, float* y, float* z) { if (!state.isInitialized) { *x = *y = *z = 0.f; return; @@ -393,7 +449,7 @@ void lovrHeadsetGetVelocity(float* x, float* y, float* z) { *z = pose.vVelocity.v[2]; } -void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) { +static void openvrGetAngularVelocity(float* x, float* y, float* z) { if (!state.isInitialized) { *x = *y = *z = 0.f; return; @@ -411,7 +467,7 @@ void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) { *z = pose.vAngularVelocity.v[2]; } -void lovrHeadsetRefreshControllers() { +static void openvrRefreshControllers() { if (!state.isInitialized) return; unsigned int leftHand = ETrackedControllerRole_TrackedControllerRole_LeftHand; @@ -439,7 +495,7 @@ void lovrHeadsetRefreshControllers() { // Add connected controllers that aren't in the list yet for (i = 0; i < 2; i++) { if ((int) controllerIds[i] != -1) { - controller = lovrHeadsetAddController(controllerIds[i]); + controller = openvrAddController(controllerIds[i]); if (!controller) continue; EventType type = EVENT_CONTROLLER_ADDED; EventData data = { .controlleradded = { controller } }; @@ -450,7 +506,7 @@ void lovrHeadsetRefreshControllers() { } } -Controller* lovrHeadsetAddController(unsigned int deviceIndex) { +static Controller* openvrAddController(unsigned int deviceIndex) { if (!state.isInitialized) return NULL; if ((int) deviceIndex == -1) { @@ -470,17 +526,17 @@ Controller* lovrHeadsetAddController(unsigned int deviceIndex) { return controller; } -vec_controller_t* lovrHeadsetGetControllers() { +static vec_controller_t* openvrGetControllers() { if (!state.isInitialized) return NULL; return &state.controllers; } -int lovrHeadsetControllerIsPresent(Controller* controller) { +static int openvrControllerIsPresent(Controller* controller) { if (!state.isInitialized || !controller) return 0; return state.system->IsTrackedDeviceConnected(controller->id); } -ControllerHand lovrHeadsetControllerGetHand(Controller* controller) { +static ControllerHand openvrControllerGetHand(Controller* controller) { if (!state.isInitialized || !controller) return HAND_UNKNOWN; switch (state.system->GetControllerRoleForTrackedDeviceIndex(controller->id)) { case ETrackedControllerRole_TrackedControllerRole_LeftHand: return HAND_LEFT; @@ -489,7 +545,7 @@ ControllerHand lovrHeadsetControllerGetHand(Controller* controller) { } } -void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y, float* z) { +static void openvrControllerGetPosition(Controller* controller, float* x, float* y, float* z) { if (!state.isInitialized || !controller) { *x = *y = *z = 0.f; } @@ -506,7 +562,7 @@ void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y *z = pose.mDeviceToAbsoluteTracking.m[2][3]; } -void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) { +static void openvrControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) { if (!state.isInitialized || !controller) { *angle = *x = *y = *z = 0.f; } @@ -524,7 +580,7 @@ void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, f quat_getAngleAxis(rotation, angle, x, y, z); } -float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) { +static float openvrControllerGetAxis(Controller* controller, ControllerAxis axis) { if (!state.isInitialized || !controller) return 0.f; VRControllerState_t input; @@ -552,25 +608,25 @@ float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) return 0; } -int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button) { +static int openvrControllerIsDown(Controller* controller, ControllerButton button) { if (!state.isInitialized || !controller) return 0; VRControllerState_t input; state.system->GetControllerState(controller->id, &input, sizeof(input)); - ControllerHand hand = lovrHeadsetControllerGetHand(controller); + ControllerHand hand = openvrControllerGetHand(controller); return getButtonState(input.ulButtonPressed, button, hand); } -int lovrHeadsetControllerIsTouched(Controller* controller, ControllerButton button) { +static int openvrControllerIsTouched(Controller* controller, ControllerButton button) { if (!state.isInitialized || !controller) return 0; VRControllerState_t input; state.system->GetControllerState(controller->id, &input, sizeof(input)); - ControllerHand hand = lovrHeadsetControllerGetHand(controller); + ControllerHand hand = openvrControllerGetHand(controller); return getButtonState(input.ulButtonTouched, button, hand); } -void lovrHeadsetControllerVibrate(Controller* controller, float duration, float power) { +static void openvrControllerVibrate(Controller* controller, float duration, float power) { if (!state.isInitialized || !controller || duration <= 0) return; uint32_t axis = 0; @@ -578,7 +634,7 @@ void lovrHeadsetControllerVibrate(Controller* controller, float duration, float state.system->TriggerHapticPulse(controller->id, axis, uSeconds); } -ModelData* lovrHeadsetControllerNewModelData(Controller* controller) { +static ModelData* openvrControllerNewModelData(Controller* controller) { if (!state.isInitialized || !controller) return NULL; int id = controller->id; @@ -679,7 +735,7 @@ ModelData* lovrHeadsetControllerNewModelData(Controller* controller) { return modelData; } -void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) { +static void openvrRenderTo(headsetRenderCallback callback, void* userdata) { if (!state.isInitialized) return; if (!state.texture) { @@ -759,3 +815,43 @@ void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) { lovrGraphicsSetColor(oldColor); } } + +static void openvrUpdate(float dt) { +} + + +HeadsetInterface lovrHeadsetOpenVRDriver = { + openvrIsAvailable, + openvrInit, + openvrDestroy, + openvrPoll, + openvrIsPresent, + openvrGetType, + openvrGetOriginType, + openvrIsMirrored, + openvrSetMirrored, + openvrGetDisplayDimensions, + openvrGetClipDistance, + openvrSetClipDistance, + openvrGetBoundsWidth, + openvrGetBoundsDepth, + openvrGetBoundsGeometry, + openvrGetPosition, + openvrGetEyePosition, + openvrGetOrientation, + openvrGetVelocity, + openvrGetAngularVelocity, + openvrGetControllers, + openvrControllerIsPresent, + openvrControllerGetHand, + openvrControllerGetPosition, + openvrControllerGetOrientation, + openvrControllerGetAxis, + openvrControllerIsDown, + openvrControllerIsTouched, + openvrControllerVibrate, + openvrControllerNewModelData, + openvrRenderTo, + openvrUpdate, +}; + diff --git a/src/headset/openvr.h b/src/headset/openvr.h deleted file mode 100644 index 4fd80cb8..00000000 --- a/src/headset/openvr.h +++ /dev/null @@ -1,52 +0,0 @@ -#include "headset/headset.h" -#include "graphics/texture.h" -#include "lib/glfw.h" -#include -#ifndef _WIN32 -#define __stdcall -#endif -#include - -#pragma once - -// From openvr_capi.h -extern intptr_t VR_InitInternal(EVRInitError *peError, EVRApplicationType eType); -extern void VR_ShutdownInternal(); -extern bool VR_IsHmdPresent(); -extern intptr_t VR_GetGenericInterface(const char* pchInterfaceVersion, EVRInitError* peError); -extern bool VR_IsRuntimeInstalled(); -extern const char* VR_GetVRInitErrorAsSymbol(EVRInitError error); -extern const char* VR_GetVRInitErrorAsEnglishDescription(EVRInitError error); - -typedef struct { - int isInitialized; - int isRendering; - int isMirrored; - - struct VR_IVRSystem_FnTable* system; - struct VR_IVRCompositor_FnTable* compositor; - struct VR_IVRChaperone_FnTable* chaperone; - struct VR_IVRRenderModels_FnTable* renderModels; - - unsigned int headsetIndex; - HeadsetType type; - - TrackedDevicePose_t renderPoses[16]; - RenderModel_t* deviceModels[16]; - RenderModel_TextureMap_t* deviceTextures[16]; - - vec_controller_t controllers; - - float clipNear; - float clipFar; - - uint32_t renderWidth; - uint32_t renderHeight; - float refreshRate; - float vsyncToPhotons; - - Texture* texture; -} HeadsetState; - -void lovrHeadsetRefreshControllers(); -Controller* lovrHeadsetAddController(unsigned int id); diff --git a/src/headset/webvr.c b/src/headset/webvr.c index c6f5f993..d176bc62 100644 --- a/src/headset/webvr.c +++ b/src/headset/webvr.c @@ -48,13 +48,16 @@ static void onRequestAnimationFrame(void* userdata) { } } -void lovrHeadsetInit() { - vec_init(&state.controllers); - emscripten_vr_init(); - atexit(lovrHeadsetDestroy); +static int webvrIsAvailable() { + return emscripten_vr_is_present(); } -void lovrHeadsetDestroy() { +static void webvrInit() { + vec_init(&state.controllers); + emscripten_vr_init(); +} + +static void webvrDestroy() { Controller* controller; int i; vec_foreach(&state.controllers, controller, i) { @@ -64,56 +67,56 @@ void lovrHeadsetDestroy() { vec_deinit(&state.controllers); } -void lovrHeadsetPoll() { +static void webvrPoll() { // } -int lovrHeadsetIsPresent() { +static int webvrIsPresent() { return emscripten_vr_is_present(); } -HeadsetType lovrHeadsetGetType() { +static HeadsetType webvrGetType() { return HEADSET_UNKNOWN; } -HeadsetOrigin lovrHeadsetGetOriginType() { +static HeadsetOrigin webvrGetOriginType() { return emscripten_vr_has_stage() ? ORIGIN_FLOOR : ORIGIN_HEAD; } -int lovrHeadsetIsMirrored() { +static int webvrIsMirrored() { return 1; } -void lovrHeadsetSetMirrored(int mirror) { +static void webvrSetMirrored(int mirror) { // } -void lovrHeadsetGetDisplayDimensions(int* width, int* height) { +static void webvrGetDisplayDimensions(int* width, int* height) { *width = emscripten_vr_get_display_width() / 2; *height = emscripten_vr_get_display_height(); } -void lovrHeadsetGetClipDistance(float* near, float* far) { +static void webvrGetClipDistance(float* near, float* far) { emscripten_vr_get_display_clip_distance(near, far); } -void lovrHeadsetSetClipDistance(float near, float far) { +static void webvrSetClipDistance(float near, float far) { emscripten_vr_set_display_clip_distance(near, far); } -float lovrHeadsetGetBoundsWidth() { +static float webvrGetBoundsWidth() { return emscripten_vr_get_bounds_width(); } -float lovrHeadsetGetBoundsDepth() { +static float webvrGetBoundsDepth() { return emscripten_vr_get_bounds_depth(); } -void lovrHeadsetGetBoundsGeometry(float* geometry) { +static void webvrGetBoundsGeometry(float* geometry) { memset(geometry, 0, 12 * sizeof(float)); } -void lovrHeadsetGetPosition(float* x, float* y, float* z) { +static void webvrGetPosition(float* x, float* y, float* z) { float v[3]; emscripten_vr_get_position(&v[0], &v[1], &v[2]); mat4_transform(emscripten_vr_get_sitting_to_standing_matrix(), v); @@ -122,7 +125,7 @@ void lovrHeadsetGetPosition(float* x, float* y, float* z) { *z = v[2]; } -void lovrHeadsetGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { +static void webvrGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { int i = eye == EYE_LEFT ? 0 : 1; emscripten_vr_get_eye_offset(i, x, y, z); float m[16]; @@ -134,7 +137,7 @@ void lovrHeadsetGetEyePosition(HeadsetEye eye, float* x, float* y, float* z) { *z = m[14]; } -void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float* z) { +static void webvrGetOrientation(float* angle, float* x, float* y, float* z) { float quat[4]; float m[16]; emscripten_vr_get_orientation(&quat[0], &quat[1], &quat[2], &quat[3]); @@ -143,7 +146,7 @@ void lovrHeadsetGetOrientation(float* angle, float* x, float* y, float* z) { quat_getAngleAxis(quat_fromMat4(quat, m), angle, x, y, z); } -void lovrHeadsetGetVelocity(float* x, float* y, float* z) { +static void webvrGetVelocity(float* x, float* y, float* z) { float v[3]; emscripten_vr_get_velocity(&v[0], &v[1], &v[2]); mat4_transformDirection(emscripten_vr_get_sitting_to_standing_matrix(), v); @@ -152,7 +155,7 @@ void lovrHeadsetGetVelocity(float* x, float* y, float* z) { *z = v[2]; } -void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) { +static void webvrGetAngularVelocity(float* x, float* y, float* z) { float v[3]; emscripten_vr_get_angular_velocity(&v[0], &v[1], &v[2]); mat4_transformDirection(emscripten_vr_get_sitting_to_standing_matrix(), v); @@ -161,7 +164,7 @@ void lovrHeadsetGetAngularVelocity(float* x, float* y, float* z) { *z = v[2]; } -vec_controller_t* lovrHeadsetGetControllers() { +static vec_controller_t* webvrGetControllers() { int controllerCount = emscripten_vr_get_controller_count(); while (state.controllers.length > controllerCount) { @@ -179,11 +182,11 @@ vec_controller_t* lovrHeadsetGetControllers() { return &state.controllers; } -int lovrHeadsetControllerIsPresent(Controller* controller) { +static int webvrControllerIsPresent(Controller* controller) { return emscripten_vr_controller_is_present(controller->id); } -ControllerHand lovrHeadsetControllerGetHand(Controller* controller) { +static ControllerHand webvrControllerGetHand(Controller* controller) { switch (emscripten_vr_controller_get_hand(controller->id)) { case 0: return HAND_UNKNOWN; case 1: return HAND_LEFT; @@ -192,7 +195,7 @@ ControllerHand lovrHeadsetControllerGetHand(Controller* controller) { } } -void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y, float* z) { +static void webvrControllerGetPosition(Controller* controller, float* x, float* y, float* z) { float v[3]; emscripten_vr_get_controller_position(controller->id, &v[0], &v[1], &v[2]); mat4_transform(emscripten_vr_get_sitting_to_standing_matrix(), v); @@ -201,7 +204,7 @@ void lovrHeadsetControllerGetPosition(Controller* controller, float* x, float* y *z = v[2]; } -void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) { +static void webvrControllerGetOrientation(Controller* controller, float* angle, float* x, float* y, float* z) { float quat[4]; float m[16]; emscripten_vr_get_controller_orientation(controller->id, &quat[0], &quat[1], &quat[2], &quat[3]); @@ -210,7 +213,7 @@ void lovrHeadsetControllerGetOrientation(Controller* controller, float* angle, f quat_getAngleAxis(quat_fromMat4(quat, m), angle, x, y, z); } -float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) { +static float webvrControllerGetAxis(Controller* controller, ControllerAxis axis) { switch (axis) { case CONTROLLER_AXIS_TRIGGER: return emscripten_vr_controller_get_axis(controller->id, -1); case CONTROLLER_AXIS_TOUCHPAD_X: return emscripten_vr_controller_get_axis(controller->id, 0); @@ -219,7 +222,7 @@ float lovrHeadsetControllerGetAxis(Controller* controller, ControllerAxis axis) } } -int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button) { +static int webvrControllerIsDown(Controller* controller, ControllerButton button) { switch (button) { case CONTROLLER_BUTTON_TOUCHPAD: return emscripten_vr_controller_is_down(controller->id, 0); @@ -234,19 +237,59 @@ int lovrHeadsetControllerIsDown(Controller* controller, ControllerButton button) } } -int lovrHeadsetControllerIsTouched(Controller* controller, ControllerButton button) { +static int webvrControllerIsTouched(Controller* controller, ControllerButton button) { return 0; } -void lovrHeadsetControllerVibrate(Controller* controller, float duration, float power) { +static void webvrControllerVibrate(Controller* controller, float duration, float power) { emscripten_vr_controller_vibrate(controller->id, duration * 1000, power); } -ModelData* lovrHeadsetControllerNewModelData(Controller* controller) { +static ModelData* webvrControllerNewModelData(Controller* controller) { return NULL; } -void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) { +static void webvrRenderTo(headsetRenderCallback callback, void* userdata) { state.renderCallback = callback; emscripten_vr_set_render_callback(onRequestAnimationFrame, userdata); } + +static void webvrUpdate(float dt) { +} + + +HeadsetInterface lovrHeadsetWebVRDriver = { + webvrIsAvailable, + webvrInit, + webvrDestroy, + webvrPoll, + webvrIsPresent, + webvrGetType, + webvrGetOriginType, + webvrIsMirrored, + webvrSetMirrored, + webvrGetDisplayDimensions, + webvrGetClipDistance, + webvrSetClipDistance, + webvrGetBoundsWidth, + webvrGetBoundsDepth, + webvrGetBoundsGeometry, + webvrGetPosition, + webvrGetEyePosition, + webvrGetOrientation, + webvrGetVelocity, + webvrGetAngularVelocity, + webvrGetControllers, + webvrControllerIsPresent, + webvrControllerGetHand, + webvrControllerGetPosition, + webvrControllerGetOrientation, + webvrControllerGetAxis, + webvrControllerIsDown, + webvrControllerIsTouched, + webvrControllerVibrate, + webvrControllerNewModelData, + webvrRenderTo, + webvrUpdate, +}; +