Feature.cs 18 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407
using System;
using System.Collections.Generic;

namespace UnityEngine.XR.ARSubsystems
{
    /// <summary>
    /// A set of flags representing features available in AR.
    /// </summary>
    [Flags]
    public enum Feature : ulong
    {
        /// <summary>
        /// No features are selected.
        /// </summary>
        None = 0,

        /// <summary>
        /// The world-facing camera. On a phone, this is the rear camera.
        /// </summary>
        WorldFacingCamera = 1 << 0,

        /// <summary>
        /// The user-facing camera. On a phone, this is the front camera.
        /// </summary>
        UserFacingCamera = 1 << 1,

        /// <summary>
        /// Either camera (<see cref="WorldFacingCamera"/> or <see cref="UserFacingCamera"/>).
        /// </summary>
        AnyCamera = WorldFacingCamera | UserFacingCamera,

        /// <summary>
        /// Rotation only tracking, i.e., 3 degrees of freedom without positional tracking.
        /// </summary>
        RotationOnly = 1 << 2,

        /// <summary>
        /// Both position and rotation tracking, i.e., 6 degrees of freedom.
        /// </summary>
        PositionAndRotation = 1 << 3,

        /// <summary>
        /// Any tracking mode (<see cref="RotationOnly"/> or <see cref="PositionAndRotation"/>).
        /// </summary>
        AnyTrackingMode = RotationOnly | PositionAndRotation,

        /// <summary>
        /// Face detection. See <see cref="XRFaceSubsystem"/>.
        /// </summary>
        FaceTracking = 1 << 4,

        /// <summary>
        /// Plane detection. See <see cref="XRPlaneSubsystem"/>.
        /// </summary>
        PlaneTracking = 1 << 5,

        /// <summary>
        /// Image detection. See <see cref="XRImageTrackingSubsystem"/>.
        /// </summary>
        ImageTracking = 1 << 6,

        /// <summary>
        /// 3D object detection. See <see cref="XRObjectTrackingSubsystem"/>.
        /// </summary>
        ObjectTracking = 1 << 7,

        /// <summary>
        /// Environment probes. See <see cref="XREnvironmentProbeSubsystem"/>.
        /// </summary>
        EnvironmentProbes = 1 << 8,

        /// <summary>
        /// 2D human body tracking. See <see cref="XRHumanBodySubsystem"/>.
        /// </summary>
        Body2D = 1 << 9,

        /// <summary>
        /// 3D human body tracking. See <see cref="XRHumanBodySubsystem"/>.
        /// </summary>
        Body3D = 1 << 10,

        /// <summary>
        /// Estimate scale when performing 3D human body tracking, see <see cref="Body3D"/>.
        /// </summary>
        Body3DScaleEstimation = 1 << 11,

        /// <summary>
        /// People occlusion with stencil texture enabled. See <see cref="XROcclusionSubsystem"/>.
        /// </summary>
        PeopleOcclusionStencil = 1 << 12,

        /// <summary>
        /// People occlusion with depth texture enabled. See <see cref="XROcclusionSubsystem"/>.
        /// </summary>
        PeopleOcclusionDepth = 1 << 13,

        /// <summary>
        /// Collaborative session. See <see cref="XRParticipantSubsystem"/>.
        /// </summary>
        Collaboration = 1 << 14,

        /// <summary>
        /// Auto focus enabled.
        /// </summary>
        AutoFocus = 1 << 15,

        /// <summary>
        /// Light estimation for ambient intensity.
        /// </summary>
        LightEstimationAmbientIntensity = 1 << 16,

        /// <summary>
        /// Light estimation for ambient color.
        /// </summary>
        LightEstimationAmbientColor = 1 << 17,

        /// <summary>
        /// Light estimation for ambient spherical harmonics.
        /// </summary>
        LightEstimationAmbientSphericalHarmonics = 1 << 18,

        /// <summary>
        /// Light estimation for the main light's direction.
        /// </summary>
        LightEstimationMainLightDirection = 1 << 19,

        /// <summary>
        /// Light estimation for the main light's intensity.
        /// </summary>
        LightEstimationMainLightIntensity = 1 << 20,

        /// <summary>
        /// A value with all light estimation related bits set.
        /// </summary>
        AnyLightEstimation = LightEstimationAmbientIntensity | LightEstimationAmbientColor | LightEstimationAmbientSphericalHarmonics | LightEstimationMainLightDirection | LightEstimationMainLightIntensity,

        /// <summary>
        /// Instant and Tracked raycasts.
        /// </summary>
        Raycast = 1 << 21,

        /// <summary>
        /// A feature describing real-time meshing capability.
        /// </summary>
        Meshing = 1 << 22,

        /// <summary>
        /// A feature describing classification for <see cref="Meshing"/>.
        /// </summary>
        MeshClassification = 1 << 23,

        /// <summary>
        /// A feature describing the ability to surface point clouds.
        /// </summary>
        PointCloud = 1 << 24,

