Changes to sync up with the PCVR build

This commit is contained in:
Simon 2023-07-27 21:56:20 +01:00
parent c663fdc776
commit a58e4051b5
11 changed files with 86 additions and 129 deletions

View file

@ -445,7 +445,7 @@ void VR_FrameSetup()
vr.immersive_cinematics = (vr_immersive_cinematics->value != 0.0f);
}
bool VR_GetVRProjection(int eye, float zNear, float zFar, float* projection)
bool VR_GetVRProjection(int eye, float zNear, float zFar, float zZoomX, float zZoomY, float* projection)
{
//Don't use our projection if playing a cinematic and we are not immersive
if (vr.cin_camera && !vr.immersive_cinematics)
@ -453,35 +453,23 @@ bool VR_GetVRProjection(int eye, float zNear, float zFar, float* projection)
return false;
}
if (!vr.cgzoommode)
//Just use game-calculated FOV when showing the quad screen
if (vr.using_screen_layer)
{
if (strstr(gAppState.OpenXRHMD, "meta") != NULL)
{
XrFovf fov = {};
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
fov.angleLeft += gAppState.Projections[eye].fov.angleLeft / 2.0f;
fov.angleRight += gAppState.Projections[eye].fov.angleRight / 2.0f;
fov.angleUp += gAppState.Projections[eye].fov.angleUp / 2.0f;
fov.angleDown += gAppState.Projections[eye].fov.angleDown / 2.0f;
}
XrMatrix4x4f_CreateProjectionFov(
&(gAppState.ProjectionMatrices[eye]), GRAPHICS_OPENGL_ES,
fov, zNear, zFar);
}
if (strstr(gAppState.OpenXRHMD, "pico") != NULL)
{
XrMatrix4x4f_CreateProjectionFov(
&(gAppState.ProjectionMatrices[eye]), GRAPHICS_OPENGL_ES,
gAppState.Projections[eye].fov, zNear, zFar);
}
memcpy(projection, gAppState.ProjectionMatrices[eye].m, 16 * sizeof(float));
return true;
return false;
}
return false;
XrFovf fov = gAppState.Views[eye].fov;
fov.angleLeft /= zZoomX;
fov.angleRight /= zZoomX;
fov.angleUp /= zZoomY;
fov.angleDown /= zZoomY;
XrMatrix4x4f_CreateProjectionFov(
(XrMatrix4x4f*)projection, GRAPHICS_OPENGL,
fov, zNear, zFar);
return true;
}

View file

@ -439,7 +439,7 @@ void TBXR_UpdateControllers( )
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
loc.next = &vel;
XrResult res = xrLocateSpace(aimSpace[i], gAppState.CurrentSpace, gAppState.FrameState.predictedDisplayTime, &loc);
XrResult res = xrLocateSpace(aimSpace[i], gAppState.StageSpace, gAppState.FrameState.predictedDisplayTime, &loc);
if (res != XR_SUCCESS) {
Com_Printf("xrLocateSpace error: %d", (int)res);
}

View file

