/****************************************************************************
* Copyright 2019 Nreal Techonology Limited. All rights reserved.
*
* This file is part of NRSDK.
*
* https://www.nreal.ai/
*
*****************************************************************************/
using AOT;
using System;
using System.Runtime.InteropServices;
using UnityEngine;
using static NRKernal.NRDevice;
namespace NRKernal
{
/// Glasses event.
/// The eventtype.
public delegate void GlassesEvent(NRDevice.GlassesEventType eventtype);
/// Glasses disconnect event.
/// The reason.
public delegate void GlassesDisconnectEvent(GlassesDisconnectReason reason);
/// Glassed temporary level changed.
/// The level.
public delegate void GlassedTempLevelChanged(GlassesTemperatureLevel level);
public class NRDeviceSubsystemDescriptor : IntegratedSubsystemDescriptor
{
public const string Name = "Subsystem.HMD";
public override string id => Name;
}
#region brightness KeyEvent on NrealLight.
/// Values that represent nr brightness key events.
public enum NRBrightnessKEYEvent
{
/// An enum constant representing the nr brightness key down option.
NR_BRIGHTNESS_KEY_DOWN = 0,
/// An enum constant representing the nr brightness key up option.
NR_BRIGHTNESS_KEY_UP = 1,
}
/// Brightness key event.
/// The key.
public delegate void BrightnessKeyEvent(NRBrightnessKEYEvent key);
/// Brightness value changed event.
/// The value.
public delegate void BrightnessValueChangedEvent(int value);
/// Callback, called when the nr glasses control brightness key.
/// Handle of the glasses control.
/// The key event.
/// Information describing the user.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NRGlassesControlBrightnessKeyCallback(UInt64 glasses_control_handle, int key_event, UInt64 user_data);
/// Callback, called when the nr glasses control brightness value.
/// Handle of the glasses control.
/// The value.
/// Information describing the user.
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void NRGlassesControlBrightnessValueCallback(UInt64 glasses_control_handle, int value, UInt64 user_data);
#endregion
public class NRDeviceSubsystem : IntegratedSubsystem
{
public static event GlassesEvent OnGlassesStateChanged;
public static event GlassesDisconnectEvent OnGlassesDisconnect;
private NativeHMD m_NativeHMD = null;
private NativeGlassesController m_NativeGlassesController = null;
private Exception m_InitException = null;
private static bool m_IsGlassesPlugOut = false;
private static bool m_ResetStateOnNextResume = false;
public UInt64 NativeGlassesHandler => m_NativeGlassesController.GlassesControllerHandle;
public UInt64 NativeHMDHandler => m_NativeHMD.HmdHandle;
public NativeHMD NativeHMD => m_NativeHMD;
public bool IsAvailable => !m_IsGlassesPlugOut && running && m_InitException == null;
/// Glass controll key event delegate for native.
private delegate void NRGlassesControlKeyEventCallback(UInt64 glasses_control_handle, UInt64 key_event_handle, UInt64 user_data);
/// Event queue for all listeners interested in OnBrightnessKeyCallback events.
private static event BrightnessKeyEvent OnBrightnessKeyCallback;
/// Event queue for all listeners interested in OnBrightnessValueCallback events.
private static event BrightnessValueChangedEvent OnBrightnessValueCallback;
/// The brightness minimum.
public const int BRIGHTNESS_MIN = 0;
/// The brightness maximum.
public const int BRIGHTNESS_MAX = 7;
public NRDeviceSubsystem(NRDeviceSubsystemDescriptor descriptor) : base(descriptor)
{
m_NativeGlassesController = new NativeGlassesController();
m_NativeHMD = new NativeHMD();
}
#region LifeCycle
public override void Start()
{
if (running)
{
return;
}
base.Start();
#if !UNITY_EDITOR
try
{
m_NativeGlassesController.Create();
m_NativeGlassesController.RegisGlassesWearCallBack(OnGlassesWear, 1);
m_NativeGlassesController.RegistGlassesEventCallBack(OnGlassesDisconnectEvent);
m_NativeGlassesController.Start();
m_NativeHMD.Create();
}
catch (Exception e)
{
m_InitException = e;
throw e;
}
#endif
}
/// Executes the 'glasses wear' action.
/// Handle of the glasses control.
/// The wearing status.
/// Information describing the user.
[MonoPInvokeCallback(typeof(NRGlassesControlWearCallback))]
private static void OnGlassesWear(UInt64 glasses_control_handle, int wearing_status, UInt64 user_data)
{
MainThreadDispather.QueueOnMainThread(() =>
{
OnGlassesStateChanged?.Invoke(wearing_status == 1 ? GlassesEventType.PutOn : GlassesEventType.PutOff);
});
}
/// Executes the 'glasses disconnect event' action.
/// Thrown when an exception error condition occurs.
/// Handle of the glasses control.
/// Information describing the user.
/// The reason.
[MonoPInvokeCallback(typeof(NRGlassesControlNotifyQuitAppCallback))]
private static void OnGlassesDisconnectEvent(UInt64 glasses_control_handle, IntPtr user_data, GlassesDisconnectReason reason)
{
if (m_IsGlassesPlugOut)
{
return;
}
m_IsGlassesPlugOut = true;
OnGlassesDisconnect?.Invoke(reason);
}
public void RegestEvents(GlassesEvent onGlassesWear, GlassesDisconnectEvent onGlassesDisconnectEvent)
{
OnGlassesStateChanged += onGlassesWear;
OnGlassesDisconnect += onGlassesDisconnectEvent;
}
public void ResetStateOnNextResume()
{
m_ResetStateOnNextResume = true;
}
public override void Pause()
{
if (!running)
{
return;
}
base.Pause();
#if !UNITY_EDITOR
m_NativeGlassesController?.Pause();
m_NativeHMD?.Pause();
#endif
}
public override void Resume()
{
if (running)
{
return;
}
base.Resume();
if (m_ResetStateOnNextResume)
{
m_ResetStateOnNextResume = false;
m_IsGlassesPlugOut = false;
}
#if !UNITY_EDITOR
m_NativeGlassesController?.Resume();
m_NativeHMD?.Resume();
#endif
}
public override void Stop()
{
if (!running)
{
return;
}
base.Stop();
#if !UNITY_EDITOR
m_NativeGlassesController?.Stop();
m_NativeGlassesController?.Destroy();
m_NativeHMD.Destroy();
#endif
}
#endregion
#region Glasses
/// Gets the temperature level.
/// The temperature level.
public GlassesTemperatureLevel TemperatureLevel
{
get
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
#if !UNITY_EDITOR
return m_NativeGlassesController.GetTempratureLevel();
#else
return GlassesTemperatureLevel.TEMPERATURE_LEVEL_NORMAL;
#endif
}
}
#endregion
#region HMD
public NRDeviceType GetDeviceType()
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
#if !UNITY_EDITOR
return m_NativeHMD.GetDeviceType();
#else
return NRDeviceType.NrealLight;
#endif
}
public bool IsFeatureSupported(NRSupportedFeature feature)
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
#if !UNITY_EDITOR
return m_NativeHMD.IsFeatureSupported(feature);
#else
return true;
#endif
}
/// Gets the resolution of device.
/// device index.
/// The device resolution.
public NativeResolution GetDeviceResolution(NativeDevice device)
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
#if !UNITY_EDITOR
return m_NativeHMD.GetEyeResolution((int)device);
#else
return new NativeResolution(1920, 1080);
#endif
}
/// Gets device fov.
/// The display index.
/// [in,out] The out device fov.
/// A NativeResult.
public void GetEyeFov(NativeDevice device, ref NativeFov4f fov)
{
if (!IsAvailable || (device != NativeDevice.LEFT_DISPLAY && device != NativeDevice.RIGHT_DISPLAY))
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
#if !UNITY_EDITOR
fov = m_NativeHMD.GetEyeFovInCoord(device);
#else
fov = new NativeFov4f(0, 0, 1, 1);
#endif
}
/// Get the intrinsic matrix of device.
/// The device intrinsic matrix.
public NRDistortionParams GetDeviceDistortion(NativeDevice device)
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
NRDistortionParams result = new NRDistortionParams();
#if !UNITY_EDITOR
m_NativeHMD.GetCameraDistortion((int)device, ref result);
#endif
return result;
}
/// Get the intrinsic matrix of device.
/// The device intrinsic matrix.
public NativeMat3f GetDeviceIntrinsicMatrix(NativeDevice device)
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
NativeMat3f result = new NativeMat3f();
#if !UNITY_EDITOR
m_NativeHMD.GetCameraIntrinsicMatrix((int)device, ref result);
#endif
return result;
}
/// Get the project matrix of camera in unity.
/// [out] True to result.
/// The znear.
/// The zfar.
/// project matrix of camera.
public EyeProjectMatrixData GetEyeProjectMatrix(out bool result, float znear, float zfar)
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
result = false;
EyeProjectMatrixData m_EyeProjectMatrix = new EyeProjectMatrixData();
#if !UNITY_EDITOR
result = m_NativeHMD.GetProjectionMatrix(ref m_EyeProjectMatrix, znear, zfar);
#endif
return m_EyeProjectMatrix;
}
/// Get the offset position between device and head.
/// The device pose from head.
public Pose GetDevicePoseFromHead(NativeDevice device)
{
if (!IsAvailable)
{
throw new NRGlassesNotAvailbleError("Device is not available.");
}
#if !UNITY_EDITOR
return m_NativeHMD.GetDevicePoseFromHead(device);
#else
return Pose.identity;
#endif
}
#endregion
#region brightness KeyEvent on NrealLight.
/// Adds an event listener to 'callback'.
/// The callback.
public void AddEventListener(BrightnessKeyEvent callback)
{
OnBrightnessKeyCallback += callback;
}
///
/// Adds an event listener to 'callback'.
/// The callback.
public void AddEventListener(BrightnessValueChangedEvent callback)
{
OnBrightnessValueCallback += callback;
}
/// Removes the event listener.
/// The callback.
public void RemoveEventListener(BrightnessKeyEvent callback)
{
OnBrightnessKeyCallback -= callback;
}
/// Removes the event listener.
/// The callback.
public void RemoveEventListener(BrightnessValueChangedEvent callback)
{
OnBrightnessValueCallback -= callback;
}
/// Gets the brightness.
/// The brightness.
public int GetBrightness()
{
if (!IsAvailable)
{
return -1;
}
#if !UNITY_EDITOR
int brightness = -1;
var result = NativeApi.NRGlassesControlGetBrightness(NativeGlassesHandler, ref brightness);
return result == NativeResult.Success ? brightness : -1;
#else
return 0;
#endif
}
/// Sets the brightness.
/// The brightness.
public void SetBrightness(int brightness)
{
if (!IsAvailable)
{
return;
}
AsyncTaskExecuter.Instance.RunAction(() =>
{
#if !UNITY_EDITOR
NativeApi.NRGlassesControlSetBrightness(NativeGlassesHandler, brightness);
#endif
});
}
/// Executes the 'brightness key callback internal' action.
/// Handle of the glasses control.
/// The key event.
/// Information describing the user.
[MonoPInvokeCallback(typeof(NRGlassesControlBrightnessKeyCallback))]
private static void OnBrightnessKeyCallbackInternal(UInt64 glasses_control_handle, int key_event, UInt64 user_data)
{
OnBrightnessKeyCallback?.Invoke((NRBrightnessKEYEvent)key_event);
}
/// Executes the 'brightness value callback internal' action.
/// Handle of the glasses control.
/// The brightness.
/// Information describing the user.
[MonoPInvokeCallback(typeof(NRGlassesControlBrightnessValueCallback))]
private static void OnBrightnessValueCallbackInternal(UInt64 glasses_control_handle, int brightness, UInt64 user_data)
{
OnBrightnessValueCallback?.Invoke(brightness);
}
/// Event queue for all listeners interested in KeyEvent events.
private static event NRGlassControlKeyEvent OnKeyEventCallback;
///
/// Adds an key event listener.
/// The callback.
public void AddKeyEventListener(NRGlassControlKeyEvent callback)
{
OnKeyEventCallback += callback;
}
/// Removes the key event listener.
/// The callback.
public void RemoveKeyEventListener(NRGlassControlKeyEvent callback)
{
OnKeyEventCallback -= callback;
}
/// Executes the 'key event callback internal' action.
/// Handle of the glasses control.
/// Handle of the key event.
/// Information describing the user.
[MonoPInvokeCallback(typeof(NRGlassesControlKeyEventCallback))]
private static void OnKeyEventCallbackInternal(UInt64 glasses_control_handle, UInt64 key_event_handle, UInt64 user_data)
{
int keyType = 0;
int keyFunc = 0;
int keyParam = 0;
#if !UNITY_EDITOR
NativeResult result = NativeApi.NRGlassesControlKeyEventGetType(glasses_control_handle, key_event_handle, ref keyType);
if (result == NativeResult.Success)
result = NativeApi.NRGlassesControlKeyEventGetFunction(glasses_control_handle, key_event_handle, ref keyFunc);
if (result == NativeResult.Success)
result = NativeApi.NRGlassesControlKeyEventGetParam(glasses_control_handle, key_event_handle, ref keyParam);
#endif
NRKeyEventInfo keyEvtInfo = new NRKeyEventInfo();
keyEvtInfo.keyType = (NRKeyType)keyType;
keyEvtInfo.keyFunc = (NRKeyFunction)keyFunc;
keyEvtInfo.keyParam = keyParam;
OnKeyEventCallback?.Invoke(keyEvtInfo);
}
///
/// Regis glasses controller extra callbacks.
public void RegisGlassesControllerExtraCallbacks()
{
if (!IsAvailable)
{
NRDebugger.Warning("[NRDevice] Can not regist event when glasses disconnect...");
return;
}
#if !UNITY_EDITOR
NativeApi.NRGlassesControlSetBrightnessKeyCallback(NativeGlassesHandler, OnBrightnessKeyCallbackInternal, 0);
NativeApi.NRGlassesControlSetBrightnessValueCallback(NativeGlassesHandler, OnBrightnessValueCallbackInternal, 0);
NativeApi.NRGlassesControlSetKeyEventCallback(NativeGlassesHandler, OnKeyEventCallbackInternal, 0);
#endif
}
#endregion
private struct NativeApi
{
/// Nr glasses control get brightness.
/// Handle of the glasses control.
/// [in,out] The out brightness.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRGlassesControlGetBrightness(UInt64 glasses_control_handle, ref int out_brightness);
/// Nr glasses control set brightness.
/// Handle of the glasses control.
/// The brightness.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary)]
public static extern NativeResult NRGlassesControlSetBrightness(UInt64 glasses_control_handle, int brightness);
/// Callback, called when the nr glasses control set brightness key.
/// Handle of the glasses control.
/// The callback.
/// Information describing the user.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern NativeResult NRGlassesControlSetBrightnessKeyCallback(UInt64 glasses_control_handle, NRGlassesControlBrightnessKeyCallback callback, UInt64 user_data);
/// Callback, called when the nr glasses control set brightness value.
/// Handle of the glasses control.
/// The callback.
/// Information describing the user.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern NativeResult NRGlassesControlSetBrightnessValueCallback(UInt64 glasses_control_handle, NRGlassesControlBrightnessValueCallback callback, UInt64 user_data);
/// Registe the callback when the nr glasses control issue key event.
/// Handle of the glasses control.
/// The called.
/// Information describing the user.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern NativeResult NRGlassesControlSetKeyEventCallback(UInt64 glasses_control_handle, NRGlassesControlKeyEventCallback callback, UInt64 user_data);
/// Get key type of key event.
/// Handle of the glasses control.
/// Handle of key event.
/// Key type retrieved.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern NativeResult NRGlassesControlKeyEventGetType(UInt64 glasses_control_handle, UInt64 key_event_handle, ref int out_key_event_type);
/// Get key function of key event.
/// Handle of the glasses control.
/// Handle of key event.
/// Key funtion retrieved.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern NativeResult NRGlassesControlKeyEventGetFunction(UInt64 glasses_control_handle, UInt64 key_event_handle, ref int out_key_event_function);
/// Get key parameter of key event.
/// Handle of the glasses control.
/// Handle of key event.
/// Key parameter retrieved.
/// A NativeResult.
[DllImport(NativeConstants.NRNativeLibrary, CallingConvention = CallingConvention.Cdecl)]
public static extern NativeResult NRGlassesControlKeyEventGetParam(UInt64 glasses_control_handle, UInt64 key_event_handle, ref int out_key_event_param);
}
}
}