/**************************************************************************** * 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); } } }