SW 중심대학 OSS GIT 서버 박건태, 이승준, 고기완, 이준호 새로운 배포
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
14 KiB

4 years ago
  1. using System;
  2. using Unity.Jobs;
  3. using Unity.Collections;
  4. using Unity.Collections.LowLevel.Unsafe;
  5. namespace UnityEngine.XR.ARSubsystems
  6. {
  7. /// <summary>
  8. /// A reference image library that can be constructed and modified at runtime.
  9. /// By contrast, an <see cref="XRReferenceImageLibrary"/> can only be constructed
  10. /// at edit-time and is immutable at runtime.
  11. /// </summary>
  12. /// <remarks>
  13. /// Subsystem providers must implement this class for their provider if
  14. /// <see cref="XRImageTrackingSubsystemDescriptor.supportsMutableLibrary"/>
  15. /// is <c>true</c> to provide the functionality to support runtime mutable libraries.
  16. /// This is not something consumers of the ARSubsystems package should implement.
  17. /// </remarks>
  18. /// <seealso cref="XRImageTrackingSubsystem.CreateRuntimeLibrary(XRReferenceImageLibrary)"/>
  19. public abstract class MutableRuntimeReferenceImageLibrary : RuntimeReferenceImageLibrary
  20. {
  21. /// <summary>
  22. /// This method should schedule a [Unity Job](https://docs.unity3d.com/Manual/JobSystem.html)
  23. /// which adds an image to this reference image library.
  24. /// </summary>
  25. /// <param name="imageBytes">The raw image bytes in <paramref name="format"/>. Assume the bytes will be valid until the job completes.</param>
  26. /// <param name="sizeInPixels">The width and height of the image, in pixels.</param>
  27. /// <param name="format">The format of <paramref name="imageBytes"/>. The format has already been validated with <see cref="IsTextureFormatSupported(TextureFormat)"/>.<param>
  28. /// <param name="referenceImage">The <see cref="XRReferenceImage"/> data associated with the image to add to the library.
  29. /// This includes information like physical dimensions, associated <c>Texture2D</c> (optional), and string name.</param>
  30. /// <param name="inputDeps">Input dependencies for the add image job.</param>
  31. /// <returns>A [JobHandle](https://docs.unity3d.com/ScriptReference/Unity.Jobs.JobHandle.html) which can be used
  32. /// to chain together multiple tasks or to query for completion.</returns>
  33. /// <seealso cref="ScheduleAddImageJob(NativeSlice<byte>, Vector2Int, TextureFormat, XRReferenceImage, JobHandle)"/>
  34. protected abstract JobHandle ScheduleAddImageJobImpl(
  35. NativeSlice<byte> imageBytes,
  36. Vector2Int sizeInPixels,
  37. TextureFormat format,
  38. XRReferenceImage referenceImage,
  39. JobHandle inputDeps);
  40. /// <summary>
  41. /// Asynchronously adds an image to this library.
  42. /// </summary>
  43. /// <remarks>
  44. /// <para>
  45. /// Image addition can take some time (several frames) due to extra processing that
  46. /// must occur to insert the image into the library. This is done using
  47. /// the [Unity Job System](https://docs.unity3d.com/Manual/JobSystem.html). The returned
  48. /// [JobHandle](https://docs.unity3d.com/ScriptReference/Unity.Jobs.JobHandle.html) can be used
  49. /// to chain together multiple tasks or to query for completion, but may be safely discarded if you do not need it.
  50. /// </para><para>
  51. /// This job, like all Unity jobs, can have dependencies (using the <paramref name="inputDeps"/>). This can be useful,
  52. /// for example, if <paramref name="imageBytes"/> is the output of another job. If you are adding multiple
  53. /// images to the library, it is not necessary to pass a previous <c>ScheduleAddImageJob</c> JobHandle as the input
  54. /// dependency to the next <c>ScheduleAddImageJob</c>; they can be processed concurrently.
  55. /// </para><para>
  56. /// The <paramref name="imageBytes"/> must be valid until this job completes. The caller is responsible for managing its memory.
  57. /// </para>
  58. /// </remarks>
  59. /// <param name="imageBytes">The raw image bytes in <paramref name="format"/>.</param>
  60. /// <param name="sizeInPixels">The width and height of the image, in pixels.</param>
  61. /// <param name="format">The format of <paramref name="imageBytes"/>. Test for and enumerate supported formats with
  62. /// <see cref="supportedTextureFormatCount"/>, <see cref="GetSupportedTextureFormatAt(int)"/>, and <see cref="IsTextureFormatSupported(TextureFormat)"/>.</param>
  63. /// <param name="referenceImage">The <see cref="XRReferenceImage"/> data associated with the image to add to the library.
  64. /// This includes information like physical dimensions, associated <c>Texture2D</c> (optional), and string name.
  65. /// The <see cref="XRReferenceImage.guid"/> must be set to zero (empty).
  66. /// A new guid is automatically generated for the new image.</param>
  67. /// <param name="inputDeps">(Optional) input dependencies for the add image job.</param>
  68. /// <returns>A [JobHandle](https://docs.unity3d.com/ScriptReference/Unity.Jobs.JobHandle.html) which can be used
  69. /// to chain together multiple tasks or to query for completion. May be safely discarded.</returns>
  70. /// <exception cref="System.ArgumentException">Thrown if <paramref name="imageBytes"/> does not contain any bytes.</exception>
  71. /// <exception cref="System.ArgumentException">Thrown if <paramref name="referenceImage"/><c>.guid</c> is not <c>Guid.Empty</c>.</exception>
  72. /// <exception cref="System.ArgumentNullException">Thrown if <paramref name="referenceImage"/><c>.name</c> is <c>null</c>.</exception>
  73. /// <exception cref="System.ArgumentOutOfRangeException">Thrown if <paramref name="referenceImage"/><c>.specifySize</c> is <c>true</c> and <paramref name="referenceImage"/><c>.size.x</c> contains a value less than or equal to zero.</exception>
  74. /// <exception cref="System.InvalidOperationException">Thrown if <paramref name="texture"/>'s format is not supported. You can query for support using <c>XRImageTrackingSubsystem.IsTextureFormatSupported</c>.</exception>
  75. /// <exception cref="System.ArgumentOutOfRangeException">Thrown if <paramref name="sizeInPixels"/><c>.x</c> or <paramref name="sizeInPixels"/><c>.y</c> is less than or equal to zero.</exception>
  76. public JobHandle ScheduleAddImageJob(
  77. NativeSlice<byte> imageBytes,
  78. Vector2Int sizeInPixels,
  79. TextureFormat format,
  80. XRReferenceImage referenceImage,
  81. JobHandle inputDeps = default(JobHandle))
  82. {
  83. unsafe
  84. {
  85. if (imageBytes.GetUnsafePtr() == null)
  86. throw new ArgumentException($"{nameof(imageBytes)} does not contain any bytes.", nameof(imageBytes));
  87. }
  88. if (!referenceImage.guid.Equals(Guid.Empty))
  89. throw new ArgumentException($"{nameof(referenceImage)}.{nameof(referenceImage.guid)} must be empty (all zeroes).", $"{nameof(referenceImage)}.{nameof(referenceImage.guid)}");
  90. // Generate and assign a new guid for the new image
  91. referenceImage.m_SerializedGuid = GenerateNewGuid();
  92. if (string.IsNullOrEmpty(referenceImage.name))
  93. throw new ArgumentNullException($"{nameof(referenceImage)}.{nameof(referenceImage.name)}");
  94. if (referenceImage.specifySize && referenceImage.size.x <= 0)
  95. throw new ArgumentOutOfRangeException($"{nameof(referenceImage)}.{nameof(referenceImage.size)}", referenceImage.size.x, $"Invalid physical image dimensions.");
  96. if (!IsTextureFormatSupported(format))
  97. throw new InvalidOperationException($"The texture format {format} is not supported by the current image tracking subsystem.");
  98. if (sizeInPixels.x <= 0)
  99. throw new ArgumentOutOfRangeException($"{nameof(sizeInPixels)}.{nameof(sizeInPixels.x)}", sizeInPixels.x, "Image width must be greater than zero.");
  100. if (sizeInPixels.y <= 0)
  101. throw new ArgumentOutOfRangeException($"{nameof(sizeInPixels)}.{nameof(sizeInPixels.y)}", sizeInPixels.y, "Image height must be greater than zero.");
  102. return ScheduleAddImageJobImpl(imageBytes, sizeInPixels, format, referenceImage, inputDeps);
  103. }
  104. /// <summary>
  105. /// The number of texture formats that are supported for image addition.
  106. /// </summary>
  107. public abstract int supportedTextureFormatCount { get; }
  108. /// <summary>
  109. /// Returns the supported texture format at <paramref name="index"/>. Useful for enumerating the supported texture formats for image addition.
  110. /// </summary>
  111. /// <param name="index">The index of the format to retrieve.</param>
  112. /// <returns>The supported format at <paramref name="index"/>.</returns>
  113. public TextureFormat GetSupportedTextureFormatAt(int index)
  114. {
  115. if (index < 0)
  116. throw new ArgumentOutOfRangeException(nameof(index), index, $"{nameof(index)} must be greater than or equal to zero.");
  117. if (index >= supportedTextureFormatCount)
  118. throw new ArgumentOutOfRangeException(nameof(index), index, $"{nameof(index)} must be less than {nameof(supportedTextureFormatCount)} ({supportedTextureFormatCount}).");
  119. return GetSupportedTextureFormatAtImpl(index);
  120. }
  121. /// <summary>
  122. /// Derived methods should return the [TextureFormat](https://docs.unity3d.com/ScriptReference/TextureFormat.html) at the given <paramref name="index"/>.
  123. /// <paramref name="index"/> has already been validated to be within [0..<see cref="supportedTextureFormatCount"/>).
  124. /// </summary>
  125. /// <param name="index">The index of the format to retrieve.</param>
  126. /// <returns>The supported format at <paramref name="index"/>.</returns>
  127. protected abstract TextureFormat GetSupportedTextureFormatAtImpl(int index);
  128. /// <summary>
  129. /// Determines whether the given <paramref name="format"/> is supported.
  130. /// </summary>
  131. /// <param name="format">The [TextureFormat](https://docs.unity3d.com/ScriptReference/TextureFormat.html) to test.</param>
  132. /// <returns><c>true</c> if <paramref name="format"/> is supported for image addition; otherwise <c>false</c>.</returns>
  133. public bool IsTextureFormatSupported(TextureFormat format)
  134. {
  135. int n = supportedTextureFormatCount;
  136. for (int i = 0; i < n; ++i)
  137. {
  138. if (GetSupportedTextureFormatAtImpl(i) == format)
  139. return true;
  140. }
  141. return false;
  142. }
  143. /// <summary>
  144. /// Gets an enumerator for this collection of reference images. This allows this image library to act as a collection in a <c>foreach</c> statement.
  145. /// The <see cref="Enumerator"/> is a <c>struct</c>, so no garbage is generated.
  146. /// </summary>
  147. /// <returns>An enumerator that can be used in a <c>foreach</c> statement.</returns>
  148. public Enumerator GetEnumerator()
  149. {
  150. return new Enumerator(this);
  151. }
  152. // Converts a System.Guid into two ulongs
  153. static unsafe SerializableGuid GenerateNewGuid()
  154. {
  155. var newGuid = Guid.NewGuid();
  156. var trackableId = *(TrackableId*)&newGuid;
  157. return new SerializableGuid(trackableId.subId1, trackableId.subId2);
  158. }
  159. /// <summary>
  160. /// An enumerator to be used in a <c>foreach</c> statement.
  161. /// </summary>
  162. public struct Enumerator : IEquatable<Enumerator>
  163. {
  164. internal Enumerator(MutableRuntimeReferenceImageLibrary lib)
  165. {
  166. m_Library = lib;
  167. m_Index = -1;
  168. }
  169. MutableRuntimeReferenceImageLibrary m_Library;
  170. int m_Index;
  171. /// <summary>
  172. /// Moves to the next element in the collection.
  173. /// </summary>
  174. /// <returns><c>true</c> if <see cref="Current"/> is valid after this call.</returns>
  175. public bool MoveNext() => ++m_Index < m_Library.count;
  176. /// <summary>
  177. /// The current <see cref="XRReferenceImage"/>.
  178. /// </summary>
  179. public XRReferenceImage Current => m_Library[m_Index];
  180. /// <summary>
  181. /// Disposes of the enumerator. This method does nothing.
  182. /// </summary>
  183. public void Dispose() {}
  184. /// <summary>
  185. /// Generates a hash code suitable for use in a Dictionary or HashSet.
  186. /// </summary>
  187. /// <returns>A hash code of this Enumerator.</returns>
  188. public override int GetHashCode()
  189. {
  190. unchecked
  191. {
  192. var hash = ReferenceEquals(m_Library, null) ? 0 : m_Library.GetHashCode();
  193. return hash * 486187739 + m_Index.GetHashCode();
  194. }
  195. }
  196. /// <summary>
  197. /// Compares for equality.
  198. /// </summary>
  199. /// <param name="obj">The <c>object</c> to compare against.</param>
  200. /// <returns><c>true</c> if <paramref name="obj"/> is of type <see cref="Enumerator"/> and <see cref="Equals(Enumerator)"/> is <c>true</c>.</returns>
  201. public override bool Equals(object obj) => (obj is Enumerator) && Equals((Enumerator)obj);
  202. /// <summary>
  203. /// Compares for equality.
  204. /// </summary>
  205. /// <param name="other">The other enumerator to compare against.</param>
  206. /// <returns><c>true</c> if the other enumerator is equal to this one.</returns>
  207. public bool Equals(Enumerator other)
  208. {
  209. return
  210. ReferenceEquals(m_Library, other.m_Library) &&
  211. (m_Index == other.m_Index);
  212. }
  213. /// <summary>
  214. /// Compares for equality.
  215. /// </summary>
  216. /// <param name="lhs">The left-hand side of the comparison.</param>
  217. /// <param name="rhs">The right-hand side of the comparison.</param>
  218. /// <returns>The same as <see cref="Equals(Enumerator)"/>.</returns>
  219. public static bool operator ==(Enumerator lhs, Enumerator rhs) => lhs.Equals(rhs);
  220. /// <summary>
  221. /// Compares for inequality.
  222. /// </summary>
  223. /// <param name="lhs">The left-hand side of the comparison.</param>
  224. /// <param name="rhs">The right-hand side of the comparison.</param>
  225. /// <returns>The negation of <see cref="Equals(Enumerator)"/>.</returns>
  226. public static bool operator !=(Enumerator lhs, Enumerator rhs) => !lhs.Equals(rhs);
  227. }
  228. }
  229. }