using System;
using Unity.Collections;
namespace UnityEngine.XR.ARSubsystems
{
///
/// An abstract class that provides a generic API for low-level face tracking features.
///
///
/// This class can be used to access face tracking features in your app via accessing the generic API.
/// It can also be extended to provide an implementation of a provider which provides the face tracking data
/// to the higher level code.
///
public abstract class XRFaceSubsystem : TrackingSubsystem
{
///
/// Constructs a face subsystem. Do not invoked directly; call Create on the instead.
///
public XRFaceSubsystem() => m_Provider = CreateProvider();
///
/// Start the face subsystem, i.e., start tracking faces.
///
protected sealed override void OnStart() => m_Provider.Start();
///
/// Destroy the face subsystem.
///
protected sealed override void OnDestroyed() => m_Provider.Destroy();
///
/// Stop the subsystem, i.e., stop tracking faces.
///
protected sealed override void OnStop() => m_Provider.Stop();
///
/// Get or set the maximum number of faces to track simultaneously.
///
public int maximumFaceCount
{
get => m_Provider.maximumFaceCount;
set => m_Provider.maximumFaceCount = value;
}
///
/// Get the number of faces the subsystem is able to track simultaneously.
///
public int supportedFaceCount => m_Provider.supportedFaceCount;
///
/// Get the changes (added, updated, and removed) faces since the last call to .
///
/// An Allocator to use when allocating the returned NativeArrays.
///
/// describing the faces that have been added, updated, and removed
/// since the last call to . The caller owns the memory allocated with Allocator.
///
public override TrackableChanges GetChanges(Allocator allocator)
{
var changes = m_Provider.GetChanges(XRFace.defaultValue, allocator);
#if DEVELOPMENT_BUILD || UNITY_EDITOR
m_ValidationUtility.ValidateAndDisposeIfThrown(changes);
#endif
return changes;
}
///
/// Get the mesh data associated with the face with . The
/// is reused if it is the correct size, otherwise, it is disposed and reallocated using .
///
/// The for a .
/// The allocator to use for the returned data if a resize is necessary. Must be Allocator.TempJob or Allocator.Persistent.
/// The container for the mesh data to either re-use or re-allocate.
/// Thrown if is Allocator.Temp
/// Thrown if is Allocator.None
public virtual void GetFaceMesh(TrackableId faceId, Allocator allocator, ref XRFaceMesh faceMesh)
{
if (allocator == Allocator.Temp)
throw new InvalidOperationException("Allocator.Temp is not supported. Use Allocator.TempJob if you wish to use a temporary allocator.");
if (allocator == Allocator.None)
throw new InvalidOperationException("Allocator.None is not a valid allocator.");
m_Provider.GetFaceMesh(faceId, allocator, ref faceMesh);
}
///
/// Creates an instance of an implementation-specific .
///
/// An implementation of the class.
protected abstract Provider CreateProvider();
///
/// Class to be implemented by an implementor of the .
///
protected abstract class Provider
{
///
/// Called by . Only invoked if not already running.
///
public virtual void Start() { }
///
/// Called by . Only invoked if current running.
///
public virtual void Stop() { }
///
/// Called by when the subsystem is destroyed.
///
public virtual void Destroy() { }
///
/// Get the mesh data associated with the face with . The
/// should be reused if it is the correct size, otherwise, its arrays should be reallocated with .
/// Use to ensure unused NativeArrays are disposed properly and
/// to resize individual arrays.
///
/// The for a .
/// The allocator to use for the returned data if a resize is necessary.
/// The container for the mesh data to either re-use or re-allocate.
///
///
/// var vertices = faceMesh.vertices;
/// CreateOrResizeNativeArrayIfNecessary(numVertices, allocator, ref vertices);
///
/// ...
///
/// faceMesh.Assign(new XRFaceMesh
/// {
/// vertices = vertices,
/// indices = ...
/// });
///
///
public virtual void GetFaceMesh(TrackableId faceId, Allocator allocator, ref XRFaceMesh faceMesh)
{
faceMesh.Dispose();
faceMesh = default(XRFaceMesh);
}
///
/// Get the changes (added, updated, and removed) faces since the last call to .
///
///
/// The default face. This should be used to initialize the returned NativeArrays for backwards compatibility.
/// See .
///
/// An Allocator to use when allocating the returned NativeArrays.
///
/// describing the faces that have been added, updated, and removed
/// since the last call to . The changes should be allocated using
/// .
///
public abstract TrackableChanges GetChanges(XRFace defaultFace, Allocator allocator);
///
/// Should return the maximum number of faces the subsystem is able to track simultaneously.
/// Defaults to 1.
///
public virtual int supportedFaceCount => 1;
///
/// Get or set the maximum number of faces the subsystem should attempt to track simultaneously.
/// Defaults to 1.
///
public virtual int maximumFaceCount
{
get => 1;
set
{
if (maximumFaceCount < 1)
throw new ArgumentOutOfRangeException("value", "Must track at least one face. Call Stop() if you wish to stop face tracking.");
if (maximumFaceCount > 1)
throw new NotSupportedException("This subsystem does not support multiple faces.");
}
}
}
Provider m_Provider;
#if DEVELOPMENT_BUILD || UNITY_EDITOR
ValidationUtility m_ValidationUtility =
new ValidationUtility();
#endif
}
}