﻿using JLGames.RocketDriver.Actions.Extensions;
using UnityEngine;

namespace JLGames.RocketDriver.Actions.Utils
{
    public static class CaptureUtil
    {
        /// <summary>
        /// Use the CaptureScreenshot() method under the Application class to achieve screenshots
        /// Advantages: simple, can quickly capture a frame of the picture, full screen screenshot
        /// Disadvantage: Can't take screenshots for the camera, can't take partial screenshots
        /// 使用Application类下的CaptureScreenshot()方法实现截图
        /// 优点：简单，可以快速地截取某一帧的画面、全屏截图
        /// 缺点：不能针对摄像机截图，无法进行局部截图
        /// </summary>
        /// <param name="filePath">File path.</param>
        public static void CaptureScreen(string filePath)
        {
            ScreenCapture.CaptureScreenshot(filePath, 0);
        }

        /// <summary>
        /// Take a screenshot of the camera and save it as a Texture2D object
        /// 针对相机截图，并保存为Texture2D对象
        /// </summary>
        /// <returns>The camera.</returns>
        /// <param name="camera">Camera.</param>
        public static Texture2D CaptureCamera(Camera camera)
        {
            return CaptureCamera(camera, camera.pixelRect);
        }

        /// <summary>
        /// Take a screenshot of the camera and area and save it as a Texture2D object
        /// 针对相机与区域截图，并保存为Texture2D对象
        /// </summary>  
        /// <returns>The screenshot2.</returns>  
        /// <param name="camera">Camera.要被截屏的相机</param>  
        /// <param name="rect">Rect.截屏的区域</param>  
        public static Texture2D CaptureCamera(Camera camera, Rect rect)
        {
            var width = (int) rect.width;
            var height = (int) rect.height;
            // 创建一个RenderTexture对象，区域为相机区域
            var rt = new RenderTexture(camera.pixelWidth, camera.pixelHeight, 24);
            // 临时设置相关相机的targetTexture为rt, 并手动渲染相关相机  
            camera.targetTexture = rt;
            camera.Render();
            //ps: --- 如果这样加上第二个相机，可以实现只截图某几个指定的相机一起看到的图像。  
            //ps: camera2.targetTexture = rt;  
            //ps: camera2.Render();  
            //ps: -------------------------------------------------------------------  

            // 激活这个rt, 并从中中读取像素。  
            RenderTexture.active = rt;
            var screenShot = new Texture2D(width, height, TextureFormat.ARGB32, false);
            screenShot.ReadPixels(rect, 0, 0); // 注：这个时候，它是从RenderTexture.active中读取像素  
            screenShot.Apply();

            // 重置相关参数，以使用camera继续在屏幕上显示  
            camera.targetTexture = null;
            //ps: camera2.targetTexture = null;  
            RenderTexture.active = null; // JC: added to avoid errors  
            Object.Destroy(rt);
            return screenShot;
        }

        /// <summary>
        /// Focus the camera on the object to take a screenshot and store it in the Texture2D object
        /// 把相机对焦到物件上进行截图，并存储到Texture2D对象中去
        /// </summary>
        /// <author>yoyo(http://yoyo.play175.com)</author>
        /// <param name="targetObject">需要快照的物体</param>
        /// <param name="targetCamera"></param>
        /// <param name="keepOther"></param>
        public static Texture2D CaptureGameObject(GameObject targetObject, Camera targetCamera, bool keepOther)
        {
            var width = targetCamera.pixelWidth;
            var height = targetCamera.pixelHeight;
            //记录相机信息
            var targetTexture = targetCamera.targetTexture;
            var camInfo = targetCamera.transform.CloneTransform();
            //计算物体包围盒
            var renderers = targetObject.GetComponentsInChildren<Renderer>();
            var min = targetObject.transform.position;
            var max = targetObject.transform.position;
            for (var i = 0; i < renderers.Length; i++)
            {
                min = Vector3.Min(renderers[i].bounds.min, min);
                max = Vector3.Max(renderers[i].bounds.max, max);
            }

            //把相机放到合适位置
            var center = new Vector3((max.x + min.x) / 2, (max.y + min.y) / 2, (max.z + min.z) / 2); //中心点
            var step = (max - center).normalized; //相对于中心点的单位向量
            //先放到中心点的前右上角
            targetCamera.transform.position = center + step;
            //拉到合适距离
            targetCamera.transform.position = targetCamera.transform.position +
                                              step * (max - min).magnitude * 50 / targetCamera.fieldOfView;
            //旋转方向以便看到目标
            targetCamera.transform.LookAt(center);
            var rt = new RenderTexture(width, height, 24);
            targetCamera.targetTexture = rt;
            targetCamera.Render();
            RenderTexture.active = rt; //关键点，有点类似make current 的意思
            var t = new Texture2D(width, height, TextureFormat.ARGB32, false); //false代表不需要使用mipmaps
            t.ReadPixels(new Rect(0, 0, width, height), 0, 0);
            RenderTexture.active = null; //置空，以免出错
            Object.Destroy(rt);
            //恢复相机信息
            targetCamera.targetTexture = targetTexture;
            targetCamera.transform.UpdateTransform(camInfo);
            return t;
        }
    }
}