Bug 1299932 - Part 3: Handle OpenVR controller position and orientation; r?kip draft
authorDaosheng Mu <daoshengmu@gmail.com>
Mon, 24 Oct 2016 18:09:11 +0800
changeset 437654 97011fe269b7215afb5e27b4cdfad7181eeaed7e
parent 437653 3b8350df92afc7976d1f8823ab93864722bd4c26
child 536693 ed43b8ca2a28028d667f39983bc51f7b3098ada3
push id35476
push userbmo:dmu@mozilla.com
push dateFri, 11 Nov 2016 09:27:20 +0000
reviewerskip
bugs1299932
milestone52.0a1
Bug 1299932 - Part 3: Handle OpenVR controller position and orientation; r?kip MozReview-Commit-ID: FyneJ5JfeNE
gfx/vr/VRDisplayHost.cpp
gfx/vr/VRDisplayHost.h
gfx/vr/VRManager.cpp
gfx/vr/gfxVR.cpp
gfx/vr/gfxVR.h
gfx/vr/gfxVROpenVR.cpp
gfx/vr/gfxVROpenVR.h
--- a/gfx/vr/VRDisplayHost.cpp
+++ b/gfx/vr/VRDisplayHost.cpp
@@ -181,8 +181,21 @@ VRControllerHost::SetButtonPressed(uint6
   mButtonPressed = aBit;
 }
 
 uint64_t
 VRControllerHost::GetButtonPressed()
 {
   return mButtonPressed;
 }
+
+void
+VRControllerHost::SetPose(const dom::GamepadPoseState& aPose)
+{
+  mPose = aPose;
+}
+
+const dom::GamepadPoseState&
+VRControllerHost::GetPose()
+{
+  return mPose;
+}
+
--- a/gfx/vr/VRDisplayHost.h
+++ b/gfx/vr/VRDisplayHost.h
@@ -11,16 +11,17 @@
 #include "nsString.h"
 #include "nsCOMPtr.h"
 #include "mozilla/RefPtr.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/Atomics.h"
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TypedEnumBits.h"
+#include "mozilla/dom/GamepadPoseState.h"
 
 namespace mozilla {
 namespace layers {
 class PTextureParent;
 #if defined(XP_WIN)
 class TextureSourceD3D11;
 #endif
 } // namespace layers
@@ -87,24 +88,27 @@ class VRControllerHost {
 public:
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(VRControllerHost)
 
   const VRControllerInfo& GetControllerInfo() const;
   void SetIndex(uint32_t aIndex);
   uint32_t GetIndex();
   void SetButtonPressed(uint64_t aBit);
   uint64_t GetButtonPressed();
+  void SetPose(const dom::GamepadPoseState& aPose);
+  const dom::GamepadPoseState& GetPose();
 
 protected:
   explicit VRControllerHost(VRDeviceType aType);
   virtual ~VRControllerHost();
 
   VRControllerInfo mControllerInfo;
   // The controller index in VRControllerManager.
   uint32_t mIndex;
   // The current button pressed bit of button mask.
   uint64_t mButtonPressed;
+  dom::GamepadPoseState mPose;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* GFX_VR_DISPLAY_HOST_H */
--- a/gfx/vr/VRManager.cpp
+++ b/gfx/vr/VRManager.cpp
@@ -89,16 +89,20 @@ VRManager::VRManager()
   }
 
   // OSVR is cross platform compatible
   mgr = VRDisplayManagerOSVR::Create();
   if (mgr) {
       mManagers.AppendElement(mgr);
   }
 #endif
+  // Enable gamepad extensions while VR is enabled.
+  if (gfxPrefs::VREnabled()) {
+    Preferences::SetBool("dom.gamepad.extensions.enabled", true);
+  }
 }
 
 VRManager::~VRManager()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mInitialized);
   MOZ_COUNT_DTOR(VRManager);
 }
