mirror of
https://github.com/sinai-dev/UnityExplorer.git
synced 2025-06-16 06:08:16 +08:00
193 lines
5.8 KiB
C#
193 lines
5.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
#if CPP
|
|
using Explorer.Unstrip.ImageConversion;
|
|
#endif
|
|
|
|
namespace Explorer.Helpers
|
|
{
|
|
public static class Texture2DHelpers
|
|
{
|
|
#if CPP // If Mono
|
|
#else
|
|
private static bool isNewEncodeMethod = false;
|
|
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
|
|
private static MethodInfo m_encodeToPNGMethod;
|
|
|
|
private static MethodInfo GetEncodeToPNGMethod()
|
|
{
|
|
if (ReflectionHelpers.GetTypeByName("UnityEngine.ImageConversion") is Type imageConversion)
|
|
{
|
|
isNewEncodeMethod = true;
|
|
return m_encodeToPNGMethod = imageConversion.GetMethod("EncodeToPNG", ReflectionHelpers.CommonFlags);
|
|
}
|
|
|
|
var method = typeof(Texture2D).GetMethod("EncodeToPNG", ReflectionHelpers.CommonFlags);
|
|
if (method != null)
|
|
{
|
|
return m_encodeToPNGMethod = method;
|
|
}
|
|
|
|
ExplorerCore.Log("ERROR: Cannot get any EncodeToPNG method!");
|
|
return null;
|
|
}
|
|
#endif
|
|
|
|
|
|
public static bool IsReadable(this Texture2D tex)
|
|
{
|
|
try
|
|
{
|
|
// This will cause an exception if it's not readable.
|
|
// Reason for doing it this way is not all Unity versions
|
|
// ship with the 'Texture.isReadable' property.
|
|
|
|
tex.GetPixel(0, 0);
|
|
return true;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static Texture2D Copy(Texture2D orig, Rect rect, bool isDTXnmNormal = false)
|
|
{
|
|
Color[] pixels;
|
|
|
|
if (!orig.IsReadable())
|
|
{
|
|
orig = ForceReadTexture(orig);
|
|
}
|
|
|
|
pixels = orig.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
|
|
|
|
var _newTex = new Texture2D((int)rect.width, (int)rect.height);
|
|
_newTex.SetPixels(pixels);
|
|
|
|
return _newTex;
|
|
}
|
|
|
|
public static Texture2D ForceReadTexture(Texture2D tex)
|
|
{
|
|
try
|
|
{
|
|
var origFilter = tex.filterMode;
|
|
tex.filterMode = FilterMode.Point;
|
|
|
|
var rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
|
|
rt.filterMode = FilterMode.Point;
|
|
RenderTexture.active = rt;
|
|
Graphics.Blit(tex, rt);
|
|
|
|
var _newTex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
|
|
|
|
_newTex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
|
|
_newTex.Apply(false, false);
|
|
|
|
RenderTexture.active = null;
|
|
tex.filterMode = origFilter;
|
|
|
|
return _newTex;
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
ExplorerCore.Log("Exception on ForceReadTexture: " + e.ToString());
|
|
return default;
|
|
}
|
|
}
|
|
|
|
public static void SaveTextureAsPNG(Texture2D tex, string dir, string name, bool isDTXnmNormal = false)
|
|
{
|
|
if (!Directory.Exists(dir))
|
|
{
|
|
Directory.CreateDirectory(dir);
|
|
}
|
|
|
|
byte[] data;
|
|
var savepath = dir + @"\" + name + ".png";
|
|
|
|
// Make sure we can EncodeToPNG it.
|
|
if (tex.format != TextureFormat.ARGB32 || !tex.IsReadable())
|
|
{
|
|
tex = ForceReadTexture(tex);
|
|
}
|
|
|
|
if (isDTXnmNormal)
|
|
{
|
|
tex = DTXnmToRGBA(tex);
|
|
tex.Apply(false, false);
|
|
}
|
|
|
|
#if CPP
|
|
data = tex.EncodeToPNG();
|
|
#else
|
|
if (isNewEncodeMethod)
|
|
{
|
|
data = (byte[])EncodeToPNGMethod.Invoke(null, new object[] { tex });
|
|
}
|
|
else
|
|
{
|
|
data = (byte[])EncodeToPNGMethod.Invoke(tex, new object[0]);
|
|
}
|
|
#endif
|
|
|
|
if (data == null || data.Length < 1)
|
|
{
|
|
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
|
|
}
|
|
else
|
|
{
|
|
#if CPP
|
|
// The Il2Cpp EncodeToPNG() method does return System.Byte[],
|
|
// but for some reason it is not recognized or valid.
|
|
// Simple fix is iterating into a new array manually.
|
|
|
|
byte[] safeData = new byte[data.Length];
|
|
for (int i = 0; i < data.Length; i++)
|
|
{
|
|
safeData[i] = (byte)data[i]; // not sure if cast is needed
|
|
}
|
|
|
|
File.WriteAllBytes(savepath, safeData);
|
|
#else
|
|
File.WriteAllBytes(savepath, data);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
// Converts DTXnm-format Normal Map to RGBA-format Normal Map.
|
|
public static Texture2D DTXnmToRGBA(Texture2D tex)
|
|
{
|
|
Color[] colors = tex.GetPixels();
|
|
|
|
for (int i = 0; i < colors.Length; i++)
|
|
{
|
|
Color c = colors[i];
|
|
|
|
c.r = c.a * 2 - 1; // red <- alpha
|
|
c.g = c.g * 2 - 1; // green is always the same
|
|
|
|
Vector2 rg = new Vector2(c.r, c.g); //this is the red-green vector
|
|
c.b = Mathf.Sqrt(1 - Mathf.Clamp01(Vector2.Dot(rg, rg))); //recalculate the blue channel
|
|
|
|
colors[i] = new Color(
|
|
(c.r * 0.5f) + 0.5f,
|
|
(c.g * 0.5f) + 0.25f,
|
|
(c.b * 0.5f) + 0.5f
|
|
);
|
|
}
|
|
|
|
var newtex = new Texture2D(tex.width, tex.height, TextureFormat.ARGB32, false);
|
|
newtex.SetPixels(colors);
|
|
|
|
return newtex;
|
|
}
|
|
}
|
|
}
|