using UnityEngine; using System.Collections; using System.Collections.Generic; namespace uDesktopDuplication { public class Manager : MonoBehaviour { private static Manager instance_; public static Manager instance { get { return CreateInstance(); } } public static Manager CreateInstance() { if (instance_ != null) return instance_; var manager = FindObjectOfType(); if (manager) { instance_ = manager; return manager; } var go = new GameObject("uDesktopDuplicationManager"); instance_ = go.AddComponent(); return instance_; } private List monitors_ = new List(); static public List monitors { get { return instance.monitors_; } } static public int monitorCount { get { return Lib.GetMonitorCount(); } } static public int cursorMonitorId { get { return Lib.GetCursorMonitorId(); } } static public Monitor primary { get { return instance.monitors_.Find(monitor => monitor.isPrimary); } } [Tooltip("Debug mode is not applied while running.")] [SerializeField] DebugMode debugMode = DebugMode.File; [SerializeField] float retryReinitializationDuration = 1f; private Coroutine renderCoroutine_ = null; private bool shouldReinitialize_ = false; private float reinitializationTimer_ = 0f; private bool isFirstFrame_ = true; public static event Lib.DebugLogDelegate onDebugLog = OnDebugLog; public static event Lib.DebugLogDelegate onDebugErr = OnDebugErr; [AOT.MonoPInvokeCallback(typeof(Lib.DebugLogDelegate))] private static void OnDebugLog(string msg) { Debug.Log(msg); } [AOT.MonoPInvokeCallback(typeof(Lib.DebugLogDelegate))] private static void OnDebugErr(string msg) { Debug.LogError(msg); } public delegate void ReinitializeHandler(); public static event ReinitializeHandler onReinitialized; public static Monitor GetMonitor(int id) { if (id < 0 || id >= Manager.monitors.Count) { Debug.LogErrorFormat("[uDD::Error] there is no monitor whose id is {0}.", id); return Manager.primary; } return monitors[Mathf.Clamp(id, 0, Manager.monitorCount - 1)]; } void Awake() { // for simple singleton if (instance_ == this) { return; } if (instance_ != null && instance_ != this) { Destroy(gameObject); return; } instance_ = this; Lib.SetDebugMode(debugMode); Lib.SetLogFunc(onDebugLog); Lib.SetErrorFunc(onDebugErr); Lib.Initialize(); CreateMonitors(); #if UNITY_2018_1_OR_NEWER Shader.DisableKeyword("USE_GAMMA_TO_LINEAR_SPACE"); #else Shader.EnableKeyword("USE_GAMMA_TO_LINEAR_SPACE"); #endif } void OnApplicationQuit() { Lib.Finalize(); DestroyMonitors(); } void OnEnable() { renderCoroutine_ = StartCoroutine(OnRender()); if (!isFirstFrame_) { Reinitialize(); } Lib.SetDebugMode(debugMode); Lib.SetLogFunc(onDebugLog); } void OnDisable() { if (renderCoroutine_ != null) { StopCoroutine(renderCoroutine_); renderCoroutine_ = null; } Lib.SetLogFunc(null); Lib.SetErrorFunc(null); } void Update() { Lib.Update(); ReinitializeIfNeeded(); UpdateMessage(); isFirstFrame_ = false; } [ContextMenu("Reinitialize")] public void Reinitialize() { Debug.Log("[uDD] Reinitialize"); Lib.Reinitialize(); CreateMonitors(); if (onReinitialized != null) { onReinitialized(); } } void ReinitializeIfNeeded() { bool reinitializeNeeded = false; for (int i = 0; i < monitors.Count; ++i) { var monitor = monitors[i]; var state = monitor.state; if ( state == DuplicatorState.NotSet || state == DuplicatorState.AccessLost || state == DuplicatorState.AccessDenied || state == DuplicatorState.SessionDisconnected || state == DuplicatorState.Unknown ) { reinitializeNeeded = true; break; } } if (Lib.HasMonitorCountChanged()) { reinitializeNeeded = true; } if (!shouldReinitialize_ && reinitializeNeeded) { shouldReinitialize_ = true; reinitializationTimer_ = 0f; } if (shouldReinitialize_) { if (reinitializationTimer_ > retryReinitializationDuration) { Reinitialize(); shouldReinitialize_ = false; } reinitializationTimer_ += Time.deltaTime; } } void UpdateMessage() { var message = Lib.PopMessage(); while (message != Message.None) { Debug.Log("[uDD] " + message); switch (message) { case Message.Reinitialized: ReinitializeMonitors(); break; case Message.TextureSizeChanged: RecreateTextures(); break; default: break; } message = Lib.PopMessage(); } } IEnumerator OnRender() { for (;;) { yield return new WaitForEndOfFrame(); for (int i = 0; i < monitors.Count; ++i) { var monitor = monitors[i]; if (monitor.shouldBeUpdated) { monitor.Render(); } monitor.shouldBeUpdated = false; } } } void CreateMonitors() { DestroyMonitors(); for (int i = 0; i < monitorCount; ++i) { monitors.Add(new Monitor(i)); } } void DestroyMonitors() { for (int i = 0; i < monitors.Count; ++i) { monitors[i].DestroyTexture(); } monitors.Clear(); } void ReinitializeMonitors() { for (int i = 0; i < monitorCount; ++i) { if (i == monitors.Count) { monitors.Add(new Monitor(i)); } else { monitors[i].Reinitialize(); } } } void RecreateTextures() { for (int i = 0; i < monitorCount; ++i) { monitors[i].CreateTextureIfNeeded(); } } } }