363 lines
9.1 KiB
C#
363 lines
9.1 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEditor;
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright 2012-2022 RenderHeads Ltd. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace RenderHeads.Media.AVProMovieCapture.Editor
|
|
{
|
|
public class EditorScreenshot : MonoBehaviour
|
|
{
|
|
internal enum ImageFormat
|
|
{
|
|
PNG,
|
|
JPG,
|
|
TGA,
|
|
EXR,
|
|
}
|
|
|
|
internal enum ExrPrecision
|
|
{
|
|
Half,
|
|
Float,
|
|
}
|
|
|
|
internal enum ExrCompression
|
|
{
|
|
None,
|
|
ZIP,
|
|
RLE,
|
|
PIZ,
|
|
}
|
|
|
|
[Serializable]
|
|
internal class Options
|
|
{
|
|
[SerializeField, Range(1, 100)]
|
|
internal int jpgQuality = 75;
|
|
|
|
[SerializeField]
|
|
internal ExrPrecision exrPrecision;
|
|
|
|
[SerializeField]
|
|
internal ExrCompression exrCompression;
|
|
|
|
internal Texture2D.EXRFlags GetExrFlags()
|
|
{
|
|
Texture2D.EXRFlags result = Texture2D.EXRFlags.None;
|
|
if (exrPrecision == ExrPrecision.Float) result |= Texture2D.EXRFlags.OutputAsFloat;
|
|
if (exrCompression == ExrCompression.ZIP) result |= Texture2D.EXRFlags.CompressZIP;
|
|
else if (exrCompression == ExrCompression.RLE) result |= Texture2D.EXRFlags.CompressRLE;
|
|
else if (exrCompression == ExrCompression.PIZ) result |= Texture2D.EXRFlags.CompressPIZ;
|
|
return result;
|
|
}
|
|
}
|
|
|
|
private const string SceneCameraName = "SceneCamera";
|
|
|
|
internal static RenderTexture GetSceneViewTexture()
|
|
{
|
|
RenderTexture result = null;
|
|
Camera[] cameras = FindAllCameras();
|
|
if (cameras != null)
|
|
{
|
|
Camera camera = FindCameraByName(cameras.Length, cameras, SceneCameraName);
|
|
if (camera != null)
|
|
{
|
|
if (camera.targetTexture != null)
|
|
{
|
|
// Note we have to force a render
|
|
camera.Render();
|
|
result = camera.targetTexture;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
private static RenderTexture GetSceneViewTexture2()
|
|
{
|
|
RenderTexture result = null;
|
|
RenderTexture[] rts = Resources.FindObjectsOfTypeAll<RenderTexture>();
|
|
foreach (RenderTexture rt in rts)
|
|
{
|
|
if (rt.name == "SceneView RT")
|
|
{
|
|
result = rt;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static void SceneViewToFile(string fileNamePrefix, string folderPath, ImageFormat format, Options options)
|
|
{
|
|
RenderTexture cameraTexture = GetSceneViewTexture();
|
|
if (cameraTexture != null)
|
|
{
|
|
Texture2D texture = GetReadableTexture(cameraTexture, format == ImageFormat.EXR);
|
|
if (texture != null)
|
|
{
|
|
string filePath = EditorScreenshot.GenerateFilename(fileNamePrefix, format, texture.width, texture.height);
|
|
filePath = GenerateFilePath(folderPath, filePath);
|
|
TextureToFile(texture, filePath, format, options);
|
|
if (Application.isPlaying)
|
|
{
|
|
Destroy(texture);
|
|
}
|
|
else
|
|
{
|
|
DestroyImmediate(texture);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError("SceneView texture isn't available, make sure the view is visible");
|
|
}
|
|
}
|
|
|
|
internal static Texture2D GetReadableTexture(RenderTexture texture, bool supportHDR)
|
|
{
|
|
var oldRT = RenderTexture.active;
|
|
TextureFormat format = TextureFormat.RGBA32;
|
|
if (supportHDR)
|
|
{
|
|
format = TextureFormat.RGBAFloat;
|
|
}
|
|
Texture2D destTex = new Texture2D(texture.width, texture.height, format, false, supportHDR);
|
|
RenderTexture.active = texture;
|
|
destTex.ReadPixels(new Rect(0, 0, texture.width, texture.height), 0, 0);
|
|
destTex.Apply();
|
|
RenderTexture.active = oldRT;
|
|
return destTex;
|
|
}
|
|
|
|
internal static bool SupportsTGA()
|
|
{
|
|
#if UNITY_2018_3_OR_NEWER
|
|
return true;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
internal static bool SupportsGameViewJPGTGAEXR()
|
|
{
|
|
#if UNITY_2017_3_OR_NEWER
|
|
return Application.isPlaying;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
internal static bool SupportsGameViewEXR()
|
|
{
|
|
#if UNITY_2019_1_OR_NEWER
|
|
return Application.isPlaying;
|
|
#else
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
internal static void TextureToFile(Texture2D texture, string filePath, ImageFormat format, Options options)
|
|
{
|
|
byte[] data = null;
|
|
#if UNITY_2017_1_OR_NEWER
|
|
switch (format)
|
|
{
|
|
case ImageFormat.PNG:
|
|
data = ImageConversion.EncodeToPNG(texture);
|
|
break;
|
|
case ImageFormat.JPG:
|
|
data = ImageConversion.EncodeToJPG(texture, options.jpgQuality);
|
|
break;
|
|
case ImageFormat.TGA:
|
|
#if UNITY_2018_3_OR_NEWER
|
|
data = ImageConversion.EncodeToTGA(texture);
|
|
#endif
|
|
break;
|
|
case ImageFormat.EXR:
|
|
data = ImageConversion.EncodeToEXR(texture, options.GetExrFlags());
|
|
break;
|
|
}
|
|
#else
|
|
switch (format)
|
|
{
|
|
case ImageFormat.PNG:
|
|
data = texture.EncodeToPNG();
|
|
break;
|
|
case ImageFormat.JPG:
|
|
data = texture.EncodeToJPG(options.jpgQuality);
|
|
break;
|
|
case ImageFormat.EXR:
|
|
data = texture.EncodeToEXR(options.GetExrFlags());
|
|
break;
|
|
}
|
|
#endif
|
|
if (data != null)
|
|
{
|
|
System.IO.File.WriteAllBytes(filePath, data);
|
|
OnFileWritten(filePath);
|
|
}
|
|
}
|
|
|
|
internal static void GameViewToPNG(string filePath, int superSize = 1)
|
|
{
|
|
#if UNITY_2017_1_OR_NEWER
|
|
ScreenCapture.CaptureScreenshot(filePath, superSize);
|
|
#else
|
|
Application.CaptureScreenshot(filePath, superSize);
|
|
#endif
|
|
|
|
// The screenshot will not be generated until the frame has finished (at least in Application.CaptureScreenshot())
|
|
if (!Application.isPlaying)
|
|
{
|
|
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
|
}
|
|
|
|
OnFileWritten(filePath);
|
|
}
|
|
|
|
internal static void OnFileWritten(string filePath)
|
|
{
|
|
Debug.Log("[AVProMovieCapture] File written: " + filePath);
|
|
CaptureBase.LastFileSaved = filePath;
|
|
}
|
|
|
|
|
|
internal static void RenderTextureToFile(string filePath, ImageFormat format, Options options, RenderTexture rt)
|
|
{
|
|
Texture2D texture = GetReadableTexture(rt, format == ImageFormat.EXR);
|
|
if (texture != null)
|
|
{
|
|
TextureToFile(texture, filePath, format, options);
|
|
if (Application.isPlaying)
|
|
{
|
|
Destroy(texture);
|
|
}
|
|
else
|
|
{
|
|
DestroyImmediate(texture);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static void GameViewToFile(string filePath, ImageFormat format, Options options, int superSize = 1)
|
|
{
|
|
// Coroutines aren't supported in editor mode, so we fake it using a GameObject with EditorCoroutine component
|
|
GameObject go = new GameObject("temp-screenshot");
|
|
go.hideFlags = HideFlags.HideAndDontSave;
|
|
EditorCoroutine co = go.AddComponent<EditorCoroutine>();
|
|
co.RunCoroutine(EditorScreenshot.GameViewToFileCoroutine(filePath, format, options, go, superSize));
|
|
}
|
|
|
|
internal static IEnumerator GameViewToFileCoroutine(string filePath, ImageFormat format, Options options, GameObject go, int superSize = 1)
|
|
{
|
|
yield return new WaitForEndOfFrame();
|
|
Texture2D texture = null;
|
|
#if UNITY_2017_3_OR_NEWER
|
|
if (format != ImageFormat.EXR)
|
|
{
|
|
texture = ScreenCapture.CaptureScreenshotAsTexture(superSize);
|
|
}
|
|
else
|
|
{
|
|
// For EXR we want floating point textures which CaptureScreenshotAsTexture() doesn't provide
|
|
RenderTextureFormat rtFormat = (options.exrPrecision == ExrPrecision.Float) ? RenderTextureFormat.ARGBFloat : RenderTextureFormat.ARGBHalf;
|
|
RenderTexture rt = new RenderTexture(Screen.width * superSize, Screen.height * superSize, 24, rtFormat);
|
|
rt.Create();
|
|
#if UNITY_2019_1_OR_NEWER
|
|
ScreenCapture.CaptureScreenshotIntoRenderTexture(rt);
|
|
#endif
|
|
texture = GetReadableTexture(rt, true);
|
|
Destroy(rt);
|
|
}
|
|
#endif
|
|
|
|
if (texture != null)
|
|
{
|
|
TextureToFile(texture, filePath, format, options);
|
|
if (Application.isPlaying)
|
|
{
|
|
Destroy(texture);
|
|
Destroy(go);
|
|
}
|
|
else
|
|
{
|
|
DestroyImmediate(texture);
|
|
DestroyImmediate(go);
|
|
}
|
|
}
|
|
}
|
|
|
|
internal static Camera[] FindAllCameras()
|
|
{
|
|
return Resources.FindObjectsOfTypeAll<Camera>();
|
|
}
|
|
|
|
static Camera FindCameraByName(int cameraCount, Camera[] cameras, string name)
|
|
{
|
|
Camera result = null;
|
|
for (int i = 0; i < cameraCount; i++)
|
|
{
|
|
Camera c = cameras[i];
|
|
if (c.name == name)
|
|
{
|
|
result = c;
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static string GetExtension(ImageFormat format)
|
|
{
|
|
switch (format)
|
|
{
|
|
case ImageFormat.PNG:
|
|
return "png";
|
|
case ImageFormat.JPG:
|
|
return "jpg";
|
|
case ImageFormat.TGA:
|
|
return "tga";
|
|
case ImageFormat.EXR:
|
|
return "exr";
|
|
}
|
|
throw new Exception("Unknown image format");
|
|
}
|
|
|
|
internal static Vector2 GetGameViewSize()
|
|
{
|
|
Vector2 result = Vector2.zero;
|
|
string[] res = UnityStats.screenRes.Split('x');
|
|
if (res.Length == 2)
|
|
{
|
|
result.x = int.Parse(res[0]);
|
|
result.y = int.Parse(res[1]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal static string GenerateFilename(string filenamePrefix, ImageFormat format, int width, int height)
|
|
{
|
|
string filenameExtension = GetExtension(format);
|
|
string dateTime = DateTime.Now.ToString("yyyyMMdd-HHmmss");
|
|
string filename = string.Format("{0}-{1}-{2}x{3}.{4}", filenamePrefix, dateTime, width, height, filenameExtension);
|
|
return filename;
|
|
}
|
|
|
|
internal static string GenerateFilePath(string folderPath, string fileName)
|
|
{
|
|
if (!System.IO.Directory.Exists(folderPath))
|
|
{
|
|
System.IO.Directory.CreateDirectory(folderPath);
|
|
}
|
|
return System.IO.Path.Combine(folderPath, fileName);
|
|
}
|
|
}
|
|
} |