pick appropriate headset implementation at runtime

(just fake and openvr for now. Need to add webvr support still)
This commit is contained in:
Ben Campbell 2017-10-21 22:39:33 +13:00
parent 5df4197f39
commit c694f56439
7 changed files with 164 additions and 139 deletions

View File

@ -246,7 +246,9 @@ set(LOVR_SRC
src/graphics/shader.c
src/graphics/skybox.c
src/graphics/texture.c
src/headset/fake.c
src/headset/headset.c
src/headset/openvr.c
src/lib/glad/glad.c
src/lib/lua-cjson/fpconv.c
src/lib/lua-cjson/lua_cjson.c
@ -275,10 +277,7 @@ set(LOVR_SRC
)
if(EMSCRIPTEN)
set(LOVR_HEADSET src/headset/webvr.c)
else()
# set(LOVR_HEADSET src/headset/openvr.c)
set(LOVR_HEADSET src/headset/fake.c)
set(LOVR_SRC, ${LOVR_SRC} "src/headset/webvr.c")
endif()
if(WIN32)
@ -289,7 +288,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}

View File

@ -6,6 +6,9 @@
#include "math/vec3.h"
#include "math/quat.h"
#include "util.h"
//#include "graphics/texture.h"
//#include "lib/glfw.h"
//#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

View File

@ -1,19 +0,0 @@
/* vim: set ts=2 sts=2 sw=2: */
#include "headset/headset.h"
#include "graphics/texture.h"
#include "lib/glfw.h"
#include <stdbool.h>
#ifndef _WIN32
#define __stdcall
#endif
#pragma once
/* A default fake headset to stand in for a missing VR one.
* uses mouse to look around, WASD or cursor keys to move.
* Left shift and Space move up and down.
*/
HeadsetImpl lovrHeadsetFakeDriver;

View File

@ -11,25 +11,12 @@ void lovrControllerDestroy(const Ref* ref) {
static HeadsetImpl* headset = NULL;
#if 0
// not needed yet, but if we expose driver selection to lua...
int lovrHeadsetIsDriverAvailable(HeadsetDriver driver) {
switch(driver) {
case HEADSET_DRIVER_FAKE:
return lovrHeadsetFakeImpl->isAvailable();
case HEADSET_DRIVER_OPENVR:
case HEADSET_DRIVER_WEBVR:
default:
return 0;
}
}
#endif
void lovrHeadsetInit() {
// assert(headset==NULL)
// TODO: should expose driver selection to lua, so conf can express a preference?
HeadsetImpl* drivers[] = { &lovrHeadsetFakeDriver, NULL };
HeadsetImpl* drivers[] = { &lovrHeadsetOpenVRDriver, &lovrHeadsetFakeDriver, NULL };
int i;
for (i=0; drivers[i]; ++i ) {

View File

@ -68,7 +68,6 @@ typedef vec_t(Controller*) vec_controller_t;
typedef void (*headsetRenderCallback)(HeadsetEye eye, void* userdata);
typedef struct {
int (*isAvailable)();
void (*init)();
@ -106,6 +105,11 @@ typedef struct {
} HeadsetImpl;
// headset implementations
extern HeadsetImpl lovrHeadsetOpenVRDriver;
extern HeadsetImpl lovrHeadsetFakeDriver;
void lovrHeadsetInit();
void lovrHeadsetDestroy();
void lovrHeadsetPoll();

View File

@ -1,15 +1,78 @@
/* vim: set ts=2 sts=2 sw=2: */
#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 "lib/glfw.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 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);
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 +151,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 +164,7 @@ void lovrHeadsetInit() {
}
if (!VR_IsHmdPresent() || !VR_IsRuntimeInstalled()) {
lovrHeadsetDestroy();
openvrDestroy();
return;
}
@ -109,7 +172,7 @@ void lovrHeadsetInit() {
VR_InitInternal(&vrError, EVRApplicationType_VRApplication_Scene);
if (vrError != EVRInitError_VRInitError_None) {
lovrHeadsetDestroy();
openvrDestroy();
return;
}
@ -118,28 +181,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 +223,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 +246,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 +254,7 @@ void lovrHeadsetPoll() {
case EVREventType_VREvent_TrackedDeviceActivated:
case EVREventType_VREvent_TrackedDeviceDeactivated:
case EVREventType_VREvent_TrackedDeviceRoleChanged: {
lovrHeadsetRefreshControllers();
openvrRefreshControllers();
break;
}
@ -203,7 +265,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 +295,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 +315,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 +332,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 +341,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 +375,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 +393,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 +418,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 +437,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 +455,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 +473,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 +501,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 +512,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 +532,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 +551,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 +568,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 +586,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 +614,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 +640,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;
@ -651,13 +713,13 @@ ModelData* lovrHeadsetControllerNewModelData(Controller* controller) {
return modelData;
}
TextureData* lovrHeadsetControllerNewTextureData(Controller* controller) {
static TextureData* openvrControllerNewTextureData(Controller* controller) {
if (!state.isInitialized || !controller) return NULL;
int id = controller->id;
if (!state.deviceModels[id]) {
lovrHeadsetControllerNewModelData(controller);
openvrControllerNewModelData(controller);
}
if (!state.deviceTextures[id]) {
@ -685,7 +747,7 @@ TextureData* lovrHeadsetControllerNewTextureData(Controller* controller) {
return textureData;
}
void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) {
static void openvrRenderTo(headsetRenderCallback callback, void* userdata) {
if (!state.isInitialized) return;
if (!state.texture) {
@ -764,3 +826,44 @@ void lovrHeadsetRenderTo(headsetRenderCallback callback, void* userdata) {
lovrGraphicsSetColor(oldColor);
}
}
static void openvrUpdate(float dt) {
}
HeadsetImpl 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,
openvrControllerNewTextureData,
openvrRenderTo,
openvrUpdate,
};

View File

@ -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);