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.
379 lines
12 KiB
379 lines
12 KiB
//========= Copyright 2016-2018, HTC Corporation. All rights reserved. =========== |
|
|
|
using HTC.UnityPlugin.Utility; |
|
using HTC.UnityPlugin.VRModuleManagement; |
|
using System; |
|
using UnityEngine; |
|
|
|
namespace HTC.UnityPlugin.Vive |
|
{ |
|
// ViveRoleProperty is a serializable class that preserve vive role using 2 strings. |
|
// There also has a property drawer so you can use it as a serialized field in your MonoBevaviour. |
|
// Note that when deserializing, result of type and value is based on the valid role info stored in ViveRoleEnum class |
|
[Serializable] |
|
public class ViveRoleProperty |
|
{ |
|
public delegate void RoleChangedListener(); |
|
public delegate void RoleChangedListenerEx(Type previousRoleType, int previousRoleValue); |
|
public delegate void DeviceIndexChangedListener(uint deviceIndex); |
|
|
|
public static readonly Type DefaultRoleType = typeof(HandRole); |
|
public static readonly int DefaultRoleValue = (int)HandRole.RightHand; |
|
|
|
[SerializeField] |
|
private string m_roleTypeFullName; |
|
[SerializeField] |
|
private string m_roleValueName; |
|
[SerializeField] |
|
private int m_roleValueInt; |
|
|
|
private bool m_isTypeDirty = true; |
|
private bool m_isValueDirty = true; |
|
private bool m_lockUpdate; |
|
|
|
private ViveRole.IMap m_roleMap = null; |
|
private Type m_roleType = DefaultRoleType; |
|
private int m_roleValue = DefaultRoleValue; |
|
private uint m_deviceIndex = VRModule.INVALID_DEVICE_INDEX; |
|
|
|
private Action m_onChanged; |
|
private RoleChangedListener m_onRoleChanged; |
|
private RoleChangedListenerEx m_onRoleChangedEx; |
|
private DeviceIndexChangedListener m_onDeviceIndexChanged; |
|
|
|
public Type roleType |
|
{ |
|
get |
|
{ |
|
Update(); |
|
return m_roleType; |
|
} |
|
set |
|
{ |
|
m_isTypeDirty |= ChangeProp.Set(ref m_roleTypeFullName, value.FullName); |
|
Update(); |
|
} |
|
} |
|
|
|
public int roleValue |
|
{ |
|
get |
|
{ |
|
Update(); |
|
return m_roleValue; |
|
} |
|
set |
|
{ |
|
if (ChangeProp.Set(ref m_roleValueName, m_roleMap.RoleValueInfo.GetNameByRoleValue(value))) |
|
{ |
|
m_roleValueInt = value; |
|
m_isValueDirty = true; |
|
} |
|
|
|
Update(); |
|
} |
|
} |
|
|
|
[Obsolete("Use onRoleChanged instead")] |
|
public event Action Changed |
|
{ |
|
add { m_onChanged += value; } |
|
remove { m_onChanged -= value; } |
|
} |
|
|
|
public event RoleChangedListener onRoleChanged |
|
{ |
|
add { m_onRoleChanged += value; } |
|
remove { m_onRoleChanged -= value; } |
|
} |
|
|
|
public event RoleChangedListenerEx onRoleChangedEx |
|
{ |
|
add { m_onRoleChangedEx += value; } |
|
remove { m_onRoleChangedEx -= value; } |
|
} |
|
|
|
public event DeviceIndexChangedListener onDeviceIndexChanged |
|
{ |
|
add |
|
{ |
|
var wasEmpty = m_onDeviceIndexChanged == null; |
|
|
|
m_onDeviceIndexChanged += value; |
|
|
|
if (wasEmpty && m_onDeviceIndexChanged != null && m_roleMap != null) |
|
{ |
|
m_deviceIndex = m_roleMap.GetMappedDeviceByRoleValue(m_roleValue); // update deviceIndex before first time listening to MappingChanged event |
|
m_roleMap.onRoleValueMappingChanged += OnMappingChanged; |
|
} |
|
} |
|
remove |
|
{ |
|
var wasEmpty = m_onDeviceIndexChanged == null; |
|
|
|
m_onDeviceIndexChanged -= value; |
|
|
|
if (!wasEmpty && m_onDeviceIndexChanged == null && m_roleMap != null) |
|
{ |
|
m_roleMap.onRoleValueMappingChanged -= OnMappingChanged; |
|
} |
|
} |
|
} |
|
|
|
public static ViveRoleProperty New() |
|
{ |
|
return New(DefaultRoleType, DefaultRoleValue); |
|
} |
|
|
|
public static ViveRoleProperty New(Type type, int value) |
|
{ |
|
return New(type.FullName, ViveRoleEnum.GetInfo(type).GetNameByRoleValue(value)); |
|
} |
|
|
|
public static ViveRoleProperty New<TRole>(TRole role) |
|
{ |
|
return New(typeof(TRole).FullName, role.ToString()); |
|
} |
|
|
|
public static ViveRoleProperty New(string typeFullName, string valueName) |
|
{ |
|
var prop = new ViveRoleProperty(); |
|
prop.m_roleTypeFullName = typeFullName; |
|
prop.m_roleValueName = valueName; |
|
|
|
Type roleType; |
|
if (ViveRoleEnum.ValidViveRoleTable.TryGetValue(typeFullName, out roleType)) |
|
{ |
|
var roleInfo = ViveRoleEnum.GetInfo(roleType); |
|
var roleIndex = roleInfo.GetElementIndexByName(valueName); |
|
if (roleIndex >= 0) |
|
{ |
|
prop.m_roleValueInt = roleInfo.GetRoleValueByElementIndex(roleIndex); |
|
} |
|
else |
|
{ |
|
prop.m_roleValueInt = roleInfo.InvalidRoleValue; |
|
} |
|
} |
|
|
|
return prop; |
|
} |
|
|
|
public void SetTypeDirty() { m_isTypeDirty = true; } |
|
|
|
public void SetValueDirty() { m_isValueDirty = true; } |
|
|
|
private void OnMappingChanged(ViveRole.IMap map, ViveRole.MappingChangedEventArg args) |
|
{ |
|
if (args.roleValue == m_roleValue) |
|
{ |
|
m_onDeviceIndexChanged(m_deviceIndex = args.currentDeviceIndex); |
|
} |
|
} |
|
|
|
// update type and value changes |
|
public void Update() |
|
{ |
|
if (m_lockUpdate && (m_isTypeDirty || m_isValueDirty)) { throw new Exception("Can't change value during onChange event callback"); } |
|
|
|
var oldRoleType = m_roleType; |
|
var oldRoleValue = m_roleValue; |
|
var roleTypeChanged = false; |
|
var roleValueChanged = false; |
|
var deviceIndexChanged = false; |
|
|
|
if (m_isTypeDirty || m_roleType == null) |
|
{ |
|
m_isTypeDirty = false; |
|
|
|
if (string.IsNullOrEmpty(m_roleTypeFullName) || !ViveRoleEnum.ValidViveRoleTable.TryGetValue(m_roleTypeFullName, out m_roleType)) |
|
{ |
|
m_roleType = DefaultRoleType; |
|
} |
|
|
|
roleTypeChanged = oldRoleType != m_roleType; |
|
} |
|
|
|
// maintain m_roleMap cache |
|
// m_roleMap could be null on first update |
|
if (roleTypeChanged || m_roleMap == null) |
|
{ |
|
if (m_onDeviceIndexChanged != null) |
|
{ |
|
if (m_roleMap != null) |
|
{ |
|
m_roleMap.onRoleValueMappingChanged -= OnMappingChanged; |
|
m_roleMap = ViveRole.GetMap(m_roleType); |
|
m_roleMap.onRoleValueMappingChanged += OnMappingChanged; |
|
} |
|
else |
|
{ |
|
m_roleMap = ViveRole.GetMap(m_roleType); |
|
m_deviceIndex = m_roleMap.GetMappedDeviceByRoleValue(m_roleValue); // update deviceIndex before first time listening to MappingChanged event |
|
m_roleMap.onRoleValueMappingChanged += OnMappingChanged; |
|
} |
|
} |
|
else |
|
{ |
|
m_roleMap = ViveRole.GetMap(m_roleType); |
|
} |
|
} |
|
|
|
if (m_isValueDirty || roleTypeChanged) |
|
{ |
|
m_isValueDirty = false; |
|
|
|
var info = m_roleMap.RoleValueInfo; |
|
if (string.IsNullOrEmpty(m_roleValueName) || !info.TryGetRoleValueByName(m_roleValueName, out m_roleValue)) |
|
{ |
|
m_roleValue = info.IsValidRoleValue(m_roleValueInt) ? m_roleValueInt : info.InvalidRoleValue; |
|
} |
|
|
|
roleValueChanged = oldRoleValue != m_roleValue; |
|
} |
|
|
|
if (roleTypeChanged || roleValueChanged) |
|
{ |
|
if (m_onDeviceIndexChanged != null) |
|
{ |
|
var oldDeviceIndex = m_deviceIndex; |
|
m_deviceIndex = m_roleMap.GetMappedDeviceByRoleValue(m_roleValue); |
|
|
|
if (VRModule.IsValidDeviceIndex(oldDeviceIndex) || VRModule.IsValidDeviceIndex(m_deviceIndex)) |
|
{ |
|
deviceIndexChanged = oldDeviceIndex != m_deviceIndex; |
|
} |
|
} |
|
|
|
m_lockUpdate = true; |
|
|
|
if (m_onChanged != null) { m_onChanged(); } |
|
|
|
if (m_onRoleChanged != null) { m_onRoleChanged(); } |
|
|
|
if (m_onRoleChangedEx != null) { m_onRoleChangedEx(oldRoleType, oldRoleValue); } |
|
|
|
if (deviceIndexChanged) { m_onDeviceIndexChanged(m_deviceIndex); } |
|
|
|
m_lockUpdate = false; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// |
|
/// </summary> |
|
/// <typeparam name="TRole">Can be DeviceRole, HandRole or TrackerRole</typeparam> |
|
/// <param name="role"></param> |
|
public void SetEx<TRole>(TRole role) |
|
{ |
|
Set(typeof(TRole).FullName, role.ToString()); |
|
} |
|
|
|
public void Set(Type type, int value) |
|
{ |
|
Set(type.FullName, ViveRoleEnum.GetInfo(type).GetNameByRoleValue(value)); |
|
} |
|
|
|
public void Set(ViveRoleProperty prop) |
|
{ |
|
Set(prop.m_roleTypeFullName, prop.m_roleValueName); |
|
} |
|
|
|
// set by value name to preserve the enum element, since different enum element could have same enum value |
|
public void Set(string typeFullName, string valueName) |
|
{ |
|
m_isTypeDirty |= ChangeProp.Set(ref m_roleTypeFullName, typeFullName); |
|
m_isValueDirty |= ChangeProp.Set(ref m_roleValueName, valueName); |
|
|
|
Update(); |
|
} |
|
|
|
public uint GetDeviceIndex() |
|
{ |
|
Update(); |
|
|
|
if (m_onDeviceIndexChanged == null) |
|
{ |
|
return m_roleMap.GetMappedDeviceByRoleValue(m_roleValue); |
|
} |
|
else |
|
{ |
|
return m_deviceIndex; |
|
} |
|
} |
|
|
|
public TRole ToRole<TRole>() |
|
{ |
|
Update(); |
|
|
|
TRole role; |
|
var roleInfo = ViveRoleEnum.GetInfo<TRole>(); |
|
if (m_roleType != typeof(TRole) || !roleInfo.TryGetRoleByName(m_roleValueName, out role)) |
|
{ |
|
// return invalid if role type not match or the value name not found in roleInfo |
|
return roleInfo.InvalidRole; |
|
} |
|
|
|
return role; |
|
} |
|
|
|
public bool IsRole(Type type, int value) |
|
{ |
|
Update(); |
|
|
|
return m_roleType == type && m_roleValue == value; |
|
} |
|
|
|
public bool IsRole<TRole>(TRole role) |
|
{ |
|
Update(); |
|
|
|
if (m_roleType != typeof(TRole)) { return false; } |
|
var roleInfo = ViveRoleEnum.GetInfo<TRole>(); |
|
|
|
return m_roleValue == roleInfo.ToRoleValue(role); |
|
} |
|
|
|
public static bool operator ==(ViveRoleProperty p1, ViveRoleProperty p2) |
|
{ |
|
if (ReferenceEquals(p1, p2)) { return true; } |
|
if (ReferenceEquals(p1, null)) { return false; } |
|
if (ReferenceEquals(p2, null)) { return false; } |
|
if (p1.roleType != p2.roleType) { return false; } |
|
if (p1.roleValue != p2.roleValue) { return false; } |
|
return true; |
|
} |
|
|
|
public static bool operator !=(ViveRoleProperty p1, ViveRoleProperty p2) |
|
{ |
|
return !(p1 == p2); |
|
} |
|
|
|
public bool Equals(ViveRoleProperty prop) |
|
{ |
|
return this == prop; |
|
} |
|
|
|
public override bool Equals(object obj) |
|
{ |
|
return Equals(obj as ViveRoleProperty); |
|
} |
|
|
|
public override int GetHashCode() |
|
{ |
|
Update(); |
|
|
|
var hash = 17; |
|
hash = hash * 23 + (m_roleType == null ? 0 : m_roleType.GetHashCode()); |
|
hash = hash * 23 + m_roleValue.GetHashCode(); |
|
return hash; |
|
} |
|
|
|
public override string ToString() |
|
{ |
|
Update(); |
|
|
|
return m_roleType.Name + "." + ViveRoleEnum.GetInfo(m_roleType).GetNameByRoleValue(m_roleValue); |
|
} |
|
} |
|
} |