forked from mozilla/gecko-dev
-
Notifications
You must be signed in to change notification settings - Fork 1
/
gfxVR.cpp
214 lines (174 loc) · 7.09 KB
/
gfxVR.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <math.h>
#include "gfxVR.h"
#include "mozilla/dom/GamepadEventTypes.h"
#include "mozilla/dom/GamepadBinding.h"
#include "VRDisplayHost.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using namespace mozilla;
using namespace mozilla::gfx;
Atomic<uint32_t> VRSystemManager::sDisplayBase(0);
Atomic<uint32_t> VRSystemManager::sControllerBase(0);
/* static */ uint32_t VRSystemManager::AllocateDisplayID() {
return ++sDisplayBase;
}
/* static */ uint32_t VRSystemManager::AllocateControllerID() {
return ++sControllerBase;
}
/**
* VRSystemManager::NotifyVsync must be called even when a WebVR site is
* not active, in order to poll for respond to VR Platform API requests.
* This should be called very often, ideally once per frame.
* VRSystemManager::Refresh will not activate VR hardware or
* initialize VR runtimes that have not already been activated.
*/
void VRSystemManager::NotifyVSync() {
// VRDisplayHost::NotifyVSync may modify mVRDisplays, so we iterate
// through a local copy here.
nsTArray<RefPtr<VRDisplayHost>> displays;
GetHMDs(displays);
for (const auto& display : displays) {
display->NotifyVSync();
}
// Ensure that the controller state is updated at least
// on every 2d display VSync when not in a VR presentation.
if (!GetIsPresenting()) {
HandleInput();
}
}
void VRSystemManager::Run1msTasks(double aDeltaTime) {
// To be overridden by children
}
void VRSystemManager::Run10msTasks() {
// To be overridden by children
}
void VRSystemManager::Run100msTasks() {
// To be overridden by children
}
/**
* VRSystemManager::GetHMDs must not be called unless
* VRSystemManager::ShouldInhibitEnumeration is called
* on all VRSystemManager instances and they all return
* false.
*
* This is used to ensure that VR devices that can be
* enumerated by multiple API's are only enumerated by
* one API.
*
* GetHMDs is called for the most specific API
* (ie. Oculus SDK) first before calling GetHMDs on
* more generic api's (ie. OpenVR) to ensure that a device
* is accessed using the API most optimized for it.
*
* ShouldInhibitEnumeration may also be used to prevent
* devices from jumping to other API's when they are
* intentionally ignored, such as when responding to
* requests by the VR platform to unload the libraries
* for runtime software updates.
*/
bool VRSystemManager::ShouldInhibitEnumeration() { return false; }
Matrix4x4 VRFieldOfView::ConstructProjectionMatrix(float zNear, float zFar,
bool rightHanded) const {
float upTan = tan(upDegrees * M_PI / 180.0);
float downTan = tan(downDegrees * M_PI / 180.0);
float leftTan = tan(leftDegrees * M_PI / 180.0);
float rightTan = tan(rightDegrees * M_PI / 180.0);
float handednessScale = rightHanded ? -1.0 : 1.0;
float pxscale = 2.0f / (leftTan + rightTan);
float pxoffset = (leftTan - rightTan) * pxscale * 0.5;
float pyscale = 2.0f / (upTan + downTan);
float pyoffset = (upTan - downTan) * pyscale * 0.5;
Matrix4x4 mobj;
float* m = &mobj._11;
m[0 * 4 + 0] = pxscale;
m[2 * 4 + 0] = pxoffset * handednessScale;
m[1 * 4 + 1] = pyscale;
m[2 * 4 + 1] = -pyoffset * handednessScale;
m[2 * 4 + 2] = zFar / (zNear - zFar) * -handednessScale;
m[3 * 4 + 2] = (zFar * zNear) / (zNear - zFar);
m[2 * 4 + 3] = handednessScale;
m[3 * 4 + 3] = 0.0f;
return mobj;
}
void VRSystemManager::AddGamepad(const VRControllerInfo& controllerInfo) {
dom::GamepadAdded a(
NS_ConvertUTF8toUTF16(controllerInfo.GetControllerName()),
controllerInfo.GetMappingType(), controllerInfo.GetHand(),
controllerInfo.GetDisplayID(), controllerInfo.GetNumButtons(),
controllerInfo.GetNumAxes(), controllerInfo.GetNumHaptics());
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadAdded>(mControllerCount, a);
}
void VRSystemManager::RemoveGamepad(uint32_t aIndex) {
dom::GamepadRemoved a;
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadRemoved>(aIndex, a);
}
void VRSystemManager::NewButtonEvent(uint32_t aIndex, uint32_t aButton,
bool aPressed, bool aTouched,
double aValue) {
dom::GamepadButtonInformation a(aButton, aValue, aPressed, aTouched);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadButtonInformation>(aIndex, a);
}
void VRSystemManager::NewAxisMove(uint32_t aIndex, uint32_t aAxis,
double aValue) {
dom::GamepadAxisInformation a(aAxis, aValue);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadAxisInformation>(aIndex, a);
}
void VRSystemManager::NewPoseState(uint32_t aIndex,
const dom::GamepadPoseState& aPose) {
dom::GamepadPoseInformation a(aPose);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadPoseInformation>(aIndex, a);
}
void VRSystemManager::NewHandChangeEvent(uint32_t aIndex,
const dom::GamepadHand aHand) {
dom::GamepadHandInformation a(aHand);
VRManager* vm = VRManager::Get();
vm->NotifyGamepadChange<dom::GamepadHandInformation>(aIndex, a);
}
void VRHMDSensorState::CalcViewMatrices(
const gfx::Matrix4x4* aHeadToEyeTransforms) {
gfx::Matrix4x4 matHead;
if (flags & VRDisplayCapabilityFlags::Cap_Orientation) {
matHead.SetRotationFromQuaternion(
gfx::Quaternion(pose.orientation[0], pose.orientation[1],
pose.orientation[2], pose.orientation[3]));
}
matHead.PreTranslate(-pose.position[0], -pose.position[1], -pose.position[2]);
gfx::Matrix4x4 matView =
matHead * aHeadToEyeTransforms[VRDisplayState::Eye_Left];
matView.Normalize();
memcpy(leftViewMatrix, matView.components, sizeof(matView.components));
matView = matHead * aHeadToEyeTransforms[VRDisplayState::Eye_Right];
matView.Normalize();
memcpy(rightViewMatrix, matView.components, sizeof(matView.components));
}
const IntSize VRDisplayInfo::SuggestedEyeResolution() const {
return IntSize(mDisplayState.mEyeResolution.width,
mDisplayState.mEyeResolution.height);
}
const Point3D VRDisplayInfo::GetEyeTranslation(uint32_t whichEye) const {
return Point3D(mDisplayState.mEyeTranslation[whichEye].x,
mDisplayState.mEyeTranslation[whichEye].y,
mDisplayState.mEyeTranslation[whichEye].z);
}
const Size VRDisplayInfo::GetStageSize() const {
return Size(mDisplayState.mStageSize.width, mDisplayState.mStageSize.height);
}
const Matrix4x4 VRDisplayInfo::GetSittingToStandingTransform() const {
Matrix4x4 m;
// If we could replace Matrix4x4 with a pod type, we could
// use it directly from the VRDisplayInfo struct.
memcpy(m.components, mDisplayState.mSittingToStandingTransform,
sizeof(float) * 16);
return m;
}