/* -*- 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 "nsWrapperCache.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/VRDeviceBinding.h" #include "mozilla/dom/ElementBinding.h" #include "mozilla/dom/VRDevice.h" #include "Navigator.h" #include "gfxVR.h" #include "VRDeviceProxy.h" #include "VRManagerChild.h" #include "nsIFrame.h" using namespace mozilla::gfx; namespace mozilla { namespace dom { /*static*/ bool VRDevice::RefreshVRDevices(dom::Navigator* aNavigator) { gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); return vm && vm->RefreshVRDevicesWithCallback(aNavigator); } /*static*/ void VRDevice::UpdateVRDevices(nsTArray>& aDevices, nsISupports* aParent) { nsTArray> devices; gfx::VRManagerChild* vm = gfx::VRManagerChild::Get(); nsTArray> proxyDevices; if (vm && vm->GetVRDevices(proxyDevices)) { for (size_t i = 0; i < proxyDevices.Length(); i++) { RefPtr proxyDevice = proxyDevices[i]; bool isNewDevice = true; for (size_t j = 0; j < aDevices.Length(); j++) { if (aDevices[j]->GetHMD()->GetDeviceInfo() == proxyDevice->GetDeviceInfo()) { devices.AppendElement(aDevices[j]); isNewDevice = false; } } if (isNewDevice) { gfx::VRStateValidFlags sensorBits = proxyDevice->GetDeviceInfo().GetSupportedSensorStateBits(); devices.AppendElement(new HMDInfoVRDevice(aParent, proxyDevice)); if (sensorBits & (gfx::VRStateValidFlags::State_Position | gfx::VRStateValidFlags::State_Orientation)) { devices.AppendElement(new HMDPositionVRDevice(aParent, proxyDevice)); } } } } aDevices = devices; } NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRFieldOfViewReadOnly, mParent) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRFieldOfViewReadOnly, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRFieldOfViewReadOnly, Release) JSObject* VRFieldOfViewReadOnly::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return VRFieldOfViewReadOnlyBinding::Wrap(aCx, this, aGivenProto); } already_AddRefed VRFieldOfView::Constructor(const GlobalObject& aGlobal, const VRFieldOfViewInit& aParams, ErrorResult& aRV) { RefPtr fov = new VRFieldOfView(aGlobal.GetAsSupports(), aParams.mUpDegrees, aParams.mRightDegrees, aParams.mDownDegrees, aParams.mLeftDegrees); return fov.forget(); } already_AddRefed VRFieldOfView::Constructor(const GlobalObject& aGlobal, double aUpDegrees, double aRightDegrees, double aDownDegrees, double aLeftDegrees, ErrorResult& aRV) { RefPtr fov = new VRFieldOfView(aGlobal.GetAsSupports(), aUpDegrees, aRightDegrees, aDownDegrees, aLeftDegrees); return fov.forget(); } JSObject* VRFieldOfView::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return VRFieldOfViewBinding::Wrap(aCx, this, aGivenProto); } NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VREyeParameters, mParent, mMinFOV, mMaxFOV, mRecFOV, mCurFOV, mEyeTranslation, mRenderRect) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VREyeParameters, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VREyeParameters, Release) VREyeParameters::VREyeParameters(nsISupports* aParent, const gfx::VRFieldOfView& aMinFOV, const gfx::VRFieldOfView& aMaxFOV, const gfx::VRFieldOfView& aRecFOV, const gfx::Point3D& aEyeTranslation, const gfx::VRFieldOfView& aCurFOV, const gfx::IntRect& aRenderRect) : mParent(aParent) { mMinFOV = new VRFieldOfView(aParent, aMinFOV); mMaxFOV = new VRFieldOfView(aParent, aMaxFOV); mRecFOV = new VRFieldOfView(aParent, aRecFOV); mCurFOV = new VRFieldOfView(aParent, aCurFOV); mEyeTranslation = new DOMPoint(aParent, aEyeTranslation.x, aEyeTranslation.y, aEyeTranslation.z, 0.0); mRenderRect = new DOMRect(aParent, aRenderRect.x, aRenderRect.y, aRenderRect.width, aRenderRect.height); } VRFieldOfView* VREyeParameters::MinimumFieldOfView() { return mMinFOV; } VRFieldOfView* VREyeParameters::MaximumFieldOfView() { return mMaxFOV; } VRFieldOfView* VREyeParameters::RecommendedFieldOfView() { return mRecFOV; } VRFieldOfView* VREyeParameters::CurrentFieldOfView() { return mCurFOV; } DOMPoint* VREyeParameters::EyeTranslation() { return mEyeTranslation; } DOMRect* VREyeParameters::RenderRect() { return mRenderRect; } JSObject* VREyeParameters::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return VREyeParametersBinding::Wrap(aCx, this, aGivenProto); } NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRPositionState, mParent) NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(VRPositionState, AddRef) NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(VRPositionState, Release) VRPositionState::VRPositionState(nsISupports* aParent, const gfx::VRHMDSensorState& aState) : mParent(aParent) , mVRState(aState) { mTimeStamp = aState.timestamp; if (aState.flags & gfx::VRStateValidFlags::State_Position) { mPosition = new DOMPoint(mParent, aState.position[0], aState.position[1], aState.position[2], 0.0); } if (aState.flags & gfx::VRStateValidFlags::State_Orientation) { mOrientation = new DOMPoint(mParent, aState.orientation[0], aState.orientation[1], aState.orientation[2], aState.orientation[3]); } } DOMPoint* VRPositionState::GetLinearVelocity() { if (!mLinearVelocity) { mLinearVelocity = new DOMPoint(mParent, mVRState.linearVelocity[0], mVRState.linearVelocity[1], mVRState.linearVelocity[2], 0.0); } return mLinearVelocity; } DOMPoint* VRPositionState::GetLinearAcceleration() { if (!mLinearAcceleration) { mLinearAcceleration = new DOMPoint(mParent, mVRState.linearAcceleration[0], mVRState.linearAcceleration[1], mVRState.linearAcceleration[2], 0.0); } return mLinearAcceleration; } DOMPoint* VRPositionState::GetAngularVelocity() { if (!mAngularVelocity) { mAngularVelocity = new DOMPoint(mParent, mVRState.angularVelocity[0], mVRState.angularVelocity[1], mVRState.angularVelocity[2], 0.0); } return mAngularVelocity; } DOMPoint* VRPositionState::GetAngularAcceleration() { if (!mAngularAcceleration) { mAngularAcceleration = new DOMPoint(mParent, mVRState.angularAcceleration[0], mVRState.angularAcceleration[1], mVRState.angularAcceleration[2], 0.0); } return mAngularAcceleration; } JSObject* VRPositionState::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return VRPositionStateBinding::Wrap(aCx, this, aGivenProto); } NS_IMPL_CYCLE_COLLECTING_ADDREF(VRDevice) NS_IMPL_CYCLE_COLLECTING_RELEASE(VRDevice) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(VRDevice) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(VRDevice, mParent) /* virtual */ JSObject* HMDVRDevice::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return HMDVRDeviceBinding::Wrap(aCx, this, aGivenProto); } /* virtual */ JSObject* PositionSensorVRDevice::WrapObject(JSContext* aCx, JS::Handle aGivenProto) { return PositionSensorVRDeviceBinding::Wrap(aCx, this, aGivenProto); } HMDInfoVRDevice::HMDInfoVRDevice(nsISupports* aParent, gfx::VRDeviceProxy* aHMD) : HMDVRDevice(aParent, aHMD) { MOZ_COUNT_CTOR_INHERITED(HMDInfoVRDevice, HMDVRDevice); uint64_t hmdid = aHMD->GetDeviceInfo().GetDeviceID() << 8; uint64_t devid = hmdid | 0x00; // we generate a devid with low byte 0 for the HMD, 1 for the position sensor mHWID.Truncate(); mHWID.AppendPrintf("0x%llx", hmdid); mDeviceId.Truncate(); mDeviceId.AppendPrintf("0x%llx", devid); mDeviceName.Truncate(); mDeviceName.Append(NS_ConvertASCIItoUTF16(aHMD->GetDeviceInfo().GetDeviceName())); mDeviceName.AppendLiteral(" (HMD)"); mValid = true; } HMDInfoVRDevice::~HMDInfoVRDevice() { MOZ_COUNT_DTOR_INHERITED(HMDInfoVRDevice, HMDVRDevice); } /* If a field of view that is set to all 0's is passed in, * the recommended field of view for that eye is used. */ void HMDInfoVRDevice::SetFieldOfView(const VRFieldOfViewInit& aLeftFOV, const VRFieldOfViewInit& aRightFOV, double zNear, double zFar) { gfx::VRFieldOfView left = gfx::VRFieldOfView(aLeftFOV.mUpDegrees, aLeftFOV.mRightDegrees, aLeftFOV.mDownDegrees, aLeftFOV.mLeftDegrees); gfx::VRFieldOfView right = gfx::VRFieldOfView(aRightFOV.mUpDegrees, aRightFOV.mRightDegrees, aRightFOV.mDownDegrees, aRightFOV.mLeftDegrees); if (left.IsZero()) { left = mHMD->GetDeviceInfo().GetRecommendedEyeFOV(VRDeviceInfo::Eye_Left); } if (right.IsZero()) { right = mHMD->GetDeviceInfo().GetRecommendedEyeFOV(VRDeviceInfo::Eye_Right); } mHMD->SetFOV(left, right, zNear, zFar); } already_AddRefed HMDInfoVRDevice::GetEyeParameters(VREye aEye) { gfx::IntSize sz(mHMD->GetDeviceInfo().SuggestedEyeResolution()); gfx::VRDeviceInfo::Eye eye = aEye == VREye::Left ? gfx::VRDeviceInfo::Eye_Left : gfx::VRDeviceInfo::Eye_Right; RefPtr params = new VREyeParameters(mParent, gfx::VRFieldOfView(15, 15, 15, 15), // XXX min? mHMD->GetDeviceInfo().GetMaximumEyeFOV(eye), mHMD->GetDeviceInfo().GetRecommendedEyeFOV(eye), mHMD->GetDeviceInfo().GetEyeTranslation(eye), mHMD->GetDeviceInfo().GetEyeFOV(eye), gfx::IntRect((aEye == VREye::Left) ? 0 : sz.width, 0, sz.width, sz.height)); return params.forget(); } HMDPositionVRDevice::HMDPositionVRDevice(nsISupports* aParent, gfx::VRDeviceProxy* aHMD) : PositionSensorVRDevice(aParent, aHMD) { MOZ_COUNT_CTOR_INHERITED(HMDPositionVRDevice, PositionSensorVRDevice); uint64_t hmdid = aHMD->GetDeviceInfo().GetDeviceID() << 8; uint64_t devid = hmdid | 0x01; // we generate a devid with low byte 0 for the HMD, 1 for the position sensor mHWID.Truncate(); mHWID.AppendPrintf("0x%llx", hmdid); mDeviceId.Truncate(); mDeviceId.AppendPrintf("0x%llx", devid); mDeviceName.Truncate(); mDeviceName.Append(NS_ConvertASCIItoUTF16(aHMD->GetDeviceInfo().GetDeviceName())); mDeviceName.AppendLiteral(" (Sensor)"); mValid = true; } HMDPositionVRDevice::~HMDPositionVRDevice() { MOZ_COUNT_DTOR_INHERITED(HMDPositionVRDevice, PositionSensorVRDevice); } already_AddRefed HMDPositionVRDevice::GetState() { gfx::VRHMDSensorState state = mHMD->GetSensorState(); RefPtr obj = new VRPositionState(mParent, state); return obj.forget(); } already_AddRefed HMDPositionVRDevice::GetImmediateState() { gfx::VRHMDSensorState state = mHMD->GetSensorState(); RefPtr obj = new VRPositionState(mParent, state); return obj.forget(); } void HMDPositionVRDevice::ResetSensor() { mHMD->ZeroSensor(); } } // namespace dom } // namespace mozilla