diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 75a9f598f7..0e235af98a 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2867,8 +2867,10 @@ void Application::initializeDisplayPlugins() { [this](const QSize& size) { resizeGL(); }); QObject::connect(displayPlugin.get(), &DisplayPlugin::resetSensorsRequested, this, &Application::requestReset); if (displayPlugin->isHmd()) { - QObject::connect(dynamic_cast(displayPlugin.get()), &HmdDisplayPlugin::hmdMountedChanged, + auto hmdDisplayPlugin = dynamic_cast(displayPlugin.get()); + QObject::connect(hmdDisplayPlugin, &HmdDisplayPlugin::hmdMountedChanged, DependencyManager::get().data(), &HMDScriptingInterface::mountedChanged); + QObject::connect(hmdDisplayPlugin, &HmdDisplayPlugin::hmdVisibleChanged, this, &Application::hmdVisibleChanged); } } @@ -6521,6 +6523,14 @@ void Application::resetSensors(bool andReload) { QMetaObject::invokeMethod(DependencyManager::get().data(), "reset", Qt::QueuedConnection); } +void Application::hmdVisibleChanged(bool visible) { + if (visible) { + QMetaObject::invokeMethod(DependencyManager::get().data(), "start", Qt::QueuedConnection); + } else { + QMetaObject::invokeMethod(DependencyManager::get().data(), "stop", Qt::QueuedConnection); + } +} + void Application::updateWindowTitle() const { auto nodeList = DependencyManager::get(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 14e30b8006..b2a41dc421 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -382,6 +382,8 @@ public slots: void resetSensors(bool andReload = false); void setActiveFaceTracker() const; + void hmdVisibleChanged(bool visible); + #if (PR_BUILD || DEV_BUILD) void sendWrongProtocolVersionsSignature(bool checked) { ::sendWrongProtocolVersionsSignature(checked); } #endif diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 729bfd9e45..b6fffbb4bd 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -14,6 +14,7 @@ #include #include #include +#include #include "Application.h" #include "ui/DialogsManager.h" @@ -309,7 +310,13 @@ QString LODManager::getLODFeedbackText() { void LODManager::loadSettings() { setDesktopLODTargetFPS(desktopLODDecreaseFPS.get()); - setHMDLODTargetFPS(hmdLODDecreaseFPS.get()); + Setting::Handle firstRun { Settings::firstRun, true }; + if (qApp->property(hifi::properties::OCULUS_STORE).toBool() && firstRun.get()) { + const float LOD_HIGH_QUALITY_LEVEL = 0.75f; + setHMDLODTargetFPS(LOD_HIGH_QUALITY_LEVEL * LOD_MAX_LIKELY_HMD_FPS); + } else { + setHMDLODTargetFPS(hmdLODDecreaseFPS.get()); + } } void LODManager::saveSettings() { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index ef3dfcef4b..c5e558eb3a 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -41,6 +41,8 @@ * Read-only. * @property {number} y - The y display coordinate of the top left corner of the drawable area of the Interface window. * Read-only. + * @property {boolean} interstitialModeEnabled=true - true if the interstitial graphics are displayed when the + * domain is loading, otherwise false. */ class WindowScriptingInterface : public QObject, public Dependency { @@ -620,9 +622,10 @@ signals: void redirectErrorStateChanged(bool isInErrorState); /**jsdoc - * Triggered when interstitial mode changes. + * Triggered when the interstitial mode changes. * @function Window.interstitialModeChanged - * @param {bool} interstitialMode - The mode of the interstitial is changed to. + * @param {bool} interstitialMode - The new interstitial mode value. If true, the interstitial graphics are + * displayed when the domain is loading. * @returns {Signal} */ void interstitialModeChanged(bool interstitialMode); diff --git a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h index ea11832e94..a56daaad83 100644 --- a/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h +++ b/libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.h @@ -48,6 +48,7 @@ public: signals: void hmdMountedChanged(); + void hmdVisibleChanged(bool visible); protected: virtual void hmdPresent() = 0; diff --git a/libraries/qml/src/qml/OffscreenSurface.cpp b/libraries/qml/src/qml/OffscreenSurface.cpp index cbcafe9c7d..91532534e3 100644 --- a/libraries/qml/src/qml/OffscreenSurface.cpp +++ b/libraries/qml/src/qml/OffscreenSurface.cpp @@ -317,7 +317,7 @@ void OffscreenSurface::loadInternal(const QUrl& qmlSource, { PROFILE_RANGE(app, "new QQmlComponent"); qmlComponent = new QQmlComponent(getSurfaceContext()->engine(), finalQmlSource, QQmlComponent::PreferSynchronous); - } + } if (qmlComponent->isLoading()) { connect(qmlComponent, &QQmlComponent::statusChanged, this, [=](QQmlComponent::Status) { finishQmlLoad(qmlComponent, targetContext, parent, callback); }); diff --git a/plugins/hifiSpacemouse/src/SpacemouseManager.cpp b/plugins/hifiSpacemouse/src/SpacemouseManager.cpp index 4641799b79..e5fd2a3501 100644 --- a/plugins/hifiSpacemouse/src/SpacemouseManager.cpp +++ b/plugins/hifiSpacemouse/src/SpacemouseManager.cpp @@ -20,7 +20,7 @@ #include -const QString SpacemouseManager::NAME { "Spacemouse" }; +const char* SpacemouseManager::NAME { "Spacemouse" }; const float MAX_AXIS = 75.0f; // max forward = 2x speed #define LOGITECH_VENDOR_ID 0x46d @@ -116,8 +116,8 @@ controller::Input::NamedVector SpacemouseDevice::getAvailableInputs() const { makePair(TRANSLATE_X, "TranslateX"), makePair(TRANSLATE_Y, "TranslateY"), makePair(TRANSLATE_Z, "TranslateZ"), - //makePair(ROTATE_X, "RotateX"), - //makePair(ROTATE_Y, "RotateY"), + makePair(ROTATE_X, "RotateX"), + makePair(ROTATE_Y, "RotateY"), makePair(ROTATE_Z, "RotateZ"), }; diff --git a/plugins/hifiSpacemouse/src/SpacemouseProvider.cpp b/plugins/hifiSpacemouse/src/SpacemouseProvider.cpp index c623f77d73..354b4711a3 100644 --- a/plugins/hifiSpacemouse/src/SpacemouseProvider.cpp +++ b/plugins/hifiSpacemouse/src/SpacemouseProvider.cpp @@ -38,6 +38,10 @@ public: return _inputPlugins; } + virtual void destroyInputPlugins() override { + _inputPlugins.clear(); + } + private: InputPluginList _inputPlugins; }; diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp index 0e4dac796d..f10aba7920 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.cpp @@ -23,13 +23,14 @@ void OculusBaseDisplayPlugin::resetSensors() { } bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { - ovrSessionStatus status{}; - if (!OVR_SUCCESS(ovr_GetSessionStatus(_session, &status))) { + ovrResult getStatusResult; + ovrSessionStatus status = ovr::getStatus(getStatusResult); + if (!OVR_SUCCESS(getStatusResult)) { qCWarning(oculusLog) << "Unable to fetch Oculus session status" << ovr::getError(); return false; } - if (ovr::quitRequested(status)) { + if (ovr::quitRequested(status) || ovr::displayLost(status) || !ovr::handleOVREvents()) { QMetaObject::invokeMethod(qApp, "quit"); return false; } @@ -40,11 +41,15 @@ bool OculusBaseDisplayPlugin::beginFrameRender(uint32_t frameIndex) { _hmdMounted = !_hmdMounted; emit hmdMountedChanged(); } + if (ovr::isVisible(status) != _visible) { + _visible = !_visible; + emit hmdVisibleChanged(_visible); + } _currentRenderFrameInfo = FrameInfo(); _currentRenderFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _currentRenderFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, frameIndex); - auto trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrTrue); + auto trackingState = ovr::getTrackingState(_currentRenderFrameInfo.predictedDisplayTime, ovrTrue); _currentRenderFrameInfo.renderPose = ovr::toGlm(trackingState.HeadPose.ThePose); _currentRenderFrameInfo.presentPose = _currentRenderFrameInfo.renderPose; @@ -167,7 +172,7 @@ void OculusBaseDisplayPlugin::updatePresentPose() { ovrTrackingState trackingState; _currentPresentFrameInfo.sensorSampleTime = ovr_GetTimeInSeconds(); _currentPresentFrameInfo.predictedDisplayTime = ovr_GetPredictedDisplayTime(_session, 0); - trackingState = ovr_GetTrackingState(_session, _currentRenderFrameInfo.predictedDisplayTime, ovrFalse); + trackingState = ovr::getTrackingState(_currentRenderFrameInfo.predictedDisplayTime); _currentPresentFrameInfo.presentPose = ovr::toGlm(trackingState.HeadPose.ThePose); _currentPresentFrameInfo.renderPose = _currentPresentFrameInfo.presentPose; } diff --git a/plugins/oculus/src/OculusBaseDisplayPlugin.h b/plugins/oculus/src/OculusBaseDisplayPlugin.h index f71fb8ece8..547d3ee5fe 100644 --- a/plugins/oculus/src/OculusBaseDisplayPlugin.h +++ b/plugins/oculus/src/OculusBaseDisplayPlugin.h @@ -48,4 +48,5 @@ protected: ovrViewScaleDesc _viewScaleDesc; // ovrLayerEyeFovDepth _depthLayer; bool _hmdMounted { false }; + bool _visible { true }; }; diff --git a/plugins/oculus/src/OculusDisplayPlugin.cpp b/plugins/oculus/src/OculusDisplayPlugin.cpp index 308652cacd..a34e647a5e 100644 --- a/plugins/oculus/src/OculusDisplayPlugin.cpp +++ b/plugins/oculus/src/OculusDisplayPlugin.cpp @@ -134,6 +134,10 @@ void OculusDisplayPlugin::hmdPresent() { return; } + if (!_visible) { + return; + } + PROFILE_RANGE_EX(render, __FUNCTION__, 0xff00ff00, (uint64_t)_currentFrame->frameIndex) { @@ -195,6 +199,10 @@ void OculusDisplayPlugin::hmdPresent() { if (!OVR_SUCCESS(result)) { qWarning(oculusLog) << "Failed to present" << ovr::getError(); + if (result == ovrError_DisplayLost) { + qWarning(oculusLog) << "Display lost, shutting down"; + return; + } } static int compositorDroppedFrames = 0; diff --git a/plugins/oculus/src/OculusHelpers.cpp b/plugins/oculus/src/OculusHelpers.cpp index 402b05f39c..29691e73a5 100644 --- a/plugins/oculus/src/OculusHelpers.cpp +++ b/plugins/oculus/src/OculusHelpers.cpp @@ -81,6 +81,18 @@ private: return; } +#ifdef OCULUS_APP_ID + if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { + if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { + qCWarning(oculusLog) << "Unable to initialize the platform for entitlement check - fail the check" << ovr::getError(); + return; + } else { + qCDebug(oculusLog) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); + } + } +#endif + ovrGraphicsLuid luid; if (!OVR_SUCCESS(ovr_Create(&session, &luid))) { qCWarning(oculusLog) << "Failed to acquire Oculus session" << ovr::getError(); @@ -141,18 +153,24 @@ void ovr::withSession(const std::function& f) { } ovrSessionStatus ovr::getStatus() { + ovrResult result; + return ovr::getStatus(result); +} + +ovrSessionStatus ovr::getStatus(ovrResult& result) { ovrSessionStatus status{}; withSession([&](ovrSession session) { - if (!OVR_SUCCESS(ovr_GetSessionStatus(session, &status))) { + result = ovr_GetSessionStatus(session, &status); + if (!OVR_SUCCESS(result)) { qCWarning(oculusLog) << "Failed to get session status" << ovr::getError(); } }); return status; } -ovrTrackingState ovr::getTrackingState() { +ovrTrackingState ovr::getTrackingState(double absTime, ovrBool latencyMarker) { ovrTrackingState result{}; - withSession([&](ovrSession session) { result = ovr_GetTrackingState(session, 0, ovrFalse); }); + withSession([&](ovrSession session) { result = ovr_GetTrackingState(session, absTime, latencyMarker); }); return result; } @@ -276,31 +294,25 @@ controller::Pose hifi::ovr::toControllerPose(ovrHandType hand, return pose; } -// FIXME These should be moved to an oculusPlatform plugin, they don't interact with the controller or session state -#if 0 -void handleOVREvents() { - updateSessionStatus(true); - +bool hifi::ovr::handleOVREvents() { #ifdef OCULUS_APP_ID - if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { // pop messages to see if we got a return for an entitlement check ovrMessageHandle message = ovr_PopMessage(); while (message) { switch (ovr_Message_GetType(message)) { - case ovrMessage_Entitlement_GetIsViewerEntitled: - { - if (!ovr_Message_IsError(message)) { - // this viewer is entitled, no need to flag anything - qCDebug(oculus) << "Oculus Platform entitlement check succeeded, proceeding normally"; - } else { - // we failed the entitlement check, set our flag so the app can stop - qCDebug(oculus) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; - _quitRequested = true; + case ovrMessage_Entitlement_GetIsViewerEntitled: { + if (!ovr_Message_IsError(message)) { + // this viewer is entitled, no need to flag anything + qCDebug(oculusLog) << "Oculus Platform entitlement check succeeded, proceeding normally"; + } else { + // we failed the entitlement check, quit + qCDebug(oculusLog) << "Oculus Platform entitlement check failed, app will now quit" << OCULUS_APP_ID; + return false; + } } } - } // free the message handle to cleanup and not leak ovr_FreeMessage(message); @@ -310,17 +322,5 @@ void handleOVREvents() { } } #endif + return true; } - -#ifdef OCULUS_APP_ID -if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { - if (ovr_PlatformInitializeWindows(OCULUS_APP_ID) != ovrPlatformInitialize_Success) { - // we were unable to initialize the platform for entitlement check - fail the check - _quitRequested = true; - } else { - qCDebug(oculusLog) << "Performing Oculus Platform entitlement check"; - ovr_Entitlement_GetIsViewerEntitled(); - } -} -#endif -#endif diff --git a/plugins/oculus/src/OculusHelpers.h b/plugins/oculus/src/OculusHelpers.h index 6588d9754b..bdfc4434bb 100644 --- a/plugins/oculus/src/OculusHelpers.h +++ b/plugins/oculus/src/OculusHelpers.h @@ -27,8 +27,10 @@ struct ovr { static void releaseRenderSession(ovrSession session); static void withSession(const std::function& f); static ovrSessionStatus getStatus(); - static ovrTrackingState getTrackingState(); + static ovrSessionStatus getStatus(ovrResult& result); + static ovrTrackingState getTrackingState(double absTime = 0.0, ovrBool latencyMarker = ovrFalse); static QString getError(); + static bool handleOVREvents(); static inline bool quitRequested() { return quitRequested(getStatus()); } static inline bool reorientRequested() { return reorientRequested(getStatus()); } @@ -36,6 +38,8 @@ struct ovr { static inline bool hasInputFocus() { return hasInputFocus(getStatus()); } static inline bool quitRequested(const ovrSessionStatus& status) { return status.ShouldQuit != ovrFalse; } + static inline bool displayLost(const ovrSessionStatus& status) { return status.DisplayLost != ovrFalse; } + static inline bool isVisible(const ovrSessionStatus& status) { return status.IsVisible != ovrFalse; } static inline bool reorientRequested(const ovrSessionStatus& status) { return status.ShouldRecenter != ovrFalse; } static inline bool hmdMounted(const ovrSessionStatus& status) { return status.HmdMounted != ovrFalse; } static inline bool hasInputFocus(const ovrSessionStatus& status) { return status.HasInputFocus != ovrFalse; } diff --git a/scripts/defaultScripts.js b/scripts/defaultScripts.js index 5df1b3e511..bd7e79dffc 100644 --- a/scripts/defaultScripts.js +++ b/scripts/defaultScripts.js @@ -40,8 +40,8 @@ var DEFAULT_SCRIPTS_SEPARATE = [ ]; if (Window.interstitialModeEnabled) { - DEFAULT_SCRIPTS_COMBINED.push("system/interstitialPage.js"); - DEFAULT_SCRIPTS_COMBINED.push("system/redirectOverlays.js"); + // Insert interstitial scripts at front so that they're started first. + DEFAULT_SCRIPTS_COMBINED.splice(0, 0, "system/interstitialPage.js", "system/redirectOverlays.js"); } // add a menu item for debugging diff --git a/scripts/system/interstitialPage.js b/scripts/system/interstitialPage.js index e2db032d8c..b7c5809b3a 100644 --- a/scripts/system/interstitialPage.js +++ b/scripts/system/interstitialPage.js @@ -62,11 +62,23 @@ var DEFAULT_DIMENSIONS = { x: 24, y: 24, z: 24 }; + var BLACK_SPHERE = Script.resolvePath("/~/system/assets/models/black-sphere.fbx"); + var BUTTON = Script.resourcesPath() + "images/interstitialPage/button.png"; + var BUTTON_HOVER = Script.resourcesPath() + "images/interstitialPage/button_hover.png"; + var LOADING_BAR_PLACARD = Script.resourcesPath() + "images/loadingBar_placard.png"; + var LOADING_BAR_PROGRESS = Script.resourcesPath() + "images/loadingBar_progress.png"; + + ModelCache.prefetch(BLACK_SPHERE); + TextureCache.prefetch(BUTTON); + TextureCache.prefetch(BUTTON_HOVER); + TextureCache.prefetch(LOADING_BAR_PLACARD); + TextureCache.prefetch(LOADING_BAR_PROGRESS); + var loadingSphereID = Overlays.addOverlay("model", { name: "Loading-Sphere", position: Vec3.sum(Vec3.sum(MyAvatar.position, { x: 0.0, y: -1.0, z: 0.0 }), Vec3.multiplyQbyV(MyAvatar.orientation, { x: 0, y: 0.95, z: 0 })), orientation: Quat.multiply(Quat.fromVec3Degrees({ x: 0, y: 180, z: 0 }), MyAvatar.orientation), - url: Script.resolvePath("/~/system/assets/models/black-sphere.fbx"), + url: BLACK_SPHERE, dimensions: DEFAULT_DIMENSIONS, alpha: 1, visible: isVisible, @@ -157,7 +169,7 @@ var loadingToTheSpotID = Overlays.addOverlay("image3d", { name: "Loading-Destination-Card-GoTo-Image", localPosition: { x: 0.0, y: -1.75, z: -0.3 }, - url: Script.resourcesPath() + "images/interstitialPage/button.png", + url: BUTTON, alpha: 1, visible: isVisible, emissive: true, @@ -171,7 +183,7 @@ var loadingToTheSpotHoverID = Overlays.addOverlay("image3d", { name: "Loading-Destination-Card-GoTo-Image-Hover", localPosition: { x: 0.0, y: -1.75, z: -0.3 }, - url: Script.resourcesPath() + "images/interstitialPage/button_hover.png", + url: BUTTON_HOVER, alpha: 1, visible: false, emissive: true, @@ -186,7 +198,7 @@ var loadingBarProgress = Overlays.addOverlay("image3d", { name: "Loading-Bar-Progress", localPosition: { x: 0.0, y: -0.86, z: 0.0 }, - url: Script.resourcesPath() + "images/loadingBar_progress.png", + url: LOADING_BAR_PROGRESS, alpha: 1, dimensions: { x: TOTAL_LOADING_PROGRESS, y: 0.3}, visible: isVisible, @@ -202,7 +214,7 @@ var loadingBarPlacard = Overlays.addOverlay("image3d", { name: "Loading-Bar-Placard", localPosition: { x: 0.0, y: -0.99, z: 0.4 }, - url: Script.resourcesPath() + "images/loadingBar_placard.png", + url: LOADING_BAR_PLACARD, alpha: 1, dimensions: { x: 4, y: 2.8 }, visible: isVisible, @@ -273,12 +285,21 @@ } } + function restartAudio() { + tune.ready.disconnect(restartAudio); + startAudio(); + } + function startAudio() { - sample = Audio.playSound(tune, { - localOnly: true, - position: MyAvatar.getHeadPosition(), - volume: VOLUME - }); + if (tune.downloaded) { + sample = Audio.playSound(tune, { + localOnly: true, + position: MyAvatar.getHeadPosition(), + volume: VOLUME + }); + } else { + tune.ready.connect(restartAudio); + } } function endAudio() { @@ -614,5 +635,11 @@ } } + // location.hostname may already be set by the time the script is loaded. + // Show the interstitial page if the domain isn't loaded. + if (!location.isConnected) { + domainChanged(location.hostname); + } + Script.scriptEnding.connect(cleanup); }());