You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
334 lines
12 KiB
334 lines
12 KiB
3 years ago
|
//========= 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<string> { }
|
||
|
|
||
|
[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<uint, BindingInterfaceDeviceItem> m_itemTable = new IndexedTable<uint, BindingInterfaceDeviceItem>();
|
||
|
private List<BindingInterfaceDeviceItem> m_itemPool = new List<BindingInterfaceDeviceItem>();
|
||
|
|
||
|
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<RectTransform>();
|
||
|
var deviceViewMaskRect = m_deviceView.parent.GetComponent<RectTransform>().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<Image>();
|
||
|
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<BindingInterfaceDeviceItem>();
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|