/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using Oculus.Interaction.Input; using UnityEngine; namespace Oculus.Interaction.GrabAPI { /// /// This enum indicates whether a finger within a given is required, optional, or ignored when /// determining if the rule is satisfied. /// /// /// Optional finger requirements allow for a grab to be started and continued with different fingers. Consider, for example, a /// in which all four fingers are optional and the thumb is ignored. With this grab, it is possible /// to begin a grab using only the first two fingers, then close the remaining fingers into the grab, then release the first two /// fingers out of the grab while still keeping the others curled. This will all be considered one grab action, even though no /// single finger was grabbing throughout; the grab was allowed to start without the last two fingers because those two fingers /// are optional, and it was allowed to persist when the first two fingers released because those are _also_ optional. /// public enum FingerRequirement { Ignored, Optional, Required } /// /// This enum indicates whether a grab defined by a ceases when _any_ of its required fingers release, /// or when _all_ of them release. Fingers marked or /// are not affected by this setting. /// public enum FingerUnselectMode { AllReleased, AnyReleased } /// /// This struct indicates which fingers should be taken in count for performing an interaction (for example, in /// ). All required fingers must be in use in order to start the interaction while any /// of the optional fingers is needed. For finishing the action it supports either releasing all fingers or any of them. /// [System.Serializable] public struct GrabbingRule { [SerializeField] private FingerRequirement _thumbRequirement; [SerializeField] private FingerRequirement _indexRequirement; [SerializeField] private FingerRequirement _middleRequirement; [SerializeField] private FingerRequirement _ringRequirement; [SerializeField] private FingerRequirement _pinkyRequirement; [SerializeField] private FingerUnselectMode _unselectMode; /// /// Returns the for this instance, which dictates whether the grab defined by this rule /// ends when _any_ of its required fingers release, or when _all_ of them do. /// public FingerUnselectMode UnselectMode => _unselectMode; /// /// This property checks whether this grab can be performed using only fingers marked . /// The property is true only if no fingers are marked as , false otherwise. /// public bool SelectsWithOptionals { get { return _thumbRequirement != FingerRequirement.Required && _indexRequirement != FingerRequirement.Required && _middleRequirement != FingerRequirement.Required && _ringRequirement != FingerRequirement.Required && _pinkyRequirement != FingerRequirement.Required; } } /// /// Indexer for retrieving and setting s by their type. /// /// The of the to be accessed /// Access to the requested public FingerRequirement this[HandFinger fingerID] { get { switch (fingerID) { case HandFinger.Thumb: return _thumbRequirement; case HandFinger.Index: return _indexRequirement; case HandFinger.Middle: return _middleRequirement; case HandFinger.Ring: return _ringRequirement; case HandFinger.Pinky: return _pinkyRequirement; } return FingerRequirement.Ignored; } set { switch (fingerID) { case HandFinger.Thumb: _thumbRequirement = value; break; case HandFinger.Index: _indexRequirement = value; break; case HandFinger.Middle: _middleRequirement = value; break; case HandFinger.Ring: _ringRequirement = value; break; case HandFinger.Pinky: _pinkyRequirement = value; break; } } } /// /// In-place modifies a bit mask representing the grabbing state of the various fingers, /// suppressing any detected grabs by fingers marked in this rule. /// /// public void StripIrrelevant(ref HandFingerFlags fingerFlags) { for (int i = 0; i < Constants.NUM_FINGERS; i++) { HandFinger finger = (HandFinger)i; if (this[finger] == FingerRequirement.Ignored) { fingerFlags = (HandFingerFlags)((int)fingerFlags & ~(1 << i)); } } } /// /// Projecting constructor which creates a new GrabbingRule as a subset of another. Copies the 's /// requirements for fingers included in the bit mask, setting /// rules for all other fingers. /// /// Bit mask specifying which requirements from to copy /// Original rule from which requirements should be copied public GrabbingRule(HandFingerFlags mask, in GrabbingRule otherRule) { _thumbRequirement = (mask & HandFingerFlags.Thumb) != 0 ? otherRule._thumbRequirement : FingerRequirement.Ignored; _indexRequirement = (mask & HandFingerFlags.Index) != 0 ? otherRule._indexRequirement : FingerRequirement.Ignored; _middleRequirement = (mask & HandFingerFlags.Middle) != 0 ? otherRule._middleRequirement : FingerRequirement.Ignored; _ringRequirement = (mask & HandFingerFlags.Ring) != 0 ? otherRule._ringRequirement : FingerRequirement.Ignored; _pinkyRequirement = (mask & HandFingerFlags.Pinky) != 0 ? otherRule._pinkyRequirement : FingerRequirement.Ignored; _unselectMode = otherRule.UnselectMode; } #region Defaults /// /// Standard definition for "palm grab": requires the middle three fingers to begin a grab, allowing that grab to persist /// as long as any finger continues grabbing. /// public static GrabbingRule DefaultPalmRule { get; } = new GrabbingRule() { _thumbRequirement = FingerRequirement.Optional, _indexRequirement = FingerRequirement.Required, _middleRequirement = FingerRequirement.Required, _ringRequirement = FingerRequirement.Required, _pinkyRequirement = FingerRequirement.Optional, _unselectMode = FingerUnselectMode.AllReleased }; /// /// Standard definition for "pinch grab": allows grabbing to begin when any of the first three fingers (thumb, index, middle) /// grabs, persisting the grab as long as any of those three is grabbing, and ignoring the last two fingers. /// public static GrabbingRule DefaultPinchRule { get; } = new GrabbingRule() { _thumbRequirement = FingerRequirement.Optional, _indexRequirement = FingerRequirement.Optional, _middleRequirement = FingerRequirement.Optional, _ringRequirement = FingerRequirement.Ignored, _pinkyRequirement = FingerRequirement.Ignored, _unselectMode = FingerUnselectMode.AllReleased }; /// /// Standard definition for "full grab": requires all five fingers to begin a grab, allowing that grab to persist /// as long as any finger continues grabbing. /// public static GrabbingRule FullGrab { get; } = new GrabbingRule() { _thumbRequirement = FingerRequirement.Required, _indexRequirement = FingerRequirement.Required, _middleRequirement = FingerRequirement.Required, _ringRequirement = FingerRequirement.Required, _pinkyRequirement = FingerRequirement.Required, _unselectMode = FingerUnselectMode.AllReleased }; #endregion } }