mirror of https://github.com/bjornbytes/lovr.git
commit
618be7b51d
|
@ -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}
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -1047,3 +1047,8 @@ void lovrGraphicsBindIndexBuffer(uint32_t indexBuffer) {
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
GLFWwindow* lovrGraphicsGetWindow() {
|
||||
return state.window;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
// 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,
|
||||
};
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <openvr_capi.h>
|
||||
|
||||
// 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,
|
||||
};
|
||||
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
#include "headset/headset.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "lib/glfw.h"
|
||||
#include <stdbool.h>
|
||||
#ifndef _WIN32
|
||||
#define __stdcall
|
||||
#endif
|
||||
#include <openvr_capi.h>
|
||||
|
||||
#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);
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue