tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XRFrame.cpp (7237B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
      5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/XRFrame.h"
      8 
      9 #include "VRDisplayClient.h"
     10 #include "mozilla/dom/XRReferenceSpace.h"
     11 #include "mozilla/dom/XRRenderState.h"
     12 #include "mozilla/dom/XRRigidTransform.h"
     13 #include "mozilla/dom/XRView.h"
     14 #include "mozilla/dom/XRViewerPose.h"
     15 
     16 namespace mozilla::dom {
     17 
     18 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(XRFrame, mParent, mSession)
     19 
     20 XRFrame::XRFrame(nsISupports* aParent, XRSession* aXRSession)
     21    : mParent(aParent),
     22      mSession(aXRSession),
     23      mActive(false),
     24      mAnimationFrame(false) {}
     25 
     26 JSObject* XRFrame::WrapObject(JSContext* aCx,
     27                              JS::Handle<JSObject*> aGivenProto) {
     28  return XRFrame_Binding::Wrap(aCx, this, aGivenProto);
     29 }
     30 
     31 XRSession* XRFrame::Session() { return mSession; }
     32 
     33 already_AddRefed<XRViewerPose> XRFrame::GetViewerPose(
     34    const XRReferenceSpace& aReferenceSpace, ErrorResult& aRv) {
     35  if (!mActive || !mAnimationFrame) {
     36    aRv.ThrowInvalidStateError(
     37        "GetViewerPose can only be called on an XRFrame during an "
     38        "XRSession.requestAnimationFrame callback.");
     39    return nullptr;
     40  }
     41 
     42  if (aReferenceSpace.GetSession() != mSession) {
     43    aRv.ThrowInvalidStateError(
     44        "The XRReferenceSpace passed to GetViewerPose must belong to the "
     45        "XRSession that GetViewerPose is called on.");
     46    return nullptr;
     47  }
     48 
     49  if (!mSession->CanReportPoses()) {
     50    aRv.ThrowSecurityError(
     51        "The visibilityState of the XRSpace's XRSession "
     52        "that is passed to GetViewerPose must be 'visible'.");
     53    return nullptr;
     54  }
     55 
     56  // TODO (Bug 1616393) - Check if poses must be limited:
     57  // https://immersive-web.github.io/webxr/#poses-must-be-limited
     58 
     59  bool emulatedPosition = aReferenceSpace.IsPositionEmulated();
     60 
     61  XRRenderState* renderState = mSession->GetActiveRenderState();
     62  float depthNear = (float)renderState->DepthNear();
     63  float depthFar = (float)renderState->DepthFar();
     64 
     65  RefPtr<XRViewerPose> viewerPose;
     66 
     67  gfx::VRDisplayClient* display = mSession->GetDisplayClient();
     68  if (display) {
     69    // Have a VRDisplayClient
     70    const gfx::VRDisplayInfo& displayInfo =
     71        mSession->GetDisplayClient()->GetDisplayInfo();
     72    const gfx::VRHMDSensorState& sensorState = display->GetSensorState();
     73 
     74    gfx::PointDouble3D viewerPosition = gfx::PointDouble3D(
     75        sensorState.pose.position[0], sensorState.pose.position[1],
     76        sensorState.pose.position[2]);
     77    gfx::QuaternionDouble viewerOrientation = gfx::QuaternionDouble(
     78        sensorState.pose.orientation[0], sensorState.pose.orientation[1],
     79        sensorState.pose.orientation[2], sensorState.pose.orientation[3]);
     80 
     81    gfx::Matrix4x4Double headTransform;
     82    headTransform.SetRotationFromQuaternion(viewerOrientation);
     83    headTransform.PostTranslate(viewerPosition);
     84 
     85    gfx::Matrix4x4Double originTransform;
     86    originTransform.SetRotationFromQuaternion(
     87        aReferenceSpace.GetEffectiveOriginOrientation().Inverse());
     88    originTransform.PreTranslate(-aReferenceSpace.GetEffectiveOriginPosition());
     89 
     90    headTransform *= originTransform;
     91 
     92    viewerPose = mSession->PooledViewerPose(headTransform, emulatedPosition);
     93 
     94    auto updateEye = [&](int32_t viewIndex, gfx::VRDisplayState::Eye eye) {
     95      auto offset = displayInfo.GetEyeTranslation(eye);
     96      auto eyeFromHead = gfx::Matrix4x4Double::Translation(
     97          gfx::PointDouble3D(offset.x, offset.y, offset.z));
     98      auto eyeTransform = eyeFromHead * headTransform;
     99      gfx::PointDouble3D eyePosition;
    100      gfx::QuaternionDouble eyeRotation;
    101      gfx::PointDouble3D eyeScale;
    102      eyeTransform.Decompose(eyePosition, eyeRotation, eyeScale);
    103 
    104      const gfx::VRFieldOfView fov = displayInfo.mDisplayState.eyeFOV[eye];
    105      gfx::Matrix4x4 projection =
    106          fov.ConstructProjectionMatrix(depthNear, depthFar, true);
    107      viewerPose->GetEye(viewIndex)->Update(eyePosition, eyeRotation,
    108                                            projection);
    109    };
    110 
    111    updateEye(0, gfx::VRDisplayState::Eye_Left);
    112    updateEye(1, gfx::VRDisplayState::Eye_Right);
    113  } else {
    114    auto inlineVerticalFov = renderState->GetInlineVerticalFieldOfView();
    115    const double fov =
    116        inlineVerticalFov.IsNull() ? M_PI * 0.5f : inlineVerticalFov.Value();
    117    HTMLCanvasElement* canvas = renderState->GetOutputCanvas();
    118    float aspect = 1.0f;
    119    if (canvas) {
    120      aspect = (float)canvas->Width() / (float)canvas->Height();
    121    }
    122    gfx::Matrix4x4 projection =
    123        ConstructInlineProjection((float)fov, aspect, depthNear, depthFar);
    124 
    125    viewerPose =
    126        mSession->PooledViewerPose(gfx::Matrix4x4Double(), emulatedPosition);
    127    viewerPose->GetEye(0)->Update(gfx::PointDouble3D(), gfx::QuaternionDouble(),
    128                                  projection);
    129  }
    130 
    131  return viewerPose.forget();
    132 }
    133 
    134 already_AddRefed<XRPose> XRFrame::GetPose(const XRSpace& aSpace,
    135                                          const XRSpace& aBaseSpace,
    136                                          ErrorResult& aRv) {
    137  if (!mActive) {
    138    aRv.ThrowInvalidStateError(
    139        "GetPose can not be called on an XRFrame that is not active.");
    140    return nullptr;
    141  }
    142 
    143  if (aSpace.GetSession() != mSession || aBaseSpace.GetSession() != mSession) {
    144    aRv.ThrowInvalidStateError(
    145        "The XRSpace passed to GetPose must belong to the "
    146        "XRSession that GetPose is called on.");
    147    return nullptr;
    148  }
    149 
    150  if (!mSession->CanReportPoses()) {
    151    aRv.ThrowSecurityError(
    152        "The visibilityState of the XRSpace's XRSession "
    153        "that is passed to GetPose must be 'visible'.");
    154    return nullptr;
    155  }
    156 
    157  // TODO (Bug 1616393) - Check if poses must be limited:
    158  // https://immersive-web.github.io/webxr/#poses-must-be-limited
    159 
    160  const bool emulatedPosition = aSpace.IsPositionEmulated();
    161  gfx::Matrix4x4Double base;
    162  base.SetRotationFromQuaternion(
    163      aBaseSpace.GetEffectiveOriginOrientation().Inverse());
    164  base.PreTranslate(-aBaseSpace.GetEffectiveOriginPosition());
    165 
    166  gfx::Matrix4x4Double matrix = aSpace.GetEffectiveOriginTransform() * base;
    167 
    168  RefPtr<XRRigidTransform> transform = new XRRigidTransform(mParent, matrix);
    169  RefPtr<XRPose> pose = new XRPose(mParent, transform, emulatedPosition);
    170 
    171  return pose.forget();
    172 }
    173 
    174 void XRFrame::StartAnimationFrame() {
    175  mActive = true;
    176  mAnimationFrame = true;
    177 }
    178 
    179 void XRFrame::EndAnimationFrame() { mActive = false; }
    180 
    181 void XRFrame::StartInputSourceEvent() { mActive = true; }
    182 
    183 void XRFrame::EndInputSourceEvent() { mActive = false; }
    184 
    185 gfx::Matrix4x4 XRFrame::ConstructInlineProjection(float aFov, float aAspect,
    186                                                  float aNear, float aFar) {
    187  gfx::Matrix4x4 m;
    188  const float depth = aFar - aNear;
    189  const float invDepth = 1 / depth;
    190  if (aFov == 0) {
    191    aFov = 0.5f * M_PI;
    192  }
    193 
    194  m._22 = 1.0f / tan(0.5f * aFov);
    195  m._11 = -m._22 / aAspect;
    196  m._33 = depth * invDepth;
    197  m._43 = (-aFar * aNear) * invDepth;
    198  m._34 = 1.0f;
    199 
    200  return m;
    201 }
    202 
    203 }  // namespace mozilla::dom