OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame(ovrSession session, long long frameIndex, const ovrViewScaleDesc* viewScaleDesc, ovrLayerHeader const * const * layerPtrList, unsigned int layerCount) { // TODO: Implement scaling through ApplyTransform(). // Call WaitGetPoses() to do some cleanup from the previous frame. session->compositor->WaitGetPoses(session->poses, vr::k_unMaxTrackedDeviceCount, session->gamePoses, vr::k_unMaxTrackedDeviceCount); if (layerCount == 0) return ovrError_InvalidParameter; // The first layer is assumed to be the application scene. if (layerPtrList[0]->Type != ovrLayerType_EyeFov) return ovrSuccess_NotVisible; ovrLayerEyeFov* sceneLayer = (ovrLayerEyeFov*)layerPtrList[0]; // Other layers are interpreted as overlays. for (size_t i = 1; i < vr::k_unMaxOverlayCount + 1; i++) { char keyName[vr::k_unVROverlayMaxKeyLength]; snprintf(keyName, vr::k_unVROverlayMaxKeyLength, "Revive_%d", i); // Look if the overlay already exists. vr::VROverlayHandle_t overlay; vr::EVROverlayError err = session->overlay->FindOverlay(keyName, &overlay); // If this layer is defined in the list, show it. If not, hide the layer if it exists. if (i < layerCount) { // Create a new overlay if it doesn't exist. if (err == vr::VROverlayError_UnknownOverlay) { char title[vr::k_unVROverlayMaxNameLength]; snprintf(title, vr::k_unVROverlayMaxNameLength, "Revive Layer %d", i); session->overlay->CreateOverlay(keyName, title, &overlay); } // A layer was added, but not defined, hide it. if (layerPtrList[i] == nullptr) { session->overlay->HideOverlay(overlay); continue; } // Overlays are assumed to be monoscopic quads. _ASSERT(layerPtrList[i]->Type == ovrLayerType_Quad); ovrLayerQuad* layer = (ovrLayerQuad*)layerPtrList[i]; // Set the high quality overlay. if (layer->Header.Flags & ovrLayerFlag_HighQuality) session->overlay->SetHighQualityOverlay(overlay); // Transform the overlay. vr::HmdMatrix34_t transform = REV_OvrPoseToHmdMatrix(layer->QuadPoseCenter); session->overlay->SetOverlayWidthInMeters(overlay, layer->QuadSize.x); if (layer->Header.Flags & ovrLayerFlag_HeadLocked) session->overlay->SetOverlayTransformTrackedDeviceRelative(overlay, vr::k_unTrackedDeviceIndex_Hmd, &transform); else session->overlay->SetOverlayTransformAbsolute(overlay, session->compositor->GetTrackingSpace(), &transform); // Set the texture and show the overlay. ovrTextureSwapChain chain = layer->ColorTexture; vr::VRTextureBounds_t bounds = REV_ViewportToTextureBounds(layer->Viewport, layer->ColorTexture, layer->Header.Flags); session->overlay->SetOverlayTextureBounds(overlay, &bounds); session->overlay->SetOverlayTexture(overlay, &chain->current); // TODO: Handle overlay errors. session->overlay->ShowOverlay(overlay); } else { if (err == vr::VROverlayError_UnknownOverlay) break; // Hide all overlays no longer visible. session->overlay->HideOverlay(overlay); } } // Submit the scene layer. for (int i = 0; i < ovrEye_Count; i++) { ovrTextureSwapChain chain = sceneLayer->ColorTexture[i]; session->ColorTexture[i] = chain; vr::VRTextureBounds_t bounds = REV_ViewportToTextureBounds(sceneLayer->Viewport[i], sceneLayer->ColorTexture[i], sceneLayer->Header.Flags); vr::EVRCompositorError err = session->compositor->Submit((vr::EVREye)i, &chain->current, &bounds); if (err != vr::VRCompositorError_None) return REV_CompositorErrorToOvrError(err); } return ovrSuccess; }
OVR_PUBLIC_FUNCTION(ovrResult) ovr_SubmitFrame(ovrSession session, long long frameIndex, const ovrViewScaleDesc* viewScaleDesc, ovrLayerHeader const * const * layerPtrList, unsigned int layerCount) { // TODO: Implement scaling through ApplyTransform(). if (!session) return ovrError_InvalidSession; if (layerCount == 0 || !layerPtrList) return ovrError_InvalidParameter; // Other layers are interpreted as overlays. for (size_t i = 0; i < ovrMaxLayerCount; i++) { // If this layer is defined in the list, show it. If not, hide the layer if it exists. if (i < layerCount) { // Create a new overlay if it doesn't exist. if (session->overlays[i] == vr::k_ulOverlayHandleInvalid) { char keyName[vr::k_unVROverlayMaxKeyLength]; snprintf(keyName, vr::k_unVROverlayMaxKeyLength, "revive.runtime.layer%d", i); char title[vr::k_unVROverlayMaxNameLength]; snprintf(title, vr::k_unVROverlayMaxNameLength, "Revive Layer %d", i); session->overlay->CreateOverlay(keyName, title, &session->overlays[i]); } // A layer was added, but not defined, hide it. if (layerPtrList[i] == nullptr) { session->overlay->HideOverlay(session->overlays[i]); continue; } // Overlays are assumed to be monoscopic quads. if (layerPtrList[i]->Type != ovrLayerType_Quad) continue; ovrLayerQuad* layer = (ovrLayerQuad*)layerPtrList[i]; // Set the high quality overlay. // FIXME: Why are High quality overlays headlocked in OpenVR? //if (layer->Header.Flags & ovrLayerFlag_HighQuality) // session->overlay->SetHighQualityOverlay(overlay); // Transform the overlay. vr::HmdMatrix34_t transform = REV_OvrPoseToHmdMatrix(layer->QuadPoseCenter); session->overlay->SetOverlayWidthInMeters(session->overlays[i], layer->QuadSize.x); if (layer->Header.Flags & ovrLayerFlag_HeadLocked) session->overlay->SetOverlayTransformTrackedDeviceRelative(session->overlays[i], vr::k_unTrackedDeviceIndex_Hmd, &transform); else session->overlay->SetOverlayTransformAbsolute(session->overlays[i], session->compositor->GetTrackingSpace(), &transform); // Set the texture and show the overlay. ovrTextureSwapChain chain = layer->ColorTexture; vr::VRTextureBounds_t bounds = REV_ViewportToTextureBounds(layer->Viewport, layer->ColorTexture, layer->Header.Flags); session->overlay->SetOverlayTextureBounds(session->overlays[i], &bounds); session->overlay->SetOverlayTexture(session->overlays[i], &chain->current); // TODO: Handle overlay errors. session->overlay->ShowOverlay(session->overlays[i]); } else { if (session->overlays[i] != vr::k_ulOverlayHandleInvalid) { // Destory all overlays no longer listed. session->overlay->DestroyOverlay(session->overlays[i]); session->overlays[i] = vr::k_ulOverlayHandleInvalid; } } } // The first layer is assumed to be the application scene. vr::EVRCompositorError err = vr::VRCompositorError_None; if (layerPtrList[0]->Type == ovrLayerType_EyeFov) { ovrLayerEyeFov* sceneLayer = (ovrLayerEyeFov*)layerPtrList[0]; // Submit the scene layer. for (int i = 0; i < ovrEye_Count; i++) { ovrTextureSwapChain chain = sceneLayer->ColorTexture[i]; vr::VRTextureBounds_t bounds = REV_ViewportToTextureBounds(sceneLayer->Viewport[i], sceneLayer->ColorTexture[i], sceneLayer->Header.Flags); float left, right, top, bottom; g_VRSystem->GetProjectionRaw((vr::EVREye)i, &left, &right, &top, &bottom); // Shrink the bounds to account for the overlapping fov ovrFovPort fov = sceneLayer->Fov[i]; float uMin = 0.5f + 0.5f * left / fov.LeftTan; float uMax = 0.5f + 0.5f * right / fov.RightTan; float vMin = 0.5f - 0.5f * bottom / fov.UpTan; float vMax = 0.5f - 0.5f * top / fov.DownTan; // Combine the fov bounds with the viewport bounds bounds.uMin += uMin * bounds.uMax; bounds.uMax *= uMax; bounds.vMin += vMin * bounds.vMax; bounds.vMax *= vMax; if (chain->texture[i].eType == vr::API_OpenGL) { bounds.vMin = 1.0f - bounds.vMin; bounds.vMax = 1.0f - bounds.vMax; } err = session->compositor->Submit((vr::EVREye)i, &chain->current, &bounds); if (err != vr::VRCompositorError_None) break; } } // The first layer is assumed to be the application scene. if (layerPtrList[0]->Type == ovrLayerType_EyeMatrix) { ovrLayerEyeMatrix* sceneLayer = (ovrLayerEyeMatrix*)layerPtrList[0]; // Submit the scene layer. for (int i = 0; i < ovrEye_Count; i++) { ovrTextureSwapChain chain = sceneLayer->ColorTexture[i]; vr::VRTextureBounds_t bounds = REV_ViewportToTextureBounds(sceneLayer->Viewport[i], sceneLayer->ColorTexture[i], sceneLayer->Header.Flags); float left, right, top, bottom; g_VRSystem->GetProjectionRaw((vr::EVREye)i, &left, &right, &top, &bottom); // Shrink the bounds to account for the overlapping fov ovrVector2f fov = { .5f / sceneLayer->Matrix[i].M[0][0], .5f / sceneLayer->Matrix[i].M[1][1] }; float uMin = 0.5f + 0.5f * left / fov.x; float uMax = 0.5f + 0.5f * right / fov.x; float vMin = 0.5f - 0.5f * bottom / fov.y; float vMax = 0.5f - 0.5f * top / fov.y; // Combine the fov bounds with the viewport bounds bounds.uMin += uMin * bounds.uMax; bounds.uMax *= uMax; bounds.vMin += vMin * bounds.vMax; bounds.vMax *= vMax; if (chain->texture[i].eType == vr::API_OpenGL) { bounds.vMin = 1.0f - bounds.vMin; bounds.vMax = 1.0f - bounds.vMax; } err = session->compositor->Submit((vr::EVREye)i, &chain->current, &bounds); if (err != vr::VRCompositorError_None) break; } } // Call WaitGetPoses() to do some cleanup from the previous frame. session->compositor->WaitGetPoses(session->poses, vr::k_unMaxTrackedDeviceCount, session->gamePoses, vr::k_unMaxTrackedDeviceCount); g_FrameIndex = frameIndex; return REV_CompositorErrorToOvrError(err); }