using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Scripting;
using UnityEngine.XR.ARSubsystems;
namespace UnityEngine.XR.ARKit
{
///
/// Registration utility to register the ARKit human body subsystem.
///
internal static class ARKitHumanBodyRegistration
{
///
/// Register the ARKit human body subsystem if iOS and not the editor.
///
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void Register()
{
#if UNITY_IOS && !UNITY_EDITOR
const string k_SubsystemId = "ARKit-HumanBody";
XRHumanBodySubsystemCinfo humanBodySubsystemCinfo = new XRHumanBodySubsystemCinfo()
{
id = k_SubsystemId,
implementationType = typeof(ARKitHumanBodySubsystem),
supportsHumanBody2D = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodyPose2DEstimation(),
supportsHumanBody3D = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DEstimation(),
supportsHumanBody3DScaleEstimation = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DScaleEstimation(),
supportsHumanStencilImage = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationStencil(),
supportsHumanDepthImage = NativeApi.UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationDepth(),
};
if (!XRHumanBodySubsystem.Register(humanBodySubsystemCinfo))
{
Debug.LogErrorFormat("Cannot register the {0} subsystem", k_SubsystemId);
}
#endif
}
///
/// Container to wrap the native ARKit human body APIs.
///
static class NativeApi
{
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodyPose2DEstimation();
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DEstimation();
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodyPose3DScaleEstimation();
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationStencil();
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_DoesSupportBodySegmentationDepth();
}
}
///
/// This subsystem provides implementing functionality for the XRHumanBodySubsystem class.
///
[Preserve]
class ARKitHumanBodySubsystem : XRHumanBodySubsystem
{
///
/// Create the implementation provider.
///
///
/// The implementation provider.
///
protected override Provider CreateProvider()
{
return new ARKitProvider();
}
///
/// The implementation provider class.
///
class ARKitProvider : XRHumanBodySubsystem.Provider
{
///
/// Construct the implementation provider.
///
public ARKitProvider() => NativeApi.UnityARKit_HumanBodyProvider_Construct();
///
/// Start the provider.
///
public override void Start() => NativeApi.UnityARKit_HumanBodyProvider_Start();
///
/// Stop the provider.
///
public override void Stop() => NativeApi.UnityARKit_HumanBodyProvider_Stop();
///
/// Destroy the human body subsystem by first ensuring that the subsystem has been stopped and then
/// destroying the provider.
///
public override void Destroy() => NativeApi.UnityARKit_HumanBodyProvider_Destruct();
///
/// Sets whether human body pose 2D estimation is enabled.
///
/// Whether the human body pose 2D estimation should be enabled.
///
///
/// true if the human body pose 2D estimation is set to the given value. Otherwise, false.
///
///
/// Current restrictions limit either human body pose estimation to be enabled or human segmentation images
/// to be enabled. At this time, these features are mutually exclusive.
///
public override bool TrySetHumanBodyPose2DEstimationEnabled(bool enabled)
{
return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanBodyPose2DEstimationEnabled(enabled);
}
///
/// Sets whether human body pose 3D estimation is enabled.
///
/// Whether the human body pose 3D estimation should be enabled.
///
///
/// true if the human body pose 3D estimation is set to the given value. Otherwise, false.
///
///
/// Current restrictions limit either human body pose estimation to be enabled or human segmentation images
/// to be enabled. At this time, these features are mutually exclusive.
///
public override bool TrySetHumanBodyPose3DEstimationEnabled(bool enabled)
{
return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DEstimationEnabled(enabled);
}
///
/// Sets whether 3D human body scale estimation is enabled.
///
/// Whether the 3D human body scale estimation should be enabled.
///
///
/// true if the 3D human body scale estimation is set to the given value. Otherwise, false.
///
public override bool TrySetHumanBodyPose3DScaleEstimationEnabled(bool enabled)
{
return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DScaleEstimationEnabled(enabled);
}
///
/// Set the human segmentation stencil mode.
///
/// The mode for the human segmentation stencil.
///
/// true if the method successfully set the human segmentation stencil mode. Otherwise,
/// false.
///
///
/// Current restrictions limit either human body pose estimation to be enabled or human segmentation images
/// to be enabled. At this time, these features are mutually exclusive.
///
public override bool TrySetHumanSegmentationStencilMode(HumanSegmentationMode humanSegmentationStencilMode)
{
return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanSegmentationStencilMode(humanSegmentationStencilMode);
}
///
/// Set the human segmentation depth mode.
///
/// The mode for the human segmentation depth.
///
/// true if the method successfully set the human segmentation depth mode. Otherwise,
/// false.
///
///
/// Current restrictions limit either human body pose estimation to be enabled or human segmentation images
/// to be enabled. At this time, these features are mutually exclusive.
///
public override bool TrySetHumanSegmentationDepthMode(HumanSegmentationMode humanSegmentationDepthMode)
{
return NativeApi.UnityARKit_HumanBodyProvider_TrySetHumanSegmentationDepthMode(humanSegmentationDepthMode);
}
///
/// Queries for the set of human body changes.
///
/// The default human body.
/// The memory allocator to use for the returns trackable changes.
///
/// The set of human body changes.
///
public override unsafe TrackableChanges GetChanges(XRHumanBody defaultHumanBody, Allocator allocator)
{
int numAddedHumanBodies;
void* addedHumanBodiesPointer;
int numUpdatedHumanBodies;
void* updatedHumanBodiesPointer;
int numRemovedHumanBodyIds;
void* removedHumanBodyIdsPointer;
int stride;
var context = NativeApi.UnityARKit_HumanBodyProvider_AcquireChanges(out numAddedHumanBodies, out addedHumanBodiesPointer,
out numUpdatedHumanBodies, out updatedHumanBodiesPointer,
out numRemovedHumanBodyIds, out removedHumanBodyIdsPointer,
out stride);
try
{
// Wrap the navite pointers into a native array and then copy them into a separate native array enabled
// with temporary allocations.
return new TrackableChanges(
addedHumanBodiesPointer, numAddedHumanBodies,
updatedHumanBodiesPointer, numUpdatedHumanBodies,
removedHumanBodyIdsPointer, numRemovedHumanBodyIds,
defaultHumanBody, stride,
allocator);
}
finally
{
NativeApi.UnityARKit_HumanBodyProvider_ReleaseChanges(context);
}
}
///
/// Get the skeleton joints for the requested trackable identifier.
///
/// The human body trackable identifier for which to query.
/// The memory allocator to use for the returned arrays.
/// The array of skeleton joints to update and returns.
public override unsafe void GetSkeleton(TrackableId trackableId, Allocator allocator, ref NativeArray skeleton)
{
int numJoints;
void* joints = NativeApi.UnityARKit_HumanBodyProvider_AcquireJoints(trackableId, out numJoints);
try
{
if (joints == null)
{
numJoints = 0;
}
if (!skeleton.IsCreated || (skeleton.Length != numJoints))
{
if (skeleton.IsCreated)
{
skeleton.Dispose();
}
skeleton = new NativeArray(numJoints, allocator);
}
if (joints != null)
{
NativeArray tmp = NativeArrayUnsafeUtility.ConvertExistingDataToNativeArray(joints, numJoints, Allocator.None);
skeleton.CopyFrom(tmp);
}
}
finally
{
NativeApi.UnityARKit_HumanBodyProvider_ReleaseJoints(joints);
}
}
///
/// Get the human body pose 2D joints for the current frame.
///
/// The default value for the human body pose 2D joint.
/// The orientation of the device so that the joint positions may be
/// adjusted as required.
/// The allocator to use for the returned array memory.
///
/// The array of human body pose 2D joints.
///
///
/// The returned array may be empty if the system is not enabled or if the system does not detect a human
/// body.
///
public override unsafe NativeArray GetHumanBodyPose2DJoints(XRHumanBodyPose2DJoint defaultHumanBodyPose2DJoint,
ScreenOrientation screenOrientation,
Allocator allocator)
{
int length, elementSize;
var joints = NativeApi.UnityARKit_HumanBodyProvider_AcquireHumanBodyPose2DJoints(screenOrientation, out length, out elementSize);
try
{
var returnJoints = NativeCopyUtility.PtrToNativeArrayWithDefault(defaultHumanBodyPose2DJoint,
joints, elementSize, length,
allocator);
return returnJoints;
}
finally
{
NativeApi.UnityARKit_HumanBodyProvider_ReleaseHumanBodyPose2DJoints(joints);
}
}
///
/// Gets the human stencil texture descriptor.
///
/// The human stencil texture descriptor to be populated, if
/// available.
///
/// true if the human stencil texture descriptor is available and is returned. Otherwise,
/// false.
///
public override bool TryGetHumanStencil(out XRTextureDescriptor humanStencilDescriptor)
{
return NativeApi.UnityARKit_HumanBodyProvider_TryGetHumanStencil(out humanStencilDescriptor);
}
///
/// Get the human depth texture descriptor.
///
/// The human depth texture descriptor to be populated, if available
///
///
/// true if the human depth texture descriptor is available and is returned. Otherwise,
/// false.
///
public override bool TryGetHumanDepth(out XRTextureDescriptor humanDepthDescriptor)
{
return NativeApi.UnityARKit_HumanBodyProvider_TryGetHumanDepth(out humanDepthDescriptor);
}
}
///
/// Container to wrap the native ARKit human body APIs.
///
static class NativeApi
{
[DllImport("__Internal")]
public static extern void UnityARKit_HumanBodyProvider_Construct();
[DllImport("__Internal")]
public static extern void UnityARKit_HumanBodyProvider_Start();
[DllImport("__Internal")]
public static extern void UnityARKit_HumanBodyProvider_Stop();
[DllImport("__Internal")]
public static extern void UnityARKit_HumanBodyProvider_Destruct();
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanBodyPose2DEstimationEnabled(bool enabled);
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DEstimationEnabled(bool enabled);
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanBodyPose3DScaleEstimationEnabled(bool enabled);
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanSegmentationStencilMode(HumanSegmentationMode humanSegmentationStencilMode);
[DllImport("__Internal")]
public static extern bool UnityARKit_HumanBodyProvider_TrySetHumanSegmentationDepthMode(HumanSegmentationMode humanSegmentationDepthMode);
[DllImport("__Internal")]
public static extern unsafe void* UnityARKit_HumanBodyProvider_AcquireChanges(out int numAddedHumanBodies, out void* addedBodys,
out int numUpdatedHumanBodies, out void* updatedBodys,
out int numRemovedHumanBodyIds, out void* removedBodyIds,
out int stride);
[DllImport("__Internal")]
public static extern unsafe void UnityARKit_HumanBodyProvider_ReleaseChanges(void* context);
[DllImport("__Internal")]
public static extern unsafe void* UnityARKit_HumanBodyProvider_AcquireJoints(TrackableId trackableId, out int numJoints);
[DllImport("__Internal")]
public static extern unsafe void UnityARKit_HumanBodyProvider_ReleaseJoints(void* joints);
[DllImport("__Internal")]
public static unsafe extern void* UnityARKit_HumanBodyProvider_AcquireHumanBodyPose2DJoints(ScreenOrientation screenOrientation,
out int length,
out int elementSize);
[DllImport("__Internal")]
public static unsafe extern void UnityARKit_HumanBodyProvider_ReleaseHumanBodyPose2DJoints(void* joints);
[DllImport("__Internal")]
public static unsafe extern bool UnityARKit_HumanBodyProvider_TryGetHumanStencil(out XRTextureDescriptor humanStencilDescriptor);
[DllImport("__Internal")]
public static unsafe extern bool UnityARKit_HumanBodyProvider_TryGetHumanDepth(out XRTextureDescriptor humanDepthDescriptor);
}
}
}