--- a/gfx/vr/gfxVR.cpp
+++ b/gfx/vr/gfxVR.cpp
@@ -108,8 +108,20 @@ VRControllerManager::NewAxisMove(uint32_
 {
   dom::GamepadAxisInformation a(aIndex, dom::GamepadServiceType::VR,
                                 aAxis, aValue);
 
   VRManager* vm = VRManager::Get();
   MOZ_ASSERT(vm);
   vm->NotifyGamepadChange<dom::GamepadAxisInformation>(a);
 }
+
+void
+VRControllerManager::NewPoseState(uint32_t aIndex,
+                                  const dom::GamepadPoseState& aPose)
+{
+  dom::GamepadPoseInformation a(aIndex, dom::GamepadServiceType::VR,
+                                aPose);
+
+  VRManager* vm = VRManager::Get();
+  MOZ_ASSERT(vm);
+  vm->NotifyGamepadChange<dom::GamepadPoseInformation>(a);
+}
--- a/gfx/vr/gfxVR.h
+++ b/gfx/vr/gfxVR.h
@@ -15,16 +15,20 @@
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/TypedEnumBits.h"
 
 namespace mozilla {
 namespace layers {
 class PTextureParent;
 }
+namespace dom {
+enum class GamepadMappingType : uint32_t;
+struct GamepadPoseState;
+}
 namespace gfx {
 class VRLayerParent;
 class VRDisplayHost;
 class VRControllerHost;
 
 enum class VRDeviceType : uint16_t {
   Oculus,
   OpenVR,
@@ -247,16 +251,17 @@ public:
   static uint32_t AllocateControllerID();
   virtual bool Init() = 0;
   virtual void Destroy() = 0;
   virtual void HandleInput() = 0;
   virtual void GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult) = 0;
   virtual void ScanForDevices() = 0;
   void NewButtonEvent(uint32_t aIndex, uint32_t aButton, bool aPressed);
   void NewAxisMove(uint32_t aIndex, uint32_t aAxis, double aValue);
+  void NewPoseState(uint32_t aIndex, const dom::GamepadPoseState& aPose);
   void AddGamepad(const char* aID, uint32_t aMapping,
                   uint32_t aNumButtons, uint32_t aNumAxes);
   void RemoveGamepad(uint32_t aIndex);
 
 protected:
   VRControllerManager() : mInstalled(false), mControllerCount(0) {}
   virtual ~VRControllerManager() {}
 
@@ -264,14 +269,17 @@ protected:
   uint32_t mControllerCount;
   static Atomic<uint32_t> sControllerBase;
 
 private:
   virtual void HandleButtonPress(uint32_t aControllerIdx,
                                  uint64_t aButtonPressed) = 0;
   virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
                               float aValue) = 0;
+  virtual void HandlePoseTracking(uint32_t aControllerIdx,
+                                  const dom::GamepadPoseState& aPose,
+                                  VRControllerHost* aController) = 0;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* GFX_VR_H */
--- a/gfx/vr/gfxVROpenVR.cpp
+++ b/gfx/vr/gfxVROpenVR.cpp
@@ -485,17 +485,17 @@ VRDisplayManagerOpenVR::GetHMDs(nsTArray
 }
 
 VRControllerOpenVR::VRControllerOpenVR()
   : VRControllerHost(VRDeviceType::OpenVR)
 {
   MOZ_COUNT_CTOR_INHERITED(VRControllerOpenVR, VRControllerHost);
   mControllerInfo.mControllerName.AssignLiteral("OpenVR HMD");
 #ifdef MOZ_GAMEPAD
-  mControllerInfo.mMappingType = static_cast<uint32_t>(dom::GamepadMappingType::_empty);
+  mControllerInfo.mMappingType = static_cast<uint32_t>(GamepadMappingType::_empty);
 #else
   mControllerInfo.mMappingType = 0;
 #endif
   mControllerInfo.mNumButtons = gNumOpenVRButtonMask;
   mControllerInfo.mNumAxes = gNumOpenVRAxis;
 }
 
 VRControllerOpenVR::~VRControllerOpenVR()
@@ -578,16 +578,19 @@ VRControllerManagerOpenVR::HandleInput()
   uint32_t axis = 0;
 
   if (!mOpenVRInstalled) {
     return;
   }
 
   MOZ_ASSERT(mVRSystem);
 
+  vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount];
+  mVRSystem->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, 0.0f,
+                                             poses, vr::k_unMaxTrackedDeviceCount);
   // Process OpenVR controller state
   for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
     controller = mOpenVRController[i];
 
     MOZ_ASSERT(mVRSystem->GetTrackedDeviceClass(controller->GetTrackedIndex())
                == vr::TrackedDeviceClass_Controller);
 
     if (mVRSystem->GetControllerState(controller->GetTrackedIndex(), &state)) {
@@ -600,16 +603,54 @@ VRControllerManagerOpenVR::HandleInput()
       axis = static_cast<uint32_t>(VRControllerAxisType::TrackpadYAxis);
       HandleAxisMove(controller->GetIndex(), axis,
                      state.rAxis[gOpenVRAxes[axis]].y);
 
       axis = static_cast<uint32_t>(VRControllerAxisType::Trigger);
       HandleAxisMove(controller->GetIndex(), axis,
                      state.rAxis[gOpenVRAxes[axis]].x);
     }
