mirror of
https://github.com/GrahamKracker/UnityExplorer.git
synced 2025-07-02 11:32:29 +08:00
2.0.3
* Fixed a few issues related to the Texture2D support/export.
This commit is contained in:
@ -37,6 +37,10 @@ namespace Explorer.CacheObject
|
|||||||
{
|
{
|
||||||
interactive = new InteractiveTexture2D();
|
interactive = new InteractiveTexture2D();
|
||||||
}
|
}
|
||||||
|
else if (valueType == typeof(Texture))
|
||||||
|
{
|
||||||
|
interactive = new InteractiveTexture();
|
||||||
|
}
|
||||||
else if (valueType == typeof(Sprite))
|
else if (valueType == typeof(Sprite))
|
||||||
{
|
{
|
||||||
interactive = new InteractiveSprite();
|
interactive = new InteractiveSprite();
|
||||||
|
@ -208,11 +208,13 @@
|
|||||||
<Compile Include="CacheObject\CacheMethod.cs" />
|
<Compile Include="CacheObject\CacheMethod.cs" />
|
||||||
<Compile Include="CacheObject\CacheProperty.cs" />
|
<Compile Include="CacheObject\CacheProperty.cs" />
|
||||||
<Compile Include="CacheObject\CacheObjectBase.cs" />
|
<Compile Include="CacheObject\CacheObjectBase.cs" />
|
||||||
|
<Compile Include="Helpers\Texture2DHelpers.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\InteractiveValue.cs" />
|
<Compile Include="UI\InteractiveValue\InteractiveValue.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\Object\InteractiveDictionary.cs" />
|
<Compile Include="UI\InteractiveValue\Object\InteractiveDictionary.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\Object\InteractiveEnumerable.cs" />
|
<Compile Include="UI\InteractiveValue\Object\InteractiveEnumerable.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\Object\InteractiveGameObject.cs" />
|
<Compile Include="UI\InteractiveValue\Object\InteractiveGameObject.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\Object\InteractiveSprite.cs" />
|
<Compile Include="UI\InteractiveValue\Object\InteractiveSprite.cs" />
|
||||||
|
<Compile Include="UI\InteractiveValue\Object\InteractiveTexture.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\Object\InteractiveTexture2D.cs" />
|
<Compile Include="UI\InteractiveValue\Object\InteractiveTexture2D.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\Struct\InteractiveQuaternion.cs" />
|
<Compile Include="UI\InteractiveValue\Struct\InteractiveQuaternion.cs" />
|
||||||
<Compile Include="UI\InteractiveValue\Struct\InteractiveRect.cs" />
|
<Compile Include="UI\InteractiveValue\Struct\InteractiveRect.cs" />
|
||||||
|
@ -10,7 +10,7 @@ namespace Explorer
|
|||||||
public class ExplorerCore
|
public class ExplorerCore
|
||||||
{
|
{
|
||||||
public const string NAME = "Explorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")";
|
public const string NAME = "Explorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")";
|
||||||
public const string VERSION = "2.0.2";
|
public const string VERSION = "2.0.3";
|
||||||
public const string AUTHOR = "Sinai";
|
public const string AUTHOR = "Sinai";
|
||||||
public const string GUID = "com.sinai.explorer";
|
public const string GUID = "com.sinai.explorer";
|
||||||
|
|
||||||
|
194
src/Helpers/Texture2DHelpers.cs
Normal file
194
src/Helpers/Texture2DHelpers.cs
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
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
|
||||||
|
#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 other, Rect rect, bool isDTXnmNormal = false)
|
||||||
|
{
|
||||||
|
Color[] pixels;
|
||||||
|
|
||||||
|
if (!other.IsReadable())
|
||||||
|
{
|
||||||
|
other = ForceReadTexture(other, isDTXnmNormal);
|
||||||
|
}
|
||||||
|
|
||||||
|
pixels = other.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, bool isDTXnmNormal = false)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var origFilter = tex.filterMode;
|
||||||
|
tex.filterMode = FilterMode.Point;
|
||||||
|
|
||||||
|
RenderTexture rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
|
||||||
|
rt.filterMode = FilterMode.Point;
|
||||||
|
RenderTexture.active = rt;
|
||||||
|
Graphics.Blit(tex, rt);
|
||||||
|
|
||||||
|
Texture2D _newTex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
|
||||||
|
_newTex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
|
||||||
|
|
||||||
|
if (isDTXnmNormal)
|
||||||
|
{
|
||||||
|
_newTex = DTXnmToRGBA(_newTex);
|
||||||
|
}
|
||||||
|
|
||||||
|
_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";
|
||||||
|
|
||||||
|
// Fix for non-Readable or Compressed textures.
|
||||||
|
tex = ForceReadTexture(tex, isDTXnmNormal);
|
||||||
|
|
||||||
|
if (isDTXnmNormal)
|
||||||
|
{
|
||||||
|
tex = DTXnmToRGBA(tex);
|
||||||
|
tex.Apply(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if CPP
|
||||||
|
data = tex.EncodeToPNG();
|
||||||
|
#else
|
||||||
|
var method = EncodeToPNGMethod;
|
||||||
|
|
||||||
|
if (isNewEncodeMethod)
|
||||||
|
{
|
||||||
|
data = (byte[])method.Invoke(null, new object[] { tex });
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data = (byte[])method.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 method will return invalid byte data.
|
||||||
|
// However, we can just iterate into safe C# byte[] array.
|
||||||
|
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.RGBA32, false);
|
||||||
|
newtex.SetPixels(colors);
|
||||||
|
|
||||||
|
return newtex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -213,6 +213,7 @@ namespace Explorer.UI.Inspectors
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var cached = CacheFactory.GetCacheObject(member, target);
|
var cached = CacheFactory.GetCacheObject(member, target);
|
||||||
|
|
||||||
if (cached != null)
|
if (cached != null)
|
||||||
{
|
{
|
||||||
cachedSigs.Add(sig);
|
cachedSigs.Add(sig);
|
||||||
|
@ -198,31 +198,33 @@ namespace Explorer.UI
|
|||||||
return m_toStringMethod;
|
return m_toStringMethod;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetButtonLabel()
|
public string GetButtonLabel()
|
||||||
{
|
{
|
||||||
if (Value == null) return null;
|
if (Value == null) return null;
|
||||||
|
|
||||||
|
var valueType = ReflectionHelpers.GetActualType(Value);
|
||||||
|
|
||||||
string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
|
string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
|
||||||
|
|
||||||
var classColor = ValueType.IsAbstract && ValueType.IsSealed
|
var classColor = valueType.IsAbstract && valueType.IsSealed
|
||||||
? Syntax.Class_Static
|
? Syntax.Class_Static
|
||||||
: Syntax.Class_Instance;
|
: Syntax.Class_Instance;
|
||||||
|
|
||||||
string typeLabel = $"<color={classColor}>{ValueType.FullName}</color>";
|
string typeLabel = $"<color={classColor}>{valueType.FullName}</color>";
|
||||||
|
|
||||||
if (Value is UnityEngine.Object)
|
if (Value is UnityEngine.Object)
|
||||||
{
|
{
|
||||||
label = label.Replace($"({ValueType.FullName})", $"({typeLabel})");
|
label = label.Replace($"({valueType.FullName})", $"({typeLabel})");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!label.Contains(ValueType.FullName))
|
if (!label.Contains(valueType.FullName))
|
||||||
{
|
{
|
||||||
label += $" ({typeLabel})";
|
label += $" ({typeLabel})";
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
label = label.Replace(ValueType.FullName, typeLabel);
|
label = label.Replace(valueType.FullName, typeLabel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,9 @@ using Explorer.CacheObject;
|
|||||||
|
|
||||||
namespace Explorer.UI
|
namespace Explorer.UI
|
||||||
{
|
{
|
||||||
|
// TODO: Re-work class using InteractiveEnumerable or maybe InteractiveCollection for the Keys/Value lists.
|
||||||
|
// Make the keys and values editable.
|
||||||
|
|
||||||
public class InteractiveDictionary : InteractiveValue, IExpandHeight
|
public class InteractiveDictionary : InteractiveValue, IExpandHeight
|
||||||
{
|
{
|
||||||
public bool IsExpanded { get; set; }
|
public bool IsExpanded { get; set; }
|
||||||
|
@ -2,27 +2,50 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Explorer.Helpers;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace Explorer.UI
|
namespace Explorer.UI
|
||||||
{
|
{
|
||||||
public class InteractiveSprite : InteractiveTexture2D
|
public class InteractiveSprite : InteractiveTexture2D
|
||||||
{
|
{
|
||||||
public override void GetTexture2D()
|
private Sprite refSprite;
|
||||||
|
|
||||||
|
public override void UpdateValue()
|
||||||
{
|
{
|
||||||
#if CPP
|
#if CPP
|
||||||
if (Value != null && Value.Il2CppCast(typeof(Sprite)) is Sprite sprite)
|
if (Value != null && Value.Il2CppCast(typeof(Sprite)) is Sprite sprite)
|
||||||
|
{
|
||||||
|
refSprite = sprite;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
if (Value is Sprite sprite)
|
if (Value is Sprite sprite)
|
||||||
|
{
|
||||||
|
refSprite = sprite;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
base.UpdateValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void GetTexture2D()
|
||||||
{
|
{
|
||||||
currentTex = sprite.texture;
|
if (refSprite)
|
||||||
texContent = new GUIContent
|
|
||||||
{
|
{
|
||||||
image = currentTex
|
currentTex = refSprite.texture;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void GetGUIContent()
|
||||||
|
{
|
||||||
|
// Check if the Sprite.textureRect is just the entire texture
|
||||||
|
if (refSprite.textureRect != new Rect(0, 0, currentTex.width, currentTex.height))
|
||||||
|
{
|
||||||
|
// It's not, do a sub-copy.
|
||||||
|
currentTex = Texture2DHelpers.Copy(refSprite.texture, refSprite.textureRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.GetGUIContent();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
30
src/UI/InteractiveValue/Object/InteractiveTexture.cs
Normal file
30
src/UI/InteractiveValue/Object/InteractiveTexture.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Explorer.UI
|
||||||
|
{
|
||||||
|
// This class is possibly unnecessary.
|
||||||
|
// It's just for CacheMembers that have 'Texture' as the value type, but is actually a Texture2D.
|
||||||
|
|
||||||
|
public class InteractiveTexture : InteractiveTexture2D
|
||||||
|
{
|
||||||
|
public override void GetTexture2D()
|
||||||
|
{
|
||||||
|
#if CPP
|
||||||
|
if (Value != null && Value.Il2CppCast(typeof(Texture2D)) is Texture2D tex)
|
||||||
|
#else
|
||||||
|
if (Value is Texture2D tex)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
currentTex = tex;
|
||||||
|
texContent = new GUIContent
|
||||||
|
{
|
||||||
|
image = currentTex
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,6 +6,7 @@ using Explorer.CacheObject;
|
|||||||
using Explorer.Config;
|
using Explorer.Config;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using Explorer.Helpers;
|
||||||
#if CPP
|
#if CPP
|
||||||
using Explorer.Unstrip.ImageConversion;
|
using Explorer.Unstrip.ImageConversion;
|
||||||
#endif
|
#endif
|
||||||
@ -43,12 +44,16 @@ namespace Explorer.UI
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
currentTex = tex;
|
currentTex = tex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void GetGUIContent()
|
||||||
|
{
|
||||||
texContent = new GUIContent
|
texContent = new GUIContent
|
||||||
{
|
{
|
||||||
image = currentTex
|
image = currentTex
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public override void DrawValue(Rect window, float width)
|
public override void DrawValue(Rect window, float width)
|
||||||
{
|
{
|
||||||
@ -56,23 +61,21 @@ namespace Explorer.UI
|
|||||||
|
|
||||||
GUIUnstrip.BeginHorizontal();
|
GUIUnstrip.BeginHorizontal();
|
||||||
|
|
||||||
if (currentTex)
|
if (currentTex && !IsExpanded)
|
||||||
{
|
|
||||||
if (!IsExpanded)
|
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
if (GUILayout.Button("v", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
{
|
{
|
||||||
IsExpanded = true;
|
IsExpanded = true;
|
||||||
|
GetGUIContent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else if (currentTex)
|
||||||
{
|
{
|
||||||
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
if (GUILayout.Button("^", new GUILayoutOption[] { GUILayout.Width(25) }))
|
||||||
{
|
{
|
||||||
IsExpanded = false;
|
IsExpanded = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
base.DrawValue(window, width);
|
base.DrawValue(window, width);
|
||||||
|
|
||||||
@ -111,8 +114,6 @@ namespace Explorer.UI
|
|||||||
GUILayout.EndHorizontal();
|
GUILayout.EndHorizontal();
|
||||||
|
|
||||||
if (GUILayout.Button("Save to PNG", new GUILayoutOption[] { GUILayout.Width(100f) }))
|
if (GUILayout.Button("Save to PNG", new GUILayoutOption[] { GUILayout.Width(100f) }))
|
||||||
{
|
|
||||||
if (currentTex)
|
|
||||||
{
|
{
|
||||||
var name = RemoveInvalidFilenameChars(currentTex.name ?? "");
|
var name = RemoveInvalidFilenameChars(currentTex.name ?? "");
|
||||||
if (string.IsNullOrEmpty(name))
|
if (string.IsNullOrEmpty(name))
|
||||||
@ -127,15 +128,10 @@ namespace Explorer.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveTextureAsPNG(currentTex, saveFolder, name, false);
|
Texture2DHelpers.SaveTextureAsPNG(currentTex, saveFolder, name, false);
|
||||||
|
|
||||||
ExplorerCore.Log($@"Saved to {saveFolder}\{name}.png!");
|
ExplorerCore.Log($@"Saved to {saveFolder}\{name}.png!");
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
ExplorerCore.Log("Cannot save a null texture!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string RemoveInvalidFilenameChars(string s)
|
private string RemoveInvalidFilenameChars(string s)
|
||||||
@ -148,107 +144,6 @@ namespace Explorer.UI
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
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";
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (isDTXnmNormal)
|
|
||||||
{
|
|
||||||
tex = DTXnmToRGBA(tex);
|
|
||||||
tex.Apply(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
data = tex.EncodeToPNG();
|
|
||||||
|
|
||||||
if (data == null)
|
|
||||||
{
|
|
||||||
ExplorerCore.Log("Couldn't get data with EncodeToPNG (probably ReadOnly?), trying manually...");
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
var origFilter = tex.filterMode;
|
|
||||||
tex.filterMode = FilterMode.Point;
|
|
||||||
|
|
||||||
RenderTexture rt = RenderTexture.GetTemporary(tex.width, tex.height);
|
|
||||||
rt.filterMode = FilterMode.Point;
|
|
||||||
RenderTexture.active = rt;
|
|
||||||
Graphics.Blit(tex, rt);
|
|
||||||
|
|
||||||
Texture2D _newTex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
|
|
||||||
_newTex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
|
|
||||||
|
|
||||||
if (isDTXnmNormal)
|
|
||||||
{
|
|
||||||
_newTex = DTXnmToRGBA(_newTex);
|
|
||||||
}
|
|
||||||
|
|
||||||
_newTex.Apply(false, false);
|
|
||||||
|
|
||||||
RenderTexture.active = null;
|
|
||||||
tex.filterMode = origFilter;
|
|
||||||
|
|
||||||
data = _newTex.EncodeToPNG();
|
|
||||||
//data = _newTex.GetRawTextureData();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data == null || data.Length < 1)
|
|
||||||
{
|
|
||||||
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if CPP
|
|
||||||
// The IL2CPP method will return invalid byte data.
|
|
||||||
// However, we can just iterate into safe C# byte[] array.
|
|
||||||
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.RGBA32, false);
|
|
||||||
newtex.SetPixels(colors);
|
|
||||||
|
|
||||||
return newtex;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,8 +161,15 @@ namespace Explorer.UI.Main
|
|||||||
GUIUnstrip.EndScrollView();
|
GUIUnstrip.EndScrollView();
|
||||||
GUILayout.EndVertical();
|
GUILayout.EndVertical();
|
||||||
}
|
}
|
||||||
catch
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
ExplorerCore.Log("Exception drawing search results!");
|
||||||
|
while (e != null)
|
||||||
|
{
|
||||||
|
ExplorerCore.Log(e);
|
||||||
|
e = e.InnerException;
|
||||||
|
}
|
||||||
|
|
||||||
m_searchResults.Clear();
|
m_searchResults.Clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user