/****************************************************************************** * Copyright (C) Ultraleap, Inc. 2011-2021. * * * * Use subject to the terms of the Apache License 2.0 available at * * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * * between Ultraleap and you, your company or other organization. * ******************************************************************************/ using System; using UnityEngine; /** HandModelBase defines abstract methods as a template for building Leap hand models*/ namespace Leap.Unity { public enum Chirality { Left, Right }; public enum ModelType { Graphics, Physics }; [ExecuteInEditMode] public abstract class HandModelBase : MonoBehaviour { public event Action OnBegin; public event Action OnFinish; /// Called directly after the HandModelBase's UpdateHand(). /// public event Action OnUpdate; private bool init = false; private bool isTracked = false; public bool IsTracked { get { return isTracked; } } public abstract Chirality Handedness { get; set; } public abstract ModelType HandModelType { get; } public virtual void InitHand() { } public virtual void BeginHand() { if (OnBegin != null) { OnBegin(); } isTracked = true; } public abstract void UpdateHand(); public void UpdateHandWithEvent() { UpdateHand(); if (OnUpdate != null) { OnUpdate(); } } public virtual void FinishHand() { if (OnFinish != null) { OnFinish(); } isTracked = false; } public abstract Hand GetLeapHand(); public abstract void SetLeapHand(Hand hand); /// /// Returns whether or not this hand model supports editor persistence. This is false by default and must be /// opt-in by a developer making their own hand model script if they want editor persistence. /// public virtual bool SupportsEditorPersistence() { return false; } [Tooltip("Optionally set a Leap Provider to use for tracking frames \n" + "If you do not set one, the first provider found in the scene will be used. \n" + "If no provider is found this gameobject will disable itself")] public LeapProvider leapProvider; private void Awake() { if (!Application.isPlaying) { return; } init = false; if (leapProvider == null) { //Try to set the provider for the user leapProvider = Hands.Provider; if (leapProvider == null) { Debug.LogError("No leap provider found in the scene, hand model has been disabled", this.gameObject); this.enabled = false; this.gameObject.SetActive(false); return; } } if (HandModelType == ModelType.Graphics) { leapProvider.OnUpdateFrame -= UpdateFrame; leapProvider.OnUpdateFrame += UpdateFrame; } else { leapProvider.OnFixedFrame -= FixedUpdateFrame; leapProvider.OnFixedFrame += FixedUpdateFrame; } } private void OnDestroy() { if (leapProvider == null) { return; } leapProvider.OnUpdateFrame -= UpdateFrame; leapProvider.OnFixedFrame -= FixedUpdateFrame; } void UpdateFrame(Frame frame) { if (this == null) { leapProvider.OnUpdateFrame -= UpdateFrame; return; } var hand = frame.GetHand(Handedness); UpdateBase(hand); } void FixedUpdateFrame(Frame frame) { var hand = frame.GetHand(Handedness); UpdateBase(hand); } void UpdateBase(Hand hand) { SetLeapHand(hand); if (hand == null) { if (IsTracked) { FinishHand(); } } else { if (!IsTracked) { if (!init) { InitHand(); init = true; } BeginHand(); } if (gameObject.activeInHierarchy) { UpdateHand(); } } } #if UNITY_EDITOR //Only Runs in editor private void Update() { if (!Application.isPlaying && SupportsEditorPersistence()) { //Try to set the provider for the user var Provider = Hands.Provider; Hand hand = null; if (Provider == null) { //If we still have a null hand, construct one manually if (hand == null) { hand = TestHandFactory.MakeTestHand(Handedness == Chirality.Left, unitType: TestHandFactory.UnitType.LeapUnits); hand.Transform(transform.GetLeapMatrix()); } } else { hand = Provider.CurrentFrame.GetHand(Handedness); } UpdateBase(hand); } } #endif } }