/*
* 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
}
}