//========= Copyright 2016-2018, HTC Corporation. All rights reserved. =========== using HTC.UnityPlugin.Utility; using HTC.UnityPlugin.VRModuleManagement; using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.EventSystems; using UnityEngine.UI; namespace HTC.UnityPlugin.Vive.BindingInterface { public class BindingInterfaceDevicePanelController : MonoBehaviour { private const float MIN_DEVICE_VIEW_SCALE = 0.01f; private const float MAX_DEVICE_VIEW_SCALE = 5f; [Serializable] public class UnityEventString : UnityEvent { } [SerializeField] private Animator m_animator; [SerializeField] private InputField m_inputDeviceSN; [SerializeField] private Image m_modelIcon; [SerializeField] private Button m_buttonCheck; [SerializeField] private BindingInterfaceDeviceItem m_deviceItem; [SerializeField] private float m_deviceViewMargin = 20f; [SerializeField] private bool m_showDebugBoundRect = false; [SerializeField] private UnityEventString m_onSelectDevice = new UnityEventString(); [SerializeField] private UnityEventString m_onMouseEnterDevice = new UnityEventString(); [SerializeField] private UnityEventString m_onMouseExitDevice = new UnityEventString(); private bool m_initialized; private bool m_trackingEnabled; private ViveRole.IMap m_selectedRoleMap; private RectTransform m_deviceView; private float m_deviceViewMaskWidth; private float m_deviceViewMaskHeight; private IndexedTable m_itemTable = new IndexedTable(); private List m_itemPool = new List(); private void Initialize() { if (m_initialized) { return; } m_initialized = true; m_itemPool.Add(m_deviceItem); m_deviceItem.onClick += m_onSelectDevice.Invoke; m_deviceItem.onEnter += OnEnterDevice; m_deviceItem.onExit += OnExitDevice; m_deviceItem.gameObject.SetActive(false); m_deviceView = m_deviceItem.transform.parent.GetComponent(); var deviceViewMaskRect = m_deviceView.parent.GetComponent().rect; m_deviceViewMaskWidth = deviceViewMaskRect.width; m_deviceViewMaskHeight = deviceViewMaskRect.height; } public void EnableTracking() { if (m_trackingEnabled) { return; } m_trackingEnabled = true; Initialize(); m_inputDeviceSN.text = string.Empty; CheckInputDeviceSN(string.Empty); for (uint deviceIndex = 0; deviceIndex < VRModule.MAX_DEVICE_COUNT; ++deviceIndex) { if (VRModule.GetCurrentDeviceState(deviceIndex).isConnected) { OnDeviceConnected(deviceIndex, true); } } VRModule.onDeviceConnected += OnDeviceConnected; } public void DisableTracking() { if (!m_trackingEnabled) { return; } m_trackingEnabled = false; VRModule.onDeviceConnected -= OnDeviceConnected; for (int i = 0, imax = m_itemTable.Count; i < imax; ++i) { var item = m_itemTable.GetValueByIndex(i); m_itemPool.Add(m_itemTable.GetValueByIndex(i)); item.gameObject.SetActive(false); } m_itemTable.Clear(); } private void OnDisable() { DisableTracking(); } private Vector3[] m_itemCorners = new Vector3[4]; private Image m_bound; private void Update() { if (m_trackingEnabled) { var boundRect = new Rect() { xMin = float.MaxValue, xMax = float.MinValue, yMin = float.MaxValue, yMax = float.MinValue, }; if (m_showDebugBoundRect && m_bound == null) { var boundObj = new GameObject(); boundObj.transform.SetParent(m_deviceView.transform, false); boundObj.transform.SetAsFirstSibling(); m_bound = boundObj.AddComponent(); m_bound.color = new Color(1f, 0f, 0f, 5f); } for (int i = 0, imax = m_itemTable.Count; i < imax; ++i) { var item = m_itemTable.GetValueByIndex(i); if (!item.isDisplayed) { continue; } item.UpdatePosition(); item.rectTransform.GetWorldCorners(m_itemCorners); for (int j = 0; j < 4; ++j) { m_itemCorners[j] = m_deviceView.InverseTransformPoint(m_itemCorners[j]); } boundRect.xMin = Mathf.Min(boundRect.xMin, m_itemCorners[0].x, m_itemCorners[1].x, m_itemCorners[2].x, m_itemCorners[3].x); boundRect.xMax = Mathf.Max(boundRect.xMax, m_itemCorners[0].x, m_itemCorners[1].x, m_itemCorners[2].x, m_itemCorners[3].x); boundRect.yMin = Mathf.Min(boundRect.yMin, m_itemCorners[0].y, m_itemCorners[1].y, m_itemCorners[2].y, m_itemCorners[3].y); boundRect.yMax = Mathf.Max(boundRect.yMax, m_itemCorners[0].y, m_itemCorners[1].y, m_itemCorners[2].y, m_itemCorners[3].y); } // calculate view panel's scale to let view rect includes all devices var innerWidth = m_deviceViewMaskWidth - (m_deviceViewMargin * 2f); var innerHeight = m_deviceViewMaskHeight - (m_deviceViewMargin * 2f); var maxBoundWidth = Mathf.Max(Mathf.Abs(boundRect.xMin), Mathf.Abs(boundRect.xMax)) * 2f; var maxBoundHeight = Mathf.Max(Mathf.Abs(boundRect.yMin), Mathf.Abs(boundRect.yMax)) * 2f; float scale; if (innerWidth / innerHeight >= maxBoundWidth / maxBoundHeight) { // if viewRect is wider then boundRect scale = innerHeight / maxBoundHeight; } else { // if boundRect is wider then viewRect scale = innerWidth / maxBoundWidth; } scale = Mathf.Clamp(scale, MIN_DEVICE_VIEW_SCALE, MAX_DEVICE_VIEW_SCALE); if (m_showDebugBoundRect) { m_bound.rectTransform.sizeDelta = new Vector2(boundRect.width, boundRect.height); m_bound.rectTransform.localPosition = boundRect.center; } m_deviceView.localScale = new Vector3(scale, scale, 1f); } } private void OnDeviceConnected(uint deviceIndex, bool connected) { BindingInterfaceDeviceItem item; if (connected) { if (m_itemPool.Count == 0) { var itemObj = Instantiate(m_deviceItem.gameObject); itemObj.transform.SetParent(m_deviceItem.transform.parent, false); item = itemObj.GetComponent(); item.onClick += m_onSelectDevice.Invoke; item.onEnter += OnEnterDevice; item.onExit += OnExitDevice; } else { item = m_itemPool[m_itemPool.Count - 1]; m_itemPool.RemoveAt(m_itemPool.Count - 1); // remove last } m_itemTable.Add(deviceIndex, item); item.deviceIndex = deviceIndex; item.isBound = m_selectedRoleMap.IsDeviceConnectedAndBound(deviceIndex); item.UpdateModel(); } else { item = m_itemTable[deviceIndex]; m_itemTable.Remove(deviceIndex); m_itemPool.Add(item); } item.gameObject.SetActive(connected); } private void OnEnterDevice(uint deviceIndex) { var deviceState = VRModule.GetCurrentDeviceState(deviceIndex); var deviceSN = deviceState.serialNumber; m_inputDeviceSN.text = deviceSN; CheckInputDeviceSN(deviceSN); m_modelIcon.gameObject.SetActive(true); BindingInterfaceSpriteManager.SetupDeviceIcon(m_modelIcon, deviceState.deviceModel, true); if (m_onMouseEnterDevice != null) { m_onMouseEnterDevice.Invoke(deviceSN); } } private void OnExitDevice(uint deviceIndex) { var deviceSN = VRModule.GetCurrentDeviceState(deviceIndex).serialNumber; m_inputDeviceSN.text = string.Empty; CheckInputDeviceSN(string.Empty); m_modelIcon.gameObject.SetActive(false); if (m_onMouseExitDevice != null) { m_onMouseExitDevice.Invoke(deviceSN); } } public void CheckInputDeviceSN(string inputStr) { if (string.IsNullOrEmpty(inputStr)) { m_buttonCheck.interactable = false; m_modelIcon.gameObject.SetActive(false); } else { m_buttonCheck.interactable = true; m_modelIcon.gameObject.SetActive(true); uint deviceIndex; if (VRModule.TryGetConnectedDeviceIndex(inputStr, out deviceIndex)) { BindingInterfaceSpriteManager.SetupDeviceIcon(m_modelIcon, VRModule.GetCurrentDeviceState(deviceIndex).deviceModel, true); } else { BindingInterfaceSpriteManager.SetupDeviceIcon(m_modelIcon, ViveRoleBindingsHelper.GetDeviceModelHint(inputStr), false); } } } public void UpdateForBindingChanged() { for (int i = 0, imax = m_itemTable.Count; i < imax; ++i) { var deviceIndex = m_itemTable.GetKeyByIndex(i); var item = m_itemTable.GetValueByIndex(i); item.isBound = m_selectedRoleMap.IsDeviceConnectedAndBound(deviceIndex); item.UpdateModel(); } } public void ConfirmInputDeviceSN() { if (m_onSelectDevice != null) { m_onSelectDevice.Invoke(m_inputDeviceSN.text); } } public void DeselectCheckButton() { EventSystem.current.SetSelectedGameObject(null); } public void SelecRoleSet(ViveRole.IMap roleMap) { m_selectedRoleMap = roleMap; } public void SetAnimatorSlideLeft() { if (m_animator.isInitialized) { m_animator.SetTrigger("SlideDeviceViewLeft"); } } public void SetAnimatorSlideRight() { if (m_animator.isInitialized) { m_animator.SetTrigger("SlideDeviceViewRight"); } } public void SetAnimatorIsEditing(bool value) { if (m_animator.isInitialized) { m_animator.SetBool("isEditing", value); } } } }