// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using UltimateXR.Avatar;
using UltimateXR.Core.Components.Composite;
using UnityEngine;
using UnityEngine.XR;
namespace UltimateXR.Devices
{
///
/// Base class for tracking devices.
///
public abstract class UxrTrackingDevice : UxrAvatarComponent, IUxrTrackingDevice, IUxrTrackingUpdater
{
#region Inspector Properties/Serialized Fields
[Header("Mixed Reality:")] [SerializeField] private bool _hideAvatarInPassthrough = true;
#endregion
#region Public Types & Data
///
/// Default update order.
///
public const int OrderStandard = 0;
///
/// Default update order for post-process tracking devices such as hand-tracking.
///
public const int OrderPostprocess = 10;
///
/// Gets the headset device name.
///
public static string HeadsetDeviceName
{
get
{
var inputDevices = new List();
InputDevices.GetDevices(inputDevices);
foreach (var device in inputDevices)
{
if (device.characteristics.HasFlag(InputDeviceCharacteristics.HeadMounted))
{
return device.name;
}
}
return string.Empty;
}
}
///
/// Gets the tracking update order.
/// There are cases where more than one tracking device might be active. We use TrackingUpdateOrder
/// for cases where there is one that should be applied after the other(s). For example an Oculus Rift
/// together with a Leap Motion setup has one tracking component for each. But Leap Motion should
/// override the tracking values of the rift controllers if the Leap Motion component is active.
/// In this case Oculus, like most tracking devices, has a value of
/// while Leap Motion has a value of so that the tracking
/// devices update the avatar in the correct order.
///
public virtual int TrackingUpdateOrder => OrderStandard;
///
/// Gets whether the device headset renders on top of the real world.
///
public virtual bool IsMixedRealityDevice => false;
#endregion
#region Implicit IUxrDevice
///
public abstract string SDKDependency { get; }
///
public event EventHandler DeviceConnected;
#endregion
#region Implicit IUxrTrackingDevice
///
public event EventHandler SensorsUpdating;
///
public event EventHandler SensorsUpdated;
///
public event EventHandler AvatarUpdating;
///
public event EventHandler AvatarUpdated;
#endregion
#region Explicit IUxrTrackingUpdater
///
void IUxrTrackingUpdater.UpdateAvatar()
{
OnAvatarUpdating();
UpdateAvatar();
OnAvatarUpdated();
}
///
void IUxrTrackingUpdater.UpdateSensors()
{
OnSensorsUpdating();
UpdateSensors();
OnSensorsUpdated();
}
#endregion
#region Public Methods
///
/// Tries to get the connected headset device.
///
/// Returns the headset device if found
/// Whether the device was found
public static bool GetHeadsetDevice(out InputDevice inputDevice)
{
var inputDevices = new List();
InputDevices.GetDevices(inputDevices);
foreach (var device in inputDevices)
{
if (device.characteristics.HasFlag(InputDeviceCharacteristics.HeadMounted))
{
inputDevice = device;
return true;
}
}
inputDevice = new InputDevice();
return false;
}
#endregion
#region Unity
///
/// Sets events to null in order to help remove unused references.
///
protected override void OnDestroy()
{
base.OnDestroy();
DeviceConnected = null;
SensorsUpdating = null;
SensorsUpdated = null;
AvatarUpdating = null;
AvatarUpdated = null;
}
#endregion
#region Event Trigger Methods
///
/// Event trigger for the event. Can be used to override in child classes in order to
/// use the event without subscribing to the parent.
///
/// Event parameters
/// Calling the base implementation is required in child classes in order for the event to propagate correctly.
protected virtual void OnDeviceConnected(UxrDeviceConnectEventArgs e)
{
// Hide the avatar renderers in passthrough mode for mixed reality devices?
if (e.IsConnected && IsMixedRealityDevice && _hideAvatarInPassthrough)
{
Avatar.RenderMode = UxrAvatarRenderModes.None;
}
DeviceConnected?.Invoke(this, e);
}
///
/// Event trigger for the event. Can be used to override in child classes in order to use
/// the event without subscribing to the parent.
///
/// Event parameters
/// Calling the base implementation is required in child classes in order for the event to propagate correctly.
protected virtual void OnAvatarUpdating()
{
AvatarUpdating?.Invoke(this, EventArgs.Empty);
}
///
/// Event trigger for the event. Can be used to override in child classes in order to use
/// the event without subscribing to the parent.
///
/// Event parameters
/// Calling the base implementation is required in child classes in order for the event to propagate correctly.
protected virtual void OnAvatarUpdated()
{
AvatarUpdated?.Invoke(this, EventArgs.Empty);
}
///
/// Event trigger for the event. Can be used to override in child classes in order to
/// use the event without subscribing to the parent.
///
/// Event parameters
/// Calling the base implementation is required in child classes in order for the event to propagate correctly.
protected virtual void OnSensorsUpdating()
{
SensorsUpdating?.Invoke(this, EventArgs.Empty);
}
///
/// Event trigger for the event. Can be used to override in child classes in order to use
/// the event without subscribing to the parent.
///
/// Event parameters
/// Calling the base implementation is required in child classes in order for the event to propagate correctly.
protected virtual void OnSensorsUpdated()
{
SensorsUpdated?.Invoke(this, EventArgs.Empty);
}
#endregion
#region Protected Methods
///
/// Overriden in child classes to implement the update of the current sensor data.
///
protected virtual void UpdateSensors()
{
}
///
/// Overriden in child classes to implement the update of the avatar using the current sensor data.
///
protected virtual void UpdateAvatar()
{
}
#endregion
}
}