using AOT; using EZXR.Glass.Core; using EZXR.Glass.Device; using EZXR.Glass.Recording; using EZXR.Glass.SixDof; using System; using System.Collections; using System.IO; using System.Runtime.InteropServices; using UnityEngine; namespace EZXR.Glass.Projection { public class ProjectionManager : MonoBehaviour { private static ProjectionManager instance; public static ProjectionManager Instance { get { return instance; } } public Camera projectionCamera; RenderTexture renderTexture; /// /// 0是不做任何操作,1是开始,2是正在执行投录屏,-1是被停止 /// int startProjection; /// Renders the event delegate described by eventID. /// Identifier for the event. private delegate void RenderEventDelegate(int eventID); /// Handle of the render thread. private static RenderEventDelegate RenderThreadHandle = new RenderEventDelegate(RunOnRenderThread); /// The render thread handle pointer. private static IntPtr RenderThreadHandlePtr = Marshal.GetFunctionPointerForDelegate(RenderThreadHandle); /// /// 测试用,保存一张渲染的图 /// bool justSaveOnePic; private GameObject cameraRigObj; private void Awake() { instance = this; ProjectionAPI.Init(OnStart, OnStop); NativeLib.CallBack_OnProjectionDetected += OnProjectionDetected; NativeLib.Resume(); projectionCamera.GetComponent().enabled = false; } // Start is called before the first frame update void Start() { Debug.Log("ProjectionManager ==> Init Start"); StartCoroutine(Init()); DontDestroyOnLoad(this.gameObject); } IEnumerator Init() { yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame(); Debug.Log("ProjectionManager ==> Init 0"); while (!NativeTracking.GetIsARSessionInited()) { yield return new WaitForEndOfFrame(); } Debug.Log("ProjectionManager ==> Init 1"); CameraResolution cameraResolution = new CameraResolution(); #if UNITY_EDITOR cameraResolution.width = 1280; cameraResolution.height = 960; StartCoroutine(WaitEndOfFrame()); #else Debug.Log("ProjectionManager ==> Init 2"); NormalRGBCameraDevice rgbCameraDevice = new NormalRGBCameraDevice(); int[] sizeRgbCamera = rgbCameraDevice.getCameraSize(); cameraResolution.width = sizeRgbCamera[0]; cameraResolution.height = sizeRgbCamera[1]; #endif Debug.Log("ProjectionManager ==> Init 3"); renderTexture = new RenderTexture(cameraResolution.width, cameraResolution.height, 24, RenderTextureFormat.DefaultHDR); projectionCamera.targetTexture = renderTexture; Debug.Log("ProjectionManager ==> Init renderTexture size: " + renderTexture.width + "," + renderTexture.height + "; GetNativeTexturePtr: " + renderTexture.GetNativeTexturePtr().ToInt32()); } // Update is called once per frame void Update() { //if (Input.GetKeyDown(KeyCode.Escape)) //{ // Debug.Log("ProjectionManager ==> justSaveOnePic: true"); // justSaveOnePic = true; //} if (NativeTracking.GetIsARSessionInited()) { if (startProjection == 1) { if (renderTexture != null) { startProjection = 2; Debug.Log("ProjectionManager ==> Start: " + renderTexture.GetNativeTexturePtr().ToInt32()); projectionCamera.enabled = true; projectionCamera.GetComponent().enabled = true; ProjectionAPI.Start(renderTexture.GetNativeTexturePtr().ToInt32(), 1280, 960); StartCoroutine(WaitEndOfFrame()); } } else if (startProjection == -1) { StopProjection(); } } if (cameraRigObj == null) { cameraRigObj = HMDPoseTracker.Instance.gameObject; } if (cameraRigObj != null && cameraRigObj.transform.parent != null) { Transform bodyRig = cameraRigObj.transform.parent; if (cameraRigObj.transform.parent != null && bodyRig.name != "XRMan") { this.transform.position = bodyRig.position; this.transform.rotation = bodyRig.rotation; } } else { this.transform.position = Vector3.zero; this.transform.rotation = Quaternion.identity; } } void StopProjection() { Debug.Log("ProjectionManager ==> StopProjection"); projectionCamera.enabled = false; projectionCamera.GetComponent().enabled = false; startProjection = 0; StopAllCoroutines(); } private void OnDestroy() { Debug.Log("ProjectionManager ==> OnDestroy startProjection=" + startProjection); ProjectionAPI.DeInit(); } private void OnApplicationPause(bool pause) { if (pause) { Debug.Log("ProjectionManager OnApplicationPause 0"); if (startProjection == 2) { Debug.Log("ProjectionManager OnApplicationPause 1"); StopProjection(); Debug.Log("ProjectionManager OnApplicationPause 2"); NativeLib.Pause(); ProjectionAPI.Stop(); } } else { Debug.Log("ProjectionManager OnApplicationPause 3"); NativeLib.Resume(); Debug.Log("ProjectionManager OnApplicationPause 4"); } } /// /// 开始投屏或录屏 /// /// 0投屏 1录屏 2截屏 void OnStart(int type) { Debug.Log("ProjectionManager ==> OnStart: " + type); startProjection = 1; } /// /// 投屏或录屏结束了(是一个被动通知,应用收到后只需要处理好自身停止录屏的逻辑不需要调用stop接口。整个投录屏功能结束才会回调此处,应用退出或者到后台都不会回调这里) /// void OnStop() { Debug.Log("ProjectionManager ==> OnStop"); startProjection = -1; } void OnProjectionDetected() { Debug.Log("ProjectionManager ==> OnProjectionDetected"); startProjection = 1; } IEnumerator WaitEndOfFrame() { //camera刚开启的当前帧是不渲染的 yield return new WaitForEndOfFrame(); while (true) { yield return new WaitForEndOfFrame(); if (justSaveOnePic) { Debug.Log("ProjectionManager ==> SaveRenderTexture"); justSaveOnePic = false; SaveRenderTexture(); } #if !UNITY_EDITOR GL.IssuePluginEvent(RenderThreadHandlePtr, 0); #endif } } void SaveRenderTexture() { Debug.Log("ProjectionManager ==> SaveRenderTexture 0"); RenderTexture.active = renderTexture; Texture2D texture = new Texture2D(renderTexture.width, renderTexture.height, TextureFormat.ARGB32, false); texture.ReadPixels(new Rect(0, 0, renderTexture.width, renderTexture.height), 0, 0); texture.Apply(); Debug.Log("ProjectionManager ==> SaveRenderTexture 1"); byte[] bytes = texture.EncodeToPNG(); Debug.Log("ProjectionManager ==> SaveRenderTexture size: " + bytes.Length); string path = Path.Combine(Application.persistentDataPath, "saved.png"); Debug.Log("ProjectionManager ==> SaveRenderTexture path: " + path); File.WriteAllBytes(path, bytes); Debug.Log("ProjectionManager ==> SaveRenderTexture 2"); } /// Executes the 'on render thread' operation. /// Identifier for the event. [MonoPInvokeCallback(typeof(RenderEventDelegate))] private static void RunOnRenderThread(int eventID) { long timeStamp = (long)(ARFrame.HeadPoseRgbTimestamp * 1e9); //Debug.Log("ProjectionManager ==> RunOnRenderThread HeadPoseRgbTimestamp: " + timeStamp); ProjectionAPI.NotifyNewFrame(timeStamp); } } }