|
@@ -0,0 +1,230 @@
|
|
|
+using System;
|
|
|
+using System.Collections;
|
|
|
+using System.Collections.Generic;
|
|
|
+using System.Globalization;
|
|
|
+using System.IO;
|
|
|
+using System.Reflection;
|
|
|
+using ExIni;
|
|
|
+using UnityEngine;
|
|
|
+using UnityInjector;
|
|
|
+using UnityInjector.Attributes;
|
|
|
+
|
|
|
+namespace CM3D2.ToukaScreenShot.Plugin
|
|
|
+{
|
|
|
+ [PluginVersion("0.1.0.2")]
|
|
|
+ [PluginName("Com3d2.ToukaScreenShot.Plugin")]
|
|
|
+ [PluginFilter("COM3D2x64")]
|
|
|
+ public class ToukaScreenShot : PluginBase
|
|
|
+ {
|
|
|
+ private readonly bool[] bLayerMask = new bool[32];
|
|
|
+
|
|
|
+ private readonly FieldInfo fBloom =
|
|
|
+ typeof(CameraMain).GetField("m_gcBloom", BindingFlags.Instance | BindingFlags.NonPublic);
|
|
|
+
|
|
|
+ private bool altKey;
|
|
|
+ private bool bgActiveBack = true;
|
|
|
+ private Color bgColorBack = Color.black;
|
|
|
+ private bool bgVisible = true;
|
|
|
+ private bool bloomBack;
|
|
|
+ private bool bloomOff = true;
|
|
|
+ private bool ctrlKey = true;
|
|
|
+
|
|
|
+ private string fileNameEnd = "";
|
|
|
+ private string fileNameHead = "img";
|
|
|
+ private string folderName = "ScreenShot";
|
|
|
+ private Camera mainCamera;
|
|
|
+ private int maskBack;
|
|
|
+ private bool noConfigFlg;
|
|
|
+ private bool shiftKey;
|
|
|
+ private IniFile sPreferences;
|
|
|
+ private string triggerKey = "s";
|
|
|
+
|
|
|
+ private void Start()
|
|
|
+ {
|
|
|
+ sPreferences = Preferences;
|
|
|
+ var defaultVisibleLayers = new HashSet<int>
|
|
|
+ {
|
|
|
+ 0,
|
|
|
+ 1,
|
|
|
+ 10
|
|
|
+ };
|
|
|
+ for (var i = 0; i < bLayerMask.Length; i++)
|
|
|
+ bLayerMask[i] = GetValueIni("Visible", $"Layer{i}", defaultVisibleLayers.Contains(i));
|
|
|
+
|
|
|
+ folderName = GetValueIni("File", "Folder", "ScreenShot");
|
|
|
+ fileNameHead = GetValueIni("File", "Head", "img");
|
|
|
+ fileNameEnd = GetValueIni("File", "End", "");
|
|
|
+ bgVisible = GetValueIni("Visible", "BG", false);
|
|
|
+ bloomOff = GetValueIni("Effect", "BloomOff", true);
|
|
|
+ altKey = GetValueIni("Command", "Alt", false);
|
|
|
+ ctrlKey = GetValueIni("Command", "Ctrl", true);
|
|
|
+ shiftKey = GetValueIni("Command", "Shift", false);
|
|
|
+ triggerKey = GetValueIni("Command", "Trigger", "s");
|
|
|
+ if (noConfigFlg) SaveConfig();
|
|
|
+ }
|
|
|
+
|
|
|
+ private T GetValueIni<T>(string section, string key, T @default)
|
|
|
+ {
|
|
|
+ bool TryParse(string value, out T resultVal)
|
|
|
+ {
|
|
|
+ try
|
|
|
+ {
|
|
|
+ resultVal = (T) Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ catch (Exception e)
|
|
|
+ {
|
|
|
+ Debug.LogWarning($"Failed to parse {section} => {key} value {value} because {e.Message}");
|
|
|
+ resultVal = default;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var iniKey = sPreferences[section][key];
|
|
|
+ if (iniKey != null && !string.IsNullOrEmpty(iniKey.Value) &&
|
|
|
+ TryParse(iniKey.Value, out var result)) return result;
|
|
|
+ iniKey.Value = Convert.ToString(@default, CultureInfo.InvariantCulture);
|
|
|
+ result = @default;
|
|
|
+ noConfigFlg = true;
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void Update()
|
|
|
+ {
|
|
|
+ var pressedAlt = Input.GetKey(KeyCode.LeftAlt) || Input.GetKey(KeyCode.RightAlt);
|
|
|
+ var pressedCtrl = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
|
|
|
+ var pressedShift = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
|
|
|
+ if (altKey == pressedAlt && ctrlKey == pressedCtrl && shiftKey == pressedShift && Input.GetKeyDown(triggerKey))
|
|
|
+ StartCoroutine(ExecScreenShot());
|
|
|
+ }
|
|
|
+
|
|
|
+ private IEnumerator ExecScreenShot()
|
|
|
+ {
|
|
|
+ yield return new WaitForEndOfFrame();
|
|
|
+ mainCamera = Camera.main;
|
|
|
+ BackUpCamera();
|
|
|
+
|
|
|
+ var ss = GetToukaScreenShot();
|
|
|
+ File.WriteAllBytes(GetTimeFileName(), ss.EncodeToPNG());
|
|
|
+
|
|
|
+ // Actually unload textures and GC unused stuff to free up memory
|
|
|
+ yield return Resources.UnloadUnusedAssets();
|
|
|
+ GC.Collect();
|
|
|
+
|
|
|
+ GameMain.Instance.SoundMgr.PlaySe("se022.ogg", false);
|
|
|
+ }
|
|
|
+
|
|
|
+ private Texture2D GetToukaScreenShot()
|
|
|
+ {
|
|
|
+ var ss = GameMain.Instance.CMSystem.ScreenShotSuperSize switch
|
|
|
+ {
|
|
|
+ CMSystem.SSSuperSizeType.X1 => 1,
|
|
|
+ CMSystem.SSSuperSizeType.X2 => 2,
|
|
|
+ CMSystem.SSSuperSizeType.X4 => 4,
|
|
|
+ _ => 1
|
|
|
+ };
|
|
|
+
|
|
|
+ var aa = GameMain.Instance.CMSystem.Antialias switch
|
|
|
+ {
|
|
|
+ CMSystem.AntiAliasType.None => 0,
|
|
|
+ CMSystem.AntiAliasType.X2 => 1,
|
|
|
+ CMSystem.AntiAliasType.X4 => 4,
|
|
|
+ CMSystem.AntiAliasType.X8 => 8,
|
|
|
+ _ => 8,
|
|
|
+ };
|
|
|
+
|
|
|
+ var w = Screen.width * ss;
|
|
|
+ var h = Screen.height * ss;
|
|
|
+
|
|
|
+ var rt = RenderTexture.GetTemporary(w, h, 24, RenderTextureFormat.ARGB32, RenderTextureReadWrite.sRGB, aa);
|
|
|
+ rt.filterMode = FilterMode.Bilinear;
|
|
|
+ SetCameraMask();
|
|
|
+
|
|
|
+ mainCamera.backgroundColor = new Color(0f, 0f, 0f, 1f);
|
|
|
+ var blackBgTex = RenderScreenShot(rt, w, h);
|
|
|
+
|
|
|
+ mainCamera.backgroundColor = new Color(1f, 1f, 1f, 1f);
|
|
|
+ var whiteBgTex = RenderScreenShot(rt, w, h);
|
|
|
+
|
|
|
+ ResetCamera();
|
|
|
+ mainCamera.targetTexture = null;
|
|
|
+ RenderTexture.ReleaseTemporary(rt);
|
|
|
+
|
|
|
+ var blackPix = blackBgTex.GetPixels32();
|
|
|
+ var whitePix = whiteBgTex.GetPixels32();
|
|
|
+ var resultPix = new Color32[blackPix.Length];
|
|
|
+
|
|
|
+ for (var i = 0; i < resultPix.Length; i++)
|
|
|
+ {
|
|
|
+ var wp = whitePix[i];
|
|
|
+ var bp = blackPix[i];
|
|
|
+ var diff = wp.r - bp.r;
|
|
|
+ if (diff < 0) diff = 0;
|
|
|
+ resultPix[i] = new Color32((byte)((wp.r + bp.r) >> 1), (byte)((wp.g + bp.g) >> 1), (byte)((wp.b + bp.b) >> 1), (byte) ~diff);
|
|
|
+ }
|
|
|
+
|
|
|
+ var result = new Texture2D(w, h);
|
|
|
+ result.SetPixels32(resultPix);
|
|
|
+
|
|
|
+ // Mark both for destroying so they can be unloaded by UnloadUnusedAssets
|
|
|
+ Destroy(blackBgTex);
|
|
|
+ Destroy(whiteBgTex);
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ private string GetTimeFileName(string postfix = "")
|
|
|
+ {
|
|
|
+ var targetFolder = Path.Combine(UTY.gameProjectPath, folderName);
|
|
|
+ if (!Directory.Exists(targetFolder)) Directory.CreateDirectory(targetFolder);
|
|
|
+ return Path.Combine(targetFolder, $"{fileNameHead}{DateTime.Now:yyyyMMddHHmmss}{postfix}{fileNameEnd}.png");
|
|
|
+ }
|
|
|
+
|
|
|
+ private void BackUpCamera()
|
|
|
+ {
|
|
|
+ maskBack = mainCamera.cullingMask;
|
|
|
+ bgColorBack = mainCamera.backgroundColor;
|
|
|
+ if (!bgVisible) bgActiveBack = GameMain.Instance.BgMgr.current_bg_object.activeSelf;
|
|
|
+ if (!bloomOff) return;
|
|
|
+ var bloom = (Bloom) fBloom.GetValue(GameMain.Instance.MainCamera);
|
|
|
+ bloomBack = bloom.enabled;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void ResetCamera()
|
|
|
+ {
|
|
|
+ mainCamera.cullingMask = maskBack;
|
|
|
+ mainCamera.backgroundColor = bgColorBack;
|
|
|
+ if (!bgVisible) GameMain.Instance.BgMgr.current_bg_object.SetActive(bgActiveBack);
|
|
|
+ if (!bloomOff) return;
|
|
|
+ var bloom = (Bloom) fBloom.GetValue(GameMain.Instance.MainCamera);
|
|
|
+ bloom.enabled = bloomBack;
|
|
|
+ }
|
|
|
+
|
|
|
+ private void SetCameraMask()
|
|
|
+ {
|
|
|
+ var num = 0;
|
|
|
+ for (var i = 0; i < bLayerMask.Length; i++)
|
|
|
+ if (bLayerMask[i])
|
|
|
+ num += 1 << i;
|
|
|
+
|
|
|
+ mainCamera.cullingMask = num;
|
|
|
+ if (!bgVisible) GameMain.Instance.BgMgr.current_bg_object.SetActive(false);
|
|
|
+ if (!bloomOff) return;
|
|
|
+ var bloom = (Bloom) fBloom.GetValue(GameMain.Instance.MainCamera);
|
|
|
+ bloom.enabled = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Texture2D RenderScreenShot(RenderTexture rt, int w, int h)
|
|
|
+ {
|
|
|
+ mainCamera.targetTexture = rt;
|
|
|
+ mainCamera.Render();
|
|
|
+ var texture2D = new Texture2D(w, h, TextureFormat.ARGB32, false);
|
|
|
+ var prev = RenderTexture.active;
|
|
|
+ RenderTexture.active = rt;
|
|
|
+ texture2D.ReadPixels(new Rect(0f, 0f, w, h), 0, 0, false);
|
|
|
+ RenderTexture.active = prev;
|
|
|
+ return texture2D;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|