1
0
Fork 0
mirror of https://github.com/bjornbytes/lovr.git synced 2024-07-23 22:23:35 +00:00
lovr/src/headset/vive.c

364 lines
12 KiB
C
Raw Normal View History

2016-09-17 04:37:30 +00:00
#include "vive.h"
2016-10-03 18:26:54 +00:00
#include <stdbool.h>
2016-10-24 21:09:32 +00:00
#ifndef WIN32
#define __stdcall
#endif
2016-09-17 04:37:30 +00:00
#include <openvr_capi.h>
#include <stdlib.h>
#include "../util.h"
#include "../graphics/graphics.h"
typedef struct {
struct VR_IVRSystem_FnTable* vrSystem;
struct VR_IVRCompositor_FnTable* vrCompositor;
2016-09-30 06:54:38 +00:00
struct VR_IVRChaperone_FnTable* vrChaperone;
2016-09-17 04:37:30 +00:00
2016-10-03 01:09:33 +00:00
unsigned int headsetIndex;
unsigned int controllerIndex[CONTROLLER_HAND_RIGHT + 1];
Controller* controllers[CONTROLLER_HAND_RIGHT + 1];
2016-09-17 04:37:30 +00:00
2016-09-27 06:48:09 +00:00
float clipNear;
float clipFar;
2016-09-17 04:37:30 +00:00
uint32_t renderWidth;
uint32_t renderHeight;
GLuint framebuffer;
GLuint depthbuffer;
GLuint texture;
2016-09-27 01:38:45 +00:00
GLuint resolveFramebuffer;
GLuint resolveTexture;
2016-09-17 04:37:30 +00:00
} ViveState;
static HeadsetInterface interface = {
2016-10-01 21:12:55 +00:00
.isPresent = viveIsPresent,
2016-09-17 21:25:08 +00:00
.getType = viveGetType,
2016-10-24 23:03:29 +00:00
.getDisplayDimensions = viveGetDisplayDimensions,
2016-10-01 21:12:55 +00:00
.getClipDistance = viveGetClipDistance,
.setClipDistance = viveSetClipDistance,
2016-10-02 01:09:18 +00:00
.getTrackingSize = viveGetTrackingSize,
.isBoundsVisible = viveIsBoundsVisible,
.setBoundsVisible = viveSetBoundsVisible,
2016-10-01 21:12:55 +00:00
.getPosition = viveGetPosition,
.getOrientation = viveGetOrientation,
2016-09-17 04:37:30 +00:00
.getVelocity = viveGetVelocity,
2016-10-01 21:12:55 +00:00
.getAngularVelocity = viveGetAngularVelocity,
2016-10-03 01:09:33 +00:00
.getController = viveGetController,
2016-10-03 18:12:06 +00:00
.isControllerPresent = viveIsControllerPresent,
2016-10-03 18:12:21 +00:00
.getControllerPosition = viveGetControllerPosition,
2016-10-03 18:16:48 +00:00
.getControllerOrientation = viveGetControllerOrientation,
2016-10-24 22:52:16 +00:00
.getControllerHand = viveGetControllerHand,
2016-09-17 04:37:30 +00:00
.renderTo = viveRenderTo
};
2016-10-03 18:10:24 +00:00
static TrackedDevicePose_t viveGetPose(ViveState* state, unsigned int deviceIndex) {
ETrackingUniverseOrigin origin = ETrackingUniverseOrigin_TrackingUniverseStanding;
float secondsInFuture = 0.f;
2016-10-04 00:02:01 +00:00
TrackedDevicePose_t poses[16];
state->vrSystem->GetDeviceToAbsoluteTrackingPose(origin, secondsInFuture, poses, 16);
2016-10-03 18:10:24 +00:00
return poses[deviceIndex];
}
2016-09-17 04:37:30 +00:00
Headset* viveInit() {
Headset* this = malloc(sizeof(Headset));
ViveState* state = malloc(sizeof(ViveState));
2016-11-08 22:44:03 +00:00
if (!this || !state) return NULL;
2016-09-17 04:37:30 +00:00
2016-09-25 05:38:48 +00:00
this->state = state;
2016-09-17 04:37:30 +00:00
this->interface = &interface;
if (!VR_IsHmdPresent()) {
return NULL;
2016-09-17 04:37:30 +00:00
} else if (!VR_IsRuntimeInstalled()) {
return NULL;
2016-09-17 04:37:30 +00:00
}
EVRInitError vrError;
2016-09-27 06:48:09 +00:00
VR_InitInternal(&vrError, EVRApplicationType_VRApplication_Scene);
2016-09-17 04:37:30 +00:00
if (vrError != EVRInitError_VRInitError_None) {
return NULL;
}
char fnTableName[128];
sprintf(fnTableName, "FnTable:%s", IVRSystem_Version);
state->vrSystem = (struct VR_IVRSystem_FnTable*) VR_GetGenericInterface(fnTableName, &vrError);
if (vrError != EVRInitError_VRInitError_None || state->vrSystem == NULL) {
return NULL;
}
sprintf(fnTableName, "FnTable:%s", IVRCompositor_Version);
state->vrCompositor = (struct VR_IVRCompositor_FnTable*) VR_GetGenericInterface(fnTableName, &vrError);
if (vrError != EVRInitError_VRInitError_None || state->vrCompositor == NULL) {
return NULL;
}
2016-09-30 06:54:38 +00:00
sprintf(fnTableName, "FnTable:%s", IVRChaperone_Version);
state->vrChaperone = (struct VR_IVRChaperone_FnTable*) VR_GetGenericInterface(fnTableName, &vrError);
if (vrError != EVRInitError_VRInitError_None || state->vrChaperone == NULL) {
return NULL;
}
2016-10-03 01:09:33 +00:00
state->headsetIndex = k_unTrackedDeviceIndex_Hmd;
2016-09-27 07:24:28 +00:00
state->clipNear = 0.1f;
state->clipFar = 30.f;
2016-09-17 04:37:30 +00:00
state->vrSystem->GetRecommendedRenderTargetSize(&state->renderWidth, &state->renderHeight);
2016-10-03 01:09:33 +00:00
Controller* leftController = malloc(sizeof(Controller));
leftController->hand = CONTROLLER_HAND_LEFT;
state->controllers[CONTROLLER_HAND_LEFT] = leftController;
state->controllerIndex[CONTROLLER_HAND_LEFT] = state->vrSystem->GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole_TrackedControllerRole_LeftHand);
Controller* rightController = malloc(sizeof(Controller));
rightController->hand = CONTROLLER_HAND_RIGHT;
state->controllers[CONTROLLER_HAND_RIGHT] = rightController;
state->controllerIndex[CONTROLLER_HAND_RIGHT] = state->vrSystem->GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole_TrackedControllerRole_RightHand);
2016-09-17 04:37:30 +00:00
glGenFramebuffers(1, &state->framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, state->framebuffer);
glGenRenderbuffers(1, &state->depthbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, state->depthbuffer);
2016-09-27 01:38:45 +00:00
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH_COMPONENT, state->renderWidth, state->renderHeight);
2016-09-17 04:37:30 +00:00
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, state->depthbuffer);
glGenTextures(1, &state->texture);
2016-09-27 01:38:45 +00:00
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, state->texture);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA8, state->renderWidth, state->renderHeight, 1);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, state->texture, 0);
glGenFramebuffers(1, &state->resolveFramebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, state->resolveFramebuffer);
glGenTextures(1, &state->resolveTexture);
glBindTexture(GL_TEXTURE_2D, state->resolveTexture);
2016-09-17 04:37:30 +00:00
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, state->renderWidth, state->renderHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
2016-09-27 01:38:45 +00:00
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, state->resolveTexture, 0);
2016-09-17 04:37:30 +00:00
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
return NULL;
2016-09-17 04:37:30 +00:00
}
glBindFramebuffer(GL_FRAMEBUFFER, 0);
return this;
}
void viveDestroy(void* headset) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
free(state->controllers[CONTROLLER_HAND_LEFT]);
free(state->controllers[CONTROLLER_HAND_RIGHT]);
free(state);
free(this);
}
2016-10-03 18:40:20 +00:00
char viveIsPresent(void* headset) {
2016-09-17 04:37:30 +00:00
Headset* this = (Headset*) headset;
ViveState* state = this->state;
2016-10-03 18:40:20 +00:00
return state->vrSystem->IsTrackedDeviceConnected(state->headsetIndex);
2016-10-01 21:12:55 +00:00
}
2016-09-17 04:37:30 +00:00
2016-10-01 21:12:55 +00:00
const char* viveGetType(void* headset) {
return "Vive";
2016-09-17 04:37:30 +00:00
}
2016-10-24 23:03:29 +00:00
void viveGetDisplayDimensions(void* headset, int* width, int* height) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
*width = state->renderWidth;
*height = state->renderHeight;
}
2016-09-27 06:48:09 +00:00
void viveGetClipDistance(void* headset, float* near, float* far) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
*near = state->clipNear;
*far = state->clipFar;
}
2016-10-01 21:12:55 +00:00
void viveSetClipDistance(void* headset, float near, float far) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
state->clipNear = near;
state->clipFar = far;
2016-09-17 04:37:30 +00:00
}
2016-10-01 21:17:26 +00:00
void viveGetTrackingSize(void* headset, float* width, float* depth) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
state->vrChaperone->GetPlayAreaSize(width, depth);
}
2016-10-01 22:11:45 +00:00
char viveIsBoundsVisible(void* headset) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
return state->vrChaperone->AreBoundsVisible();
}
void viveSetBoundsVisible(void* headset, char visible) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
state->vrChaperone->ForceBoundsVisible(visible);
}
2016-09-17 21:25:08 +00:00
void viveGetPosition(void* headset, float* x, float* y, float* z) {
2016-09-17 04:37:30 +00:00
Headset* this = (Headset*) headset;
ViveState* state = this->state;
2016-10-03 18:10:24 +00:00
TrackedDevicePose_t pose = viveGetPose(state, state->headsetIndex);
2016-09-17 04:37:30 +00:00
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*x = *y = *z = 0.f;
return;
}
2016-09-17 21:25:08 +00:00
*x = pose.mDeviceToAbsoluteTracking.m[0][3];
*y = pose.mDeviceToAbsoluteTracking.m[1][3];
*z = pose.mDeviceToAbsoluteTracking.m[2][3];
2016-09-17 04:37:30 +00:00
}
2016-10-04 00:02:01 +00:00
void viveGetOrientation(void* headset, float* w, float* x, float* y, float *z) {
Headset* this = (Headset*) headset;
ViveState* state = this->state;
TrackedDevicePose_t pose = viveGetPose(state, state->headsetIndex);
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*w = *x = *y = *z = 0.f;
return;
}
float matrix[16];
2016-10-04 01:00:33 +00:00
mat4_getRotation(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), w, x, y, z);
2016-09-17 21:25:08 +00:00
}
void viveGetVelocity(void* headset, float* x, float* y, float* z) {
2016-09-17 04:37:30 +00:00
Headset* this = (Headset*) headset;
ViveState* state = this->state;
2016-10-03 18:10:24 +00:00
TrackedDevicePose_t pose = viveGetPose(state, state->headsetIndex);
2016-09-17 04:37:30 +00:00
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*x = *y = *z = 0.f;
return;
}
2016-09-17 21:25:08 +00:00
*x = pose.vVelocity.v[0];
*y = pose.vVelocity.v[1];
*z = pose.vVelocity.v[2];
2016-09-17 04:37:30 +00:00
}
2016-10-01 21:12:55 +00:00
void viveGetAngularVelocity(void* headset, float* x, float* y, float* z) {
2016-09-17 04:37:30 +00:00
Headset* this = (Headset*) headset;
ViveState* state = this->state;
2016-10-03 18:10:24 +00:00
TrackedDevicePose_t pose = viveGetPose(state, state->headsetIndex);
2016-10-01 21:12:55 +00:00
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*x = *y = *z = 0.f;
return;
}
*x = pose.vAngularVelocity.v[0];
*y = pose.vAngularVelocity.v[1];
*z = pose.vAngularVelocity.v[2];
2016-09-17 04:37:30 +00:00
}
2016-10-03 01:09:33 +00:00
Controller* viveGetController(void* headset, ControllerHand hand) {
Headset* this = headset;
ViveState* state = this->state;
return state->controllers[hand];
}
2016-10-03 18:12:06 +00:00
char viveIsControllerPresent(void* headset, Controller* controller) {
Headset* this = headset;
ViveState* state = this->state;
return state->vrSystem->IsTrackedDeviceConnected(state->controllerIndex[controller->hand]);
}
2016-10-03 18:12:21 +00:00
void viveGetControllerPosition(void* headset, Controller* controller, float* x, float* y, float* z) {
Headset* this = headset;
ViveState* state = this->state;
TrackedDevicePose_t pose = viveGetPose(state, state->controllerIndex[controller->hand]);
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*x = *y = *z = 0.f;
return;
}
*x = pose.mDeviceToAbsoluteTracking.m[0][3];
*y = pose.mDeviceToAbsoluteTracking.m[1][3];
*z = pose.mDeviceToAbsoluteTracking.m[2][3];
}
2016-10-03 18:16:48 +00:00
void viveGetControllerOrientation(void* headset, Controller* controller, float* w, float* x, float* y, float* z) {
Headset* this = headset;
ViveState* state = this->state;
TrackedDevicePose_t pose = viveGetPose(state, state->controllerIndex[controller->hand]);
if (!pose.bPoseIsValid || !pose.bDeviceIsConnected) {
*w = *x = *y = *z = 0.f;
return;
}
2016-10-04 01:00:33 +00:00
float matrix[16];
mat4_getRotation(mat4_fromMat44(matrix, pose.mDeviceToAbsoluteTracking.m), w, x, y, z);
2016-10-03 18:16:48 +00:00
}
2016-10-24 22:52:16 +00:00
ControllerHand viveGetControllerHand(void* headset, Controller* controller) {
return controller->hand;
}
2016-09-17 04:37:30 +00:00
void viveRenderTo(void* headset, headsetRenderCallback callback, void* userdata) {
Headset* this = headset;
ViveState* state = this->state;
2016-09-27 06:48:09 +00:00
float headMatrix[16], eyeMatrix[16], projectionMatrix[16];
float (*matrix)[4];
EGraphicsAPIConvention graphicsConvention = EGraphicsAPIConvention_API_OpenGL;
2016-09-17 04:37:30 +00:00
TrackedDevicePose_t pose;
2016-09-27 06:48:09 +00:00
state->vrCompositor->WaitGetPoses(&pose, 1, NULL, 0);
matrix = pose.mDeviceToAbsoluteTracking.m;
mat4_invert(mat4_fromMat34(headMatrix, matrix));
2016-09-27 01:38:45 +00:00
2016-09-17 04:37:30 +00:00
for (int i = 0; i < 2; i++) {
EVREye eye = (i == 0) ? EVREye_Eye_Left : EVREye_Eye_Right;
2016-09-27 06:48:09 +00:00
matrix = state->vrSystem->GetEyeToHeadTransform(eye).m;
mat4_invert(mat4_fromMat34(eyeMatrix, matrix));
2016-09-29 07:21:38 +00:00
mat4 transformMatrix = mat4_multiply(eyeMatrix, headMatrix);
2016-09-27 06:48:09 +00:00
float near = state->clipNear;
float far = state->clipFar;
matrix = state->vrSystem->GetProjectionMatrix(eye, near, far, graphicsConvention).m;
mat4_fromMat44(projectionMatrix, matrix);
2016-09-17 04:37:30 +00:00
2016-09-27 01:38:45 +00:00
glEnable(GL_MULTISAMPLE);
2016-09-17 04:37:30 +00:00
glBindFramebuffer(GL_FRAMEBUFFER, state->framebuffer);
glViewport(0, 0, state->renderWidth, state->renderHeight);
2016-09-27 01:38:45 +00:00
2016-09-29 07:21:38 +00:00
lovrGraphicsClear(1, 1);
lovrGraphicsPush();
lovrGraphicsOrigin();
2016-11-02 03:48:04 +00:00
lovrGraphicsMatrixTransform(transformMatrix);
2016-09-29 07:21:38 +00:00
lovrGraphicsSetProjectionRaw(projectionMatrix);
2016-09-17 04:37:30 +00:00
callback(i, userdata);
2016-09-29 07:21:38 +00:00
lovrGraphicsPop();
2016-09-27 01:38:45 +00:00
2016-09-17 04:37:30 +00:00
glBindFramebuffer(GL_FRAMEBUFFER, 0);
2016-09-27 01:38:45 +00:00
glDisable(GL_MULTISAMPLE);
glBindFramebuffer(GL_READ_FRAMEBUFFER, state->framebuffer);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, state->resolveFramebuffer);
glBlitFramebuffer(0, 0, state->renderWidth, state->renderHeight, 0, 0, state->renderWidth, state->renderHeight, GL_COLOR_BUFFER_BIT, GL_LINEAR);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
2016-09-17 04:37:30 +00:00
2016-10-01 22:13:54 +00:00
uintptr_t texture = (uintptr_t) state->resolveTexture;
Texture_t eyeTexture = { (void*) texture, graphicsConvention, EColorSpace_ColorSpace_Gamma };
2016-09-17 04:37:30 +00:00
EVRSubmitFlags flags = EVRSubmitFlags_Submit_Default;
state->vrCompositor->Submit(eye, &eyeTexture, NULL, flags);
}
}