using System;
using Unity.Collections;
using UnityEngine.SubsystemsImplementation;
namespace UnityEngine.XR.ARSubsystems
{
///
/// This subsystem provides information regarding the detection of planes (that is, flat surfaces) in the real-world
/// environment.
///
///
/// This is a base class with an abstract provider type to be implemented by provider plug-in packages.
/// This class itself does not implement plane detection.
///
public class XRPlaneSubsystem
: TrackingSubsystem
{
#if DEVELOPMENT_BUILD || UNITY_EDITOR
ValidationUtility m_ValidationUtility = new();
#endif
///
/// Do not invoke this constructor directly.
///
///
/// If you are implementing your own custom subsystem [Lifecycle management](xref:xr-plug-in-management-provider#lifecycle-management),
/// use the [SubsystemManager](xref:UnityEngine.SubsystemManager)
/// to enumerate the available s, then call
/// XRPlaneSubsystemDescriptor.Register() on the desired descriptor.
///
public XRPlaneSubsystem() { }
///
/// Get or set the requested to enable different modes of detection.
///
/// Thrown if is set to
/// something other than when plane detection is not supported.
public PlaneDetectionMode requestedPlaneDetectionMode
{
get => provider.requestedPlaneDetectionMode;
set => provider.requestedPlaneDetectionMode = value;
}
///
/// Get the current in use by the provider.
///
public PlaneDetectionMode currentPlaneDetectionMode => provider.currentPlaneDetectionMode;
///
/// Gets a struct containing any changes to detected planes since the last
/// time you called this method. You are responsible to the returned
/// TrackableChanges instance.
///
/// An Allocator to use for the returned NativeArrays.
/// The .
///
/// The struct returned by this method contains separate
/// objects for the added, updated, and removed planes. These arrays are created
/// using the type specified by .
///
public override TrackableChanges GetChanges(Allocator allocator)
{
var changes = provider.GetChanges(BoundedPlane.defaultValue, allocator);
#if DEVELOPMENT_BUILD || UNITY_EDITOR
m_ValidationUtility.ValidateAndDisposeIfThrown(changes);
#endif
return changes;
}
///
/// Gets the boundary vertices of a given based on its .
///
/// The of a .
/// An to use if needs to be created.
/// is not supported. Use if you need temporary memory.
/// The boundary vertices will be stored here. If the given array is the same length as
/// the number of vertices, it is overwritten with the new data. Otherwise, it is disposed and recreated with
/// the correct length.
public void GetBoundary(
TrackableId trackableId,
Allocator allocator,
ref NativeArray boundary)
{
switch (allocator)
{
case Allocator.Temp:
throw new InvalidOperationException("Allocator.Temp is not supported. Use Allocator.TempJob if you wish to use a temporary allocator.");
case Allocator.None:
throw new InvalidOperationException("Allocator.None is not a valid allocator.");
default:
provider.GetBoundary(trackableId, allocator, ref boundary);
break;
}
}
///
/// Creates or resizes the if necessary. If has been allocated
/// and its length is equal to , then this method does nothing. If its length is
/// different, then it is first disposed before being assigned to a new NativeArray.
///
/// The length that will have after this method returns.
/// If allocation is necessary, this allocator will be used to create the new NativeArray.
/// The array to create or resize.
/// The type of elements held by the .
protected static void CreateOrResizeNativeArrayIfNecessary(
int length,
Allocator allocator,
ref NativeArray array) where T : struct
{
if (array.IsCreated)
{
if (array.Length != length)
{
array.Dispose();
array = new NativeArray(length, allocator);
}
}
else
{
array = new NativeArray(length, allocator);
}
}
///
/// The provider API for -derived classes to implement.
///
public abstract class Provider : SubsystemProvider
{
///
/// Creates or resizes the if necessary. If
/// has been allocated and its length is equal to , then this method
/// does nothing. If its length is different, then it is first disposed before being assigned
/// to a new NativeArray.
///
/// The length that will have after this method returns.
/// If allocation is necessary, this allocator will be used to create the new NativeArray.
/// The array to create or resize.
/// The type of elements held by the .
protected static void CreateOrResizeNativeArrayIfNecessary(
int length,
Allocator allocator,
ref NativeArray array) where T : struct
{
if (array.IsCreated)
{
if (array.Length != length)
{
array.Dispose();
array = new NativeArray(length, allocator);
}
}
else
{
array = new NativeArray(length, allocator);
}
}
///
/// Gets the boundary vertices of a given based on its .
///
/// The of a .
/// An to use if needs to be created.
/// is not supported. Use if you need temporary memory.
/// The boundary vertices will be stored here. If the given array is the same length as
/// the number of vertices, it is overwritten with the new data. Otherwise, it is disposed and recreated with
/// the correct length.
///
/// See for a helper method implementation.
///
public virtual void GetBoundary(
TrackableId trackableId,
Allocator allocator,
ref NativeArray boundary)
{
throw new NotSupportedException("Boundary vertices are not supported.");
}
///
/// Gets a struct containing any changes to detected planes since the last
/// time you called this method. You are responsible to the returned
/// TrackableChanges instance.
///
/// The default plane. You should use this to initialize the returned
/// instance by passing it to the constructor
/// .
///
/// An Allocator to use when allocating the returned NativeArrays.
/// The changes to planes since the last call to this method.
public abstract TrackableChanges GetChanges(BoundedPlane defaultPlane, Allocator allocator);
///
/// Get or set the requested .
///
public abstract PlaneDetectionMode requestedPlaneDetectionMode { get; set; }
///
/// Get the current plane detection mode in use by the provider.
///
public virtual PlaneDetectionMode currentPlaneDetectionMode => PlaneDetectionMode.None;
}
}
}