@ -874,10 +874,11 @@ void ovrApp_Clear(ovrApp* app) {
memset(&app->ViewportConfig, 0, sizeof(XrViewConfigurationProperties));
memset(&app->ViewConfigurationView, 0, ovrMaxNumEyes * sizeof(XrViewConfigurationView));
app->SystemId = XR_NULL_SYSTEM_ID;
app->LocalSpace = XR_NULL_HANDLE;
app->HeadSpace = XR_NULL_HANDLE;
app->StageSpace = XR_NULL_HANDLE;
app->FakeStageSpace = XR_NULL_HANDLE;
app->CurrentSpace = XR_NULL_HANDLE;
app->SessionActive = false;
app->SupportedDisplayRefreshRates = NULL;
app->RequestedDisplayRefreshRateIndex = 0;
@ -1335,6 +1336,7 @@ void TBXR_InitialiseResolution()
XrViewConfigurationProperties viewportConfig;
viewportConfig.type = XR_TYPE_VIEW_CONFIGURATION_PROPERTIES;
viewportConfig.next = NULL;
OXR(xrGetViewConfigurationProperties(
gAppState.Instance, gAppState.SystemId, viewportConfigType, &viewportConfig));
ALOGV(
@ -1424,12 +1426,8 @@ void TBXR_EnterVR( ) {
void TBXR_LeaveVR( ) {
if (gAppState.Session) {
OXR(xrDestroySpace(gAppState.HeadSpace));
// StageSpace is optional.
if (gAppState.StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(gAppState.StageSpace));
}
OXR(xrDestroySpace(gAppState.FakeStageSpace));
gAppState.CurrentSpace = XR_NULL_HANDLE;
OXR(xrDestroySpace(gAppState.LocalSpace));
OXR(xrDestroySpace(gAppState.StageSpace));
OXR(xrDestroySession(gAppState.Session));
gAppState.Session = NULL;
}
@ -1554,14 +1552,12 @@ void TBXR_InitRenderer( ) {
free(referenceSpaces);
if (gAppState.CurrentSpace == XR_NULL_HANDLE) {
TBXR_Recenter();
}
TBXR_Recenter();
gAppState.Projections = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView)));
gAppState.Views = (XrView*)(malloc(ovrMaxNumEyes * sizeof(XrView)));
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
memset(&gAppState.Projections[eye], 0, sizeof(XrView));
gAppState.Projections[eye].type = XR_TYPE_VIEW;
memset(&gAppState.Views[eye], 0, sizeof(XrView));
gAppState.Views[eye].type = XR_TYPE_VIEW;
}
if (strstr(gAppState.OpenXRHMD, "pico") != NULL)
@ -1585,7 +1581,7 @@ void TBXR_InitRenderer( ) {
void VR_DestroyRenderer( )
{
ovrRenderer_Destroy(&gAppState.Renderer);
free(gAppState.Projections);
free(gAppState.Views);
}
void TBXR_InitialiseOpenXR()
@ -1710,57 +1706,29 @@ void TBXR_Recenter() {
XrReferenceSpaceCreateInfo spaceCreateInfo = {};
spaceCreateInfo.type = XR_TYPE_REFERENCE_SPACE_CREATE_INFO;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1.0f;
if (gAppState.CurrentSpace != XR_NULL_HANDLE) {
if (gAppState.StageSpace != XR_NULL_HANDLE) {
vec3_t rotation = {0, 0, 0};
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace(gAppState.HeadSpace, gAppState.CurrentSpace, gAppState.FrameState.predictedDisplayTime, &loc));
OXR(xrLocateSpace(gAppState.HeadSpace, gAppState.StageSpace, gAppState.FrameState.predictedDisplayTime, &loc));
QuatToYawPitchRoll(loc.pose.orientation, rotation, vr.hmdorientation);
spaceCreateInfo.poseInReferenceSpace.orientation.x = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.y = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.z = 0;
spaceCreateInfo.poseInReferenceSpace.orientation.w = 1;
}
// Delete previous space instances
if (gAppState.StageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(gAppState.StageSpace));
}
if (gAppState.FakeStageSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(gAppState.FakeStageSpace));
if (gAppState.LocalSpace != XR_NULL_HANDLE) {
OXR(xrDestroySpace(gAppState.LocalSpace));
}
// 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_STAGE;
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0f;
OXR(xrCreateReferenceSpace(gAppState.Session, &spaceCreateInfo, &gAppState.StageSpace));
ALOGV("Created stage space");
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_LOCAL;
spaceCreateInfo.poseInReferenceSpace.position.y = -1.6750f;
OXR(xrCreateReferenceSpace(gAppState.Session, &spaceCreateInfo, &gAppState.FakeStageSpace));
ALOGV("Created fake stage space from local space with offset");
gAppState.CurrentSpace = gAppState.FakeStageSpace;
if (stageSupported) {
spaceCreateInfo.referenceSpaceType = XR_REFERENCE_SPACE_TYPE_STAGE;
spaceCreateInfo.poseInReferenceSpace.position.y = 0.0f;
OXR(xrCreateReferenceSpace(gAppState.Session, &spaceCreateInfo, &gAppState.StageSpace));
ALOGV("Created stage space");
gAppState.CurrentSpace = gAppState.StageSpace;
}
}
void TBXR_UpdateStageBounds() {
XrExtent2Df stageBounds = {};
XrResult result;
OXR(result = xrGetReferenceSpaceBoundsRect(
gAppState.Session, XR_REFERENCE_SPACE_TYPE_STAGE, &stageBounds));
if (result != XR_SUCCESS) {
ALOGE("Stage bounds query failed: using small defaults");
stageBounds.width = 1.0f;
stageBounds.height = 1.0f;
gAppState.CurrentSpace = gAppState.FakeStageSpace;
}
OXR(xrCreateReferenceSpace(gAppState.Session, &spaceCreateInfo, &gAppState.LocalSpace));
}
void TBXR_WaitForSessionActive()
@ -1786,7 +1754,7 @@ static void TBXR_GetHMDOrientation() {
// The better the prediction, the less black will be pulled in at the edges.
XrSpaceLocation loc = {};
loc.type = XR_TYPE_SPACE_LOCATION;
OXR(xrLocateSpace(gAppState.HeadSpace, gAppState.CurrentSpace, gAppState.FrameState.predictedDisplayTime, &loc));
OXR(xrLocateSpace(gAppState.HeadSpace, gAppState.StageSpace, gAppState.FrameState.predictedDisplayTime, &loc));
gAppState.xfStageFromHead = loc.pose;
const XrQuaternionf quatHmd = gAppState.xfStageFromHead.orientation;
@ -1812,7 +1780,6 @@ void TBXR_FrameSetup()
{
TBXR_ProcessMessageQueue();
GLboolean stageBoundsDirty = GL_TRUE;
if (ovrApp_HandleXrEvents(&gAppState))
{
TBXR_Recenter();
@ -1823,12 +1790,6 @@ void TBXR_FrameSetup()
continue;
}
if (stageBoundsDirty)
{
TBXR_UpdateStageBounds();
stageBoundsDirty = GL_FALSE;
}
break;
}
@ -1901,10 +1862,16 @@ void TBXR_ClearFrameBuffer(int width, int height)
void TBXR_prepareEyeBuffer(int eye )
{
vr.eye = eye;
ovrFramebuffer* frameBuffer = &(gAppState.Renderer.FrameBuffer[eye]);
ovrFramebuffer_Acquire(frameBuffer);
ovrFramebuffer_SetCurrent(frameBuffer);
TBXR_ClearFrameBuffer(frameBuffer->ColorSwapChain.Width, frameBuffer->ColorSwapChain.Height);
//Seems odd, but used to move the HUD elements to be central on the player's view
//HMDs with a symmetric fov (like the PICO) will have 0 in this value, but the Meta Quest
//will have an asymmetric fov and the HUD would be very misaligned as a result
vr.off_center_fov = -(gAppState.Views[eye].fov.angleLeft + gAppState.Views[eye].fov.angleRight) / 2.0f;
}
void TBXR_finishEyeBuffer(int eye )
@ -1931,7 +1898,7 @@ void TBXR_updateProjections()
projectionInfo.type = XR_TYPE_VIEW_LOCATE_INFO;
projectionInfo.viewConfigurationType = gAppState.ViewportConfig.viewConfigurationType;
projectionInfo.displayTime = gAppState.FrameState.predictedDisplayTime;
projectionInfo.space = gAppState.HeadSpace;
projectionInfo.space = gAppState.LocalSpace;
XrViewState viewState = {XR_TYPE_VIEW_STATE, NULL};
@ -1944,7 +1911,7 @@ void TBXR_updateProjections()
&viewState,
projectionCapacityInput,
&projectionCountOutput,
gAppState.Projections));
gAppState.Views));
}
void TBXR_submitFrame()
@ -1955,28 +1922,9 @@ void TBXR_submitFrame()
TBXR_updateProjections();
XrFovf fov = {};
XrPosef viewTransform[2];
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
XrPosef xfHeadFromEye = gAppState.Projections[eye].pose;
XrPosef xfStageFromEye = XrPosef_Multiply(gAppState.xfStageFromHead, xfHeadFromEye);
viewTransform[eye] = XrPosef_Inverse(xfStageFromEye);
fov.angleLeft += gAppState.Projections[eye].fov.angleLeft / 2.0f;
fov.angleRight += gAppState.Projections[eye].fov.angleRight / 2.0f;
fov.angleUp += gAppState.Projections[eye].fov.angleUp / 2.0f;
fov.angleDown += gAppState.Projections[eye].fov.angleDown / 2.0f;
}
vr.fov_x = (fabs(fov.angleLeft) + fabs(fov.angleRight)) * 180.0f / M_PI;
vr.fov_y = (fabs(fov.angleUp) + fabs(fov.angleDown)) * 180.0f / M_PI;
if (vr.cgzoommode)
{
fov.angleLeft /= 1.3f;
fov.angleRight /= 1.3f;
fov.angleUp /= 1.3f;
fov.angleDown /= 1.3f;
}
//Calculate the maximum extent fov for use in culling in the engine (we won't want to cull inside this fov)
vr.fov_x = (fabs(gAppState.Views[0].fov.angleLeft) + fabs(gAppState.Views[1].fov.angleLeft)) * 180.0f / M_PI;
vr.fov_y = (fabs(gAppState.Views[0].fov.angleUp) + fabs(gAppState.Views[0].fov.angleUp)) * 180.0f / M_PI;
gAppState.LayerCount = 0;
memset(gAppState.Layers, 0, sizeof(xrCompositorLayer_Union) * ovrMaxLayerCount);
@ -1987,16 +1935,26 @@ void TBXR_submitFrame()
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 = gAppState.CurrentSpace;
projection_layer.space = gAppState.LocalSpace;
projection_layer.viewCount = ovrMaxNumEyes;
projection_layer.views = projection_layer_elements;
for (int eye = 0; eye < ovrMaxNumEyes; eye++) {
XrFovf fov = gAppState.Views[eye].fov;
if (vr.cgzoommode)
{
fov.angleLeft /= 1.3f;
fov.angleRight /= 1.3f;
fov.angleUp /= 1.3f;
fov.angleDown /= 1.3f;
}
ovrFramebuffer* frameBuffer = &gAppState.Renderer.FrameBuffer[eye];
memset(&projection_layer_elements[eye], 0, sizeof(XrCompositionLayerProjectionView));
projection_layer_elements[eye].type = XR_TYPE_COMPOSITION_LAYER_PROJECTION_VIEW;
projection_layer_elements[eye].pose = gAppState.xfStageFromHead;
projection_layer_elements[eye].pose = gAppState.Views[eye].pose;
projection_layer_elements[eye].fov = fov;
memset(&projection_layer_elements[eye].subImage, 0, sizeof(XrSwapchainSubImage));
projection_layer_elements[eye].subImage.swapchain =
@ -2020,7 +1978,7 @@ void TBXR_submitFrame()
quad_layer.type = XR_TYPE_COMPOSITION_LAYER_QUAD;
quad_layer.next = NULL;
quad_layer.layerFlags = XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
quad_layer.space = gAppState.CurrentSpace;
quad_layer.space = gAppState.StageSpace;
quad_layer.eyeVisibility = XR_EYE_VISIBILITY_BOTH;
memset(&quad_layer.subImage, 0, sizeof(XrSwapchainSubImage));
quad_layer.subImage.swapchain = gAppState.Renderer.FrameBuffer[0].ColorSwapChain.Handle;

View file

@ -235,14 +235,14 @@ typedef struct
XrViewConfigurationProperties ViewportConfig;
XrViewConfigurationView ViewConfigurationView[ovrMaxNumEyes];
XrSystemId SystemId;
XrSpace LocalSpace;
XrSpace HeadSpace;
XrSpace StageSpace;
XrSpace FakeStageSpace;
XrSpace CurrentSpace;
GLboolean SessionActive;
XrPosef xfStageFromHead;
XrView* Projections;
XrMatrix4x4f ProjectionMatrices[2];
XrView* Views;
float currentDisplayRefreshRate;
@ -303,7 +303,7 @@ void surfaceMessageQueue_PostMessage(surfaceMessageQueue * messageQueue, const s
void VR_FrameSetup();
bool VR_UseScreenLayer();
float VR_GetScreenLayerDistance();
bool VR_GetVRProjection(int eye, float zNear, float zFar, float* projection);
bool VR_GetVRProjection(int eye, float zNear, float zFar, float zZoomX, float zZoomY, float* projection);
void VR_HandleControllerInput();
void VR_SetHMDOrientation(float pitch, float yaw, float roll );
void VR_SetHMDPosition(float x, float y, float z );

View file

@ -33,10 +33,12 @@ typedef struct {
float remote_snapTurn; // how much turn has been applied to the yaw by joystick for a remote controlled entity
int remote_cooldown;
int eye;
bool using_screen_layer;
bool third_person;
float fov_x;
float fov_y;
float off_center_fov;
float tempWeaponVelocity;

View file

@ -38,6 +38,9 @@ void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
xoffset *= -1;
}
//We need to add an offset due to the effect of the compositor projection for asymmetric FOVs
xoffset += vr->off_center_fov * 640;
*x *= screenXScale;
*y *= screenYScale;
if (w != NULL) {

View file

@ -129,7 +129,7 @@ typedef struct {
//JKXR Functions
bool (*TBXR_useScreenLayer) ( void );
bool (*TBXR_GetVRProjection) (int eye, float zNear, float zFar, float* projection);
bool (*TBXR_GetVRProjection) (int eye, float zNear, float zFar, float zZoomX, float zZoomY, float* projection);
} refimport_t;

View file

@ -1431,8 +1431,6 @@ const void *RB_DrawBuffer( const void *data ) {
cmd = (const drawBufferCommand_t *)data;
tr.stereoFrame = (stereoFrame_t )cmd->buffer;
// clear screen for debugging
if ( r_clear->integer ) {
qglClearColor( 0, 0, 0, 1 );

View file

@ -1018,7 +1018,6 @@ typedef struct {
model_t *currentModel;
viewParms_t viewParms;
stereoFrame_t stereoFrame;
float identityLight; // 1.0 / ( 1 << overbrightBits )
int identityLightByte; // identityLight * 255

View file

@ -528,7 +528,7 @@ R_SetupProjection
void R_SetupProjection( void ) {
float xmin, xmax, ymin, ymax;
float width, height, depth;
float zNear, zFar;
float zNear, zFar, zZoomX, zZoomY;
// dynamically compute far clip plane distance
SetFarClip();
@ -538,14 +538,20 @@ void R_SetupProjection( void ) {
//
zNear = r_znear->value;
zFar = tr.viewParms.zFar;
zZoomX = 1.0f;
zZoomY = 1.0f;
if (!tr.refdef.override_fov &&
ri.TBXR_GetVRProjection((int)tr.stereoFrame, zNear, zFar, tr.viewParms.projectionMatrix))
if (tr.refdef.override_fov || vr->cgzoommode)
{
zZoomX = vr->fov_x / tr.refdef.fov_x;
zZoomY = vr->fov_y / tr.refdef.fov_y;
}
if (ri.TBXR_GetVRProjection(vr->eye, zNear, zFar, zZoomX, zZoomY, tr.viewParms.projectionMatrix))
{
return;
}
ymax = zNear * tan( tr.refdef.fov_y * M_PI / 360.0f );
ymin = -ymax;

View file

@ -37,6 +37,9 @@ void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) {
xoffset *= -1;
}
//We need to add an offset due to the effect of the compositor projection for asymmetric FOVs
xoffset += vr->off_center_fov * 640;
*x *= screenXScale;
*y *= screenYScale;
if (w != NULL) {