diff --git a/libraries/plugins/src/plugins/OculusPlatformPlugin.h b/libraries/plugins/src/plugins/OculusPlatformPlugin.h new file mode 100644 index 0000000000..fc28b983df --- /dev/null +++ b/libraries/plugins/src/plugins/OculusPlatformPlugin.h @@ -0,0 +1,35 @@ +// +// Created by Wayne Chen on 2018/12/20 +// Copyright 2018 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 +// +#pragma once + +#include +#include + +#include + +using Ticket = QByteArray; +using TicketRequestCallback = std::function; + + +class OculusPlatformPlugin { +public: + virtual ~OculusPlatformPlugin() = default; + + virtual bool init() = 0; + virtual void shutdown() = 0; + + virtual bool isRunning() = 0; + + virtual void runCallbacks() = 0; + + virtual void requestTicket(TicketRequestCallback callback) = 0; + + virtual QString getLoggedInUserID() = 0; + + virtual QString getOculusVRBuildID() = 0; +}; diff --git a/plugins/oculusPlatform/CMakeLists.txt b/plugins/oculusPlatform/CMakeLists.txt new file mode 100644 index 0000000000..89608794ae --- /dev/null +++ b/plugins/oculusPlatform/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# Created by Bradley Austin Davis on 2015/10/25 +# Copyright 2015 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 +# + +if (WIN32 AND (NOT USE_GLES)) + + # if we were passed an Oculus App ID for entitlement checks, send that along + if (DEFINED ENV{OCULUS_APP_ID}) + add_definitions(-DOCULUS_APP_ID="$ENV{OCULUS_APP_ID}") + endif () + + set(TARGET_NAME oculusPlatform) + setup_hifi_plugin(Multimedia) + link_hifi_libraries( + shared task gl shaders gpu ${PLATFORM_GL_BACKEND} controllers ui qml + plugins ui-plugins display-plugins input-plugins + audio-client networking render-utils + ${PLATFORM_GL_BACKEND} + ) + include_hifi_library_headers(octree) + + add_dependency_external_projects(LibOVR) + find_package(LibOVR REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVR_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${LIBOVR_LIBRARIES}) + target_link_libraries(${TARGET_NAME} Winmm.lib) + + add_dependency_external_projects(LibOVRPlatform) + find_package(LibOVRPlatform REQUIRED) + target_include_directories(${TARGET_NAME} PRIVATE ${LIBOVRPLATFORM_INCLUDE_DIRS}) + target_link_libraries(${TARGET_NAME} ${LIBOVRPLATFORM_LIBRARIES}) +endif() diff --git a/plugins/oculusPlatform/src/OculusAPIPlugin.cpp b/plugins/oculusPlatform/src/OculusAPIPlugin.cpp new file mode 100644 index 0000000000..4646b595fd --- /dev/null +++ b/plugins/oculusPlatform/src/OculusAPIPlugin.cpp @@ -0,0 +1,116 @@ +// +// Created by Wayne Chen on 2018/12/20 +// Copyright 2018 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 +// + +#include "OculusAPIPlugin.h" + +#include +#include +#include + +#include + +#define OVRPL_DISABLED +#include + +#include +#include "OculusHelpers.h" + +static const Ticket INVALID_TICKET = Ticket(); +//static std::atomic_bool initialized { false }; +static std::atomic_bool initialized { false }; +static ovrSession session { nullptr }; + +bool OculusAPIPlugin::init() { + if (session) { + return initialized; + } + + ovrInitParams initParams{ ovrInit_RequestVersion | ovrInit_FocusAware, OVR_MINOR_VERSION, nullptr, 0, 0 }; + initParams.Flags |= ovrInit_Invisible; + + if (!OVR_SUCCESS(ovr_Initialize(&initParams))) { + qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << hifi::ovr::getError(); + return initialized; + } + +#ifdef OCULUS_APP_ID + + if (qApp->property(hifi::properties::OCULUS_STORE).toBool()) { + auto result = ovr_PlatformInitializeWindows(OCULUS_APP_ID); + if (result != ovrPlatformInitialize_Success && result != ovrPlatformInitialize_PreLoaded) { + qCWarning(oculusLog) << "Unable to initialize the platform for entitlement check - fail the check" << hifi::ovr::getError(); + } else { + qCDebug(oculusLog) << "Performing Oculus Platform entitlement check"; + ovr_Entitlement_GetIsViewerEntitled(); + using namespace std::chrono_literals; + std::this_thread::sleep_for(100ms); + auto message = ovr_PopMessage(); + if (ovr_Message_GetType(message) == ovrMessage_Entitlement_GetIsViewerEntitled && ovr_Message_IsError(message)) { + qDebug() << QString(ovr_Error_GetMessage(ovr_Message_GetError(message))); + } + } + } +#endif + + //ovrGraphicsLuid luid; + //if (!OVR_SUCCESS(ovr_Create(&session, &luid))) { + // qCWarning(oculusLog) << "Failed to acquire Oculus session" << hifi::ovr::getError(); + // return initialized; + //} else { + // ovrResult setFloorLevelOrigin = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); + // if (!OVR_SUCCESS(setFloorLevelOrigin)) { + // qCWarning(oculusLog) << "Failed to set the Oculus tracking origin to floor level" << hifi::ovr::getError(); + // } + //} + initialized = true; + return initialized; +} + +void OculusAPIPlugin::shutdown() { +} + +void OculusAPIPlugin::runCallbacks() { +} + +void OculusAPIPlugin::requestTicket(TicketRequestCallback callback) { +} + +bool OculusAPIPlugin::isRunning() { + return initialized; +} + +QString OculusAPIPlugin::getLoggedInUserID() { + if (initialized) { + QTimer timer; + timer.start(1000); + auto request = ovr_User_GetLoggedInUser(); + ovrMessageHandle message { nullptr }; + using namespace std::chrono_literals; + std::this_thread::sleep_for(100ms); + while ((message = ovr_PopMessage()) != nullptr) { + if (!timer.isActive()) { + qCDebug(oculusLog) << "login user id timeout after 1 second"; + return ""; + } else if (ovr_Message_GetType(message) == ovrMessage_User_GetLoggedInUser) { + if (!ovr_Message_IsError(message)) { + ovrUserHandle user = ovr_Message_GetUser(message); + qCDebug(oculusLog) << "UserID: " << ovr_User_GetID(user) << ", Oculus ID: " << ovr_User_GetOculusID(user); + return ovr_User_GetOculusID(user); + } else { + qDebug() << "Error getting user id: " << QString(ovr_Error_GetMessage(ovr_Message_GetError(message))); + return ""; + } + } + } + return ""; + } +} + +QString OculusAPIPlugin::getOculusVRBuildID() { + return QString(OVR_MAJOR_VERSION + "." + OVR_MINOR_VERSION); +} diff --git a/plugins/oculusPlatform/src/OculusAPIPlugin.h b/plugins/oculusPlatform/src/OculusAPIPlugin.h new file mode 100644 index 0000000000..90acf65fc6 --- /dev/null +++ b/plugins/oculusPlatform/src/OculusAPIPlugin.h @@ -0,0 +1,26 @@ +// +// Created by Wayne Chen on 2018/12/20 +// Copyright 2018 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 +// +#pragma once + +#include + +class OculusAPIPlugin : public OculusPlatformPlugin { +public: + bool init() override; + void shutdown() override; + + bool isRunning() override; + + void runCallbacks() override; + + void requestTicket(TicketRequestCallback callback) override; + + QString getLoggedInUserID() override; + + QString getOculusVRBuildID() override; +}; diff --git a/plugins/oculusPlatform/src/OculusHelpers.cpp b/plugins/oculusPlatform/src/OculusHelpers.cpp new file mode 100644 index 0000000000..29691e73a5 --- /dev/null +++ b/plugins/oculusPlatform/src/OculusHelpers.cpp @@ -0,0 +1,326 @@ +// +// Created by Bradley Austin Davis on 2015/08/08 +// Copyright 2015 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 +// + +#include "OculusHelpers.h" + +#include + +#include +#include +#include +#include + +#define OVRPL_DISABLED +#include + +#include +#include +#include +#include + +Q_LOGGING_CATEGORY(displayplugins, "hifi.plugins.display") +Q_LOGGING_CATEGORY(oculusLog, "hifi.plugins.display.oculus") + +using namespace hifi; + +static wchar_t* REQUIRED_OCULUS_DLL = L"LibOVRRT64_1.dll"; +static wchar_t FOUND_PATH[MAX_PATH]; + +bool ovr::available() { + static std::once_flag once; + static bool result{ false }; + std::call_once(once, [&] { + static const QString DEBUG_FLAG("HIFI_DEBUG_OPENVR"); + static bool enableDebugOpenVR = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG); + if (enableDebugOpenVR) { + return; + } + + ovrDetectResult detect = ovr_Detect(0); + if (!detect.IsOculusServiceRunning || !detect.IsOculusHMDConnected) { + return; + } + + DWORD searchResult = SearchPathW(NULL, REQUIRED_OCULUS_DLL, NULL, MAX_PATH, FOUND_PATH, NULL); + if (searchResult <= 0) { + return; + } + + result = true; + }); + + return result; +} + +class ovrImpl { + using Mutex = std::mutex; + using Lock = std::unique_lock; + std::mutex mutex; + ovrSession session{ nullptr }; + size_t renderCount{ 0 }; + +private: + void setupSession(bool render) { + if (session) { + return; + } + ovrInitParams initParams{ ovrInit_RequestVersion | ovrInit_FocusAware, OVR_MINOR_VERSION, nullptr, 0, 0 }; + if (render) { + initParams.Flags |= ovrInit_MixedRendering; + } else { + initParams.Flags |= ovrInit_Invisible; + } + + if (!OVR_SUCCESS(ovr_Initialize(&initParams))) { + qCWarning(oculusLog) << "Failed to initialze Oculus SDK" << ovr::getError(); + 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(); + return; + } else { + ovrResult setFloorLevelOrigin = ovr_SetTrackingOriginType(session, ovrTrackingOrigin::ovrTrackingOrigin_FloorLevel); + if (!OVR_SUCCESS(setFloorLevelOrigin)) { + qCWarning(oculusLog) << "Failed to set the Oculus tracking origin to floor level" << ovr::getError(); + } + } + } + + void releaseSession() { + if (!session) { + return; + } + ovr_Destroy(session); + session = nullptr; + ovr_Shutdown(); + } + +public: + void withSession(const std::function& f) { + Lock lock(mutex); + if (!session) { + setupSession(false); + } + f(session); + } + + ovrSession acquireRenderSession() { + Lock lock(mutex); + if (renderCount++ == 0) { + releaseSession(); + setupSession(true); + } + return session; + } + + void releaseRenderSession(ovrSession session) { + Lock lock(mutex); + if (--renderCount == 0) { + releaseSession(); + } + } +} _ovr; + +ovrSession ovr::acquireRenderSession() { + return _ovr.acquireRenderSession(); +} + +void ovr::releaseRenderSession(ovrSession session) { + _ovr.releaseRenderSession(session); +} + +void ovr::withSession(const std::function& f) { + _ovr.withSession(f); +} + +ovrSessionStatus ovr::getStatus() { + ovrResult result; + return ovr::getStatus(result); +} + +ovrSessionStatus ovr::getStatus(ovrResult& result) { + ovrSessionStatus status{}; + withSession([&](ovrSession session) { + result = ovr_GetSessionStatus(session, &status); + if (!OVR_SUCCESS(result)) { + qCWarning(oculusLog) << "Failed to get session status" << ovr::getError(); + } + }); + return status; +} + +ovrTrackingState ovr::getTrackingState(double absTime, ovrBool latencyMarker) { + ovrTrackingState result{}; + withSession([&](ovrSession session) { result = ovr_GetTrackingState(session, absTime, latencyMarker); }); + return result; +} + +QString ovr::getError() { + static ovrErrorInfo error; + ovr_GetLastErrorInfo(&error); + return QString(error.ErrorString); +} + +controller::Pose hifi::ovr::toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose) { + // When the sensor-to-world rotation is identity the coordinate axes look like this: + // + // user + // forward + // -z + // | + // y| user + // y o----x right + // o-----x user + // | up + // | + // z + // + // Rift + + // From ABOVE the hand canonical axes looks like this: + // + // | | | | y | | | | + // | | | | | | | | | + // | | | | | + // |left | / x---- + \ |right| + // | _/ z \_ | + // | | | | + // | | | | + // + + // So when the user is in Rift space facing the -zAxis with hands outstretched and palms down + // the rotation to align the Touch axes with those of the hands is: + // + // touchToHand = halfTurnAboutY * quaterTurnAboutX + + // Due to how the Touch controllers fit into the palm there is an offset that is different for each hand. + // You can think of this offset as the inverse of the measured rotation when the hands are posed, such that + // the combination (measurement * offset) is identity at this orientation. + // + // Qoffset = glm::inverse(deltaRotation when hand is posed fingers forward, palm down) + // + // An approximate offset for the Touch can be obtained by inspection: + // + // Qoffset = glm::inverse(glm::angleAxis(sign * PI/2.0f, zAxis) * glm::angleAxis(PI/4.0f, xAxis)) + // + // So the full equation is: + // + // Q = combinedMeasurement * touchToHand + // + // Q = (deltaQ * QOffset) * (yFlip * quarterTurnAboutX) + // + // Q = (deltaQ * inverse(deltaQForAlignedHand)) * (yFlip * quarterTurnAboutX) + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat touchToHand = yFlip * quarterX; + + static const glm::quat leftQuarterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuarterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuarterZ) * touchToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand; + + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = + glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, -CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET * 1.5f); + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + auto translationOffset = (hand == ovrHand_Left ? leftTranslationOffset : rightTranslationOffset); + auto rotationOffset = (hand == ovrHand_Left ? leftRotationOffset : rightRotationOffset); + + glm::quat rotation = toGlm(handPose.ThePose.Orientation); + + controller::Pose pose; + pose.translation = toGlm(handPose.ThePose.Position); + pose.translation += rotation * translationOffset; + pose.rotation = rotation * rotationOffset; + pose.angularVelocity = rotation * toGlm(handPose.AngularVelocity); + pose.velocity = toGlm(handPose.LinearVelocity); + pose.valid = true; + return pose; +} + +controller::Pose hifi::ovr::toControllerPose(ovrHandType hand, + const ovrPoseStatef& handPose, + const ovrPoseStatef& lastHandPose) { + static const glm::quat yFlip = glm::angleAxis(PI, Vectors::UNIT_Y); + static const glm::quat quarterX = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_X); + static const glm::quat touchToHand = yFlip * quarterX; + + static const glm::quat leftQuarterZ = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_Z); + static const glm::quat rightQuarterZ = glm::angleAxis(PI_OVER_TWO, Vectors::UNIT_Z); + + static const glm::quat leftRotationOffset = glm::inverse(leftQuarterZ) * touchToHand; + static const glm::quat rightRotationOffset = glm::inverse(rightQuarterZ) * touchToHand; + + static const float CONTROLLER_LENGTH_OFFSET = 0.0762f; // three inches + static const glm::vec3 CONTROLLER_OFFSET = + glm::vec3(CONTROLLER_LENGTH_OFFSET / 2.0f, -CONTROLLER_LENGTH_OFFSET / 2.0f, CONTROLLER_LENGTH_OFFSET * 1.5f); + static const glm::vec3 leftTranslationOffset = glm::vec3(-1.0f, 1.0f, 1.0f) * CONTROLLER_OFFSET; + static const glm::vec3 rightTranslationOffset = CONTROLLER_OFFSET; + + auto translationOffset = (hand == ovrHand_Left ? leftTranslationOffset : rightTranslationOffset); + auto rotationOffset = (hand == ovrHand_Left ? leftRotationOffset : rightRotationOffset); + + glm::quat rotation = toGlm(handPose.ThePose.Orientation); + + controller::Pose pose; + pose.translation = toGlm(lastHandPose.ThePose.Position); + pose.translation += rotation * translationOffset; + pose.rotation = rotation * rotationOffset; + pose.angularVelocity = toGlm(lastHandPose.AngularVelocity); + pose.velocity = toGlm(lastHandPose.LinearVelocity); + pose.valid = true; + return pose; +} + +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(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); + + // pop the next message to check, if there is one + message = ovr_PopMessage(); + } + } +#endif + return true; +} diff --git a/plugins/oculusPlatform/src/OculusHelpers.h b/plugins/oculusPlatform/src/OculusHelpers.h new file mode 100644 index 0000000000..bdfc4434bb --- /dev/null +++ b/plugins/oculusPlatform/src/OculusHelpers.h @@ -0,0 +1,127 @@ +// +// Created by Bradley Austin Davis on 2015/05/26 +// Copyright 2015 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 +// +#pragma once + +#include + +#include +#include +#include +#include + +#include + +Q_DECLARE_LOGGING_CATEGORY(displayplugins) +Q_DECLARE_LOGGING_CATEGORY(oculusLog) + +namespace hifi { + +struct ovr { + static bool available(); + static ovrSession acquireRenderSession(); + static void releaseRenderSession(ovrSession session); + static void withSession(const std::function& f); + static ovrSessionStatus getStatus(); + 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()); } + static inline bool hmdMounted() { return hmdMounted(getStatus()); } + 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; } + + // Convenience method for looping over each eye with a lambda + static inline void for_each_eye(const std::function& f) { + for (ovrEyeType eye = ovrEye_Left; eye < ovrEye_Count; eye = static_cast(eye + 1)) { + f(eye); + } + } + + static inline void for_each_hand(const std::function& f) { + for (ovrHandType hand = ovrHand_Left; hand < ovrHand_Count; hand = static_cast(hand + 1)) { + f(hand); + } + } + + static inline glm::mat4 toGlm(const ovrMatrix4f& om) { + return glm::transpose(glm::make_mat4(&om.M[0][0])); + } + + static inline glm::mat4 toGlm(const ovrFovPort& fovport, float nearPlane = 0.01f, float farPlane = 10000.0f) { + return toGlm(ovrMatrix4f_Projection(fovport, nearPlane, farPlane, true)); + } + + static inline glm::vec3 toGlm(const ovrVector3f& ov) { + return glm::make_vec3(&ov.x); + } + + static inline glm::vec2 toGlm(const ovrVector2f& ov) { + return glm::make_vec2(&ov.x); + } + + static inline glm::uvec2 toGlm(const ovrSizei& ov) { + return glm::uvec2(ov.w, ov.h); + } + + static inline glm::quat toGlm(const ovrQuatf& oq) { + return glm::make_quat(&oq.x); + } + + static inline glm::mat4 toGlm(const ovrPosef& op) { + glm::mat4 orientation = glm::mat4_cast(toGlm(op.Orientation)); + glm::mat4 translation = glm::translate(glm::mat4(), toGlm(op.Position)); + return translation * orientation; + } + + static inline ovrMatrix4f fromGlm(const glm::mat4& m) { + ovrMatrix4f result; + glm::mat4 transposed(glm::transpose(m)); + memcpy(result.M, &(transposed[0][0]), sizeof(float) * 16); + return result; + } + + static inline ovrVector3f fromGlm(const glm::vec3& v) { + return { v.x, v.y, v.z }; + } + + static inline ovrVector2f fromGlm(const glm::vec2& v) { + return { v.x, v.y }; + } + + static inline ovrSizei fromGlm(const glm::uvec2& v) { + return { (int)v.x, (int)v.y }; + } + + static inline ovrQuatf fromGlm(const glm::quat& q) { + return { q.x, q.y, q.z, q.w }; + } + + static inline ovrPosef poseFromGlm(const glm::mat4& m) { + glm::vec3 translation = glm::vec3(m[3]) / m[3].w; + glm::quat orientation = glm::quat_cast(m); + ovrPosef result; + result.Orientation = fromGlm(orientation); + result.Position = fromGlm(translation); + return result; + } + + static controller::Pose toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose); + static controller::Pose toControllerPose(ovrHandType hand, const ovrPoseStatef& handPose, const ovrPoseStatef& lastHandPose); + +}; + +} // namespace hifi diff --git a/plugins/oculusPlatform/src/OculusPlatformProvider.cpp b/plugins/oculusPlatform/src/OculusPlatformProvider.cpp new file mode 100644 index 0000000000..097ddceb29 --- /dev/null +++ b/plugins/oculusPlatform/src/OculusPlatformProvider.cpp @@ -0,0 +1,40 @@ +// +// Created by Clément Brisset on 12/14/16 +// Copyright 2016 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 +// + +#include + +#include +#include +#include + +#include + +#include "OculusAPIPlugin.h" + +class OculusAPIProvider : public QObject, public OculusPlatformProvider { + Q_OBJECT + Q_PLUGIN_METADATA(IID OculusPlatformProvider_iid FILE "plugin.json") + Q_INTERFACES(OculusPlatformProvider) + +public: + OculusAPIProvider(QObject* parent = nullptr) : QObject(parent) {} + virtual ~OculusAPIProvider() {} + + virtual OculusPlatformPluginPointer getOculusPlatformPlugin() override { + static std::once_flag once; + std::call_once(once, [&] { + _oculusPlatformPlugin = std::make_shared(); + }); + return _oculusPlatformPlugin; + } + +private: + OculusPlatformPluginPointer _oculusPlatformPlugin; +}; + +#include "OculusPlatformProvider.moc" diff --git a/plugins/oculusPlatform/src/plugin.json b/plugins/oculusPlatform/src/plugin.json new file mode 100644 index 0000000000..8799a7245a --- /dev/null +++ b/plugins/oculusPlatform/src/plugin.json @@ -0,0 +1 @@ +{"name":"Oculus Platform"}