using System;
using System.Collections;
using System.Collections.Generic;
#if UNITY_EDITOR
using System.Linq;
using UnityEditor;
#endif
namespace UnityEngine.XR.ARSubsystems
{
///
/// A reference image library is a collection of images to search for in the physical environment when image
/// tracking is enabled.
///
///
/// Image libraries are immutable at runtime. To create and manipulate an image library via Editor scripts, use the
/// extension methods in [XRReferenceImageLibraryExtensions](UnityEditor.XR.ARSubsystems.XRReferenceImageLibraryExtensions).
/// If you need to mutate the library at runtime, see .
///
[CreateAssetMenu(fileName="ReferenceImageLibrary", menuName="XR/Reference Image Library", order=1001)]
[HelpURL("features/image-tracking")]
public class XRReferenceImageLibrary
: ScriptableObject
, IReferenceImageLibrary
, ISerializationCallbackReceiver
, IEnumerable
{
///
/// The number of images in the library.
///
public int count => m_Images.Count;
///
/// (Read Only) Binary data associated with a string key.
///
///
/// This is used by providers to associate provider-specific data with the library. During Player Build (in an
/// [IPreprocessBuildWithReport.OnPreprocessBuild](xref:UnityEditor.Build.IPreprocessBuildWithReport.OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport))
/// callback), the data store is first cleared. Each enabled provider then has an opportunity to add one or more
/// entries for itself.
///
/// Providers can use this to store a serialized version of the image library specific to that provider.
/// Set data with .
///
public IReadOnlyDictionary dataStore => m_DataStore.dictionary;
///
/// Gets an enumerator which can be used to iterate over the reference images in this library.
///
///
/// This examples iterates over the reference images contained in the library.
///
/// XRReferenceImageLibrary imageLibrary = ...
/// foreach (var referenceImage in imageLibrary)
/// {
/// Debug.LogFormat("Image guid: {0}", referenceImage.guid);
/// }
///
///
/// Returns an enumerator which can be used to iterate over the reference images in the library.
public List.Enumerator GetEnumerator() => m_Images.GetEnumerator();
///
/// Gets an enumerator which can be used to iterate over the reference images in this library.
///
/// Returns an object which can be used to iterate over the reference images in this library.
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
///
/// Gets an enumerator which can be used to iterate over the reference images in this library.
///
/// Returns an object which can be used to iterate over the reference images in this library.
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
///
/// Get an image by index.
///
/// The index of the image in the library. Must be between 0 and count - 1.
/// The at .
/// Thrown if is not between 0 and - 1.
public XRReferenceImage this[int index]
{
get
{
if (count == 0)
throw new IndexOutOfRangeException("The reference image library is empty; cannot index into it.");
if (index < 0 || index >= count)
throw new IndexOutOfRangeException(string.Format("{0} is out of range. 'index' must be between 0 and {1}", index, count - 1));
return m_Images[index];
}
}
///
/// Get the index of in the image library.
///
/// The to find.
/// The zero-based index of the , or -1 if not found.
public int indexOf(XRReferenceImage referenceImage)
{
return m_Images.IndexOf(referenceImage);
}
///
/// A GUID associated with this reference library.
/// The GUID is used to uniquely identify this library at runtime.
///
public Guid guid => GuidUtil.Compose(m_GuidLow, m_GuidHigh);
///
/// Invoked before serialization.
///
void ISerializationCallbackReceiver.OnBeforeSerialize() => m_DataStore.Serialize();
///
/// Invoked after serialization.
///
void ISerializationCallbackReceiver.OnAfterDeserialize() => m_DataStore.Deserialize();
#if UNITY_EDITOR
internal static IEnumerable All() => AssetDatabase
.FindAssets($"t:{nameof(XRReferenceImageLibrary)}")
.Select(AssetDatabase.GUIDToAssetPath)
.Select(AssetDatabase.LoadAssetAtPath);
void Awake()
{
// We need to generate a new guid for new assets
var shouldGenerateNewGuid = (m_GuidLow == 0 && m_GuidHigh == 0);
// If this asset was duplicated from another, then we need to generate a unique guid, so
// check against all existing XRReferenceImageLibraries in the asset database.
if (!shouldGenerateNewGuid)
{
var currentGuid = guid;
shouldGenerateNewGuid = All().Any(library => library != this && library.guid.Equals(currentGuid));
}
if (shouldGenerateNewGuid)
{
var bytes = Guid.NewGuid().ToByteArray();
m_GuidLow = BitConverter.ToUInt64(bytes, 0);
m_GuidHigh = BitConverter.ToUInt64(bytes, 8);
EditorUtility.SetDirty(this);
}
}
internal void InternalClearDataStore()
{
m_DataStore.dictionary.Clear();
EditorUtility.SetDirty(this);
}
internal void InternalSetDataForKey(string key, byte[] data)
{
bool isDirty;
if (data == null)
{
isDirty = m_DataStore.dictionary.Remove(key);
}
else
{
m_DataStore.dictionary[key] = data;
isDirty = true;
}
if (isDirty)
{
EditorUtility.SetDirty(this);
}
}
#endif
#pragma warning disable CS0649
[SerializeField]
ulong m_GuidLow;
[SerializeField]
ulong m_GuidHigh;
#pragma warning restore CS0649
[SerializeField]
SerializableDictionary m_DataStore = new SerializableDictionary();
[SerializeField]
internal List m_Images = new List();
}
}