        /// <summary>
        /// A feature allowing environment depth iomages to be captured.
        /// </summary>
        EnvironmentDepth = 1 << 25,
    }

    /// <summary>
    /// Extension methods for <see cref="Feature"/> flags.
    /// </summary>
    public static class FeatureExtensions
    {
        /// <summary>
        /// Tests whether any of the features in <paramref name="features"/> are present in <paramref name="self"/>.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="features">The Features to test against.</param>
        /// <returns><c>true</c> if any of the features in <paramref name="features"/> are also in <paramref name="self"/>,
        /// otherwise <c>false</c>.</returns>
        public static bool Any(this Feature self, Feature features) => (self & features) != Feature.None;

        /// <summary>
        /// Tests whether all the features in <paramref name="features"/> are present in <paramref name="self"/>.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="features">The Features to test against.</param>
        /// <returns><c>true</c> if all the features in <paramref name="features"/> are also in <paramref name="self"/>,
        /// otherwise <c>false</c>.</returns>
        public static bool All(this Feature self, Feature features) => (self & features) == features;

        /// <summary>
        /// Tests whether there are any common features between <paramref name="self"/> and <paramref name="features"/>.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="features">The Features to test against.</param>
        /// <returns><c>true</c> if none of the features in <paramref name="self"/> are in <paramref name="features"/>,
        /// otherwise <c>false</c>.</returns>
        public static bool None(this Feature self, Feature features) => (self & features) == Feature.None;

        /// <summary>
        /// Computes the union of <paramref name="self"/> and <paramref name="features"/>,
        /// i.e., the set of features in <paramref name="self"/> or <paramref name="features"/> or both.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="features">Features to union with <paramref name="self"/></param>
        /// <returns>The union of <paramref name="self"/> and <paramref name="features"/>,
        /// i.e., the set of features in <paramref name="self"/> or <paramref name="features"/> or both.</returns>
        public static Feature Union(this Feature self, Feature features) => self | features;

        /// <summary>
        /// Computes the intersection of <paramref name="self"/> and <paramref name="features"/>,
        /// i.e., the set of features present in both <paramref name="self"/> and <paramref name="features"/>.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="features">Features to intersect with <paramref name="self"/></param>
        /// <returns>The intersection of <paramref name="self"/> and <paramref name="features"/>,
        /// i.e., the set of features common to both <paramref name="self"/> and <paramref name="features"/>.</returns>
        public static Feature Intersection(this Feature self, Feature features) => self & features;

        /// <summary>
        /// Computes the set difference, i.e., removes all flags in <paramref name="features"/> from <paramref name="self"/>.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="features">Features to remove from <paramref name="self"/></param>
        /// <returns>The set difference of <paramref name="self"/> and <paramref name="features"/>,
        /// i.e., all members of <paramref name="self"/> which do not belong to <paramref name="features"/>.</returns>
        public static Feature SetDifference(this Feature self, Feature features) => self & ~features;

        /// <summary>
        /// Computes the symmetric difference, i.e.,
        /// the set of all features that belong to exactly one of <paramref name="self"/> and <paramref name="features"/>
        /// (present in one but not both).
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="features">Features with which to compute the symmetric difference against <paramref name="self"/></param>
        /// <returns>The symmetric difference of <paramref name="self"/> and <paramref name="features"/>,
        /// i.e., the features that belong to <paramref name="self"/> or <paramref name="features"/>, but not both.</returns>
        public static Feature SymmetricDifference(this Feature self, Feature features) => self ^ features;

        /// <summary>
        /// Sets or removes one or more <see cref="Feature"/> flags.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <param name="feature">The <see cref="Feature"/>(s) to set or remove.</param>
        /// <param name="enabled">If <c>true</c>, the flag(s) in <paramref name="feature"/> will be set. If <c>false</c>, it/they will be removed.</param>
        /// <returns><paramref name="self"/> with the <see cref="Feature"/>(s) set or removed according to the value of <paramref name="enabled"/>.</returns>
        public static Feature SetEnabled(this Feature self, Feature feature, bool enabled) => enabled ? self | feature : self & ~feature;

        /// <summary>
        /// Filters just the camera-related <see cref="Feature"/> flags.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <returns>The camera-related <see cref="Feature"/> flags from <paramref name="self"/>.</returns>
        /// <seealso cref="Feature.AnyCamera"/>
        public static Feature Cameras(this Feature self) => self.Intersection(Feature.AnyCamera);

        /// <summary>
        /// Filters just the tracking-related <see cref="Feature"/> flags.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <returns>The tracking-related <see cref="Feature"/> flags from <paramref name="self"/>.</returns>
        /// <seealso cref="Feature.AnyTrackingMode"/>
        public static Feature TrackingModes(this Feature self) => self.Intersection(Feature.AnyTrackingMode);

