123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- /****************************************************************************
- * Copyright 2019 Nreal Techonology Limited. All rights reserved.
- *
- * This file is part of NRSDK.
- *
- * https://www.nreal.ai/
- *
- *****************************************************************************/
- namespace NRKernal
- {
- using AOT;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Runtime.InteropServices;
- using UnityEngine;
- using UnityEngine.UI;
- #if UNITY_EDITOR
- using UnityEditor;
- #endif
- /// <summary> A nr virtual displayer. </summary>
- [HelpURL("https://developer.nreal.ai/develop/unity/customize-phone-controller")]
- [ScriptOrder(NativeConstants.NRVIRTUALDISPLAY_ORDER)]
- public class NRVirtualDisplayer : SingletonBehaviour<NRVirtualDisplayer>, ISystemButtonStateReceiver
- {
- /// <summary>
- /// Event queue for all listeners interested in onDisplayScreenChanged events.
- /// </summary>
- public static event Action<Resolution> OnDisplayScreenChangedEvent;
- /// <summary> State of the system button. </summary>
- [NonSerialized] public static SystemInputState SystemButtonState = new SystemInputState();
- /// <summary> The camera. </summary>
- [SerializeField] Camera m_UICamera;
- /// <summary> The virtual controller. </summary>
- [SerializeField] MultiScreenController m_VirtualController;
- private ISystemButtonStateProvider m_ISystemButtonStateProvider;
- /// <summary> The screen resolution. </summary>
- private Vector2 m_ScreenResolution;
- /// <summary> Not supported on runtime. </summary>
- private const float ScaleFactor = 1f;
- /// <summary> The virtual display FPS. </summary>
- public static int VirtualDisplayFPS = 24;
- /// <summary> The current time. </summary>
- private float m_CurrentTime;
- public enum DisplayMode
- {
- None,
- Unity,
- AndroidNative
- }
- private DisplayMode m_DisplayMode = DisplayMode.AndroidNative;
- public static DisplayMode displayMode
- {
- get
- {
- if (Instance != null)
- {
- return Instance.m_DisplayMode;
- }
- else
- {
- return DisplayMode.AndroidNative;
- }
- }
- }
- #if UNITY_EDITOR
- private static RenderTexture m_ControllerScreen;
- #endif
- private NRDisplaySubsystem m_Subsystem;
- public NRDisplaySubsystem Subsystem
- {
- get
- {
- if (m_Subsystem == null)
- {
- string str_match = NRDisplaySubsystemDescriptor.Name;
- List<NRDisplaySubsystemDescriptor> descriptors = new List<NRDisplaySubsystemDescriptor>();
- NRSubsystemManager.GetSubsystemDescriptors(descriptors);
- foreach (var des in descriptors)
- {
- if (des.id.Equals(str_match))
- {
- m_Subsystem = des.Create();
- }
- }
- }
- return m_Subsystem;
- }
- }
- /// <summary> Event queue for all listeners interested in OnMultiDisplayInited events. </summary>
- public event Action OnMultiDisplayInitialized;
- /// <summary> True to run in background. </summary>
- public static bool RunInBackground = true;
- /// <summary> True if is initialize, false if not. </summary>
- private bool m_IsInitialized = false;
- private void OnApplicationPause(bool pause)
- {
- if (!m_IsInitialized || isDirty)
- {
- return;
- }
- if (RunInBackground)
- {
- if (pause)
- {
- this.Pause();
- }
- else
- {
- this.Resume();
- }
- }
- else
- {
- NRDevice.ForceKill();
- }
- }
- /// <summary> Starts this object. </summary>
- void Start()
- {
- if (isDirty) return;
- this.CreateDisplay();
- }
- private void CreateDisplay()
- {
- if (m_IsInitialized) return;
- NRDebugger.Info("[NRVirtualDisplayer] Create display.");
- try
- {
- NRDevice.Instance.Init();
- }
- catch (Exception e)
- {
- NRDebugger.Error("[NRVirtualDisplayer] NRDevice init error:" + e.ToString());
- throw;
- }
- Subsystem.ListenMainScrResolutionChanged(OnDisplayResolutionChanged);
- Subsystem.Start();
- #if !UNITY_EDITOR && UNITY_ANDROID
- if (m_VirtualController == null)
- {
- var phoneScreenReplayceTool = FindObjectOfType<NRPhoneDisplayReplayceTool>();
- if (phoneScreenReplayceTool == null)
- {
- NRDebugger.Info("[NRVirtualDisplayer] Use default phone sceen provider.");
- this.BindVirtualDisplayProvider(new NRDefaultPhoneScreenProvider());
- }
- else
- {
- NRDebugger.Info("[NRVirtualDisplayer] Use replayced phone sceen provider.");
- this.BindVirtualDisplayProvider(phoneScreenReplayceTool.CreatePhoneScreenProvider());
- }
- }
- else
- {
- this.BindVirtualDisplayProvider(null);
- }
- #else
- this.BindVirtualDisplayProvider(null);
- #endif
- NRSessionManager.Instance.VirtualDisplayer = this;
- NRDebugger.Info("[NRVirtualDisplayer] Initialize");
- m_IsInitialized = true;
- OnMultiDisplayInitialized?.Invoke();
- }
- private void Pause()
- {
- if (!m_IsInitialized)
- {
- return;
- }
- Subsystem.Pause();
- }
- private void Resume()
- {
- if (!m_IsInitialized)
- {
- return;
- }
- Subsystem.Resume();
- }
- private void Update()
- {
- if (!m_IsInitialized) return;
- #if UNITY_EDITOR
- UpdateEmulator();
- if (m_VirtualController)
- {
- m_VirtualController.gameObject.SetActive(NRInput.EmulateVirtualDisplayInEditor);
- }
- #endif
- if (m_DisplayMode == DisplayMode.Unity)
- {
- if (Subsystem.running)
- {
- m_CurrentTime += Time.deltaTime;
- }
- if (Subsystem.running && m_CurrentTime > (1f / VirtualDisplayFPS))
- {
- m_CurrentTime = 0;
- m_UICamera?.Render();
- }
- }
- }
- /// <summary> Destories this object. </summary>
- public void Stop()
- {
- Subsystem.Stop();
- #if UNITY_EDITOR
- m_ControllerScreen?.Release();
- m_ControllerScreen = null;
- #endif
- }
- /// <summary>
- /// Base OnDestroy method that destroys the Singleton's unique instance. Called by Unity when
- /// destroying a MonoBehaviour. Scripts that extend Singleton should be sure to call
- /// base.OnDestroy() to ensure the underlying static Instance reference is properly cleaned up. </summary>
- new void OnDestroy()
- {
- if (isDirty) return;
- base.OnDestroy();
- this.Stop();
- }
- /// <summary> If m_VirtualController is null, use android native
- /// fragment as the virtual controller provider. </summary>
- private void BindVirtualDisplayProvider(NRPhoneScreenProviderBase provider)
- {
- if (m_ISystemButtonStateProvider != null)
- {
- return;
- }
- bool targetOSX = false;
- #if UNITY_EDITOR
- targetOSX = EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.StandaloneOSX;
- #endif
- if (Application.platform == RuntimePlatform.OSXPlayer || targetOSX)
- {
- // No virtual controller on Mac
- m_DisplayMode = DisplayMode.None;
- m_ISystemButtonStateProvider = null;
- if (m_VirtualController != null)
- {
- m_VirtualController.gameObject.SetActive(false);
- }
- }
- else if (provider != null && m_VirtualController == null && Application.platform == RuntimePlatform.Android)
- {
- m_DisplayMode = DisplayMode.AndroidNative;
- m_ISystemButtonStateProvider = provider;
- NRDebugger.Info("[NRVirtualDisplayer] Bind android native controller");
- }
- else
- {
- m_DisplayMode = DisplayMode.Unity;
- transform.position = Vector3.one * 99999f;
- m_ISystemButtonStateProvider = m_VirtualController;
- NRDebugger.Info("[NRVirtualDisplayer] Bind unity virtual controller");
- #if UNITY_EDITOR
- var canvas = transform.GetComponentInChildren<Canvas>();
- var scaler = canvas.transform.GetComponent<CanvasScaler>();
- if (scaler != null)
- {
- scaler.enabled = false;
- }
- SetVirtualDisplayResolution();
- InitEmulator();
- #else
- if (m_UICamera != null)
- {
- this.m_UICamera.enabled = false;
- }
- #endif
- }
- m_ISystemButtonStateProvider?.BindReceiver(this);
- }
- public void OnDataReceived(SystemButtonState state)
- {
- lock (SystemButtonState)
- {
- state.TransformTo(SystemButtonState);
- }
- }
- /// <summary> Updates the resolution described by size. </summary>
- /// <param name="size"> The size.</param>
- public void UpdateResolution(Vector2 size)
- {
- #if UNITY_EDITOR
- NRPhoneScreen.Resolution = size;
- this.SetVirtualDisplayResolution();
- this.UpdateEmulatorScreen(size * ScaleFactor);
- #endif
- var m_PointRaycaster = gameObject.GetComponentInChildren<NRMultScrPointerRaycaster>();
- if (m_PointRaycaster != null)
- {
- m_PointRaycaster.UpdateScreenSize(size * ScaleFactor);
- }
- if (m_ISystemButtonStateProvider != null && m_ISystemButtonStateProvider is NRPhoneScreenProviderBase)
- {
- ((NRPhoneScreenProviderBase)m_ISystemButtonStateProvider).ResizeView((int)size.x, (int)size.y);
- }
- }
- #if UNITY_EDITOR
- /// <summary> Sets virtual display resolution. </summary>
- private void SetVirtualDisplayResolution()
- {
- m_ScreenResolution = NRPhoneScreen.Resolution;
- if (m_ControllerScreen != null)
- {
- m_ControllerScreen.Release();
- }
- m_ControllerScreen = new RenderTexture(
- (int)(m_ScreenResolution.x * ScaleFactor),
- (int)(m_ScreenResolution.y * ScaleFactor),
- 24
- );
- m_UICamera.targetTexture = m_ControllerScreen;
- m_UICamera.aspect = m_ScreenResolution.x / m_ScreenResolution.y;
- m_UICamera.orthographicSize = 6;
- }
- #endif
- /// <summary> Executes the 'display resolution changed' action. </summary>
- /// <param name="w"> The width.</param>
- /// <param name="h"> The height.</param>
- [MonoPInvokeCallback(typeof(NRDisplayResolutionCallback))]
- public static void OnDisplayResolutionChanged(int w, int h)
- {
- NRDebugger.Info("[NRVirtualDisplayer] Display resolution changed width:{0} height:{1}", w, h);
- MainThreadDispather.QueueOnMainThread(delegate ()
- {
- NRVirtualDisplayer.Instance.UpdateResolution(new Vector2(w, h));
- OnDisplayScreenChangedEvent?.Invoke(new Resolution()
- {
- width = w,
- height = h
- });
- });
- }
- #region Emulator
- #if UNITY_EDITOR
- /// <summary> The emulator touch. </summary>
- private static Vector2 m_EmulatorTouch = Vector2.zero;
- /// <summary> The emulator phone screen anchor. </summary>
- private Vector2 m_EmulatorPhoneScreenAnchor;
- /// <summary> Width of the emulator raw image. </summary>
- private float m_EmulatorRawImageWidth;
- /// <summary> Height of the emulator raw image. </summary>
- private float m_EmulatorRawImageHeight;
- /// <summary> The emulator phone raw image. </summary>
- private RawImage emulatorPhoneRawImage;
- /// <summary> Gets emulator screen touch. </summary>
- /// <returns> The emulator screen touch. </returns>
- public static Vector2 GetEmulatorScreenTouch()
- {
- return m_EmulatorTouch;
- }
- /// <summary> Initializes the emulator. </summary>
- private void InitEmulator()
- {
- GameObject emulatorVirtualController = new GameObject("NREmulatorVirtualController");
- DontDestroyOnLoad(emulatorVirtualController);
- Canvas controllerCanvas = emulatorVirtualController.AddComponent<Canvas>();
- controllerCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
- GameObject rawImageObj = new GameObject("RamImage");
- rawImageObj.transform.parent = controllerCanvas.transform;
- emulatorPhoneRawImage = rawImageObj.AddComponent<RawImage>();
- emulatorPhoneRawImage.raycastTarget = false;
- UpdateEmulatorScreen(m_ScreenResolution * ScaleFactor);
- }
- /// <summary> Updates the emulator screen described by size. </summary>
- /// <param name="size"> The size.</param>
- private void UpdateEmulatorScreen(Vector2 size)
- {
- float scaleRate = 0.18f;
- m_EmulatorRawImageWidth = size.x * scaleRate;
- m_EmulatorRawImageHeight = size.y * scaleRate;
- emulatorPhoneRawImage.rectTransform.pivot = Vector2.right;
- emulatorPhoneRawImage.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, 0f, 0f);
- emulatorPhoneRawImage.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, 0f, 0f);
- emulatorPhoneRawImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, m_EmulatorRawImageWidth);
- emulatorPhoneRawImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, m_EmulatorRawImageHeight);
- emulatorPhoneRawImage.texture = m_ControllerScreen;
- Vector2 gameViewSize = Handles.GetMainGameViewSize();
- m_EmulatorPhoneScreenAnchor = new Vector2(gameViewSize.x - m_EmulatorRawImageWidth, 0f);
- }
- /// <summary> Updates the emulator. </summary>
- private void UpdateEmulator()
- {
- if (NRInput.EmulateVirtualDisplayInEditor
- && Input.GetMouseButton(0)
- && Input.mousePosition.x > m_EmulatorPhoneScreenAnchor.x
- && Input.mousePosition.y < (m_EmulatorPhoneScreenAnchor.y + m_EmulatorRawImageHeight))
- {
- m_EmulatorTouch.x = (Input.mousePosition.x - m_EmulatorPhoneScreenAnchor.x) / m_EmulatorRawImageWidth * 2f - 1f;
- m_EmulatorTouch.y = (Input.mousePosition.y - m_EmulatorPhoneScreenAnchor.y) / m_EmulatorRawImageHeight * 2f - 1f;
- }
- else
- {
- m_EmulatorTouch = Vector2.zero;
- }
- }
- #endif
- #endregion
- }
- }
|