// // GVRInterface.cpp // gvr-interface/src // // Created by Stephen Birarda on 11/18/14. // Copyright 2013 High Fidelity, Inc. // // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // #ifdef ANDROID #include #include #include #include #ifdef HAVE_LIBOVR #include #include #endif #endif #include #include #include #include "GVRMainWindow.h" #include "RenderingClient.h" #include "GVRInterface.h" static QString launchURLString = QString(); #ifdef ANDROID extern "C" { JNIEXPORT void Java_io_highfidelity_gvrinterface_InterfaceActivity_handleHifiURL(JNIEnv *jni, jclass clazz, jstring hifiURLString) { launchURLString = QAndroidJniObject(hifiURLString).toString(); } } #endif GVRInterface::GVRInterface(int argc, char* argv[]) : QApplication(argc, argv), _mainWindow(NULL), _inVRMode(false) { setApplicationName("gvr-interface"); setOrganizationName("highfidelity"); setOrganizationDomain("io"); if (!launchURLString.isEmpty()) { // did we get launched with a lookup URL? If so it is time to give that to the AddressManager qDebug() << "We were opened via a hifi URL -" << launchURLString; } _client = new RenderingClient(this, launchURLString); launchURLString = QString(); connect(this, &QGuiApplication::applicationStateChanged, this, &GVRInterface::handleApplicationStateChange); #if defined(ANDROID) && defined(HAVE_LIBOVR) QAndroidJniEnvironment jniEnv; QPlatformNativeInterface* interface = QApplication::platformNativeInterface(); jobject activity = (jobject) interface->nativeResourceForIntegration("QtActivity"); ovr_RegisterHmtReceivers(&*jniEnv, activity); // PLATFORMACTIVITY_REMOVAL: Temp workaround for PlatformActivity being // stripped from UnityPlugin. Alternate is to use LOCAL_WHOLE_STATIC_LIBRARIES // but that increases the size of the plugin by ~1MiB OVR::linkerPlatformActivity++; #endif // call our idle function whenever we can QTimer* idleTimer = new QTimer(this); connect(idleTimer, &QTimer::timeout, this, &GVRInterface::idle); idleTimer->start(0); // call our quit handler before we go down connect(this, &QCoreApplication::aboutToQuit, this, &GVRInterface::handleApplicationQuit); } void GVRInterface::handleApplicationQuit() { _client->cleanupBeforeQuit(); } void GVRInterface::idle() { #if defined(ANDROID) && defined(HAVE_LIBOVR) if (!_inVRMode && ovr_IsHeadsetDocked()) { qDebug() << "The headset just got docked - enter VR mode."; enterVRMode(); } else if (_inVRMode) { if (ovr_IsHeadsetDocked()) { static int counter = 0; // Get the latest head tracking state, predicted ahead to the midpoint of the time // it will be displayed. It will always be corrected to the real values by // time warp, but the closer we get, the less black will be pulled in at the edges. const double now = ovr_GetTimeInSeconds(); static double prev; const double rawDelta = now - prev; prev = now; const double clampedPrediction = std::min( 0.1, rawDelta * 2); ovrSensorState sensor = ovrHmd_GetSensorState(OvrHmd, now + clampedPrediction, true ); auto ovrOrientation = sensor.Predicted.Pose.Orientation; glm::quat newOrientation(ovrOrientation.w, ovrOrientation.x, ovrOrientation.y, ovrOrientation.z); _client->setOrientation(newOrientation); if (counter++ % 100000 == 0) { qDebug() << "GetSensorState in frame" << counter << "-" << ovrOrientation.x << ovrOrientation.y << ovrOrientation.z << ovrOrientation.w; } } else { qDebug() << "The headset was undocked - leaving VR mode."; leaveVRMode(); } } OVR::KeyState& backKeyState = _mainWindow->getBackKeyState(); auto backEvent = backKeyState.Update(ovr_GetTimeInSeconds()); if (backEvent == OVR::KeyState::KEY_EVENT_LONG_PRESS) { qDebug() << "Attemping to start the Platform UI Activity."; ovr_StartPackageActivity(_ovr, PUI_CLASS_NAME, PUI_GLOBAL_MENU); } else if (backEvent == OVR::KeyState::KEY_EVENT_DOUBLE_TAP || backEvent == OVR::KeyState::KEY_EVENT_SHORT_PRESS) { qDebug() << "Got an event we should cancel for!"; } else if (backEvent == OVR::KeyState::KEY_EVENT_DOUBLE_TAP) { qDebug() << "The button is down!"; } #endif } void GVRInterface::handleApplicationStateChange(Qt::ApplicationState state) { switch(state) { case Qt::ApplicationActive: qDebug() << "The application is active."; break; case Qt::ApplicationSuspended: qDebug() << "The application is being suspended."; break; default: break; } } void GVRInterface::enterVRMode() { #if defined(ANDROID) && defined(HAVE_LIBOVR) // Default vrModeParms ovrModeParms vrModeParms; vrModeParms.AsynchronousTimeWarp = true; vrModeParms.AllowPowerSave = true; vrModeParms.DistortionFileName = NULL; vrModeParms.EnableImageServer = false; vrModeParms.CpuLevel = 2; vrModeParms.GpuLevel = 2; vrModeParms.GameThreadTid = 0; QAndroidJniEnvironment jniEnv; QPlatformNativeInterface* interface = QApplication::platformNativeInterface(); jobject activity = (jobject) interface->nativeResourceForIntegration("QtActivity"); vrModeParms.ActivityObject = activity; ovrHmdInfo hmdInfo; _ovr = ovr_EnterVrMode(vrModeParms, &hmdInfo); _inVRMode = true; #endif } void GVRInterface::leaveVRMode() { #if defined(ANDROID) && defined(HAVE_LIBOVR) ovr_LeaveVrMode(_ovr); _inVRMode = false; #endif }