672{
673 previousState = currentState;
674
675 try
676 {
677 T5_ControllerState state = new T5_ControllerState();
678
679 var result = NativePlugin.GetControllerState(glassesHandle, controllerIndex, ref state);
680
681 currentState = (result == 0)
682 ? state
683 : (T5_ControllerState?)null;
684 }
685 catch (Exception e)
686 {
687 currentState = null;
689 }
690 }
691
693 {
694
695 return currentState?.GetButton(button) ?? false;
696 }
697
698 public bool TryGetButton(
WandButton button, out
bool pressed)
699 {
700 pressed = currentState?.GetButton(button) ?? false;
701
702
703 return currentState.HasValue;
704 }
705
707 {
708
709
710
711 var pressed = currentState?.GetButton(button) ?? false;
712
713
714
715 var previouslyPressed = previousState?.GetButton(button) ?? false;
716
717
718 if (!previousState.HasValue && currentState.HasValue)
719 {
720 return pressed;
721 }
722
723 return pressed && !previouslyPressed;
724 }
725
726 public bool TryGetButtonDown(
WandButton button, out
bool buttonDown)
727 {
728
729 buttonDown = GetButtonDown(button);
730 return currentState.HasValue;
731 }
732
734 {
735
736
737 var pressed = currentState?.GetButton(button) ?? false;
738
739
740
741 var previouslyPressed = previousState?.GetButton(button) ?? false;
742
743
744 return previousState.HasValue
745 ? !pressed && previouslyPressed
746
747
748
749 : false;
750 }
751
752 public bool TryGetButtonUp(
WandButton button, out
bool buttonUp)
753 {
754
755 buttonUp = GetButtonUp(button);
756 return currentState.HasValue;
757 }
758
759 public Vector2 GetStickTilt()
760 {
761 return currentState?.Stick ?? Vector2.zero;
762 }
763
764 public bool TryGetStickTilt(out Vector2 stickTilt)
765 {
766 stickTilt = GetStickTilt();
767 return currentState.HasValue;
768 }
769
770 public float GetTrigger()
771 {
772 return currentState?.Trigger ?? 0.0f;
773 }
774
775 public bool TryGetTrigger(out float triggerDisplacement)
776 {
777 triggerDisplacement = GetTrigger();
778 return currentState.HasValue;
779 }
780
781 #endregion Public Functions
782
783
784 #region Overrides
785
786 public new void Reset(WandSettings wandSettings)
787 {
788 base.Reset(wandSettings);
789 }
790
791 public new virtual void Update(WandSettings wandSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
792 {
793 if (wandSettings == null)
794 {
795 Log.
Error(
"WandSettings configuration required for Wand tracking updates.");
796 return;
797 }
798
799 base.Update(wandSettings, scaleSettings, gameBoardSettings);
800 }
801
802 protected override void SetDefaultPoseGameboardSpace(WandSettings settings)
803 {
804 pose_UGBD = GetDefaultPoseGameboardSpace(settings);
805
806 fingertipsPose_GameboardSpace = pose_UGBD;
807 aimPose_GameboardSpace = pose_UGBD;
808 }
809
810 protected static Pose GetDefaultPoseGameboardSpace(WandSettings settings)
811 {
812 Vector3 defaultPosition = DEFAULT_WAND_POSITION_GAME_BOARD_SPACE;
813
814 defaultPosition += DEFAULT_WAND_HANDEDNESS_OFFSET_GAME_BOARD_SPACE
815 * (settings.controllerIndex == ControllerIndex.Right ? 1f : -1f);
816 return new Pose(defaultPosition, DEFAULT_WAND_ROTATION_GAME_BOARD_SPACE);
817 }
818
819 protected override void SetPoseUnityWorldSpace(ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
820 {
821 pose_UWRLD = GameboardToWorldSpace(pose_UGBD, scaleSettings, gameBoardSettings);
822 fingertipsPose_UnityWorldSpace = GameboardToWorldSpace(fingertipsPose_GameboardSpace, scaleSettings, gameBoardSettings);
823 aimPose_UnityWorldSpace = GameboardToWorldSpace(aimPose_GameboardSpace, scaleSettings, gameBoardSettings);
824 }
825
826 protected override bool TryCheckConnected(out bool connected)
827 {
828 if (!wandAvailabilityErroredOnce)
829 {
830 try
831 {
832 T5_Bool wandAvailable = false;
833 int result = NativePlugin.GetWandAvailability(glassesHandle, ref wandAvailable, controllerIndex);
834
835 if (result == 0)
836 {
837 isConnected = wandAvailable;
838 connected = wandAvailable;
839 return true;
840 }
841 }
842 catch (DllNotFoundException e)
843 {
844 Log.
Info(
"Could not connect to Tilt Five plugin for wand: {0}", e.Message);
845 wandAvailabilityErroredOnce = true;
846 }
847 catch (Exception e)
848 {
850 "Failed to connect to Tilt Five plugin for wand availability: {0}",
851 e.ToString());
852 wandAvailabilityErroredOnce = true;
853 }
854 }
855
856 isConnected = false;
857 connected = false;
858 return false;
859 }
860
861 protected override bool TryGetStateFromPlugin(out T5_ControllerState controllerState, out bool poseIsValid, GameBoardSettings gameBoardSettings)
862 {
863 if (!TryGetWandControlsState(glassesHandle, out var controllerStateResult, controllerIndex))
864 {
865 poseIsValid = false;
866 controllerState = new T5_ControllerState();
867
868 return false;
869 }
870
871 controllerState = controllerStateResult.Value;
872 poseIsValid =
Glasses.IsTracked(glassesHandle) && controllerState.PoseValid;
873
874 return true;
875 }
876
877 protected override void SetPoseGameboardSpace(in T5_ControllerState controllerState,
878 WandSettings wandSettings, ScaleSettings scaleSettings, GameBoardSettings gameboardSettings)
879 {
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894 Vector3 gripPosition_UGBD = ConvertPosGBDToUGBD(controllerState.GripPos_GBD);
895 Vector3 fingertipsPosition_UGBD = ConvertPosGBDToUGBD(controllerState.FingertipsPos_GBD);
896 Vector3 aimPosition_UGBD = ConvertPosGBDToUGBD(controllerState.AimPos_GBD);
897 var rotation_UGBD = CalculateRotation(controllerState.RotToWND_GBD);
898
899 ProcessTrackingData(gripPosition_UGBD, fingertipsPosition_UGBD, aimPosition_UGBD,
900 rotation_UGBD, wandSettings, scaleSettings, gameboardSettings,
901 out pose_UGBD, out fingertipsPose_GameboardSpace, out aimPose_GameboardSpace);
902 }
903
911 protected override void SetInvalidPoseGameboardSpace(in T5_ControllerState t5_ControllerState, WandSettings settings, ScaleSettings scaleSettings, GameBoardSettings gameboardSettings)
912 {
913 SetPoseGameboardSpace(t5_ControllerState, settings, scaleSettings, gameboardSettings);
914 }
915
916 protected override void SetDrivenObjectTransform(WandSettings wandSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
917 {
918 if (wandSettings.GripPoint != null)
919 {
920 wandSettings.GripPoint.transform.SetPositionAndRotation(gripPose_UnityWorldSpace.position, gripPose_UnityWorldSpace.rotation);
921 }
922
923 if (wandSettings.FingertipPoint != null)
924 {
925 wandSettings.FingertipPoint.transform.SetPositionAndRotation(fingertipsPose_UnityWorldSpace.position, fingertipsPose_UnityWorldSpace.rotation);
926 }
927
928 if (wandSettings.AimPoint != null)
929 {
930 wandSettings.AimPoint.transform.SetPositionAndRotation(aimPose_UnityWorldSpace.position, aimPose_UnityWorldSpace.rotation);
931 }
932 }
933
934 public virtual void Dispose()
935 {
936 Log.
Info($
"Glasses {glassesHandle} {controllerIndex} Wand disconnected");
937 }
938
939 #endregion Overrides
940
941
942 #region Private Helper Functions
943
944 protected Quaternion CalculateRotation(Quaternion rotToWND_GBD)
945 {
946 Quaternion rotToDW_GBD = Quaternion.AngleAxis(90f, Vector3.right);
947 Quaternion rotToGBD_DW = Quaternion.Inverse(rotToDW_GBD);
948 Quaternion rotToWND_DW = rotToWND_GBD * rotToGBD_DW;
949 Quaternion rotToUGBD_UWND = new Quaternion(rotToWND_DW.x, -rotToWND_DW.y, rotToWND_DW.z, rotToWND_DW.w);
950 return rotToUGBD_UWND;
951 }
952
953 protected void ProcessTrackingData(Vector3 gripPosition_UGBD, Vector3 fingertipsPosition_UGBD, Vector3 aimPosition_UGBD, Quaternion rotToUGBD_WND,
954 WandSettings wandSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings,
955 out Pose gripPose_UGBD, out Pose fingertipsPose_UGBD, out Pose aimPose_UGBD)
956 {
957 var incomingGripPose_UGBD = new Pose(gripPosition_UGBD, rotToUGBD_WND);
958 var incomingFingertipsPose_UGBD = new Pose(fingertipsPosition_UGBD, rotToUGBD_WND);
959 var incomingAimPose_UGBD = new Pose(aimPosition_UGBD, rotToUGBD_WND);
960
961
962
963
964
965
966
967
968 var staleGripPose_UGBD = pose_UGBD;
969 var staleFingertipsPose_UGBD = fingertipsPose_GameboardSpace;
970 var staleAimPose_UGBD = aimPose_GameboardSpace;
971
972 var gripPointOffsetDistance = 0f;
973 var fingertipsPointOffsetDistance = Mathf.Max((fingertipsPosition_UGBD - gripPosition_UGBD).magnitude,
974 (staleFingertipsPose_UGBD.position - staleGripPose_UGBD.position).magnitude);
975 var aimPointOffsetDistance = Mathf.Max((aimPosition_UGBD - gripPosition_UGBD).magnitude,
976 (staleAimPose_UGBD.position - staleGripPose_UGBD.position).magnitude);
977
978
979 gripPose_UGBD = FilterTrackingPointPose(staleGripPose_UGBD, staleGripPose_UGBD, incomingGripPose_UGBD, gripPointOffsetDistance, wandSettings);
980 fingertipsPose_UGBD = FilterTrackingPointPose(staleGripPose_UGBD, staleFingertipsPose_UGBD, incomingFingertipsPose_UGBD, fingertipsPointOffsetDistance, wandSettings);
981 aimPose_UGBD = FilterTrackingPointPose(staleGripPose_UGBD, staleAimPose_UGBD, incomingAimPose_UGBD, aimPointOffsetDistance, wandSettings);
982
983 }
984
985 protected Pose FilterTrackingPointPose(Pose staleGripPointPose, Pose staleTrackingPointPose,
986 Pose newTrackingPointPose, float trackingPointOffsetDistance, WandSettings settings)
987 {
988 if (!isTracked && settings.RejectUntrackedPositionData)
989 {
990 switch (settings.FailureMode)
991 {
992 default:
993
994 case TrackableSettings.TrackingFailureMode.FreezePosition:
995
996
997
998 var extrapolatedPosition = staleGripPointPose.position +
999 Quaternion.Inverse(newTrackingPointPose.rotation) * Vector3.forward * trackingPointOffsetDistance;
1000 return new Pose(extrapolatedPosition, newTrackingPointPose.rotation);
1001 case TrackableSettings.TrackingFailureMode.FreezePositionAndRotation:
1002 return staleTrackingPointPose;
1003 case TrackableSettings.TrackingFailureMode.SnapToDefault:
1004 return GetDefaultPoseGameboardSpace(settings);
1005 }
1006 }
1007 else
1008 {
1009 return newTrackingPointPose;
1010 }
1011 }
1012
1013 #endregion Private Helper Functions
1014 }
1015
1016#if UNITY_2019_1_OR_NEWER && INPUTSYSTEM_AVAILABLE
1017 private class WandDeviceCore : WandCore
1018 {
1019 internal WandDevice wandDevice;
1020
1021 private enum TrackingState : int
1022 {
1024 Limited,
1025 Tracking
1026 }
1027
1028 public WandDeviceCore(GlassesHandle glassesHandle, ControllerIndex controllerIndex) : base(glassesHandle, controllerIndex)
1029 {
1030 if(
Glasses.TryGetGlassesDevice(glassesHandle, out var glassesDevice))
1031 {
1032 wandDevice = Input.GetWandDevice(glassesDevice.PlayerIndex, controllerIndex);
1033 InputSystem.QueueConfigChangeEvent(wandDevice);
1034 InputSystem.EnableDevice(wandDevice);
1035
1036 var inputUserCount = InputUser.all.Count;
1037 var playerIndex = (int)glassesDevice.PlayerIndex;
1038 var headPoseRoot =
Glasses.GetPoseRoot(glassesDevice.PlayerIndex);
1039
1040 if (headPoseRoot != null && inputUserCount >= playerIndex)
1041 {
1042 var playerInput = headPoseRoot.GetComponentInChildren<PlayerInput>();
1043
1044 if(playerInput != null)
1045 {
1046 InputUser.PerformPairingWithDevice(wandDevice, playerInput.user);
1047 }
1048 }
1049 }
1050 }
1051
1052 public override void Dispose()
1053 {
1054 base.Dispose();
1055 InputSystem.QueueConfigChangeEvent(wandDevice);
1056 InputSystem.DisableDevice(wandDevice);
1057 }
1058
1059 public override void GetLatestInputs()
1060 {
1061 base.GetLatestInputs();
1062
1063
1064
1065 if (!wandDevice.added || !wandDevice.enabled)
1066 {
1067 return;
1068 }
1069
1070 InputSystem.QueueDeltaStateEvent(wandDevice.TiltFive, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.T5));
1071 InputSystem.QueueDeltaStateEvent(wandDevice.One, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.One));
1072 InputSystem.QueueDeltaStateEvent(wandDevice.Two, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.Two));
1073 InputSystem.QueueDeltaStateEvent(wandDevice.Three, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.Three));
1074 InputSystem.QueueDeltaStateEvent(wandDevice.A, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.A));
1075 InputSystem.QueueDeltaStateEvent(wandDevice.B, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.B));
1076 InputSystem.QueueDeltaStateEvent(wandDevice.X, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.X));
1077 InputSystem.QueueDeltaStateEvent(wandDevice.Y, currentState.HasValue && currentState.Value.TryGetButton(
WandButton.Y));
1078
1079 InputSystem.QueueDeltaStateEvent(wandDevice.Stick, currentState.HasValue ? currentState.Value.TryGetStick() : Vector2.zero);
1080 InputSystem.QueueDeltaStateEvent(wandDevice.Trigger, currentState.HasValue ? currentState.Value.TryGetTrigger() : 0f);
1081 }
1082
1083 protected override void SetDrivenObjectTransform(WandSettings wandSettings, ScaleSettings scaleSettings, GameBoardSettings gameBoardSettings)
1084 {
1085 base.SetDrivenObjectTransform(wandSettings, scaleSettings, gameBoardSettings);
1086
1087
1088
1089 if (!wandDevice.added || !wandDevice.enabled)
1090 {
1091 return;
1092 }
1093
1094
1095 QueueDeltaStateEvent(wandDevice.devicePosition, pose_UWRLD.position);
1096 QueueDeltaStateEvent(wandDevice.FingertipsPosition, fingertipsPose_UnityWorldSpace.position);
1097 QueueDeltaStateEvent(wandDevice.AimPosition, aimPose_UnityWorldSpace.position);
1098
1099 QueueDeltaStateEvent(wandDevice.RawGripPosition, pose_UGBD.position);
1100 QueueDeltaStateEvent(wandDevice.RawFingertipsPosition, fingertipsPose_GameboardSpace.position);
1101 QueueDeltaStateEvent(wandDevice.RawAimPosition, aimPose_GameboardSpace.position);
1102
1103 QueueDeltaStateEvent(wandDevice.deviceRotation, pose_UWRLD.rotation);
1104 QueueDeltaStateEvent(wandDevice.RawRotation, pose_UGBD.rotation);
1105
1106 InputSystem.QueueDeltaStateEvent(wandDevice.isTracked, isTracked);
1107
1108 var trackingState = TrackingState.Tracking;
1109 if (!isTracked)
1110 {
1111 trackingState = wandSettings.FailureMode == TrackableSettings.TrackingFailureMode.FreezePosition
1112 ? TrackingState.Limited
1113 : TrackingState.None;
1114 }
1115
1116 InputSystem.QueueDeltaStateEvent(wandDevice.trackingState, (int)trackingState);
1117 }
1118
1119 private static void QueueDeltaStateEvent(Vector3Control vector3Control, Vector3 delta)
1120 {
1121 InputSystem.QueueDeltaStateEvent(vector3Control.x, delta.x);
1122 InputSystem.QueueDeltaStateEvent(vector3Control.y, delta.y);
1123 InputSystem.QueueDeltaStateEvent(vector3Control.z, delta.z);
1124 }
1125
1126
1127
1128 private static void QueueDeltaStateEvent(QuaternionControl quaternionControl, Quaternion delta)
1129 {
1130 InputSystem.QueueDeltaStateEvent(quaternionControl.w, delta.w);
1131 InputSystem.QueueDeltaStateEvent(quaternionControl.x, delta.x);
1132 InputSystem.QueueDeltaStateEvent(quaternionControl.y, delta.y);
1133 InputSystem.QueueDeltaStateEvent(quaternionControl.z, delta.z);
1134 }
1135 }
1136#endif
1137
1138 #endregion Private Classes
1139 }
1140
1141}
TiltFive.Input.WandButton WandButton
static void Info(string m, params object[] list)
INFO logging function call.
static void Error(string m, params object[] list)
ERROR logging function call.