+
+    // Start to process pose
+    const ::vr::TrackedDevicePose_t& pose = poses[controller->GetTrackedIndex()];
+
+    if (pose.bDeviceIsConnected && pose.bPoseIsValid &&
+      pose.eTrackingResult == vr::TrackingResult_Running_OK) {
+      gfx::Matrix4x4 m;
+
+      // NOTE! mDeviceToAbsoluteTracking is a 3x4 matrix, not 4x4.  But
+      // because of its arrangement, we can copy the 12 elements in and
+      // then transpose them to the right place.  We do this so we can
+      // pull out a Quaternion.
+      memcpy(&m.components, &pose.mDeviceToAbsoluteTracking, sizeof(float) * 12);
+      m.Transpose();
+
+      gfx::Quaternion rot;
+      rot.SetFromRotationMatrix(m);
+      rot.Invert();
+
+      GamepadPoseState poseState;
+      poseState.flags |= GamepadCapabilityFlags::Cap_Orientation;
+      poseState.orientation[0] = rot.x;
+      poseState.orientation[1] = rot.y;
+      poseState.orientation[2] = rot.z;
+      poseState.orientation[3] = rot.w;
+      poseState.angularVelocity[0] = pose.vAngularVelocity.v[0];
+      poseState.angularVelocity[1] = pose.vAngularVelocity.v[1];
+      poseState.angularVelocity[2] = pose.vAngularVelocity.v[2];
+
+      poseState.flags |= GamepadCapabilityFlags::Cap_Position;
+      poseState.position[0] = m._41;
+      poseState.position[1] = m._42;
+      poseState.position[2] = m._43;
+      poseState.linearVelocity[0] = pose.vVelocity.v[0];
+      poseState.linearVelocity[1] = pose.vVelocity.v[1];
+      poseState.linearVelocity[2] = pose.vVelocity.v[2];
+      HandlePoseTracking(controller->GetIndex(), poseState, controller);
+    }
   }
 }
 
 void
 VRControllerManagerOpenVR::HandleButtonPress(uint32_t aControllerIdx,
                                              uint64_t aButtonPressed)
 {
   uint64_t buttonMask = 0;
@@ -640,16 +681,27 @@ VRControllerManagerOpenVR::HandleAxisMov
                                           float aValue)
 {
   if (aValue != 0.0f) {
     NewAxisMove(aControllerIdx, aAxis, aValue);
   }
 }
 
 void
+VRControllerManagerOpenVR::HandlePoseTracking(uint32_t aControllerIdx,
+                                              const GamepadPoseState& aPose,
+                                              VRControllerHost* aController)
+{
+  if (aPose != aController->GetPose()) {
+    aController->SetPose(aPose);
+    NewPoseState(aControllerIdx, aPose);
+  }
+}
+
+void
 VRControllerManagerOpenVR::GetControllers(nsTArray<RefPtr<VRControllerHost>>& aControllerResult)
 {
   if (!mOpenVRInstalled) {
     return;
   }
 
   aControllerResult.Clear();
   for (uint32_t i = 0; i < mOpenVRController.Length(); ++i) {
--- a/gfx/vr/gfxVROpenVR.h
+++ b/gfx/vr/gfxVROpenVR.h
@@ -119,16 +119,19 @@ public:
 private:
   VRControllerManagerOpenVR();
   ~VRControllerManagerOpenVR();
 
   virtual void HandleButtonPress(uint32_t aControllerIdx,
                                  uint64_t aButtonPressed) override;
   virtual void HandleAxisMove(uint32_t aControllerIdx, uint32_t aAxis,
                               float aValue) override;
+  virtual void HandlePoseTracking(uint32_t aControllerIdx,
+                                  const dom::GamepadPoseState& aPose,
+                                  VRControllerHost* aController) override;
 
   bool mOpenVRInstalled;
   nsTArray<RefPtr<impl::VRControllerOpenVR>> mOpenVRController;
   vr::IVRSystem *mVRSystem;
 };
 
 } // namespace gfx
 } // namespace mozilla