Backed out changeset 2450366cf7ca (bug 1891629) for causing win msix mochitest failures
[gecko.git] / dom / vr / XRFrame.cpp
blob639bb2b01950e28006db7815fe3c6d3bfe56ff6b
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/. */
7 #include "mozilla/dom/XRFrame.h"
8 #include "mozilla/dom/XRRenderState.h"
9 #include "mozilla/dom/XRRigidTransform.h"
10 #include "mozilla/dom/XRViewerPose.h"
11 #include "mozilla/dom/XRView.h"
12 #include "mozilla/dom/XRReferenceSpace.h"
13 #include "VRDisplayClient.h"
15 namespace mozilla::dom {
17 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(XRFrame, mParent, mSession)
19 XRFrame::XRFrame(nsISupports* aParent, XRSession* aXRSession)
20 : mParent(aParent),
21 mSession(aXRSession),
22 mActive(false),
23 mAnimationFrame(false) {}
25 JSObject* XRFrame::WrapObject(JSContext* aCx,
26 JS::Handle<JSObject*> aGivenProto) {
27 return XRFrame_Binding::Wrap(aCx, this, aGivenProto);
30 XRSession* XRFrame::Session() { return mSession; }
32 already_AddRefed<XRViewerPose> XRFrame::GetViewerPose(
33 const XRReferenceSpace& aReferenceSpace, ErrorResult& aRv) {
34 if (!mActive || !mAnimationFrame) {
35 aRv.ThrowInvalidStateError(
36 "GetViewerPose can only be called on an XRFrame during an "
37 "XRSession.requestAnimationFrame callback.");
38 return nullptr;
41 if (aReferenceSpace.GetSession() != mSession) {
42 aRv.ThrowInvalidStateError(
43 "The XRReferenceSpace passed to GetViewerPose must belong to the "
44 "XRSession that GetViewerPose is called on.");
45 return nullptr;
48 if (!mSession->CanReportPoses()) {
49 aRv.ThrowSecurityError(
50 "The visibilityState of the XRSpace's XRSession "
51 "that is passed to GetViewerPose must be 'visible'.");
52 return nullptr;
55 // TODO (Bug 1616393) - Check if poses must be limited:
56 // https://immersive-web.github.io/webxr/#poses-must-be-limited
58 bool emulatedPosition = aReferenceSpace.IsPositionEmulated();
60 XRRenderState* renderState = mSession->GetActiveRenderState();
61 float depthNear = (float)renderState->DepthNear();
62 float depthFar = (float)renderState->DepthFar();
64 RefPtr<XRViewerPose> viewerPose;
66 gfx::VRDisplayClient* display = mSession->GetDisplayClient();
67 if (display) {
68 // Have a VRDisplayClient
69 const gfx::VRDisplayInfo& displayInfo =
70 mSession->GetDisplayClient()->GetDisplayInfo();
71 const gfx::VRHMDSensorState& sensorState = display->GetSensorState();
73 gfx::PointDouble3D viewerPosition = gfx::PointDouble3D(
74 sensorState.pose.position[0], sensorState.pose.position[1],
75 sensorState.pose.position[2]);
76 gfx::QuaternionDouble viewerOrientation = gfx::QuaternionDouble(
77 sensorState.pose.orientation[0], sensorState.pose.orientation[1],
78 sensorState.pose.orientation[2], sensorState.pose.orientation[3]);
80 gfx::Matrix4x4Double headTransform;
81 headTransform.SetRotationFromQuaternion(viewerOrientation);
82 headTransform.PostTranslate(viewerPosition);
84 gfx::Matrix4x4Double originTransform;
85 originTransform.SetRotationFromQuaternion(
86 aReferenceSpace.GetEffectiveOriginOrientation().Inverse());
87 originTransform.PreTranslate(-aReferenceSpace.GetEffectiveOriginPosition());
89 headTransform *= originTransform;
91 viewerPose = mSession->PooledViewerPose(headTransform, emulatedPosition);
93 auto updateEye = [&](int32_t viewIndex, gfx::VRDisplayState::Eye eye) {
94 auto offset = displayInfo.GetEyeTranslation(eye);
95 auto eyeFromHead = gfx::Matrix4x4Double::Translation(
96 gfx::PointDouble3D(offset.x, offset.y, offset.z));
97 auto eyeTransform = eyeFromHead * headTransform;
98 gfx::PointDouble3D eyePosition;
99 gfx::QuaternionDouble eyeRotation;
100 gfx::PointDouble3D eyeScale;
101 eyeTransform.Decompose(eyePosition, eyeRotation, eyeScale);
103 const gfx::VRFieldOfView fov = displayInfo.mDisplayState.eyeFOV[eye];
104 gfx::Matrix4x4 projection =
105 fov.ConstructProjectionMatrix(depthNear, depthFar, true);
106 viewerPose->GetEye(viewIndex)->Update(eyePosition, eyeRotation,
107 projection);
110 updateEye(0, gfx::VRDisplayState::Eye_Left);
111 updateEye(1, gfx::VRDisplayState::Eye_Right);
112 } else {
113 auto inlineVerticalFov = renderState->GetInlineVerticalFieldOfView();
114 const double fov =
115 inlineVerticalFov.IsNull() ? M_PI * 0.5f : inlineVerticalFov.Value();
116 HTMLCanvasElement* canvas = renderState->GetOutputCanvas();
117 float aspect = 1.0f;
118 if (canvas) {
119 aspect = (float)canvas->Width() / (float)canvas->Height();
121 gfx::Matrix4x4 projection =
122 ConstructInlineProjection((float)fov, aspect, depthNear, depthFar);
124 viewerPose =
125 mSession->PooledViewerPose(gfx::Matrix4x4Double(), emulatedPosition);
126 viewerPose->GetEye(0)->Update(gfx::PointDouble3D(), gfx::QuaternionDouble(),
127 projection);
130 return viewerPose.forget();
133 already_AddRefed<XRPose> XRFrame::GetPose(const XRSpace& aSpace,
134 const XRSpace& aBaseSpace,
135 ErrorResult& aRv) {
136 if (!mActive) {
137 aRv.ThrowInvalidStateError(
138 "GetPose can not be called on an XRFrame that is not active.");
139 return nullptr;
142 if (aSpace.GetSession() != mSession || aBaseSpace.GetSession() != mSession) {
143 aRv.ThrowInvalidStateError(
144 "The XRSpace passed to GetPose must belong to the "
145 "XRSession that GetPose is called on.");
146 return nullptr;
149 if (!mSession->CanReportPoses()) {
150 aRv.ThrowSecurityError(
151 "The visibilityState of the XRSpace's XRSession "
152 "that is passed to GetPose must be 'visible'.");
153 return nullptr;
156 // TODO (Bug 1616393) - Check if poses must be limited:
157 // https://immersive-web.github.io/webxr/#poses-must-be-limited
159 const bool emulatedPosition = aSpace.IsPositionEmulated();
160 gfx::Matrix4x4Double base;
161 base.SetRotationFromQuaternion(
162 aBaseSpace.GetEffectiveOriginOrientation().Inverse());
163 base.PreTranslate(-aBaseSpace.GetEffectiveOriginPosition());
165 gfx::Matrix4x4Double matrix = aSpace.GetEffectiveOriginTransform() * base;
167 RefPtr<XRRigidTransform> transform = new XRRigidTransform(mParent, matrix);
168 RefPtr<XRPose> pose = new XRPose(mParent, transform, emulatedPosition);
170 return pose.forget();
173 void XRFrame::StartAnimationFrame() {
174 mActive = true;
175 mAnimationFrame = true;
178 void XRFrame::EndAnimationFrame() { mActive = false; }
180 void XRFrame::StartInputSourceEvent() { mActive = true; }
182 void XRFrame::EndInputSourceEvent() { mActive = false; }
184 gfx::Matrix4x4 XRFrame::ConstructInlineProjection(float aFov, float aAspect,
185 float aNear, float aFar) {
186 gfx::Matrix4x4 m;
187 const float depth = aFar - aNear;
188 const float invDepth = 1 / depth;
189 if (aFov == 0) {
190 aFov = 0.5f * M_PI;
193 m._22 = 1.0f / tan(0.5f * aFov);
194 m._11 = -m._22 / aAspect;
195 m._33 = depth * invDepth;
196 m._43 = (-aFar * aNear) * invDepth;
197 m._34 = 1.0f;
199 return m;
202 } // namespace mozilla::dom