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