2022-07-12 16:53:46 +00:00
|
|
|
#include "VRBase.h"
|
2022-07-17 12:45:02 +00:00
|
|
|
#include "VRInput.h"
|
2022-07-12 16:53:46 +00:00
|
|
|
#include "VRRenderer.h"
|
|
|
|
|
2022-10-17 16:39:02 +00:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdlib>
|
|
|
|
#include <cstring>
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-09-20 16:57:58 +00:00
|
|
|
XrFovf fov;
|
2022-07-12 16:53:46 +00:00
|
|
|
XrView* projections;
|
2022-07-15 13:41:21 +00:00
|
|
|
XrPosef invViewTransform[2];
|
|
|
|
XrFrameState frameState = {};
|
2022-09-12 23:39:44 +00:00
|
|
|
bool initialized = false;
|
|
|
|
bool stageSupported = false;
|
2022-07-27 17:47:11 +00:00
|
|
|
int vrConfig[VR_CONFIG_MAX] = {};
|
2022-10-08 12:38:49 +00:00
|
|
|
ovrMatrix4f vrMatrix[VR_MATRIX_COUNT];
|
2022-07-17 12:45:02 +00:00
|
|
|
|
2022-08-01 15:11:23 +00:00
|
|
|
XrVector3f hmdorientation;
|
|
|
|
XrVector3f hmdposition;
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-10-17 21:13:18 +00:00
|
|
|
#ifdef OPENXR
|
|
|
|
|
2022-07-12 16:53:46 +00:00
|
|
|
void VR_UpdateStageBounds(ovrApp* pappState) {
|
2022-07-24 12:25:04 +00:00
|
|
|
XrExtent2Df stageBounds = {};
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
XrResult result;
|
2022-08-28 19:09:02 +00:00
|
|
|
OXR(result = xrGetReferenceSpaceBoundsRect(pappState->Session, XR_REFERENCE_SPACE_TYPE_STAGE, &stageBounds));
|
2022-07-24 12:25:04 +00:00
|
|
|
if (result != XR_SUCCESS) {
|
|
|
|
ALOGV("Stage bounds query failed: using small defaults");
|
|
|
|
stageBounds.width = 1.0f;
|
|
|
|
stageBounds.height = 1.0f;
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
pappState->CurrentSpace = pappState->FakeStageSpace;
|
|
|
|
}
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
ALOGV("Stage bounds: width = %f, depth %f", stageBounds.width, stageBounds.height);
|
2022-07-12 16:53:46 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 11:14:53 +00:00
|
|
|
void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight) {
|
2022-07-12 16:53:46 +00:00
|
|
|
static int width = 0;
|
|
|
|
static int height = 0;
|
2022-07-24 12:25:04 +00:00
|
|
|
|
2022-07-23 11:14:53 +00:00
|
|
|
if (engine) {
|
2022-07-24 12:25:04 +00:00
|
|
|
// Enumerate the viewport configurations.
|
|
|
|
uint32_t viewportConfigTypeCount = 0;
|
|
|
|
OXR(xrEnumerateViewConfigurations(
|
|
|
|
engine->appState.Instance, engine->appState.SystemId, 0, &viewportConfigTypeCount, NULL));
|
|
|
|
|
|
|
|
XrViewConfigurationType* viewportConfigurationTypes =
|
|
|
|
(XrViewConfigurationType*)malloc(viewportConfigTypeCount * sizeof(XrViewConfigurationType));
|
|
|
|
|
|
|
|
OXR(xrEnumerateViewConfigurations(
|
|
|
|
engine->appState.Instance,
|
|
|
|
engine->appState.SystemId,
|
|
|
|
viewportConfigTypeCount,
|
|
|
|
&viewportConfigTypeCount,
|
|
|
|
viewportConfigurationTypes));
|
|
|
|
|
|
|
|
ALOGV("Available Viewport Configuration Types: %d", viewportConfigTypeCount);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < viewportConfigTypeCount; i++) {
|
|
|
|
const XrViewConfigurationType viewportConfigType = viewportConfigurationTypes[i];
|
|
|
|
|
|
|
|
ALOGV(
|
|
|
|
"Viewport configuration type %d : %s",
|
|
|
|
viewportConfigType,
|
|
|
|
viewportConfigType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO ? "Selected" : "");
|
|
|
|
|
|
|
|
XrViewConfigurationProperties viewportConfig;
|
|
|
|
viewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
|
|
|
|
OXR(xrGetViewConfigurationProperties(
|
|
|
|
engine->appState.Instance, engine->appState.SystemId, viewportConfigType, &viewportConfig));
|
|
|
|
ALOGV(
|
|
|
|
"FovMutable=%s ConfigurationType %d",
|
|
|
|
viewportConfig.fovMutable ? "true" : "false",
|
|
|
|
viewportConfig.viewConfigurationType);
|
|
|
|
|
|
|
|
uint32_t viewCount;
|
|
|
|
OXR(xrEnumerateViewConfigurationViews(
|
|
|
|
engine->appState.Instance, engine->appState.SystemId, viewportConfigType, 0, &viewCount, NULL));
|
|
|
|
|
|
|
|
if (viewCount > 0) {
|
|
|
|
XrViewConfigurationView* elements =
|
|
|
|
(XrViewConfigurationView*)malloc(viewCount * sizeof(XrViewConfigurationView));
|
|
|
|
|
|
|
|
for (uint32_t e = 0; e < viewCount; e++) {
|
|
|
|
elements[e].type = XR_TYPE_VIEW_CONFIGURATION_VIEW;
|
|
|
|
elements[e].next = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
OXR(xrEnumerateViewConfigurationViews(
|
|
|
|
engine->appState.Instance,
|
|
|
|
engine->appState.SystemId,
|
|
|
|
viewportConfigType,
|
|
|
|
viewCount,
|
|
|
|
&viewCount,
|
|
|
|
elements));
|
|
|
|
|
|
|
|
// Cache the view config properties for the selected config type.
|
|
|
|
if (viewportConfigType == XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO) {
|
|
|
|
assert(viewCount == ovrMaxNumEyes);
|
|
|
|
for (uint32_t e = 0; e < viewCount; e++) {
|
|
|
|
engine->appState.ViewConfigurationView[e] = elements[e];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(elements);
|
|
|
|
} else {
|
|
|
|
ALOGE("Empty viewport configuration type: %d", viewCount);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(viewportConfigurationTypes);
|
|
|
|
|
|
|
|
*pWidth = width = engine->appState.ViewConfigurationView[0].recommendedImageRectWidth;
|
|
|
|
*pHeight = height = engine->appState.ViewConfigurationView[0].recommendedImageRectHeight;
|
2022-07-23 11:14:53 +00:00
|
|
|
} else {
|
2022-07-12 16:53:46 +00:00
|
|
|
//use cached values
|
|
|
|
*pWidth = width;
|
|
|
|
*pHeight = height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void VR_Recenter(engine_t* engine) {
|
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
// Calculate recenter reference
|
|
|
|
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
|
|
|
|
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
|
|
|
|
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
|
|
|
|
if (engine->appState.CurrentSpace != XR_NULL_HANDLE) {
|
|
|
|
XrSpaceLocation loc = {};
|
|
|
|
loc.type = XR_TYPE_SPACE_LOCATION;
|
|
|
|
OXR(xrLocateSpace(engine->appState.HeadSpace, engine->appState.CurrentSpace, engine->predictedDisplayTime, &loc));
|
2022-08-01 15:11:23 +00:00
|
|
|
hmdorientation = XrQuaternionf_ToEulerAngles(loc.pose.orientation);
|
2022-07-24 12:25:04 +00:00
|
|
|
|
2022-09-01 16:08:08 +00:00
|
|
|
vrConfig[VR_CONFIG_RECENTER_YAW] += (int)hmdorientation.y;
|
|
|
|
float recenterYaw = ToRadians((float)vrConfig[VR_CONFIG_RECENTER_YAW]);
|
2022-07-24 12:25:04 +00:00
|
|
|
spaceCreateInfo.poseInReferenceSpace.orientation.x = 0;
|
|
|
|
spaceCreateInfo.poseInReferenceSpace.orientation.y = sin(recenterYaw / 2);
|
|
|
|
spaceCreateInfo.poseInReferenceSpace.orientation.z = 0;
|
|
|
|
spaceCreateInfo.poseInReferenceSpace.orientation.w = cos(recenterYaw / 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Delete previous space instances
|
|
|
|
if (engine->appState.StageSpace != XR_NULL_HANDLE) {
|
|
|
|
OXR(xrDestroySpace(engine->appState.StageSpace));
|
|
|
|
}
|
|
|
|
if (engine->appState.FakeStageSpace != XR_NULL_HANDLE) {
|
|
|
|
OXR(xrDestroySpace(engine->appState.FakeStageSpace));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a default stage space to use if SPACE_TYPE_STAGE is not
|
|
|
|
// supported, or calls to xrGetReferenceSpaceBoundsRect fail.
|
|
|
|
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
|
2022-07-31 18:05:08 +00:00
|
|
|
#ifdef OPENXR_FLOOR_STAGE
|
2022-07-24 12:25:04 +00:00
|
|
|
spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f;
|
2022-07-31 18:05:08 +00:00
|
|
|
#endif
|
2022-07-24 12:25:04 +00:00
|
|
|
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.FakeStageSpace));
|
|
|
|
ALOGV("Created fake stage space from local space with offset");
|
|
|
|
engine->appState.CurrentSpace = engine->appState.FakeStageSpace;
|
|
|
|
|
|
|
|
if (stageSupported) {
|
|
|
|
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
|
|
|
|
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0;
|
|
|
|
OXR(xrCreateReferenceSpace(engine->appState.Session, &spaceCreateInfo, &engine->appState.StageSpace));
|
|
|
|
ALOGV("Created stage space");
|
2022-07-31 18:05:08 +00:00
|
|
|
#ifdef OPENXR_FLOOR_STAGE
|
2022-07-24 12:25:04 +00:00
|
|
|
engine->appState.CurrentSpace = engine->appState.StageSpace;
|
2022-07-31 18:05:08 +00:00
|
|
|
#endif
|
2022-07-24 12:25:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Update menu orientation
|
2022-09-01 16:08:08 +00:00
|
|
|
vrConfig[VR_CONFIG_MENU_PITCH] = (int)hmdorientation.x;
|
|
|
|
vrConfig[VR_CONFIG_MENU_YAW] = 0;
|
2022-07-12 16:53:46 +00:00
|
|
|
}
|
|
|
|
|
2022-08-29 20:06:59 +00:00
|
|
|
void VR_InitRenderer( engine_t* engine, bool multiview ) {
|
2022-08-16 14:47:31 +00:00
|
|
|
if (initialized) {
|
|
|
|
VR_DestroyRenderer(engine);
|
|
|
|
}
|
|
|
|
|
2022-07-12 16:53:46 +00:00
|
|
|
int eyeW, eyeH;
|
2022-07-24 12:25:04 +00:00
|
|
|
VR_GetResolution(engine, &eyeW, &eyeH);
|
2022-09-01 16:08:08 +00:00
|
|
|
vrConfig[VR_CONFIG_VIEWPORT_WIDTH] = eyeW;
|
|
|
|
vrConfig[VR_CONFIG_VIEWPORT_HEIGHT] = eyeH;
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
// Get the viewport configuration info for the chosen viewport configuration type.
|
|
|
|
engine->appState.ViewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
|
2022-08-29 20:06:59 +00:00
|
|
|
OXR(xrGetViewConfigurationProperties(engine->appState.Instance, engine->appState.SystemId, XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO, &engine->appState.ViewportConfig));
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
uint32_t numOutputSpaces = 0;
|
|
|
|
OXR(xrEnumerateReferenceSpaces(engine->appState.Session, 0, &numOutputSpaces, NULL));
|
2022-08-29 20:06:59 +00:00
|
|
|
XrReferenceSpaceType* referenceSpaces = (XrReferenceSpaceType*)malloc(numOutputSpaces * sizeof(XrReferenceSpaceType));
|
|
|
|
OXR(xrEnumerateReferenceSpaces(engine->appState.Session, numOutputSpaces, &numOutputSpaces, referenceSpaces));
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
for (uint32_t i = 0; i < numOutputSpaces; i++) {
|
|
|
|
if (referenceSpaces[i] == XR_REFERENCE_SPACE_TYPE_STAGE) {
|
2022-09-12 23:39:44 +00:00
|
|
|
stageSupported = true;
|
2022-07-24 12:25:04 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
free(referenceSpaces);
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
if (engine->appState.CurrentSpace == XR_NULL_HANDLE) {
|
|
|
|
VR_Recenter(engine);
|
|
|
|
}
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView)));
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-09-14 17:53:55 +00:00
|
|
|
void* vulkanContext = nullptr;
|
|
|
|
if (engine->useVulkan) {
|
|
|
|
vulkanContext = &engine->graphicsBindingVulkan;
|
|
|
|
}
|
|
|
|
ovrRenderer_Create(engine->appState.Session, &engine->appState.Renderer,
|
2022-07-24 12:25:04 +00:00
|
|
|
engine->appState.ViewConfigurationView[0].recommendedImageRectWidth,
|
2022-08-29 20:06:59 +00:00
|
|
|
engine->appState.ViewConfigurationView[0].recommendedImageRectHeight,
|
2022-09-14 17:53:55 +00:00
|
|
|
multiview, vulkanContext);
|
2022-09-12 23:39:44 +00:00
|
|
|
initialized = true;
|
2022-07-12 16:53:46 +00:00
|
|
|
}
|
|
|
|
|
2022-07-23 11:14:53 +00:00
|
|
|
void VR_DestroyRenderer( engine_t* engine ) {
|
2022-07-24 12:25:04 +00:00
|
|
|
ovrRenderer_Destroy(&engine->appState.Renderer);
|
|
|
|
free(projections);
|
2022-09-12 23:39:44 +00:00
|
|
|
initialized = false;
|
2022-07-12 16:53:46 +00:00
|
|
|
}
|
|
|
|
|
2022-09-04 10:36:52 +00:00
|
|
|
bool VR_InitFrame( engine_t* engine ) {
|
2022-09-12 23:39:44 +00:00
|
|
|
bool stageBoundsDirty = true;
|
2022-07-24 12:25:04 +00:00
|
|
|
if (ovrApp_HandleXrEvents(&engine->appState)) {
|
|
|
|
VR_Recenter(engine);
|
|
|
|
}
|
2022-09-12 23:39:44 +00:00
|
|
|
if (engine->appState.SessionActive == false) {
|
2022-08-19 14:59:39 +00:00
|
|
|
return false;
|
2022-07-24 12:25:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (stageBoundsDirty) {
|
|
|
|
VR_UpdateStageBounds(&engine->appState);
|
2022-09-12 23:39:44 +00:00
|
|
|
stageBoundsDirty = false;
|
2022-07-24 12:25:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: OpenXR does not use the concept of frame indices. Instead,
|
|
|
|
// XrWaitFrame returns the predicted display time.
|
|
|
|
XrFrameWaitInfo waitFrameInfo = {};
|
|
|
|
waitFrameInfo.type = XR_TYPE_FRAME_WAIT_INFO;
|
|
|
|
waitFrameInfo.next = NULL;
|
|
|
|
|
|
|
|
frameState.type = XR_TYPE_FRAME_STATE;
|
|
|
|
frameState.next = NULL;
|
|
|
|
|
|
|
|
OXR(xrWaitFrame(engine->appState.Session, &waitFrameInfo, &frameState));
|
|
|
|
engine->predictedDisplayTime = frameState.predictedDisplayTime;
|
|
|
|
if (!frameState.shouldRender) {
|
2022-08-19 14:59:39 +00:00
|
|
|
return false;
|
2022-07-24 12:25:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get the HMD pose, predicted for the middle of the time period during which
|
|
|
|
// the new eye images will be displayed. The number of frames predicted ahead
|
|
|
|
// depends on the pipeline depth of the engine and the synthesis rate.
|
|
|
|
// The better the prediction, the less black will be pulled in at the edges.
|
|
|
|
XrFrameBeginInfo beginFrameDesc = {};
|
|
|
|
beginFrameDesc.type = XR_TYPE_FRAME_BEGIN_INFO;
|
|
|
|
beginFrameDesc.next = NULL;
|
|
|
|
OXR(xrBeginFrame(engine->appState.Session, &beginFrameDesc));
|
|
|
|
|
|
|
|
XrViewLocateInfo projectionInfo = {};
|
|
|
|
projectionInfo.type = XR_TYPE_VIEW_LOCATE_INFO;
|
|
|
|
projectionInfo.viewConfigurationType = engine->appState.ViewportConfig.viewConfigurationType;
|
|
|
|
projectionInfo.displayTime = frameState.predictedDisplayTime;
|
|
|
|
projectionInfo.space = engine->appState.CurrentSpace;
|
|
|
|
|
|
|
|
XrViewState viewState = {XR_TYPE_VIEW_STATE, NULL};
|
|
|
|
|
|
|
|
uint32_t projectionCapacityInput = ovrMaxNumEyes;
|
|
|
|
uint32_t projectionCountOutput = projectionCapacityInput;
|
|
|
|
|
|
|
|
OXR(xrLocateViews(
|
|
|
|
engine->appState.Session,
|
|
|
|
&projectionInfo,
|
|
|
|
&viewState,
|
|
|
|
projectionCapacityInput,
|
|
|
|
&projectionCountOutput,
|
|
|
|
projections));
|
|
|
|
//
|
|
|
|
|
2022-09-20 16:57:58 +00:00
|
|
|
fov = {};
|
2022-07-24 12:25:04 +00:00
|
|
|
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
|
2022-09-20 16:57:58 +00:00
|
|
|
fov.angleLeft += projections[eye].fov.angleLeft / 2.0f;
|
|
|
|
fov.angleRight += projections[eye].fov.angleRight / 2.0f;
|
|
|
|
fov.angleUp += projections[eye].fov.angleUp / 2.0f;
|
|
|
|
fov.angleDown += projections[eye].fov.angleDown / 2.0f;
|
2022-07-24 12:25:04 +00:00
|
|
|
invViewTransform[eye] = projections[eye].pose;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update HMD and controllers
|
2022-08-01 15:11:23 +00:00
|
|
|
hmdorientation = XrQuaternionf_ToEulerAngles(invViewTransform[0].orientation);
|
|
|
|
hmdposition = invViewTransform[0].position;
|
2022-07-17 12:45:02 +00:00
|
|
|
IN_VRInputFrame(engine);
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:25:04 +00:00
|
|
|
engine->appState.LayerCount = 0;
|
|
|
|
memset(engine->appState.Layers, 0, sizeof(ovrCompositorLayer_Union) * ovrMaxLayerCount);
|
2022-10-08 12:38:49 +00:00
|
|
|
|
|
|
|
// Update matrices
|
|
|
|
for (int matrix = 0; matrix < VR_MATRIX_COUNT; matrix++) {
|
|
|
|
if ((matrix == VR_PROJECTION_MATRIX_LEFT_EYE) || (matrix == VR_PROJECTION_MATRIX_RIGHT_EYE)) {
|
2022-10-17 16:39:02 +00:00
|
|
|
float nearPlane = (float)vrConfig[VR_CONFIG_FOV_SCALE] / 200.0f;
|
|
|
|
vrMatrix[matrix] = ovrMatrix4f_CreateProjectionFov(fov.angleLeft, fov.angleRight, fov.angleUp, fov.angleDown, nearPlane, 0.0f );
|
2022-10-08 12:38:49 +00:00
|
|
|
} else if ((matrix == VR_VIEW_MATRIX_LEFT_EYE) || (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) {
|
2022-11-03 19:00:30 +00:00
|
|
|
bool flatScreen = false;
|
2022-10-08 12:38:49 +00:00
|
|
|
XrPosef invView = invViewTransform[0];
|
2022-11-03 19:00:30 +00:00
|
|
|
int vrMode = vrConfig[VR_CONFIG_MODE];
|
|
|
|
if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) {
|
|
|
|
invView = XrPosef_Identity();
|
|
|
|
flatScreen = true;
|
|
|
|
}
|
2022-10-08 12:38:49 +00:00
|
|
|
|
|
|
|
// get axis mirroring configuration
|
|
|
|
float mx = vrConfig[VR_CONFIG_MIRROR_PITCH] ? -1 : 1;
|
|
|
|
float my = vrConfig[VR_CONFIG_MIRROR_YAW] ? -1 : 1;
|
|
|
|
float mz = vrConfig[VR_CONFIG_MIRROR_ROLL] ? -1 : 1;
|
|
|
|
|
|
|
|
// ensure there is maximally one axis to mirror rotation
|
|
|
|
if (mx + my + mz < 0) {
|
|
|
|
mx *= -1.0f;
|
|
|
|
my *= -1.0f;
|
|
|
|
mz *= -1.0f;
|
|
|
|
} else {
|
|
|
|
invView = XrPosef_Inverse(invView);
|
|
|
|
}
|
|
|
|
|
|
|
|
// create updated quaternion
|
|
|
|
if (mx + my + mz < 3 - EPSILON) {
|
|
|
|
XrVector3f rotation = XrQuaternionf_ToEulerAngles(invView.orientation);
|
|
|
|
XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, mx * ToRadians(rotation.x));
|
|
|
|
XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, my * ToRadians(rotation.y));
|
|
|
|
XrQuaternionf roll = XrQuaternionf_CreateFromVectorAngle({0, 0, 1}, mz * ToRadians(rotation.z));
|
|
|
|
invView.orientation = XrQuaternionf_Multiply(roll, XrQuaternionf_Multiply(pitch, yaw));
|
|
|
|
}
|
|
|
|
|
|
|
|
vrMatrix[matrix] = ovrMatrix4f_CreateFromQuaternion(&invView.orientation);
|
|
|
|
float scale = (float)VR_GetConfig(VR_CONFIG_6DOF_SCALE) * 0.000001f;
|
2022-11-03 19:00:30 +00:00
|
|
|
if (!flatScreen && vrConfig[VR_CONFIG_6DOF_ENABLED]) {
|
2022-10-08 12:38:49 +00:00
|
|
|
vrMatrix[matrix].M[0][3] -= hmdposition.x * (vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f) * scale;
|
|
|
|
vrMatrix[matrix].M[1][3] -= hmdposition.y * (vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f) * scale;
|
|
|
|
vrMatrix[matrix].M[2][3] -= hmdposition.z * (vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f) * scale;
|
|
|
|
}
|
2022-10-20 19:23:27 +00:00
|
|
|
if (abs(vrConfig[VR_CONFIG_CAMERA_DISTANCE]) > 0) {
|
2022-10-28 12:59:12 +00:00
|
|
|
XrVector3f forward = {0.0f, 0.0f, (float)vrConfig[VR_CONFIG_CAMERA_DISTANCE] * 0.001f * scale};
|
2022-10-20 19:23:27 +00:00
|
|
|
forward = XrQuaternionf_Rotate(invView.orientation, forward);
|
|
|
|
forward = XrVector3f_ScalarMultiply(forward, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f);
|
|
|
|
vrMatrix[matrix].M[0][3] += forward.x;
|
|
|
|
vrMatrix[matrix].M[1][3] += forward.y;
|
|
|
|
vrMatrix[matrix].M[2][3] += forward.z;
|
|
|
|
}
|
2022-10-29 17:19:25 +00:00
|
|
|
if (abs(vrConfig[VR_CONFIG_CAMERA_HEIGHT]) > 0) {
|
|
|
|
XrVector3f up = {0.0f, -(float)vrConfig[VR_CONFIG_CAMERA_HEIGHT] * 0.001f * scale, 0.0f};
|
|
|
|
up = XrQuaternionf_Rotate(invView.orientation, up);
|
|
|
|
up = XrVector3f_ScalarMultiply(up, vrConfig[VR_CONFIG_MIRROR_AXIS_Y] ? -1.0f : 1.0f);
|
|
|
|
vrMatrix[matrix].M[0][3] += up.x;
|
|
|
|
vrMatrix[matrix].M[1][3] += up.y;
|
|
|
|
vrMatrix[matrix].M[2][3] += up.z;
|
|
|
|
}
|
2022-10-29 17:31:57 +00:00
|
|
|
if (abs(vrConfig[VR_CONFIG_CAMERA_SIDE]) > 0) {
|
|
|
|
XrVector3f side = {-(float)vrConfig[VR_CONFIG_CAMERA_SIDE] * 0.001f * scale, 0.0f, 0.0f};
|
|
|
|
side = XrQuaternionf_Rotate(invView.orientation, side);
|
|
|
|
side = XrVector3f_ScalarMultiply(side, vrConfig[VR_CONFIG_MIRROR_AXIS_X] ? -1.0f : 1.0f);
|
|
|
|
vrMatrix[matrix].M[0][3] += side.x;
|
|
|
|
vrMatrix[matrix].M[1][3] += side.y;
|
|
|
|
vrMatrix[matrix].M[2][3] += side.z;
|
|
|
|
}
|
2022-10-08 12:38:49 +00:00
|
|
|
if (vrConfig[VR_CONFIG_6DOF_PRECISE] && (matrix == VR_VIEW_MATRIX_RIGHT_EYE)) {
|
|
|
|
float dx = fabs(invViewTransform[1].position.x - invViewTransform[0].position.x);
|
|
|
|
float dy = fabs(invViewTransform[1].position.y - invViewTransform[0].position.y);
|
|
|
|
float dz = fabs(invViewTransform[1].position.z - invViewTransform[0].position.z);
|
|
|
|
float ipd = sqrt(dx * dx + dy * dy + dz * dz);
|
|
|
|
XrVector3f separation = {ipd * scale, 0.0f, 0.0f};
|
|
|
|
separation = XrQuaternionf_Rotate(invView.orientation, separation);
|
|
|
|
separation = XrVector3f_ScalarMultiply(separation, vrConfig[VR_CONFIG_MIRROR_AXIS_Z] ? -1.0f : 1.0f);
|
|
|
|
vrMatrix[matrix].M[0][3] -= separation.x;
|
|
|
|
vrMatrix[matrix].M[1][3] -= separation.y;
|
|
|
|
vrMatrix[matrix].M[2][3] -= separation.z;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
2022-09-04 10:36:52 +00:00
|
|
|
return true;
|
|
|
|
}
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-09-04 10:36:52 +00:00
|
|
|
void VR_BeginFrame( engine_t* engine, int fboIndex ) {
|
|
|
|
vrConfig[VR_CONFIG_CURRENT_FBO] = fboIndex;
|
2022-09-12 23:39:44 +00:00
|
|
|
ovrFramebuffer_Acquire(&engine->appState.Renderer.FrameBuffer[fboIndex]);
|
2022-07-15 13:41:21 +00:00
|
|
|
}
|
2022-07-12 16:53:46 +00:00
|
|
|
|
2022-07-24 12:14:21 +00:00
|
|
|
void VR_EndFrame( engine_t* engine ) {
|
2022-09-04 10:36:52 +00:00
|
|
|
int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO];
|
2022-08-19 14:59:39 +00:00
|
|
|
VR_BindFramebuffer(engine);
|
2022-07-24 12:25:04 +00:00
|
|
|
|
2022-09-01 16:08:08 +00:00
|
|
|
// Show mouse cursor
|
|
|
|
int size = vrConfig[VR_CONFIG_MOUSE_SIZE];
|
2022-10-16 18:28:45 +00:00
|
|
|
int vrMode = vrConfig[VR_CONFIG_MODE];
|
|
|
|
bool screenMode = (vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN);
|
|
|
|
if (screenMode && (size > 0)) {
|
2022-09-12 23:39:44 +00:00
|
|
|
int x = vrConfig[VR_CONFIG_MOUSE_X];
|
|
|
|
int y = vrConfig[VR_CONFIG_MOUSE_Y];
|
|
|
|
ovrRenderer_MouseCursor(&engine->appState.Renderer, x, y, size);
|
2022-09-01 16:08:08 +00:00
|
|
|
}
|
|
|
|
|
2022-10-12 14:21:54 +00:00
|
|
|
ovrFramebuffer_Release(&engine->appState.Renderer.FrameBuffer[fboIndex]);
|
2022-09-04 10:36:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void VR_FinishFrame( engine_t* engine ) {
|
2022-07-24 12:25:04 +00:00
|
|
|
|
2022-09-04 10:36:52 +00:00
|
|
|
int vrMode = vrConfig[VR_CONFIG_MODE];
|
2022-07-24 12:25:04 +00:00
|
|
|
XrCompositionLayerProjectionView projection_layer_elements[2] = {};
|
|
|
|
if ((vrMode == VR_MODE_MONO_6DOF) || (vrMode == VR_MODE_STEREO_6DOF)) {
|
2022-09-01 16:08:08 +00:00
|
|
|
vrConfig[VR_CONFIG_MENU_YAW] = (int)hmdorientation.y;
|
2022-07-24 12:25:04 +00:00
|
|
|
|
|
|
|
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
|
2022-09-04 10:36:52 +00:00
|
|
|
int imageLayer = engine->appState.Renderer.Multiview ? eye : 0;
|
|
|
|
ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[0];
|
2022-09-21 14:44:31 +00:00
|
|
|
XrPosef pose = invViewTransform[0];
|
|
|
|
if (vrMode != VR_MODE_MONO_6DOF) {
|
|
|
|
if (!engine->appState.Renderer.Multiview) {
|
|
|
|
frameBuffer = &engine->appState.Renderer.FrameBuffer[eye];
|
|
|
|
}
|
|
|
|
pose = invViewTransform[eye];
|
2022-07-24 12:25:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView));
|
|
|
|
projection_layer_elements[eye].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
|
2022-09-21 14:44:31 +00:00
|
|
|
projection_layer_elements[eye].pose = pose;
|
2022-07-25 17:42:28 +00:00
|
|
|
projection_layer_elements[eye].fov = fov;
|
2022-07-24 12:25:04 +00:00
|
|
|
|
|
|
|
memset(&projection_layer_elements[eye].subImage, 0, sizeof(XrSwapchainSubImage));
|
|
|
|
projection_layer_elements[eye].subImage.swapchain = frameBuffer->ColorSwapChain.Handle;
|
|
|
|
projection_layer_elements[eye].subImage.imageRect.offset.x = 0;
|
|
|
|
projection_layer_elements[eye].subImage.imageRect.offset.y = 0;
|
|
|
|
projection_layer_elements[eye].subImage.imageRect.extent.width = frameBuffer->ColorSwapChain.Width;
|
|
|
|
projection_layer_elements[eye].subImage.imageRect.extent.height = frameBuffer->ColorSwapChain.Height;
|
2022-08-14 09:45:52 +00:00
|
|
|
projection_layer_elements[eye].subImage.imageArrayIndex = imageLayer;
|
2022-07-24 12:25:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrCompositionLayerProjection projection_layer = {};
|
|
|
|
projection_layer.type = XR_TYPE_COMPOSITION_LAYER_PROJECTION;
|
|
|
|
projection_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
|
|
|
projection_layer.layerFlags |= XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
|
|
|
|
projection_layer.space = engine->appState.CurrentSpace;
|
|
|
|
projection_layer.viewCount = ovrMaxNumEyes;
|
|
|
|
projection_layer.views = projection_layer_elements;
|
|
|
|
|
|
|
|
engine->appState.Layers[engine->appState.LayerCount++].Projection = projection_layer;
|
2022-10-16 18:28:45 +00:00
|
|
|
} else if ((vrMode == VR_MODE_MONO_SCREEN) || (vrMode == VR_MODE_STEREO_SCREEN)) {
|
2022-07-24 12:25:04 +00:00
|
|
|
|
2022-10-16 18:28:45 +00:00
|
|
|
// Flat screen pose
|
2022-09-01 16:08:08 +00:00
|
|
|
float distance = (float)vrConfig[VR_CONFIG_CANVAS_DISTANCE];
|
|
|
|
float menuPitch = ToRadians((float)vrConfig[VR_CONFIG_MENU_PITCH]);
|
|
|
|
float menuYaw = ToRadians((float)vrConfig[VR_CONFIG_MENU_YAW]);
|
2022-07-24 12:25:04 +00:00
|
|
|
XrVector3f pos = {
|
2022-09-01 16:08:08 +00:00
|
|
|
invViewTransform[0].position.x - sin(menuYaw) * distance,
|
2022-07-24 12:25:04 +00:00
|
|
|
invViewTransform[0].position.y,
|
2022-09-01 16:08:08 +00:00
|
|
|
invViewTransform[0].position.z - cos(menuYaw) * distance
|
2022-07-24 12:25:04 +00:00
|
|
|
};
|
2022-09-01 16:08:08 +00:00
|
|
|
XrQuaternionf pitch = XrQuaternionf_CreateFromVectorAngle({1, 0, 0}, -menuPitch);
|
|
|
|
XrQuaternionf yaw = XrQuaternionf_CreateFromVectorAngle({0, 1, 0}, menuYaw);
|
2022-10-16 18:28:45 +00:00
|
|
|
|
|
|
|
// Setup the cylinder layer
|
|
|
|
XrCompositionLayerCylinderKHR cylinder_layer = {};
|
|
|
|
cylinder_layer.type = XR_TYPE_COMPOSITION_LAYER_CYLINDER_KHR;
|
|
|
|
cylinder_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
|
|
|
|
cylinder_layer.space = engine->appState.CurrentSpace;
|
|
|
|
memset(&cylinder_layer.subImage, 0, sizeof(XrSwapchainSubImage));
|
|
|
|
cylinder_layer.subImage.imageRect.offset.x = 0;
|
|
|
|
cylinder_layer.subImage.imageRect.offset.y = 0;
|
|
|
|
cylinder_layer.subImage.imageRect.extent.width = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Width;
|
|
|
|
cylinder_layer.subImage.imageRect.extent.height = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Height;
|
|
|
|
cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[0].ColorSwapChain.Handle;
|
|
|
|
cylinder_layer.subImage.imageArrayIndex = 0;
|
2022-08-15 17:55:09 +00:00
|
|
|
cylinder_layer.pose.orientation = XrQuaternionf_Multiply(pitch, yaw);
|
2022-07-24 12:25:04 +00:00
|
|
|
cylinder_layer.pose.position = pos;
|
|
|
|
cylinder_layer.radius = 12.0f;
|
2022-08-01 15:11:23 +00:00
|
|
|
cylinder_layer.centralAngle = M_PI * 0.5f;
|
2022-08-15 15:41:04 +00:00
|
|
|
cylinder_layer.aspectRatio = 1;
|
2022-07-24 12:25:04 +00:00
|
|
|
|
2022-10-16 18:28:45 +00:00
|
|
|
// Build the cylinder layer
|
|
|
|
if (vrMode == VR_MODE_MONO_SCREEN) {
|
|
|
|
cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
|
|
|
|
engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer;
|
|
|
|
} else if (engine->appState.Renderer.Multiview) {
|
|
|
|
cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT;
|
|
|
|
engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer;
|
|
|
|
cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT;
|
|
|
|
cylinder_layer.subImage.imageArrayIndex = 1;
|
|
|
|
engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer;
|
|
|
|
} else {
|
|
|
|
cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_LEFT;
|
|
|
|
engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer;
|
|
|
|
cylinder_layer.eyeVisibility = XR_EYE_VISIBILITY_RIGHT;
|
|
|
|
cylinder_layer.subImage.swapchain = engine->appState.Renderer.FrameBuffer[1].ColorSwapChain.Handle;
|
|
|
|
engine->appState.Layers[engine->appState.LayerCount++].Cylinder = cylinder_layer;
|
|
|
|
}
|
2022-07-24 12:25:04 +00:00
|
|
|
} else {
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Compose the layers for this frame.
|
|
|
|
const XrCompositionLayerBaseHeader* layers[ovrMaxLayerCount] = {};
|
|
|
|
for (int i = 0; i < engine->appState.LayerCount; i++) {
|
|
|
|
layers[i] = (const XrCompositionLayerBaseHeader*)&engine->appState.Layers[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
XrFrameEndInfo endFrameInfo = {};
|
|
|
|
endFrameInfo.type = XR_TYPE_FRAME_END_INFO;
|
|
|
|
endFrameInfo.displayTime = frameState.predictedDisplayTime;
|
|
|
|
endFrameInfo.environmentBlendMode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
|
|
|
endFrameInfo.layerCount = engine->appState.LayerCount;
|
|
|
|
endFrameInfo.layers = layers;
|
|
|
|
|
|
|
|
OXR(xrEndFrame(engine->appState.Session, &endFrameInfo));
|
2022-09-04 10:36:52 +00:00
|
|
|
int instances = engine->appState.Renderer.Multiview ? 1 : ovrMaxNumEyes;
|
|
|
|
for (int i = 0; i < instances; i++) {
|
|
|
|
ovrFramebuffer* frameBuffer = &engine->appState.Renderer.FrameBuffer[instances];
|
|
|
|
frameBuffer->TextureSwapChainIndex++;
|
|
|
|
frameBuffer->TextureSwapChainIndex %= frameBuffer->TextureSwapChainLength;
|
|
|
|
}
|
2022-08-17 17:14:36 +00:00
|
|
|
}
|
2022-07-15 13:41:21 +00:00
|
|
|
|
2022-07-27 17:47:11 +00:00
|
|
|
int VR_GetConfig( VRConfig config ) {
|
|
|
|
return vrConfig[config];
|
2022-07-24 18:04:29 +00:00
|
|
|
}
|
|
|
|
|
2022-07-27 17:47:11 +00:00
|
|
|
void VR_SetConfig( VRConfig config, int value) {
|
|
|
|
vrConfig[config] = value;
|
2022-07-26 15:20:46 +00:00
|
|
|
}
|
|
|
|
|
2022-10-12 14:21:54 +00:00
|
|
|
void* VR_BindFramebuffer(engine_t *engine) {
|
|
|
|
if (!initialized) return nullptr;
|
2022-09-04 10:36:52 +00:00
|
|
|
int fboIndex = vrConfig[VR_CONFIG_CURRENT_FBO];
|
2022-10-12 14:21:54 +00:00
|
|
|
return ovrFramebuffer_SetCurrent(&engine->appState.Renderer.FrameBuffer[fboIndex]);
|
2022-07-24 12:14:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ovrMatrix4f VR_GetMatrix( VRMatrix matrix ) {
|
2022-10-08 12:38:49 +00:00
|
|
|
return vrMatrix[matrix];
|
2022-07-15 13:41:21 +00:00
|
|
|
}
|
2022-10-17 21:13:18 +00:00
|
|
|
|
|
|
|
#endif
|