/**************************************************************************** * Copyright 2019 Nreal Techonology Limited. All rights reserved. * * This file is part of NRSDK. * * https://www.nreal.ai/ * *****************************************************************************/ namespace NRKernal { using System; using UnityEngine; /// /// This class obtains the runtime information of controller devices through a native controller /// plugin, and would use these info to update controller states. internal partial class NRControllerProvider : ControllerProviderBase { /// The native controller. private NativeController m_NativeController; /// The processed frame. private int m_ProcessedFrame; /// True to need initialize. private bool m_NeedInit = true; /// True to need recenter. private bool m_NeedRecenter; /// Array of home pressing timers. private float[] homePressingTimerArr = new float[NRInput.MAX_CONTROLLER_STATE_COUNT]; /// The home long press time. private const float HOME_LONG_PRESS_TIME = 1.1f; /// Constructor. /// The states. public NRControllerProvider(ControllerState[] states) : base(states) { } /// Gets the number of controllers. /// The number of controllers. public override int ControllerCount { get { if (!Inited) return 0; return m_NativeController.GetControllerCount(); } } /// Gets a version. /// Zero-based index of the controller. /// The version. public string GetVersion(int index) { if (m_NativeController != null) { return m_NativeController.GetVersion(index); } return string.Empty; } public ControllerHandEnum GetHandednessType() { if (m_NativeController != null) { return m_NativeController.GetHandednessType() == HandednessType.LEFT_HANDEDNESS ? ControllerHandEnum.Left : ControllerHandEnum.Right; } return ControllerHandEnum.Right; } /// Executes the 'pause' action. public override void OnPause() { if (m_NativeController != null) { m_NativeController.Pause(); } } /// Executes the 'resume' action. public override void OnResume() { if (m_NativeController != null) { m_NativeController.Resume(); } } /// Updates this object. public override void Update() { if (m_ProcessedFrame == Time.frameCount) return; m_ProcessedFrame = Time.frameCount; if (m_NeedInit) { InitNativeController(); return; } if (!Inited) return; int availableCount = ControllerCount; if (availableCount > 0 && NRInput.GetControllerAvailableFeature(ControllerAvailableFeature.CONTROLLER_AVAILABLE_FEATURE_POSITION)) { UpdateHeadPoseToController(); } for (int i = 0; i < availableCount; i++) { UpdateControllerState(i); } } /// Executes the 'destroy' action. public override void OnDestroy() { if (m_NativeController != null) { m_NativeController.Destroy(); m_NativeController = null; } } /// Trigger haptic vibration. /// Zero-based index of the controller. /// (Optional) The duration in seconds. /// (Optional) The frequency. /// (Optional) The amplitude. public override void TriggerHapticVibration(int index, float durationSeconds = 0.1f, float frequency = 1000f, float amplitude = 0.5f) { if (!Inited) return; if (states[index].controllerType == ControllerType.CONTROLLER_TYPE_PHONE) { PhoneVibrateTool.TriggerVibrate(durationSeconds); } else { if (m_NativeController != null && NRInput.GetControllerAvailableFeature(ControllerAvailableFeature.CONTROLLER_AVAILABLE_FEATURE_HAPTIC_VIBRATE)) { Int64 durationNano = (Int64)(durationSeconds * 1000000000); m_NativeController.TriggerHapticVibrate(index, durationNano, frequency, amplitude); } } } /// Recenters this object. public override void Recenter() { base.Recenter(); m_NeedRecenter = true; } /// Initializes the native controller. private void InitNativeController() { m_NativeController = new NativeController(); if (m_NativeController.Init()) { Inited = true; NRDebugger.Info("[NRControllerProvider] Init Succeed"); } else { m_NativeController = null; NRDebugger.Error("[NRControllerProvider] Init Failed !!"); } #if !UNITY_EDITOR NRDebugger.Info("[NRInput] version:" + GetVersion(0)); #endif m_NeedInit = false; } /// Updates the controller state described by index. /// Zero-based index of the. private void UpdateControllerState(int index) { m_NativeController.UpdateState(index); states[index].controllerType = m_NativeController.GetControllerType(index); #if UNITY_EDITOR if (NRInput.EmulateVirtualDisplayInEditor) { states[index].controllerType = ControllerType.CONTROLLER_TYPE_PHONE; } #endif states[index].availableFeature = (ControllerAvailableFeature)m_NativeController.GetAvailableFeatures(index); states[index].connectionState = m_NativeController.GetConnectionState(index); states[index].rotation = m_NativeController.GetPose(index).rotation; states[index].position = m_NativeController.GetPose(index).position; states[index].gyro = m_NativeController.GetGyro(index); states[index].accel = m_NativeController.GetAccel(index); states[index].mag = m_NativeController.GetMag(index); states[index].touchPos = m_NativeController.GetTouch(index); states[index].isTouching = m_NativeController.IsTouching(index); states[index].recentered = false; states[index].isCharging = m_NativeController.IsCharging(index); states[index].batteryLevel = m_NativeController.GetBatteryLevel(index); states[index].buttonsState = (ControllerButton)m_NativeController.GetButtonState(index); states[index].buttonsDown = (ControllerButton)m_NativeController.GetButtonDown(index); states[index].buttonsUp = (ControllerButton)m_NativeController.GetButtonUp(index); IControllerStateParser stateParser = ControllerStateParseUtility.GetControllerStateParser(states[index].controllerType, index); if (stateParser != null) { stateParser.ParserControllerState(states[index]); } CheckRecenter(index); if (m_NeedRecenter) { for (int i = 0; i < ControllerCount; i++) { states[i].recentered = true; m_NativeController.RecenterController(i); } m_NeedRecenter = false; } } /// Check recenter. /// Zero-based index of the. private void CheckRecenter(int index) { if (states[index].GetButton(ControllerButton.HOME)) { homePressingTimerArr[index] += Time.deltaTime; if (homePressingTimerArr[index] > HOME_LONG_PRESS_TIME) { homePressingTimerArr[index] = float.MinValue; Recenter(); } } else { homePressingTimerArr[index] = 0f; } } /// Updates the head pose to controller. private void UpdateHeadPoseToController() { if (m_NativeController != null && NRInput.CameraCenter) { m_NativeController.UpdateHeadPose(new Pose(NRInput.CameraCenter.position, NRInput.CameraCenter.rotation)); } } } }