/************************************************************************************ Copyright : Copyright (c) Facebook Technologies, LLC and its affiliates. All rights reserved. Your use of this SDK or tool is subject to the Oculus SDK License Agreement, available at https://developer.oculus.com/licenses/oculussdk/ Unless required by applicable law or agreed to in writing, the Utilities 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 System.Collections.Generic; using UnityEngine; using UnityEngine.Assertions; using UnityEngine.Serialization; namespace Oculus.Interaction.PoseDetection { public class ShapeRecognizerActiveState : MonoBehaviour, IActiveState { [SerializeField, Interface(typeof(IHand))] private MonoBehaviour _hand; public IHand Hand { get; private set; } [SerializeField] private ShapeRecognizer[] _shapes; public IReadOnlyList Shapes => _shapes; private IFingerFeatureStateProvider FingerFeatureStateProvider { get; set; } public Handedness Handedness => Hand.Handedness; struct FingerFeatureStateUsage { public HandFinger handFinger; public ShapeRecognizer.FingerFeatureConfig config; } private List _allFingerStates = new List(); protected virtual void Awake() { Hand = _hand as IHand; } protected virtual void Start() { Assert.IsNotNull(Hand); Assert.IsNotNull(_shapes); for (var index = 0; index < _shapes.Length; index++) { var sr = _shapes[index]; if (sr == null) { Assert.IsNotNull(sr, "_shapes[" + index + "] != null"); } } bool foundAspect = Hand.GetHandAspect(out IFingerFeatureStateProvider state); Assert.IsTrue(foundAspect); FingerFeatureStateProvider = state; _allFingerStates = FlattenUsedFeatures(); // Warm up the proactive evaluation InitStateProvider(); } private void InitStateProvider() { foreach (FingerFeatureStateUsage state in _allFingerStates) { FingerFeatureStateProvider.GetCurrentState(state.handFinger, state.config.Feature, out _); } } private List FlattenUsedFeatures() { var fingerFeatureStateUsages = new List(); foreach (var sr in _shapes) { int configCount = 0; for (var fingerIdx = 0; fingerIdx < Constants.NUM_FINGERS; ++fingerIdx) { var handFinger = (HandFinger)fingerIdx; foreach (var config in sr.GetFingerFeatureConfigs(handFinger)) { ++configCount; fingerFeatureStateUsages.Add(new FingerFeatureStateUsage() { handFinger = handFinger, config = config }); } } // If this assertion is hit, open the ScriptableObject in the Unity Inspector // and ensure that it has at least one valid condition. Assert.IsTrue(configCount > 0, $"Shape {sr.ShapeName} has no valid conditions."); } return fingerFeatureStateUsages; } public bool Active { get { if (!isActiveAndEnabled || _allFingerStates.Count == 0) { return false; } foreach (FingerFeatureStateUsage stateUsage in _allFingerStates) { if (!FingerFeatureStateProvider.IsStateActive(stateUsage.handFinger, stateUsage.config.Feature, stateUsage.config.Mode, stateUsage.config.State)) { return false; } } return true; } } #region Inject public void InjectAllShapeRecognizerActiveState(IHand hand, ShapeRecognizer[] shapes) { InjectHand(hand); InjectShapes(shapes); } public void InjectHand(IHand hand) { _hand = hand as MonoBehaviour; Hand = hand; } public void InjectShapes(ShapeRecognizer[] shapes) { _shapes = shapes; } #endregion } }