NRVirtualDisplayer.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451
  1. /****************************************************************************
  2. * Copyright 2019 Nreal Techonology Limited. All rights reserved.
  3. *
  4. * This file is part of NRSDK.
  5. *
  6. * https://www.nreal.ai/
  7. *
  8. *****************************************************************************/
  9. namespace NRKernal
  10. {
  11. using AOT;
  12. using System;
  13. using System.Collections;
  14. using System.Collections.Generic;
  15. using System.Runtime.InteropServices;
  16. using UnityEngine;
  17. using UnityEngine.UI;
  18. #if UNITY_EDITOR
  19. using UnityEditor;
  20. #endif
  21. /// <summary> A nr virtual displayer. </summary>
  22. [HelpURL("https://developer.nreal.ai/develop/unity/customize-phone-controller")]
  23. [ScriptOrder(NativeConstants.NRVIRTUALDISPLAY_ORDER)]
  24. public class NRVirtualDisplayer : SingletonBehaviour<NRVirtualDisplayer>, ISystemButtonStateReceiver
  25. {
  26. /// <summary>
  27. /// Event queue for all listeners interested in onDisplayScreenChanged events.
  28. /// </summary>
  29. public static event Action<Resolution> OnDisplayScreenChangedEvent;
  30. /// <summary> State of the system button. </summary>
  31. [NonSerialized] public static SystemInputState SystemButtonState = new SystemInputState();
  32. /// <summary> The camera. </summary>
  33. [SerializeField] Camera m_UICamera;
  34. /// <summary> The virtual controller. </summary>
  35. [SerializeField] MultiScreenController m_VirtualController;
  36. private ISystemButtonStateProvider m_ISystemButtonStateProvider;
  37. /// <summary> The screen resolution. </summary>
  38. private Vector2 m_ScreenResolution;
  39. /// <summary> Not supported on runtime. </summary>
  40. private const float ScaleFactor = 1f;
  41. /// <summary> The virtual display FPS. </summary>
  42. public static int VirtualDisplayFPS = 24;
  43. /// <summary> The current time. </summary>
  44. private float m_CurrentTime;
  45. public enum DisplayMode
  46. {
  47. None,
  48. Unity,
  49. AndroidNative
  50. }
  51. private DisplayMode m_DisplayMode = DisplayMode.AndroidNative;
  52. public static DisplayMode displayMode
  53. {
  54. get
  55. {
  56. if (Instance != null)
  57. {
  58. return Instance.m_DisplayMode;
  59. }
  60. else
  61. {
  62. return DisplayMode.AndroidNative;
  63. }
  64. }
  65. }
  66. #if UNITY_EDITOR
  67. private static RenderTexture m_ControllerScreen;
  68. #endif
  69. private NRDisplaySubsystem m_Subsystem;
  70. public NRDisplaySubsystem Subsystem
  71. {
  72. get
  73. {
  74. if (m_Subsystem == null)
  75. {
  76. string str_match = NRDisplaySubsystemDescriptor.Name;
  77. List<NRDisplaySubsystemDescriptor> descriptors = new List<NRDisplaySubsystemDescriptor>();
  78. NRSubsystemManager.GetSubsystemDescriptors(descriptors);
  79. foreach (var des in descriptors)
  80. {
  81. if (des.id.Equals(str_match))
  82. {
  83. m_Subsystem = des.Create();
  84. }
  85. }
  86. }
  87. return m_Subsystem;
  88. }
  89. }
  90. /// <summary> Event queue for all listeners interested in OnMultiDisplayInited events. </summary>
  91. public event Action OnMultiDisplayInitialized;
  92. /// <summary> True to run in background. </summary>
  93. public static bool RunInBackground = true;
  94. /// <summary> True if is initialize, false if not. </summary>
  95. private bool m_IsInitialized = false;
  96. private void OnApplicationPause(bool pause)
  97. {
  98. if (!m_IsInitialized || isDirty)
  99. {
  100. return;
  101. }
  102. if (RunInBackground)
  103. {
  104. if (pause)
  105. {
  106. this.Pause();
  107. }
  108. else
  109. {
  110. this.Resume();
  111. }
  112. }
  113. else
  114. {
  115. NRDevice.ForceKill();
  116. }
  117. }
  118. /// <summary> Starts this object. </summary>
  119. void Start()
  120. {
  121. if (isDirty) return;
  122. this.CreateDisplay();
  123. }
  124. private void CreateDisplay()
  125. {
  126. if (m_IsInitialized) return;
  127. NRDebugger.Info("[NRVirtualDisplayer] Create display.");
  128. try
  129. {
  130. NRDevice.Instance.Init();
  131. }
  132. catch (Exception e)
  133. {
  134. NRDebugger.Error("[NRVirtualDisplayer] NRDevice init error:" + e.ToString());
  135. throw;
  136. }
  137. Subsystem.ListenMainScrResolutionChanged(OnDisplayResolutionChanged);
  138. Subsystem.Start();
  139. #if !UNITY_EDITOR && UNITY_ANDROID
  140. if (m_VirtualController == null)
  141. {
  142. var phoneScreenReplayceTool = FindObjectOfType<NRPhoneDisplayReplayceTool>();
  143. if (phoneScreenReplayceTool == null)
  144. {
  145. NRDebugger.Info("[NRVirtualDisplayer] Use default phone sceen provider.");
  146. this.BindVirtualDisplayProvider(new NRDefaultPhoneScreenProvider());
  147. }
  148. else
  149. {
  150. NRDebugger.Info("[NRVirtualDisplayer] Use replayced phone sceen provider.");
  151. this.BindVirtualDisplayProvider(phoneScreenReplayceTool.CreatePhoneScreenProvider());
  152. }
  153. }
  154. else
  155. {
  156. this.BindVirtualDisplayProvider(null);
  157. }
  158. #else
  159. this.BindVirtualDisplayProvider(null);
  160. #endif
  161. NRSessionManager.Instance.VirtualDisplayer = this;
  162. NRDebugger.Info("[NRVirtualDisplayer] Initialize");
  163. m_IsInitialized = true;
  164. OnMultiDisplayInitialized?.Invoke();
  165. }
  166. private void Pause()
  167. {
  168. if (!m_IsInitialized)
  169. {
  170. return;
  171. }
  172. Subsystem.Pause();
  173. }
  174. private void Resume()
  175. {
  176. if (!m_IsInitialized)
  177. {
  178. return;
  179. }
  180. Subsystem.Resume();
  181. }
  182. private void Update()
  183. {
  184. if (!m_IsInitialized) return;
  185. #if UNITY_EDITOR
  186. UpdateEmulator();
  187. if (m_VirtualController)
  188. {
  189. m_VirtualController.gameObject.SetActive(NRInput.EmulateVirtualDisplayInEditor);
  190. }
  191. #endif
  192. if (m_DisplayMode == DisplayMode.Unity)
  193. {
  194. if (Subsystem.running)
  195. {
  196. m_CurrentTime += Time.deltaTime;
  197. }
  198. if (Subsystem.running && m_CurrentTime > (1f / VirtualDisplayFPS))
  199. {
  200. m_CurrentTime = 0;
  201. m_UICamera?.Render();
  202. }
  203. }
  204. }
  205. /// <summary> Destories this object. </summary>
  206. public void Stop()
  207. {
  208. Subsystem.Stop();
  209. #if UNITY_EDITOR
  210. m_ControllerScreen?.Release();
  211. m_ControllerScreen = null;
  212. #endif
  213. }
  214. /// <summary>
  215. /// Base OnDestroy method that destroys the Singleton's unique instance. Called by Unity when
  216. /// destroying a MonoBehaviour. Scripts that extend Singleton should be sure to call
  217. /// base.OnDestroy() to ensure the underlying static Instance reference is properly cleaned up. </summary>
  218. new void OnDestroy()
  219. {
  220. if (isDirty) return;
  221. base.OnDestroy();
  222. this.Stop();
  223. }
  224. /// <summary> If m_VirtualController is null, use android native
  225. /// fragment as the virtual controller provider. </summary>
  226. private void BindVirtualDisplayProvider(NRPhoneScreenProviderBase provider)
  227. {
  228. if (m_ISystemButtonStateProvider != null)
  229. {
  230. return;
  231. }
  232. bool targetOSX = false;
  233. #if UNITY_EDITOR
  234. targetOSX = EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.StandaloneOSX;
  235. #endif
  236. if (Application.platform == RuntimePlatform.OSXPlayer || targetOSX)
  237. {
  238. // No virtual controller on Mac
  239. m_DisplayMode = DisplayMode.None;
  240. m_ISystemButtonStateProvider = null;
  241. if (m_VirtualController != null)
  242. {
  243. m_VirtualController.gameObject.SetActive(false);
  244. }
  245. }
  246. else if (provider != null && m_VirtualController == null && Application.platform == RuntimePlatform.Android)
  247. {
  248. m_DisplayMode = DisplayMode.AndroidNative;
  249. m_ISystemButtonStateProvider = provider;
  250. NRDebugger.Info("[NRVirtualDisplayer] Bind android native controller");
  251. }
  252. else
  253. {
  254. m_DisplayMode = DisplayMode.Unity;
  255. transform.position = Vector3.one * 99999f;
  256. m_ISystemButtonStateProvider = m_VirtualController;
  257. NRDebugger.Info("[NRVirtualDisplayer] Bind unity virtual controller");
  258. #if UNITY_EDITOR
  259. var canvas = transform.GetComponentInChildren<Canvas>();
  260. var scaler = canvas.transform.GetComponent<CanvasScaler>();
  261. if (scaler != null)
  262. {
  263. scaler.enabled = false;
  264. }
  265. SetVirtualDisplayResolution();
  266. InitEmulator();
  267. #else
  268. if (m_UICamera != null)
  269. {
  270. this.m_UICamera.enabled = false;
  271. }
  272. #endif
  273. }
  274. m_ISystemButtonStateProvider?.BindReceiver(this);
  275. }
  276. public void OnDataReceived(SystemButtonState state)
  277. {
  278. lock (SystemButtonState)
  279. {
  280. state.TransformTo(SystemButtonState);
  281. }
  282. }
  283. /// <summary> Updates the resolution described by size. </summary>
  284. /// <param name="size"> The size.</param>
  285. public void UpdateResolution(Vector2 size)
  286. {
  287. #if UNITY_EDITOR
  288. NRPhoneScreen.Resolution = size;
  289. this.SetVirtualDisplayResolution();
  290. this.UpdateEmulatorScreen(size * ScaleFactor);
  291. #endif
  292. var m_PointRaycaster = gameObject.GetComponentInChildren<NRMultScrPointerRaycaster>();
  293. if (m_PointRaycaster != null)
  294. {
  295. m_PointRaycaster.UpdateScreenSize(size * ScaleFactor);
  296. }
  297. if (m_ISystemButtonStateProvider != null && m_ISystemButtonStateProvider is NRPhoneScreenProviderBase)
  298. {
  299. ((NRPhoneScreenProviderBase)m_ISystemButtonStateProvider).ResizeView((int)size.x, (int)size.y);
  300. }
  301. }
  302. #if UNITY_EDITOR
  303. /// <summary> Sets virtual display resolution. </summary>
  304. private void SetVirtualDisplayResolution()
  305. {
  306. m_ScreenResolution = NRPhoneScreen.Resolution;
  307. if (m_ControllerScreen != null)
  308. {
  309. m_ControllerScreen.Release();
  310. }
  311. m_ControllerScreen = new RenderTexture(
  312. (int)(m_ScreenResolution.x * ScaleFactor),
  313. (int)(m_ScreenResolution.y * ScaleFactor),
  314. 24
  315. );
  316. m_UICamera.targetTexture = m_ControllerScreen;
  317. m_UICamera.aspect = m_ScreenResolution.x / m_ScreenResolution.y;
  318. m_UICamera.orthographicSize = 6;
  319. }
  320. #endif
  321. /// <summary> Executes the 'display resolution changed' action. </summary>
  322. /// <param name="w"> The width.</param>
  323. /// <param name="h"> The height.</param>
  324. [MonoPInvokeCallback(typeof(NRDisplayResolutionCallback))]
  325. public static void OnDisplayResolutionChanged(int w, int h)
  326. {
  327. NRDebugger.Info("[NRVirtualDisplayer] Display resolution changed width:{0} height:{1}", w, h);
  328. MainThreadDispather.QueueOnMainThread(delegate ()
  329. {
  330. NRVirtualDisplayer.Instance.UpdateResolution(new Vector2(w, h));
  331. OnDisplayScreenChangedEvent?.Invoke(new Resolution()
  332. {
  333. width = w,
  334. height = h
  335. });
  336. });
  337. }
  338. #region Emulator
  339. #if UNITY_EDITOR
  340. /// <summary> The emulator touch. </summary>
  341. private static Vector2 m_EmulatorTouch = Vector2.zero;
  342. /// <summary> The emulator phone screen anchor. </summary>
  343. private Vector2 m_EmulatorPhoneScreenAnchor;
  344. /// <summary> Width of the emulator raw image. </summary>
  345. private float m_EmulatorRawImageWidth;
  346. /// <summary> Height of the emulator raw image. </summary>
  347. private float m_EmulatorRawImageHeight;
  348. /// <summary> The emulator phone raw image. </summary>
  349. private RawImage emulatorPhoneRawImage;
  350. /// <summary> Gets emulator screen touch. </summary>
  351. /// <returns> The emulator screen touch. </returns>
  352. public static Vector2 GetEmulatorScreenTouch()
  353. {
  354. return m_EmulatorTouch;
  355. }
  356. /// <summary> Initializes the emulator. </summary>
  357. private void InitEmulator()
  358. {
  359. GameObject emulatorVirtualController = new GameObject("NREmulatorVirtualController");
  360. DontDestroyOnLoad(emulatorVirtualController);
  361. Canvas controllerCanvas = emulatorVirtualController.AddComponent<Canvas>();
  362. controllerCanvas.renderMode = RenderMode.ScreenSpaceOverlay;
  363. GameObject rawImageObj = new GameObject("RamImage");
  364. rawImageObj.transform.parent = controllerCanvas.transform;
  365. emulatorPhoneRawImage = rawImageObj.AddComponent<RawImage>();
  366. emulatorPhoneRawImage.raycastTarget = false;
  367. UpdateEmulatorScreen(m_ScreenResolution * ScaleFactor);
  368. }
  369. /// <summary> Updates the emulator screen described by size. </summary>
  370. /// <param name="size"> The size.</param>
  371. private void UpdateEmulatorScreen(Vector2 size)
  372. {
  373. float scaleRate = 0.18f;
  374. m_EmulatorRawImageWidth = size.x * scaleRate;
  375. m_EmulatorRawImageHeight = size.y * scaleRate;
  376. emulatorPhoneRawImage.rectTransform.pivot = Vector2.right;
  377. emulatorPhoneRawImage.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Right, 0f, 0f);
  378. emulatorPhoneRawImage.rectTransform.SetInsetAndSizeFromParentEdge(RectTransform.Edge.Bottom, 0f, 0f);
  379. emulatorPhoneRawImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, m_EmulatorRawImageWidth);
  380. emulatorPhoneRawImage.rectTransform.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, m_EmulatorRawImageHeight);
  381. emulatorPhoneRawImage.texture = m_ControllerScreen;
  382. Vector2 gameViewSize = Handles.GetMainGameViewSize();
  383. m_EmulatorPhoneScreenAnchor = new Vector2(gameViewSize.x - m_EmulatorRawImageWidth, 0f);
  384. }
  385. /// <summary> Updates the emulator. </summary>
  386. private void UpdateEmulator()
  387. {
  388. if (NRInput.EmulateVirtualDisplayInEditor
  389. && Input.GetMouseButton(0)
  390. && Input.mousePosition.x > m_EmulatorPhoneScreenAnchor.x
  391. && Input.mousePosition.y < (m_EmulatorPhoneScreenAnchor.y + m_EmulatorRawImageHeight))
  392. {
  393. m_EmulatorTouch.x = (Input.mousePosition.x - m_EmulatorPhoneScreenAnchor.x) / m_EmulatorRawImageWidth * 2f - 1f;
  394. m_EmulatorTouch.y = (Input.mousePosition.y - m_EmulatorPhoneScreenAnchor.y) / m_EmulatorRawImageHeight * 2f - 1f;
  395. }
  396. else
  397. {
  398. m_EmulatorTouch = Vector2.zero;
  399. }
  400. }
  401. #endif
  402. #endregion
  403. }
  404. }