using System;
using System.Runtime.InteropServices;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Scripting;
using UnityEngine.XR.ARSubsystems;
namespace UnityEngine.XR.ARKit
{
///
/// ARKit implementation of the XRRaycastSubsystem. Do not create this directly. Use the SubsystemManager instead.
///
[Preserve]
public sealed class ARKitRaycastSubsystem : XRRaycastSubsystem
{
class ARKitProvider : Provider
{
IntPtr m_Self;
public ARKitProvider() => m_Self = NativeApi.Construct();
public override void Start()
{
if (m_Self != IntPtr.Zero)
{
NativeApi.Start(m_Self);
}
}
public override void Stop()
{
if (m_Self != IntPtr.Zero)
{
NativeApi.Stop(m_Self);
}
}
public override void Destroy() => NSObject.Dispose(ref m_Self);
public override unsafe TrackableChanges GetChanges(XRRaycast defaultRaycast, Allocator allocator)
{
if (m_Self == IntPtr.Zero)
return default;
NativeApi.AcquireChanges(m_Self,
out XRRaycast* added, out int addedCount,
out XRRaycast* updated, out int updatedCount,
out TrackableId* removed, out int removedCount,
out int elementSize);
try
{
return new TrackableChanges(
added, addedCount,
updated, updatedCount,
removed, removedCount,
defaultRaycast, elementSize, allocator);
}
finally
{
NativeApi.ReleaseChanges(added, updated, removed);
}
}
public override bool TryAddRaycast(Ray ray, float estimatedDistance, out XRRaycast sessionRelativeData)
{
if (m_Self == IntPtr.Zero)
{
sessionRelativeData = default;
return false;
}
return NativeApi.TryAddRaycast(m_Self, ray.origin, ray.direction, estimatedDistance, out sessionRelativeData);
}
public override void RemoveRaycast(TrackableId trackableId)
{
if (m_Self != IntPtr.Zero)
{
NativeApi.RemoveRaycast(m_Self, trackableId);
}
}
public override unsafe NativeArray Raycast(
XRRaycastHit defaultRaycastHit,
Vector2 screenPoint,
TrackableType trackableTypeMask,
Allocator allocator)
{
void* hitResults;
int count;
NativeApi.UnityARKit_Raycast_AcquireHitResults(
screenPoint,
trackableTypeMask,
out hitResults,
out count);
var results = new NativeArray(count, allocator);
NativeApi.UnityARKit_Raycast_CopyAndReleaseHitResults(
UnsafeUtility.AddressOf(ref defaultRaycastHit),
UnsafeUtility.SizeOf(),
hitResults,
results.GetUnsafePtr());
return results;
}
}
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
static void RegisterDescriptor()
{
if (!Api.AtLeast11_0())
return;
XRRaycastSubsystemDescriptor.Register(new XRRaycastSubsystemDescriptor.Cinfo
{
id = "ARKit-Raycast",
providerType = typeof(ARKitRaycastSubsystem.ARKitProvider),
subsystemTypeOverride = typeof(ARKitRaycastSubsystem),
supportsViewportBasedRaycast = true,
supportsWorldBasedRaycast = false,
supportedTrackableTypes =
TrackableType.Planes |
TrackableType.FeaturePoint,
supportsTrackedRaycasts = Api.AtLeast13_0(),
});
}
static class NativeApi
{
#if UNITY_XR_ARKIT_LOADER_ENABLED
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_AcquireHitResults")]
public static unsafe extern void UnityARKit_Raycast_AcquireHitResults(
Vector2 screenPoint,
TrackableType filter,
out void* hitResults,
out int hitCount);
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_CopyAndReleaseHitResults")]
public static unsafe extern void UnityARKit_Raycast_CopyAndReleaseHitResults(
void* defaultHit,
int stride,
void* hitResults,
void* dstBuffer);
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_Construct")]
public static extern IntPtr Construct();
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_Start")]
public static extern void Start(IntPtr self);
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_Stop")]
public static extern void Stop(IntPtr self);
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_AcquireChanges")]
public static extern unsafe void AcquireChanges(IntPtr self,
out XRRaycast* added, out int addedCount,
out XRRaycast* updated, out int updatedCount,
out TrackableId* removed, out int removedCount,
out int elementSize);
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_ReleaseChanges")]
public static extern unsafe void ReleaseChanges(XRRaycast* added, XRRaycast* updated, TrackableId* removed);
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_TryAddRaycast")]
public static extern bool TryAddRaycast(IntPtr self, Vector3 origin, Vector3 direction, float estimatedDistance, out XRRaycast raycast);
[DllImport("__Internal", EntryPoint = "UnityARKit_Raycast_RemoveRaycast")]
public static extern void RemoveRaycast(IntPtr self, TrackableId trackableId);
#else
static readonly string k_ExceptionMsg = "Apple ARKit XR Plug-in Provider not enabled in project settings.";
public static unsafe void UnityARKit_Raycast_AcquireHitResults(
Vector2 screenPoint,
TrackableType filter,
out void* hitResults,
out int hitCount)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static unsafe void UnityARKit_Raycast_CopyAndReleaseHitResults(
void* defaultHit,
int stride,
void* hitResults,
void* dstBuffer)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static IntPtr Construct()
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static void Start(IntPtr self)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static void Stop(IntPtr self)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static unsafe void AcquireChanges(IntPtr self,
out XRRaycast* added, out int addedCount,
out XRRaycast* updated, out int updatedCount,
out TrackableId* removed, out int removedCount,
out int elementSize)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static unsafe void ReleaseChanges(XRRaycast* added, XRRaycast* updated, TrackableId* removed)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static bool TryAddRaycast(IntPtr self, Vector3 origin, Vector3 direction, float estimatedDistance, out XRRaycast raycast)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
public static void RemoveRaycast(IntPtr self, TrackableId trackableId)
{
throw new System.NotImplementedException(k_ExceptionMsg);
}
#endif
}
}
}