// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System.Collections.Generic; using Unity.Profiling; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.SpatialAwareness { /// /// Class providing the default implementation of the interface. /// [HelpURL("https://docs.microsoft.com/windows/mixed-reality/mrtk-unity/features/spatial-awareness/spatial-awareness-getting-started")] public class MixedRealitySpatialAwarenessSystem : BaseDataProviderAccessCoreSystem, IMixedRealitySpatialAwarenessSystem, IMixedRealityCapabilityCheck { /// /// Constructor. /// /// The instance that loaded the service. /// The configuration profile for the service. [System.Obsolete("This constructor is obsolete (registrar parameter is no longer required) and will be removed in a future version of the Microsoft Mixed Reality Toolkit.")] public MixedRealitySpatialAwarenessSystem( IMixedRealityServiceRegistrar registrar, MixedRealitySpatialAwarenessSystemProfile profile) : this(profile) { Registrar = registrar; } /// /// Constructor. /// /// The instance that loaded the service. /// The configuration profile for the service. public MixedRealitySpatialAwarenessSystem( MixedRealitySpatialAwarenessSystemProfile profile) : base(profile) { } /// public override string Name { get; protected set; } = "Mixed Reality Spatial Awareness System"; #region IMixedRealityCapabilityCheck Implementation /// public bool CheckCapability(MixedRealityCapability capability) { foreach (var observer in GetDataProviders()) { // If one of the running data providers supports the requested capability, // the application has the needed support to leverage the desired functionality. if (observer is IMixedRealityCapabilityCheck capabilityChecker && capabilityChecker.CheckCapability(capability)) { return true; } } return false; } #endregion IMixedRealityCapabilityCheck Implementation #region IMixedRealityToolkitService Implementation /// public override void Initialize() { // Mark not initialized early so observers can use this state in their own initialization IsInitialized = false; InitializeInternal(); base.Initialize(); } /// /// Performs initialization tasks for the spatial awareness system. /// private void InitializeInternal() { MixedRealitySpatialAwarenessSystemProfile profile = ConfigurationProfile as MixedRealitySpatialAwarenessSystemProfile; if (profile != null && GetDataProviders().Count == 0) { // Register the spatial observers. for (int i = 0; i < profile.ObserverConfigurations.Length; i++) { MixedRealitySpatialObserverConfiguration configuration = profile.ObserverConfigurations[i]; object[] args = { this, configuration.ComponentName, configuration.Priority, configuration.ObserverProfile }; RegisterDataProvider( configuration.ComponentType.Type, configuration.ComponentName, configuration.RuntimePlatform, args); } } } /// public override void Disable() { base.Disable(); foreach (var provider in GetDataProviders()) { UnregisterDataProvider(provider); } } /// public override void Enable() { InitializeInternal(); // Ensure data providers are enabled (performed by the base class) base.Enable(); } /// public override void Reset() { base.Reset(); Disable(); Initialize(); Enable(); } /// public override void Destroy() { // Cleanup game objects created during execution. if (Application.isPlaying) { // Detach the child objects and clean up the parent. if (spatialAwarenessObjectParent != null) { if (Application.isEditor) { Object.DestroyImmediate(spatialAwarenessObjectParent); } else { spatialAwarenessObjectParent.transform.DetachChildren(); Object.Destroy(spatialAwarenessObjectParent); } spatialAwarenessObjectParent = null; } } base.Destroy(); } #endregion IMixedRealityToolkitService Implementation #region IMixedRealitySpatialAwarenessSystem Implementation /// /// The parent object, in the hierarchy, under which all observed game objects will be placed. /// private GameObject spatialAwarenessObjectParent = null; /// public GameObject SpatialAwarenessObjectParent => spatialAwarenessObjectParent != null ? spatialAwarenessObjectParent : (spatialAwarenessObjectParent = CreateSpatialAwarenessObjectParent); /// /// Creates the parent for spatial awareness objects so that the scene hierarchy does not get overly cluttered. /// /// /// The GameObject to which spatial awareness created objects will be parented. /// private GameObject CreateSpatialAwarenessObjectParent { get { GameObject newParent = new GameObject("Spatial Awareness System"); /// Preserve local transform when attaching to playspace. newParent.transform.SetParent(MixedRealityPlayspace.Transform, false); return newParent; } } /// public GameObject CreateSpatialAwarenessObservationParent(string name) { GameObject objectParent = new GameObject(name); /// Preserve local transform when attaching to SA object parent. objectParent.transform.SetParent(SpatialAwarenessObjectParent.transform, false); return objectParent; } private uint nextSourceId = 0; /// public uint GenerateNewSourceId() { return nextSourceId++; } private MixedRealitySpatialAwarenessSystemProfile spatialAwarenessSystemProfile = null; /// public MixedRealitySpatialAwarenessSystemProfile SpatialAwarenessSystemProfile { get { if (spatialAwarenessSystemProfile == null) { spatialAwarenessSystemProfile = ConfigurationProfile as MixedRealitySpatialAwarenessSystemProfile; } return spatialAwarenessSystemProfile; } } private static readonly ProfilerMarker GetObserversPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.GetObservers"); /// public IReadOnlyList GetObservers() { using (GetObserversPerfMarker.Auto()) { return GetDataProviders() as IReadOnlyList; } } private static readonly ProfilerMarker GetObserversTPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.GetObservers"); /// public IReadOnlyList GetObservers() where T : IMixedRealitySpatialAwarenessObserver { using (GetObserversTPerfMarker.Auto()) { return GetDataProviders(); } } private static readonly ProfilerMarker GetObserverPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.GetObserver"); /// public IMixedRealitySpatialAwarenessObserver GetObserver(string name) { using (GetObserverPerfMarker.Auto()) { return GetDataProvider(name) as IMixedRealitySpatialAwarenessObserver; } } private static readonly ProfilerMarker GetObserverTPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.GetObserver"); /// public T GetObserver(string name = null) where T : IMixedRealitySpatialAwarenessObserver { using (GetObserverTPerfMarker.Auto()) { return GetDataProvider(name); } } #region IMixedRealityDataProviderAccess Implementation private static readonly ProfilerMarker GetDataProvidersPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.GetDataProviders"); /// public override IReadOnlyList GetDataProviders() { using (GetDataProvidersPerfMarker.Auto()) { if (!typeof(IMixedRealitySpatialAwarenessObserver).IsAssignableFrom(typeof(T))) { return null; } return base.GetDataProviders(); } } private static readonly ProfilerMarker GetDataProviderPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.GetDataProvider"); /// public override T GetDataProvider(string name = null) { using (GetDataProviderPerfMarker.Auto()) { if (!typeof(IMixedRealitySpatialAwarenessObserver).IsAssignableFrom(typeof(T))) { return default(T); } return base.GetDataProvider(name); } } #endregion IMixedRealityDataProviderAccess Implementation private static readonly ProfilerMarker ResumeObserversPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.ResumeObservers"); /// public void ResumeObservers() { using (ResumeObserversPerfMarker.Auto()) { foreach (var observer in GetDataProviders()) { observer.Resume(); } } } private static readonly ProfilerMarker ResumeObserversTPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.ResumeObservers"); /// public void ResumeObservers() where T : IMixedRealitySpatialAwarenessObserver { using (ResumeObserversTPerfMarker.Auto()) { foreach (var observer in GetDataProviders()) { if (observer is T) { observer.Resume(); } } } } private static readonly ProfilerMarker ResumeObserverPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.ResumeObserver"); /// public void ResumeObserver(string name) where T : IMixedRealitySpatialAwarenessObserver { using (ResumeObserverPerfMarker.Auto()) { foreach (var observer in GetDataProviders()) { if (observer is T && observer.Name == name) { observer.Resume(); break; } } } } private static readonly ProfilerMarker SuspendObserversPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.SuspendObservers"); /// public void SuspendObservers() { using (SuspendObserversPerfMarker.Auto()) { foreach (var observer in GetDataProviders()) { observer.Suspend(); } } } private static readonly ProfilerMarker SuspendObserversTPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.SuspendObservers"); /// public void SuspendObservers() where T : IMixedRealitySpatialAwarenessObserver { using (SuspendObserversTPerfMarker.Auto()) { foreach (var observer in GetDataProviders()) { if (observer is T) { observer.Suspend(); } } } } private static readonly ProfilerMarker SuspendObserverPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.SuspendObserver"); /// public void SuspendObserver(string name) where T : IMixedRealitySpatialAwarenessObserver { using (SuspendObserverPerfMarker.Auto()) { foreach (var observer in GetDataProviders()) { if (observer is T && observer.Name == name) { observer.Suspend(); break; } } } } private static readonly ProfilerMarker ClearObservationsPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.ClearObservations"); /// public void ClearObservations() { using (ClearObservationsPerfMarker.Auto()) { foreach (var observer in GetDataProviders()) { observer.ClearObservations(); } } } private static readonly ProfilerMarker ClearObservationsTPerfMarker = new ProfilerMarker("[MRTK] MixedRealitySpatialAwarenessSystem.ClearObservations"); /// public void ClearObservations(string name) where T : IMixedRealitySpatialAwarenessObserver { using (ClearObservationsTPerfMarker.Auto()) { T observer = GetObserver(name); observer?.ClearObservations(); } } #endregion IMixedRealitySpatialAwarenessSystem Implementation } }