        /// <summary>
        /// Filters just the light estimation related <see cref="Feature"/> flags.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <returns>The light estimation related <see cref="Feature"/> flags from <paramref name="self"/>.</returns>
        public static Feature LightEstimation(this Feature self) => self.Intersection(Feature.AnyLightEstimation);

        /// <summary>
        /// Removes all camera and tracking-related <see cref="Feature"/> flags.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <returns><paramref name="self"/> with camera and tracking-related bits removed.</returns>
        /// <seealso cref="Feature.AnyCamera"/>
        /// <seealso cref="Feature.AnyTrackingMode"/>
        public static Feature WithoutCameraOrTracking(this Feature self) => self.SetDifference(Feature.AnyCamera.Union(Feature.AnyTrackingMode));

        static Feature LowestBit(this Feature self)
        {
            return self & (self ^ (self - 1));
        }

        /// <summary>
        /// Generates a single string representing the list of enabled features separated by <paramref name="separator"/> or a comma if not specified.
        /// </summary>
        /// <remarks>
        /// This method makes several heap allocations, generating garbage. It is intended for debugging purposes and
        /// should not be called frequently in a production application.
        /// </remarks>
        /// <param name="features">The <see cref="Feature"/> being extended.</param>
        /// <param name="separator">The string separator to insert between elements of the list, or ", " if omitted.</param>
        /// <returns>A string of <see cref="Feature"/>s separated by <paramref name="separator"/>. If none of the features are enabled, returns "(None)".</returns>
        public static string ToStringList(this Feature features, string separator = ", ")
        {
            var names = new List<string>();
            while (features != 0)
            {
                var feature = features.LowestBit();
                switch (feature)
                {
                    case Feature.WorldFacingCamera:
                        names.Add("World Facing Camera");
                        break;
                    case Feature.UserFacingCamera:
                        names.Add("User Facing Camera");
                        break;
                    case Feature.RotationOnly:
                        names.Add("Rotation Only");
                        break;
                    case Feature.PositionAndRotation:
                        names.Add("Rotation and Orientation");
                        break;
                    case Feature.FaceTracking:
                        names.Add("Face Tracking");
                        break;
                    case Feature.PlaneTracking:
                        names.Add("Plane Tracking");
                        break;
                    case Feature.ImageTracking:
                        names.Add("Image Tracking");
                        break;
                    case Feature.ObjectTracking:
                        names.Add("Object Tracking");
                        break;
                    case Feature.EnvironmentProbes:
                        names.Add("Environment Probes");
                        break;
                    case Feature.Body2D:
                        names.Add("2D Body Tracking");
                        break;
                    case Feature.Body3D:
                        names.Add("3D Body Tracking");
                        break;
                    case Feature.Body3DScaleEstimation:
                        names.Add("3D Body Scale Estimation");
                        break;
                    case Feature.PeopleOcclusionStencil:
                        names.Add("People Occlusion Stencil");
                        break;
                    case Feature.PeopleOcclusionDepth:
                        names.Add("People Occlusion Depth");
                        break;
                    case Feature.Collaboration:
                        names.Add("Collaboration");
                        break;
                    case Feature.AutoFocus:
                        names.Add("Auto-Focus");
                        break;
                    case Feature.LightEstimationAmbientIntensity:
                        names.Add("Light Estimation (Ambient Intensity)");
                        break;
                    case Feature.LightEstimationAmbientColor:
                        names.Add("Light Estimation (Ambient Color)");
                        break;
                    case Feature.LightEstimationAmbientSphericalHarmonics:
                        names.Add("Light Estimation (Spherical Harmonics)");
                        break;
                    case Feature.LightEstimationMainLightDirection:
                        names.Add("Light Estimation (Main Light Direction)");
                        break;
                    case Feature.LightEstimationMainLightIntensity:
                        names.Add("Light Estimation (Main Light Intensity)");
                        break;
                    case Feature.Raycast:
                        names.Add("Raycast");
                        break;
                    case Feature.Meshing:
                        names.Add("Meshing");
                        break;
                    case Feature.MeshClassification:
                        names.Add("Mesh Classification");
                        break;
                    case Feature.PointCloud:
                        names.Add("Point Cloud");
                        break;
                    case Feature.EnvironmentDepth:
                        names.Add("Environment Depth");
                        break;
                    default:
                        names.Add(feature.ToString());
                        break;
                }

                features &= (features - 1);
            }

            return names.Count > 0 ? string.Join(separator, names) : "(None)";
        }

        /// <summary>
        /// Calculates the number of enabled features in <paramref name="self"/>.
        /// </summary>
        /// <param name="self">The <see cref="Feature"/> being extended.</param>
        /// <returns>The number of enabled <see cref="Feature"/> flags.</returns>
        public static int Count(this Feature self)
        {
            int count = 0;
            ulong features = (ulong)self;
            while (features != 0)
            {
                ++count;
                // set lowest bit to zero
                features &= (features - 1);
            }

            return count;
        }
    }
}