Skip to content
This repository was archived by the owner on May 9, 2023. It is now read-only.

Commit b41f721

Browse files
committed
2.0.3
* Fixed a few issues related to the Texture2D support/export.
1 parent dd6cce1 commit b41f721

File tree

11 files changed

+311
-150
lines changed

11 files changed

+311
-150
lines changed

src/CacheObject/CacheObjectBase.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,10 @@ public virtual void Init(object obj, Type valueType)
3737
{
3838
interactive = new InteractiveTexture2D();
3939
}
40+
else if (valueType == typeof(Texture))
41+
{
42+
interactive = new InteractiveTexture();
43+
}
4044
else if (valueType == typeof(Sprite))
4145
{
4246
interactive = new InteractiveSprite();

src/Explorer.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,13 @@
208208
<Compile Include="CacheObject\CacheMethod.cs" />
209209
<Compile Include="CacheObject\CacheProperty.cs" />
210210
<Compile Include="CacheObject\CacheObjectBase.cs" />
211+
<Compile Include="Helpers\Texture2DHelpers.cs" />
211212
<Compile Include="UI\InteractiveValue\InteractiveValue.cs" />
212213
<Compile Include="UI\InteractiveValue\Object\InteractiveDictionary.cs" />
213214
<Compile Include="UI\InteractiveValue\Object\InteractiveEnumerable.cs" />
214215
<Compile Include="UI\InteractiveValue\Object\InteractiveGameObject.cs" />
215216
<Compile Include="UI\InteractiveValue\Object\InteractiveSprite.cs" />
217+
<Compile Include="UI\InteractiveValue\Object\InteractiveTexture.cs" />
216218
<Compile Include="UI\InteractiveValue\Object\InteractiveTexture2D.cs" />
217219
<Compile Include="UI\InteractiveValue\Struct\InteractiveQuaternion.cs" />
218220
<Compile Include="UI\InteractiveValue\Struct\InteractiveRect.cs" />

src/ExplorerCore.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Explorer
1010
public class ExplorerCore
1111
{
1212
public const string NAME = "Explorer " + VERSION + " (" + PLATFORM + ", " + MODLOADER + ")";
13-
public const string VERSION = "2.0.2";
13+
public const string VERSION = "2.0.3";
1414
public const string AUTHOR = "Sinai";
1515
public const string GUID = "com.sinai.explorer";
1616

src/Helpers/Texture2DHelpers.cs

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using UnityEngine;
6+
using System.IO;
7+
using System.Reflection;
8+
#if CPP
9+
using Explorer.Unstrip.ImageConversion;
10+
#endif
11+
12+
namespace Explorer.Helpers
13+
{
14+
public static class Texture2DHelpers
15+
{
16+
#if CPP
17+
#else
18+
private static bool isNewEncodeMethod = false;
19+
private static MethodInfo EncodeToPNGMethod => m_encodeToPNGMethod ?? GetEncodeToPNGMethod();
20+
private static MethodInfo m_encodeToPNGMethod;
21+
22+
private static MethodInfo GetEncodeToPNGMethod()
23+
{
24+
if (ReflectionHelpers.GetTypeByName("UnityEngine.ImageConversion") is Type imageConversion)
25+
{
26+
isNewEncodeMethod = true;
27+
return m_encodeToPNGMethod = imageConversion.GetMethod("EncodeToPNG", ReflectionHelpers.CommonFlags);
28+
}
29+
30+
var method = typeof(Texture2D).GetMethod("EncodeToPNG", ReflectionHelpers.CommonFlags);
31+
if (method != null)
32+
{
33+
return m_encodeToPNGMethod = method;
34+
}
35+
36+
ExplorerCore.Log("ERROR: Cannot get any EncodeToPNG method!");
37+
return null;
38+
}
39+
#endif
40+
41+
42+
public static bool IsReadable(this Texture2D tex)
43+
{
44+
try
45+
{
46+
// This will cause an exception if it's not readable.
47+
// Reason for doing it this way is not all Unity versions
48+
// ship with the 'Texture.isReadable' property.
49+
50+
tex.GetPixel(0, 0);
51+
return true;
52+
}
53+
catch
54+
{
55+
return false;
56+
}
57+
}
58+
59+
public static Texture2D Copy(Texture2D other, Rect rect, bool isDTXnmNormal = false)
60+
{
61+
Color[] pixels;
62+
63+
if (!other.IsReadable())
64+
{
65+
other = ForceReadTexture(other, isDTXnmNormal);
66+
}
67+
68+
pixels = other.GetPixels((int)rect.x, (int)rect.y, (int)rect.width, (int)rect.height);
69+
70+
var _newTex = new Texture2D((int)rect.width, (int)rect.height);
71+
_newTex.SetPixels(pixels);
72+
73+
return _newTex;
74+
}
75+
76+
public static Texture2D ForceReadTexture(Texture2D tex, bool isDTXnmNormal = false)
77+
{
78+
try
79+
{
80+
var origFilter = tex.filterMode;
81+
tex.filterMode = FilterMode.Point;
82+
83+
RenderTexture rt = RenderTexture.GetTemporary(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
84+
rt.filterMode = FilterMode.Point;
85+
RenderTexture.active = rt;
86+
Graphics.Blit(tex, rt);
87+
88+
Texture2D _newTex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
89+
_newTex.ReadPixels(new Rect(0, 0, tex.width, tex.height), 0, 0);
90+
91+
if (isDTXnmNormal)
92+
{
93+
_newTex = DTXnmToRGBA(_newTex);
94+
}
95+
96+
_newTex.Apply(false, false);
97+
98+
RenderTexture.active = null;
99+
tex.filterMode = origFilter;
100+
101+
return _newTex;
102+
}
103+
catch (Exception e)
104+
{
105+
ExplorerCore.Log("Exception on ForceReadTexture: " + e.ToString());
106+
return default;
107+
}
108+
}
109+
110+
public static void SaveTextureAsPNG(Texture2D tex, string dir, string name, bool isDTXnmNormal = false)
111+
{
112+
if (!Directory.Exists(dir))
113+
{
114+
Directory.CreateDirectory(dir);
115+
}
116+
117+
byte[] data;
118+
var savepath = dir + @"\" + name + ".png";
119+
120+
// Fix for non-Readable or Compressed textures.
121+
tex = ForceReadTexture(tex, isDTXnmNormal);
122+
123+
if (isDTXnmNormal)
124+
{
125+
tex = DTXnmToRGBA(tex);
126+
tex.Apply(false, false);
127+
}
128+
129+
#if CPP
130+
data = tex.EncodeToPNG();
131+
#else
132+
var method = EncodeToPNGMethod;
133+
134+
if (isNewEncodeMethod)
135+
{
136+
data = (byte[])method.Invoke(null, new object[] { tex });
137+
}
138+
else
139+
{
140+
data = (byte[])method.Invoke(tex, new object[0]);
141+
}
142+
#endif
143+
144+
if (data == null || data.Length < 1)
145+
{
146+
ExplorerCore.LogWarning("Couldn't get any data for the texture!");
147+
}
148+
else
149+
{
150+
#if CPP
151+
// The IL2CPP method will return invalid byte data.
152+
// However, we can just iterate into safe C# byte[] array.
153+
byte[] safeData = new byte[data.Length];
154+
for (int i = 0; i < data.Length; i++)
155+
{
156+
safeData[i] = (byte)data[i]; // not sure if cast is needed
157+
}
158+
159+
File.WriteAllBytes(savepath, safeData);
160+
#else
161+
File.WriteAllBytes(savepath, data);
162+
#endif
163+
}
164+
}
165+
166+
// Converts DTXnm-format Normal Map to RGBA-format Normal Map.
167+
public static Texture2D DTXnmToRGBA(Texture2D tex)
168+
{
169+
Color[] colors = tex.GetPixels();
170+
171+
for (int i = 0; i < colors.Length; i++)
172+
{
173+
Color c = colors[i];
174+
175+
c.r = c.a * 2 - 1; // red <- alpha
176+
c.g = c.g * 2 - 1; // green is always the same
177+
178+
Vector2 rg = new Vector2(c.r, c.g); //this is the red-green vector
179+
c.b = Mathf.Sqrt(1 - Mathf.Clamp01(Vector2.Dot(rg, rg))); //recalculate the blue channel
180+
181+
colors[i] = new Color(
182+
(c.r * 0.5f) + 0.5f,
183+
(c.g * 0.5f) + 0.25f,
184+
(c.b * 0.5f) + 0.5f
185+
);
186+
}
187+
188+
var newtex = new Texture2D(tex.width, tex.height, TextureFormat.RGBA32, false);
189+
newtex.SetPixels(colors);
190+
191+
return newtex;
192+
}
193+
}
194+
}

src/UI/Inspectors/ReflectionInspector.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@ void AppendParams(ParameterInfo[] _args)
213213
try
214214
{
215215
var cached = CacheFactory.GetCacheObject(member, target);
216+
216217
if (cached != null)
217218
{
218219
cachedSigs.Add(sig);

src/UI/InteractiveValue/InteractiveValue.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -198,31 +198,33 @@ private MethodInfo GetToStringMethod()
198198
return m_toStringMethod;
199199
}
200200

201-
private string GetButtonLabel()
201+
public string GetButtonLabel()
202202
{
203203
if (Value == null) return null;
204204

205+
var valueType = ReflectionHelpers.GetActualType(Value);
206+
205207
string label = (string)ToStringMethod?.Invoke(Value, null) ?? Value.ToString();
206208

207-
var classColor = ValueType.IsAbstract && ValueType.IsSealed
209+
var classColor = valueType.IsAbstract && valueType.IsSealed
208210
? Syntax.Class_Static
209211
: Syntax.Class_Instance;
210212

211-
string typeLabel = $"<color={classColor}>{ValueType.FullName}</color>";
213+
string typeLabel = $"<color={classColor}>{valueType.FullName}</color>";
212214

213215
if (Value is UnityEngine.Object)
214216
{
215-
label = label.Replace($"({ValueType.FullName})", $"({typeLabel})");
217+
label = label.Replace($"({valueType.FullName})", $"({typeLabel})");
216218
}
217219
else
218220
{
219-
if (!label.Contains(ValueType.FullName))
221+
if (!label.Contains(valueType.FullName))
220222
{
221223
label += $" ({typeLabel})";
222224
}
223225
else
224226
{
225-
label = label.Replace(ValueType.FullName, typeLabel);
227+
label = label.Replace(valueType.FullName, typeLabel);
226228
}
227229
}
228230

src/UI/InteractiveValue/Object/InteractiveDictionary.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010

1111
namespace Explorer.UI
1212
{
13+
// TODO: Re-work class using InteractiveEnumerable or maybe InteractiveCollection for the Keys/Value lists.
14+
// Make the keys and values editable.
15+
1316
public class InteractiveDictionary : InteractiveValue, IExpandHeight
1417
{
1518
public bool IsExpanded { get; set; }

src/UI/InteractiveValue/Object/InteractiveSprite.cs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,50 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5+
using Explorer.Helpers;
56
using UnityEngine;
67

78
namespace Explorer.UI
89
{
910
public class InteractiveSprite : InteractiveTexture2D
1011
{
11-
public override void GetTexture2D()
12+
private Sprite refSprite;
13+
14+
public override void UpdateValue()
1215
{
1316
#if CPP
1417
if (Value != null && Value.Il2CppCast(typeof(Sprite)) is Sprite sprite)
18+
{
19+
refSprite = sprite;
20+
}
1521
#else
1622
if (Value is Sprite sprite)
23+
{
24+
refSprite = sprite;
25+
}
1726
#endif
27+
28+
base.UpdateValue();
29+
}
30+
31+
public override void GetTexture2D()
32+
{
33+
if (refSprite)
1834
{
19-
currentTex = sprite.texture;
20-
texContent = new GUIContent
21-
{
22-
image = currentTex
23-
};
35+
currentTex = refSprite.texture;
2436
}
2537
}
2638

39+
public override void GetGUIContent()
40+
{
41+
// Check if the Sprite.textureRect is just the entire texture
42+
if (refSprite.textureRect != new Rect(0, 0, currentTex.width, currentTex.height))
43+
{
44+
// It's not, do a sub-copy.
45+
currentTex = Texture2DHelpers.Copy(refSprite.texture, refSprite.textureRect);
46+
}
47+
48+
base.GetGUIContent();
49+
}
2750
}
2851
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using UnityEngine;
6+
7+
namespace Explorer.UI
8+
{
9+
// This class is possibly unnecessary.
10+
// It's just for CacheMembers that have 'Texture' as the value type, but is actually a Texture2D.
11+
12+
public class InteractiveTexture : InteractiveTexture2D
13+
{
14+
public override void GetTexture2D()
15+
{
16+
#if CPP
17+
if (Value != null && Value.Il2CppCast(typeof(Texture2D)) is Texture2D tex)
18+
#else
19+
if (Value is Texture2D tex)
20+
#endif
21+
{
22+
currentTex = tex;
23+
texContent = new GUIContent
24+
{
25+
image = currentTex
26+
};
27+
}
28+
}
29+
}
30+
}

0 commit comments

Comments
 (0)