// %BANNER_BEGIN%
// ---------------------------------------------------------------------
// %COPYRIGHT_BEGIN%
// Copyright (c) (2021-2022) Magic Leap, Inc. All Rights Reserved.
// Use of this file is governed by the Software License Agreement, located here: https://www.magicleap.com/software-license-agreement-ml2
// Terms and conditions applicable to third-party materials accompanying this distribution may also be found in the top-level NOTICE file appearing herein.
// %COPYRIGHT_END%
// ---------------------------------------------------------------------
// %BANNER_END%
using System;
using Unity.Collections;
using UnityEngine.Scripting;
using UnityEngine.XR.ARSubsystems;
#if UNITY_XR_MAGICLEAP_PROVIDER
using UnityEngine.XR.MagicLeap.Internal;
#endif
using UnityEngine.XR.Management;
namespace UnityEngine.XR.MagicLeap
{
///
/// The Magic Leap implementation of the XRSessionSubsystem. Do not create this directly.
/// Use SessionSubsystemDescriptor.Create() instead.
///
[Preserve]
public sealed class SessionSubsystem : XRSessionSubsystem
{
#if !UNITY_2020_2_OR_NEWER
protected override Provider CreateProvider() => new MagicLeapProvider();
#endif
class MagicLeapProvider : Provider
{
public override Promise GetAvailabilityAsync()
{
var availability = SessionAvailability.Installed | SessionAvailability.Supported;
return Promise.CreateResolvedPromise(availability);
}
public override TrackingState trackingState
{
get
{
var device = InputDevices.GetDeviceAtXRNode(XRNode.CenterEye);
if (device.TryGetFeatureValue(CommonUsages.trackingState, out InputTrackingState inputTrackingState))
{
if (inputTrackingState == InputTrackingState.None)
return TrackingState.None;
if (inputTrackingState.HasFlag(InputTrackingState.Position | InputTrackingState.Rotation | InputTrackingState.Velocity | InputTrackingState.AngularVelocity))
return TrackingState.Tracking;
return TrackingState.Limited;
}
return TrackingState.None;
}
}
public override Feature requestedFeatures => SubsystemFeatures.requestedFeatures;
public override NativeArray GetConfigurationDescriptors(Allocator allocator)
=> SubsystemFeatures.AcquireConfigurationDescriptors(allocator);
public override Feature requestedTrackingMode
{
get => SubsystemFeatures.requestedFeatures.Intersection(Feature.AnyTrackingMode);
set
{
SubsystemFeatures.SetFeatureRequested(Feature.AnyTrackingMode, false);
SubsystemFeatures.SetFeatureRequested(value, true);
}
}
///
/// The current tracking mode feature flag.
///
///
/// Magic Leap will always try to use 6DoF tracking but will automatically switch to
/// 3DoF if it doesn't have a sufficient tracking environment. This will report which
/// of the two modes is currently active and
/// UnityEngine.XR.ARSubsystems.Feature.None otherwise.
///
public override Feature currentTrackingMode
{
get
{
var device = InputDevices.GetDeviceAtXRNode(XRNode.CenterEye);
if (device.TryGetFeatureValue(CommonUsages.trackingState, out InputTrackingState inputTrackingState))
{
if (inputTrackingState == InputTrackingState.None)
return Feature.None;
if (inputTrackingState.HasFlag(InputTrackingState.Position | InputTrackingState.Rotation))
return Feature.PositionAndRotation;
return Feature.RotationOnly;
}
return Feature.None;
}
}
private Feature previousConfigurationFeatures = Feature.None;
public override void Update(XRSessionUpdateParams updateParams, Configuration configuration)
{
// Magic Leap supports almost everything working at the same time except Point Clouds and Meshing
if (configuration.features.HasFlag(Feature.Meshing | Feature.PointCloud))
{
/// TODO (5/26/2020): Move MLSpatialMapper specific features to shared XRMeshSubsystem extensions
// Currently, the MeshingSubsystemComponent is required to do PointClouds on magic leap. So
// if meshing is detected at all then simply request a start to the subsystem because it will be
// handled either by ARMeshManager or the MeshingSubsystemComponent.
#if UNITY_XR_MAGICLEAP_PROVIDER
var loader = (MagicLeapLoader)XRGeneralSettings.Instance.Manager.activeLoader;
if (loader.meshSubsystem != null && !loader.meshSubsystem.running)
{
loader.StartMeshSubsystem();
}
#endif
}
else if (previousConfigurationFeatures.HasFlag(Feature.Meshing | Feature.PointCloud))
{
#if UNITY_XR_MAGICLEAP_PROVIDER
var loader = (MagicLeapLoader)XRGeneralSettings.Instance.Manager.activeLoader;
if (loader.meshSubsystem != null && loader.meshSubsystem.running)
{
loader.StopMeshSubsystem();
}
#endif
}
// Only disable and enable features that are managed by the passed in configurations.
// In some cases features are managed outside of the AR Foundation and explicitly
// setting all features based on the configuration may override those settings.
SubsystemFeatures.SetCurrentFeatureEnabled(previousConfigurationFeatures, false);
SubsystemFeatures.SetCurrentFeatureEnabled(configuration.features, true);
previousConfigurationFeatures = configuration.features;
}
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void RegisterDescriptor()
{
XRSessionSubsystemDescriptor.RegisterDescriptor(new XRSessionSubsystemDescriptor.Cinfo
{
id = MagicLeapXrProvider.SessionSubsystemId,
#if UNITY_2020_2_OR_NEWER
providerType = typeof(SessionSubsystem.MagicLeapProvider),
subsystemTypeOverride = typeof(SessionSubsystem),
#else
subsystemImplementationType = typeof(SessionSubsystem),
#endif
supportsInstall = false
});
}
}
}