зеркало из https://github.com/mozilla/gecko-dev.git
767 строки
26 KiB
C++
767 строки
26 KiB
C++
/* -*- 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 "mozilla/dom/VRServiceTest.h"
|
|
#include "mozilla/dom/VRServiceTestBinding.h"
|
|
#include "VRPuppetCommandBuffer.h"
|
|
#include <type_traits>
|
|
|
|
namespace mozilla {
|
|
using namespace gfx;
|
|
namespace dom {
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(VRMockDisplay)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(VRMockDisplay,
|
|
DOMEventTargetHelper)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(VRMockDisplay,
|
|
DOMEventTargetHelper)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VRMockDisplay)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(VRMockDisplay, DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(VRMockDisplay, DOMEventTargetHelper)
|
|
|
|
namespace {
|
|
template <class T>
|
|
bool ReadFloat32Array(T& aDestination, const Float32Array& aSource,
|
|
ErrorResult& aRv) {
|
|
constexpr size_t length = std::extent<T>::value;
|
|
aSource.ComputeLengthAndData();
|
|
if (aSource.Length() != length) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
// We don't want to MOZ_ASSERT here, as that would cause the
|
|
// browser to crash, making it difficult to debug the problem
|
|
// in JS code calling this API.
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < length; i++) {
|
|
aDestination[i] = aSource.Data()[i];
|
|
}
|
|
return true;
|
|
}
|
|
}; // anonymous namespace
|
|
|
|
VRMockDisplay::VRMockDisplay(VRServiceTest* aVRServiceTest)
|
|
: DOMEventTargetHelper(aVRServiceTest->GetOwner()),
|
|
mVRServiceTest(aVRServiceTest) {}
|
|
|
|
JSObject* VRMockDisplay::WrapObject(JSContext* aCx,
|
|
JS::Handle<JSObject*> aGivenProto) {
|
|
return VRMockDisplay_Binding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
VRHMDSensorState& VRMockDisplay::SensorState() const {
|
|
return mVRServiceTest->SystemState().sensorState;
|
|
}
|
|
|
|
VRDisplayState& VRMockDisplay::DisplayState() const {
|
|
return mVRServiceTest->SystemState().displayState;
|
|
}
|
|
|
|
void VRMockDisplay::Clear() {
|
|
VRDisplayState& displayState = DisplayState();
|
|
displayState.Clear();
|
|
VRHMDSensorState& sensorState = SensorState();
|
|
sensorState.Clear();
|
|
}
|
|
|
|
void VRMockDisplay::Create() {
|
|
Clear();
|
|
VRDisplayState& state = DisplayState();
|
|
|
|
strncpy(state.displayName, "Puppet HMD", kVRDisplayNameMaxLen);
|
|
state.eightCC = GFX_VR_EIGHTCC('P', 'u', 'p', 'p', 'e', 't', ' ', ' ');
|
|
state.isConnected = true;
|
|
state.isMounted = false;
|
|
state.capabilityFlags = VRDisplayCapabilityFlags::Cap_None |
|
|
VRDisplayCapabilityFlags::Cap_Orientation |
|
|
VRDisplayCapabilityFlags::Cap_Position |
|
|
VRDisplayCapabilityFlags::Cap_External |
|
|
VRDisplayCapabilityFlags::Cap_Present |
|
|
VRDisplayCapabilityFlags::Cap_StageParameters |
|
|
VRDisplayCapabilityFlags::Cap_MountDetection |
|
|
VRDisplayCapabilityFlags::Cap_ImmersiveVR;
|
|
state.blendMode = VRDisplayBlendMode::Opaque;
|
|
|
|
// 1836 x 2040 resolution is arbitrary and can be overridden.
|
|
// This default resolution was chosen to be within range of a
|
|
// typical VR eye buffer size. This value is derived by
|
|
// scaling a 1080x1200 per-eye panel resolution by the
|
|
// commonly used pre-lens-distortion pass scaling factor of 1.7x.
|
|
// 1.7x is commonly used in HMD's employing fresnel lenses to ensure
|
|
// a sufficient fragment shading rate in the peripheral area of the
|
|
// post-warp eye buffers.
|
|
state.eyeResolution.width = 1836; // 1080 * 1.7
|
|
state.eyeResolution.height = 2040; // 1200 * 1.7
|
|
|
|
for (uint32_t eye = 0; eye < VRDisplayState::NumEyes; ++eye) {
|
|
state.eyeTranslation[eye].x = 0.0f;
|
|
state.eyeTranslation[eye].y = 0.0f;
|
|
state.eyeTranslation[eye].z = 0.0f;
|
|
state.eyeFOV[eye] = gfx::VRFieldOfView(45.0, 45.0, 45.0, 45.0);
|
|
}
|
|
|
|
// default: 1m x 1m space, 0.75m high in seated position
|
|
state.stageSize.width = 1.0f;
|
|
state.stageSize.height = 1.0f;
|
|
|
|
state.sittingToStandingTransform[0] = 1.0f;
|
|
state.sittingToStandingTransform[1] = 0.0f;
|
|
state.sittingToStandingTransform[2] = 0.0f;
|
|
state.sittingToStandingTransform[3] = 0.0f;
|
|
|
|
state.sittingToStandingTransform[4] = 0.0f;
|
|
state.sittingToStandingTransform[5] = 1.0f;
|
|
state.sittingToStandingTransform[6] = 0.0f;
|
|
state.sittingToStandingTransform[7] = 0.0f;
|
|
|
|
state.sittingToStandingTransform[8] = 0.0f;
|
|
state.sittingToStandingTransform[9] = 0.0f;
|
|
state.sittingToStandingTransform[10] = 1.0f;
|
|
state.sittingToStandingTransform[11] = 0.0f;
|
|
|
|
state.sittingToStandingTransform[12] = 0.0f;
|
|
state.sittingToStandingTransform[13] = 0.75f;
|
|
state.sittingToStandingTransform[14] = 0.0f;
|
|
state.sittingToStandingTransform[15] = 1.0f;
|
|
|
|
VRHMDSensorState& sensorState = SensorState();
|
|
gfx::Quaternion rot;
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
|
|
sensorState.pose.orientation[0] = rot.x;
|
|
sensorState.pose.orientation[1] = rot.y;
|
|
sensorState.pose.orientation[2] = rot.z;
|
|
sensorState.pose.orientation[3] = rot.w;
|
|
sensorState.pose.angularVelocity[0] = 0.0f;
|
|
sensorState.pose.angularVelocity[1] = 0.0f;
|
|
sensorState.pose.angularVelocity[2] = 0.0f;
|
|
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
|
|
sensorState.pose.position[0] = 0.0f;
|
|
sensorState.pose.position[1] = 0.0f;
|
|
sensorState.pose.position[2] = 0.0f;
|
|
sensorState.pose.linearVelocity[0] = 0.0f;
|
|
sensorState.pose.linearVelocity[1] = 0.0f;
|
|
sensorState.pose.linearVelocity[2] = 0.0f;
|
|
}
|
|
|
|
void VRMockDisplay::SetConnected(bool aConnected) {
|
|
DisplayState().isConnected = aConnected;
|
|
}
|
|
bool VRMockDisplay::Connected() const { return DisplayState().isConnected; }
|
|
|
|
void VRMockDisplay::SetMounted(bool aMounted) {
|
|
DisplayState().isMounted = aMounted;
|
|
}
|
|
|
|
bool VRMockDisplay::Mounted() const { return DisplayState().isMounted; }
|
|
|
|
void VRMockDisplay::SetCapFlag(VRDisplayCapabilityFlags aFlag, bool aEnabled) {
|
|
if (aEnabled) {
|
|
DisplayState().capabilityFlags |= aFlag;
|
|
} else {
|
|
DisplayState().capabilityFlags &= ~aFlag;
|
|
}
|
|
}
|
|
bool VRMockDisplay::GetCapFlag(VRDisplayCapabilityFlags aFlag) const {
|
|
return ((DisplayState().capabilityFlags & aFlag) !=
|
|
VRDisplayCapabilityFlags::Cap_None);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapPosition(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_Position, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapOrientation(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_Orientation, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapPresent(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_Present, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapExternal(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_External, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapAngularAcceleration(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_AngularAcceleration, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapLinearAcceleration(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_LinearAcceleration, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapStageParameters(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_StageParameters, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapMountDetection(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_MountDetection, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetCapPositionEmulated(bool aEnabled) {
|
|
SetCapFlag(VRDisplayCapabilityFlags::Cap_PositionEmulated, aEnabled);
|
|
}
|
|
|
|
void VRMockDisplay::SetEyeFOV(VREye aEye, double aUpDegree, double aRightDegree,
|
|
double aDownDegree, double aLeftDegree) {
|
|
gfx::VRDisplayState::Eye eye = aEye == VREye::Left
|
|
? gfx::VRDisplayState::Eye_Left
|
|
: gfx::VRDisplayState::Eye_Right;
|
|
VRDisplayState& state = DisplayState();
|
|
state.eyeFOV[eye] =
|
|
gfx::VRFieldOfView(aUpDegree, aRightDegree, aDownDegree, aLeftDegree);
|
|
}
|
|
|
|
void VRMockDisplay::SetEyeOffset(VREye aEye, double aOffsetX, double aOffsetY,
|
|
double aOffsetZ) {
|
|
gfx::VRDisplayState::Eye eye = aEye == VREye::Left
|
|
? gfx::VRDisplayState::Eye_Left
|
|
: gfx::VRDisplayState::Eye_Right;
|
|
VRDisplayState& state = DisplayState();
|
|
state.eyeTranslation[eye].x = (float)aOffsetX;
|
|
state.eyeTranslation[eye].y = (float)aOffsetY;
|
|
state.eyeTranslation[eye].z = (float)aOffsetZ;
|
|
}
|
|
|
|
bool VRMockDisplay::CapPosition() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_Position);
|
|
}
|
|
|
|
bool VRMockDisplay::CapOrientation() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_Orientation);
|
|
}
|
|
|
|
bool VRMockDisplay::CapPresent() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_Present);
|
|
}
|
|
|
|
bool VRMockDisplay::CapExternal() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_External);
|
|
}
|
|
|
|
bool VRMockDisplay::CapAngularAcceleration() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_AngularAcceleration);
|
|
}
|
|
|
|
bool VRMockDisplay::CapLinearAcceleration() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_LinearAcceleration);
|
|
}
|
|
|
|
bool VRMockDisplay::CapStageParameters() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_StageParameters);
|
|
}
|
|
|
|
bool VRMockDisplay::CapMountDetection() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_MountDetection);
|
|
}
|
|
|
|
bool VRMockDisplay::CapPositionEmulated() const {
|
|
return GetCapFlag(VRDisplayCapabilityFlags::Cap_PositionEmulated);
|
|
}
|
|
|
|
void VRMockDisplay::SetEyeResolution(uint32_t aRenderWidth,
|
|
uint32_t aRenderHeight) {
|
|
DisplayState().eyeResolution.width = aRenderWidth;
|
|
DisplayState().eyeResolution.height = aRenderHeight;
|
|
}
|
|
|
|
void VRMockDisplay::SetStageSize(double aWidth, double aHeight) {
|
|
VRDisplayState& displayState = DisplayState();
|
|
displayState.stageSize.width = (float)aWidth;
|
|
displayState.stageSize.height = (float)aHeight;
|
|
}
|
|
|
|
void VRMockDisplay::SetSittingToStandingTransform(
|
|
const Float32Array& aTransform, ErrorResult& aRv) {
|
|
Unused << ReadFloat32Array(DisplayState().sittingToStandingTransform,
|
|
aTransform, aRv);
|
|
}
|
|
|
|
void VRMockDisplay::SetPose(const Nullable<Float32Array>& aPosition,
|
|
const Nullable<Float32Array>& aLinearVelocity,
|
|
const Nullable<Float32Array>& aLinearAcceleration,
|
|
const Nullable<Float32Array>& aOrientation,
|
|
const Nullable<Float32Array>& aAngularVelocity,
|
|
const Nullable<Float32Array>& aAngularAcceleration,
|
|
ErrorResult& aRv) {
|
|
VRHMDSensorState& sensorState = mVRServiceTest->SystemState().sensorState;
|
|
sensorState.Clear();
|
|
sensorState.flags = VRDisplayCapabilityFlags::Cap_None;
|
|
// sensorState.timestamp will be set automatically during
|
|
// puppet script execution
|
|
|
|
if (!aOrientation.IsNull()) {
|
|
if (!ReadFloat32Array(sensorState.pose.orientation, aOrientation.Value(),
|
|
aRv)) {
|
|
return;
|
|
}
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_Orientation;
|
|
}
|
|
if (!aAngularVelocity.IsNull()) {
|
|
if (!ReadFloat32Array(sensorState.pose.angularVelocity,
|
|
aAngularVelocity.Value(), aRv)) {
|
|
return;
|
|
}
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
|
|
}
|
|
if (!aAngularAcceleration.IsNull()) {
|
|
if (!ReadFloat32Array(sensorState.pose.angularAcceleration,
|
|
aAngularAcceleration.Value(), aRv)) {
|
|
return;
|
|
}
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_AngularAcceleration;
|
|
}
|
|
if (!aPosition.IsNull()) {
|
|
if (!ReadFloat32Array(sensorState.pose.position, aPosition.Value(), aRv)) {
|
|
return;
|
|
}
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_Position;
|
|
}
|
|
if (!aLinearVelocity.IsNull()) {
|
|
if (!ReadFloat32Array(sensorState.pose.linearVelocity,
|
|
aLinearVelocity.Value(), aRv)) {
|
|
return;
|
|
}
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
|
|
}
|
|
if (!aLinearAcceleration.IsNull()) {
|
|
if (!ReadFloat32Array(sensorState.pose.linearAcceleration,
|
|
aLinearAcceleration.Value(), aRv)) {
|
|
return;
|
|
}
|
|
sensorState.flags |= VRDisplayCapabilityFlags::Cap_LinearAcceleration;
|
|
}
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(VRMockController)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(VRMockController,
|
|
DOMEventTargetHelper)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(VRMockController,
|
|
DOMEventTargetHelper)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VRMockController)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(VRMockController, DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(VRMockController, DOMEventTargetHelper)
|
|
|
|
VRMockController::VRMockController(VRServiceTest* aVRServiceTest,
|
|
uint32_t aControllerIdx)
|
|
: DOMEventTargetHelper(aVRServiceTest->GetOwner()),
|
|
mControllerIdx(aControllerIdx) {
|
|
MOZ_ASSERT(aControllerIdx < kVRControllerMaxCount);
|
|
}
|
|
|
|
JSObject* VRMockController::WrapObject(JSContext* aCx,
|
|
JS::Handle<JSObject*> aGivenProto) {
|
|
return VRMockController_Binding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
VRControllerState& VRMockController::ControllerState() const {
|
|
return mVRServiceTest->SystemState().controllerState[mControllerIdx];
|
|
}
|
|
|
|
void VRMockController::Create() {
|
|
// Initialize with a 6dof, left-handed gamepad with one haptic actuator
|
|
// Tests are expected to modify the controller before it is sent to the
|
|
// puppet.
|
|
Clear();
|
|
VRControllerState& state = ControllerState();
|
|
strncpy(state.controllerName, "Puppet Gamepad", kVRControllerNameMaxLen);
|
|
state.hand = GamepadHand::Left;
|
|
state.flags = GamepadCapabilityFlags::Cap_Position |
|
|
GamepadCapabilityFlags::Cap_Orientation;
|
|
state.numButtons = 1;
|
|
state.numHaptics = 1;
|
|
state.triggerValue[0] = 0.0f;
|
|
}
|
|
|
|
void VRMockController::Clear() {
|
|
mVRServiceTest->ClearController(mControllerIdx);
|
|
}
|
|
|
|
void VRMockController::SetCapFlag(GamepadCapabilityFlags aFlag, bool aEnabled) {
|
|
if (aEnabled) {
|
|
ControllerState().flags |= aFlag;
|
|
} else {
|
|
ControllerState().flags &= ~aFlag;
|
|
}
|
|
}
|
|
bool VRMockController::GetCapFlag(GamepadCapabilityFlags aFlag) const {
|
|
return (ControllerState().flags & aFlag) != GamepadCapabilityFlags::Cap_None;
|
|
}
|
|
|
|
void VRMockController::SetHand(GamepadHand aHand) {
|
|
ControllerState().hand = aHand;
|
|
}
|
|
|
|
GamepadHand VRMockController::Hand() const { return ControllerState().hand; }
|
|
|
|
void VRMockController::SetCapPosition(bool aEnabled) {
|
|
SetCapFlag(GamepadCapabilityFlags::Cap_Position, aEnabled);
|
|
}
|
|
|
|
bool VRMockController::CapPosition() const {
|
|
return GetCapFlag(GamepadCapabilityFlags::Cap_Position);
|
|
}
|
|
|
|
void VRMockController::SetCapOrientation(bool aEnabled) {
|
|
SetCapFlag(GamepadCapabilityFlags::Cap_Orientation, aEnabled);
|
|
}
|
|
|
|
bool VRMockController::CapOrientation() const {
|
|
return GetCapFlag(GamepadCapabilityFlags::Cap_Orientation);
|
|
}
|
|
|
|
void VRMockController::SetCapAngularAcceleration(bool aEnabled) {
|
|
SetCapFlag(GamepadCapabilityFlags::Cap_AngularAcceleration, aEnabled);
|
|
}
|
|
|
|
bool VRMockController::CapAngularAcceleration() const {
|
|
return GetCapFlag(GamepadCapabilityFlags::Cap_AngularAcceleration);
|
|
}
|
|
|
|
void VRMockController::SetCapLinearAcceleration(bool aEnabled) {
|
|
SetCapFlag(GamepadCapabilityFlags::Cap_LinearAcceleration, aEnabled);
|
|
}
|
|
|
|
bool VRMockController::CapLinearAcceleration() const {
|
|
return GetCapFlag(GamepadCapabilityFlags::Cap_LinearAcceleration);
|
|
}
|
|
|
|
void VRMockController::SetAxisCount(uint32_t aCount) {
|
|
MOZ_ASSERT(aCount <= kVRControllerMaxAxis);
|
|
ControllerState().numAxes = aCount;
|
|
}
|
|
|
|
uint32_t VRMockController::AxisCount() const {
|
|
return ControllerState().numAxes;
|
|
}
|
|
|
|
void VRMockController::SetButtonCount(uint32_t aCount) {
|
|
MOZ_ASSERT(aCount <= kVRControllerMaxButtons);
|
|
ControllerState().numButtons = aCount;
|
|
}
|
|
|
|
uint32_t VRMockController::ButtonCount() const {
|
|
return ControllerState().numButtons;
|
|
}
|
|
|
|
void VRMockController::SetHapticCount(uint32_t aCount) {
|
|
ControllerState().numHaptics = aCount;
|
|
}
|
|
|
|
uint32_t VRMockController::HapticCount() const {
|
|
return ControllerState().numHaptics;
|
|
}
|
|
|
|
void VRMockController::SetButtonPressed(uint32_t aButtonIdx, bool aPressed) {
|
|
MOZ_ASSERT(aButtonIdx < kVRControllerMaxButtons);
|
|
if (aPressed) {
|
|
ControllerState().buttonPressed |= (1 << aButtonIdx);
|
|
} else {
|
|
ControllerState().buttonPressed &= ~(1 << aButtonIdx);
|
|
}
|
|
}
|
|
|
|
void VRMockController::SetButtonTouched(uint32_t aButtonIdx, bool aTouched) {
|
|
MOZ_ASSERT(aButtonIdx < kVRControllerMaxButtons);
|
|
if (aTouched) {
|
|
ControllerState().buttonTouched |= (1 << aButtonIdx);
|
|
} else {
|
|
ControllerState().buttonTouched &= ~(1 << aButtonIdx);
|
|
}
|
|
}
|
|
|
|
void VRMockController::SetButtonTrigger(uint32_t aButtonIdx, double aTrigger) {
|
|
MOZ_ASSERT(aButtonIdx < kVRControllerMaxButtons);
|
|
|
|
ControllerState().triggerValue[aButtonIdx] = (float)aTrigger;
|
|
}
|
|
|
|
void VRMockController::SetAxisValue(uint32_t aAxisIdx, double aValue) {
|
|
MOZ_ASSERT(aAxisIdx < kVRControllerMaxAxis);
|
|
ControllerState().axisValue[aAxisIdx] = (float)aValue;
|
|
}
|
|
|
|
void VRMockController::SetPose(
|
|
const Nullable<Float32Array>& aPosition,
|
|
const Nullable<Float32Array>& aLinearVelocity,
|
|
const Nullable<Float32Array>& aLinearAcceleration,
|
|
const Nullable<Float32Array>& aOrientation,
|
|
const Nullable<Float32Array>& aAngularVelocity,
|
|
const Nullable<Float32Array>& aAngularAcceleration, ErrorResult& aRv) {
|
|
VRControllerState& controllerState = ControllerState();
|
|
controllerState.flags = GamepadCapabilityFlags::Cap_None;
|
|
|
|
if (!aOrientation.IsNull()) {
|
|
if (!ReadFloat32Array(controllerState.pose.orientation,
|
|
aOrientation.Value(), aRv)) {
|
|
return;
|
|
}
|
|
controllerState.flags |= GamepadCapabilityFlags::Cap_Orientation;
|
|
}
|
|
if (!aAngularVelocity.IsNull()) {
|
|
if (!ReadFloat32Array(controllerState.pose.angularVelocity,
|
|
aAngularVelocity.Value(), aRv)) {
|
|
return;
|
|
}
|
|
controllerState.flags |= GamepadCapabilityFlags::Cap_AngularAcceleration;
|
|
}
|
|
if (!aAngularAcceleration.IsNull()) {
|
|
if (!ReadFloat32Array(controllerState.pose.angularAcceleration,
|
|
aAngularAcceleration.Value(), aRv)) {
|
|
return;
|
|
}
|
|
controllerState.flags |= GamepadCapabilityFlags::Cap_AngularAcceleration;
|
|
}
|
|
if (!aPosition.IsNull()) {
|
|
if (!ReadFloat32Array(controllerState.pose.position, aPosition.Value(),
|
|
aRv)) {
|
|
return;
|
|
}
|
|
controllerState.flags |= GamepadCapabilityFlags::Cap_Position;
|
|
}
|
|
if (!aLinearVelocity.IsNull()) {
|
|
if (!ReadFloat32Array(controllerState.pose.linearVelocity,
|
|
aLinearVelocity.Value(), aRv)) {
|
|
return;
|
|
}
|
|
controllerState.flags |= GamepadCapabilityFlags::Cap_LinearAcceleration;
|
|
}
|
|
if (!aLinearAcceleration.IsNull()) {
|
|
if (!ReadFloat32Array(controllerState.pose.linearAcceleration,
|
|
aLinearAcceleration.Value(), aRv)) {
|
|
return;
|
|
}
|
|
controllerState.flags |= GamepadCapabilityFlags::Cap_LinearAcceleration;
|
|
}
|
|
}
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_CLASS(VRServiceTest)
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(VRServiceTest,
|
|
DOMEventTargetHelper)
|
|
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
|
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(VRServiceTest,
|
|
DOMEventTargetHelper)
|
|
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
|
|
|
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VRServiceTest)
|
|
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
|
|
|
NS_IMPL_ADDREF_INHERITED(VRServiceTest, DOMEventTargetHelper)
|
|
NS_IMPL_RELEASE_INHERITED(VRServiceTest, DOMEventTargetHelper)
|
|
|
|
JSObject* VRServiceTest::WrapObject(JSContext* aCx,
|
|
JS::Handle<JSObject*> aGivenProto) {
|
|
return VRServiceTest_Binding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
// static
|
|
already_AddRefed<VRServiceTest> VRServiceTest::CreateTestService(
|
|
nsPIDOMWindowInner* aWindow) {
|
|
MOZ_ASSERT(aWindow);
|
|
RefPtr<VRServiceTest> service = new VRServiceTest(aWindow);
|
|
return service.forget();
|
|
}
|
|
|
|
VRServiceTest::VRServiceTest(nsPIDOMWindowInner* aWindow)
|
|
: mWindow(aWindow), mPendingState{}, mEncodedState{}, mShuttingDown(false) {
|
|
mDisplay = new VRMockDisplay(this);
|
|
for (int i = 0; i < kVRControllerMaxCount; i++) {
|
|
mControllers.AppendElement(new VRMockController(this, i));
|
|
}
|
|
ClearAll();
|
|
}
|
|
|
|
gfx::VRSystemState& VRServiceTest::SystemState() { return mPendingState; }
|
|
|
|
VRMockDisplay* VRServiceTest::GetVRDisplay() { return mDisplay; }
|
|
|
|
VRMockController* VRServiceTest::GetVRController(uint32_t aControllerIdx,
|
|
ErrorResult& aRv) {
|
|
if (aControllerIdx >= kVRControllerMaxCount) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return nullptr;
|
|
}
|
|
return mControllers[aControllerIdx];
|
|
}
|
|
|
|
void VRServiceTest::Shutdown() {
|
|
MOZ_ASSERT(!mShuttingDown);
|
|
mShuttingDown = true;
|
|
mWindow = nullptr;
|
|
}
|
|
|
|
void VRServiceTest::AddCommand(uint64_t aCommand) {
|
|
EncodeData();
|
|
mCommandBuffer.AppendElement(aCommand);
|
|
}
|
|
|
|
void VRServiceTest::End() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_End);
|
|
}
|
|
|
|
void VRServiceTest::ClearAll() {
|
|
memset(&mPendingState, 0, sizeof(VRSystemState));
|
|
memset(&mEncodedState, 0, sizeof(VRSystemState));
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_ClearAll);
|
|
}
|
|
|
|
void VRServiceTest::ClearController(uint32_t aControllerIdx) {
|
|
MOZ_ASSERT(aControllerIdx < kVRControllerMaxCount);
|
|
mPendingState.controllerState[aControllerIdx].Clear();
|
|
mEncodedState.controllerState[aControllerIdx].Clear();
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_ClearController |
|
|
(uint64_t)aControllerIdx);
|
|
}
|
|
|
|
void VRServiceTest::Timeout(uint32_t aDuration) {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_Timeout |
|
|
(uint64_t)aDuration);
|
|
}
|
|
|
|
void VRServiceTest::Wait(uint32_t aDuration) {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_Wait | (uint64_t)aDuration);
|
|
}
|
|
|
|
void VRServiceTest::WaitHapticIntensity(uint32_t aControllerIdx,
|
|
uint32_t aHapticIdx, double aIntensity,
|
|
ErrorResult& aRv) {
|
|
if (aControllerIdx >= kVRControllerMaxCount) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
if (aHapticIdx >= kVRHapticsMaxCount) {
|
|
aRv.Throw(NS_ERROR_INVALID_ARG);
|
|
return;
|
|
}
|
|
// convert to 16.16 fixed point. This must match conversion in
|
|
// VRPuppetCommandBuffer::RunCommand
|
|
uint64_t iIntensity = round((float)aIntensity * (1 << 16));
|
|
if (iIntensity > 0xffffffff) {
|
|
iIntensity = 0xffffffff;
|
|
}
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitHapticIntensity |
|
|
((uint64_t)aControllerIdx << 40) | ((uint64_t)aHapticIdx << 32) |
|
|
iIntensity);
|
|
}
|
|
|
|
void VRServiceTest::WaitSubmit() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitSubmit);
|
|
}
|
|
|
|
void VRServiceTest::WaitPresentationStart() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitPresentationStart);
|
|
}
|
|
void VRServiceTest::WaitPresentationEnd() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_WaitPresentationEnd);
|
|
}
|
|
|
|
void VRServiceTest::EncodeData() {
|
|
VRPuppetCommandBuffer::EncodeStruct(
|
|
mCommandBuffer, (uint8_t*)&mPendingState.displayState,
|
|
(uint8_t*)&mEncodedState.displayState, sizeof(VRDisplayState),
|
|
VRPuppet_Command::VRPuppet_UpdateDisplay);
|
|
VRPuppetCommandBuffer::EncodeStruct(
|
|
mCommandBuffer, (uint8_t*)&mPendingState.sensorState,
|
|
(uint8_t*)&mEncodedState.sensorState, sizeof(VRHMDSensorState),
|
|
VRPuppet_Command::VRPuppet_UpdateSensor);
|
|
VRPuppetCommandBuffer::EncodeStruct(
|
|
mCommandBuffer, (uint8_t*)&mPendingState.controllerState,
|
|
(uint8_t*)&mEncodedState.controllerState,
|
|
sizeof(VRControllerState) * kVRControllerMaxCount,
|
|
VRPuppet_Command::VRPuppet_UpdateControllers);
|
|
}
|
|
|
|
void VRServiceTest::CaptureFrame() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_CaptureFrame);
|
|
}
|
|
|
|
void VRServiceTest::AcknowledgeFrame() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_AcknowledgeFrame);
|
|
}
|
|
|
|
void VRServiceTest::RejectFrame() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_RejectFrame);
|
|
}
|
|
|
|
void VRServiceTest::StartTimer() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_StartTimer);
|
|
}
|
|
|
|
void VRServiceTest::StopTimer() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_StopTimer);
|
|
}
|
|
|
|
void VRServiceTest::Commit() {
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_Commit);
|
|
}
|
|
|
|
already_AddRefed<Promise> VRServiceTest::Run(ErrorResult& aRv) {
|
|
if (mShuttingDown) {
|
|
return nullptr;
|
|
}
|
|
|
|
AddCommand((uint64_t)VRPuppet_Command::VRPuppet_End);
|
|
|
|
RefPtr<dom::Promise> runPuppetPromise =
|
|
Promise::Create(mWindow->AsGlobal(), aRv);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
|
|
vm->RunPuppet(mCommandBuffer, runPuppetPromise, aRv);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
mCommandBuffer.Clear();
|
|
|
|
return runPuppetPromise.forget();
|
|
}
|
|
|
|
already_AddRefed<Promise> VRServiceTest::Reset(ErrorResult& aRv) {
|
|
if (mShuttingDown) {
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<dom::Promise> resetPuppetPromise =
|
|
Promise::Create(mWindow->AsGlobal(), aRv);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
gfx::VRManagerChild* vm = gfx::VRManagerChild::Get();
|
|
vm->ResetPuppet(resetPuppetPromise, aRv);
|
|
if (NS_WARN_IF(aRv.Failed())) {
|
|
return nullptr;
|
|
}
|
|
|
|
memset(&mPendingState, 0, sizeof(VRSystemState));
|
|
memset(&mEncodedState, 0, sizeof(VRSystemState));
|
|
mCommandBuffer.Clear();
|
|
|
|
return resetPuppetPromise.forget();
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|