summaryrefslogtreecommitdiff
path: root/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs360
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs567
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs211
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs.meta3
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs70
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs190
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs1244
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs.meta11
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi.meta8
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss26
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss.meta3
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader169
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader.meta9
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader156
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader.meta9
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.pngbin0 -> 15756 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.png.meta99
-rwxr-xr-xVRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.pngbin0 -> 25238 bytes
-rw-r--r--VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.png.meta99
26 files changed, 3302 insertions, 0 deletions
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools.meta
new file mode 100755
index 00000000..41410bb5
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 86107b9763a5ab3408a9884961b4191b
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor.meta
new file mode 100644
index 00000000..9ff74d2b
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 748053328138b574fb97df5308de5e24
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs
new file mode 100644
index 00000000..97d5f3d4
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs
@@ -0,0 +1,360 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+
+namespace Poi
+{
+ public class BakeToVertexColorsEditor : EditorWindow
+ {
+ //Window
+ static readonly Vector2 MIN_WINDOW_SIZE = new Vector2(316, 210);
+
+ // Version
+ Version version = new Version(1, 2);
+ string SubTitle
+ {
+ get
+ {
+ if(string.IsNullOrWhiteSpace(_subTitle))
+ _subTitle = "by Pumkin - v" + version.ToString();
+ return _subTitle;
+ }
+ }
+
+
+ //Strings
+ const string log_prefix = "<color=blue>Poi:</color> "; //color is hex or name
+
+ const string bakedSuffix_normals = "baked_normals";
+ const string bakedSuffix_position = "baked_position";
+
+ const string bakesFolderName = "Baked";
+ const string defaultUnityAssetBakesFolder = "Default Unity Resources";
+
+ const string hint_bakeAverageNormals = "Use this if you want seamless outlines";
+ const string hint_bakeVertexPositions = "Use this if you want scrolling emission";
+
+ const string button_bakeAverageNormals = "Bake Averaged Normals";
+ const string button_bakeVertexPositions = "Bake Vertex Positions";
+
+ const string warning_noMeshesDetected =
+ "No meshes detected in selection. Make sure your object has a Skinned Mesh Renderer or a Mesh Renderer with a valid Mesh assigned";
+
+ //Properties
+ static GameObject Selection
+ {
+ get => _selection;
+ set => _selection = value;
+ }
+
+ [MenuItem("Poi/Vertex Color Baker", priority = 11)]
+ public static void ShowWindow()
+ {
+ //Show existing window instance. If one doesn't exist, make one.
+ EditorWindow editorWindow = GetWindow(typeof(BakeToVertexColorsEditor));
+ editorWindow.autoRepaintOnSceneChange = true;
+ editorWindow.minSize = MIN_WINDOW_SIZE;
+
+ editorWindow.Show();
+ editorWindow.titleContent = new GUIContent("Bake Colors");
+ }
+
+ void OnGUI()
+ {
+ EditorGUILayout.LabelField("Poi Vertex Color Baker", PoiStyles.TitleLabel);
+ EditorGUILayout.LabelField(SubTitle);
+
+ PoiHelpers.DrawLine();
+
+ EditorGUI.BeginChangeCheck();
+ GameObject obj = EditorGUILayout.ObjectField("Avatar", Selection, typeof(GameObject), true) as GameObject;
+ if(EditorGUI.EndChangeCheck())
+ Selection = obj;
+
+ PoiHelpers.DrawLine();
+
+ EditorGUI.BeginDisabledGroup(!Selection);
+ {
+ EditorGUILayout.HelpBox(hint_bakeAverageNormals, MessageType.Info);
+ if(GUILayout.Button(button_bakeAverageNormals))
+ {
+ var meshes = GetAllMeshInfos(Selection);
+ if(meshes == null || meshes.Length == 0)
+ Debug.LogWarning(log_prefix + warning_noMeshesDetected);
+ else
+ BakeAveragedNormalsToColors(meshes);
+ }
+
+ PoiHelpers.DrawLine(true, false);
+ EditorGUILayout.HelpBox(hint_bakeVertexPositions, MessageType.Info);
+ if(GUILayout.Button(button_bakeVertexPositions))
+ {
+ var meshes = GetAllMeshInfos(Selection);
+ if(meshes == null || meshes.Length == 0)
+ Debug.LogWarning(log_prefix + warning_noMeshesDetected);
+ else
+ BakePositionsToColors(meshes);
+ }
+ }
+ EditorGUI.EndDisabledGroup();
+ }
+
+ /// <summary>
+ /// Saves a mesh in the same folder as the original asset
+ /// </summary>
+ /// <param name="mesh"></param>
+ /// <param name="newName">The new name of the mesh</param>
+ /// <returns>Returns the newly created mesh asset</returns>
+ static Mesh SaveMeshAsset(Mesh mesh, string newName)
+ {
+ string assetPath = AssetDatabase.GetAssetPath(mesh);
+
+ if(string.IsNullOrWhiteSpace(assetPath))
+ {
+ Debug.LogWarning(log_prefix + "Invalid asset path for " + mesh.name);
+ return null;
+ }
+
+ //Figure out folder name
+ string bakesDir = $"{Path.GetDirectoryName(assetPath)}";
+
+ //Handle default assets
+ if(bakesDir.StartsWith("Library"))
+ bakesDir = $"Assets\\{defaultUnityAssetBakesFolder}";
+
+ if(!bakesDir.EndsWith(bakesFolderName))
+ bakesDir += $"\\{bakesFolderName}";
+
+ if(!assetPath.Contains('.'))
+ assetPath += '\\';
+
+ PoiHelpers.EnsurePathExistsInAssets(bakesDir);
+
+ //Generate path
+ string pathNoExt = Path.Combine(bakesDir, newName);
+ string newPath = AssetDatabase.GenerateUniqueAssetPath($"{pathNoExt}.mesh");
+
+ //Save mesh, load it back, assign to renderer
+ Mesh newMesh = Instantiate(mesh);
+ AssetDatabase.CreateAsset(newMesh, newPath);
+
+ newMesh = AssetDatabase.LoadAssetAtPath<Mesh>(newPath);
+
+ if(newMesh == null)
+ {
+ Debug.Log(log_prefix + "Failed to load saved mesh");
+ return null;
+ }
+
+ EditorGUIUtility.PingObject(newMesh);
+ return newMesh;
+ }
+
+ /// <summary>
+ /// Sets the sharedMesh of a Skinned Mesh Renderer or Mesh Filter attached to a Mesh Renderer
+ /// </summary>
+ /// <param name="render"></param>
+ /// <param name="mesh"></param>
+ /// <returns></returns>
+ static bool SetRendererSharedMesh(Renderer render, Mesh mesh)
+ {
+ if(render is SkinnedMeshRenderer smr)
+ smr.sharedMesh = mesh;
+ else if(render is MeshRenderer mr)
+ {
+ var filter = mr.gameObject.GetComponent<MeshFilter>();
+ filter.sharedMesh = mesh;
+ }
+ else
+ return false;
+ return true;
+ }
+
+ static MeshInfo[] GetAllMeshInfos(GameObject obj)
+ {
+ return GetAllMeshInfos(obj?.GetComponentsInChildren<Renderer>(true));
+ }
+
+ static MeshInfo[] GetAllMeshInfos(params Renderer[] renderers)
+ {
+ var infos = renderers?.Select(ren =>
+ {
+ MeshInfo info = new MeshInfo();
+ if(ren is SkinnedMeshRenderer smr)
+ {
+ Mesh bakedMesh = new Mesh();
+ Transform tr = smr.gameObject.transform;
+ Quaternion origRot = tr.localRotation;
+ Vector3 origScale = tr.localScale;
+
+ tr.localRotation = Quaternion.identity;
+ tr.localScale = Vector3.one;
+
+ smr.BakeMesh(bakedMesh);
+
+ tr.localRotation = origRot;
+ tr.localScale = origScale;
+
+ info.sharedMesh = smr.sharedMesh;
+ info.bakedVertices = bakedMesh?.vertices;
+ info.bakedNormals = bakedMesh?.normals;
+ info.ownerRenderer = smr;
+ if(!info.sharedMesh)
+ Debug.LogWarning(log_prefix + $"Skinned Mesh Renderer at <b>{info.ownerRenderer.gameObject.name}</b> doesn't have a valid mesh");
+ }
+ else if(ren is MeshRenderer mr)
+ {
+ info.sharedMesh = mr.GetComponent<MeshFilter>()?.sharedMesh;
+ info.bakedVertices = info.sharedMesh?.vertices;
+ info.bakedNormals = info.sharedMesh?.normals;
+ info.ownerRenderer = mr;
+ if(!info.sharedMesh)
+ Debug.LogWarning(log_prefix + $"Mesh renderer at <b>{info.ownerRenderer.gameObject.name}</b> doesn't have a mesh filter with a valid mesh");
+ }
+ return info;
+ }).ToArray();
+
+ return infos;
+ }
+
+ static void BakePositionsToColors(MeshInfo[] meshInfos)
+ {
+ var queue = new Dictionary<MeshInfo, Mesh>();
+ try
+ {
+ AssetDatabase.StartAssetEditing();
+ foreach(var meshInfo in meshInfos)
+ {
+ if(!meshInfo.sharedMesh)
+ continue;
+
+ Vector3[] verts = meshInfo.bakedVertices; //accessing mesh.vertices on every iteration is very slow
+ Color[] colors = new Color[verts.Length];
+ for(int i = 0; i < verts.Length; i++)
+ colors[i] = new Color(verts[i].x, verts[i].y, verts[i].z);
+ meshInfo.sharedMesh.colors = colors;
+
+ //Create new mesh asset and add it to queue
+ string name = PoiHelpers.AddSuffix(meshInfo.ownerRenderer.gameObject.name, bakedSuffix_position);
+ Mesh newMesh = SaveMeshAsset(meshInfo.sharedMesh, name);
+ if(newMesh)
+ queue.Add(meshInfo, newMesh);
+ }
+ }
+ catch(Exception ex)
+ {
+ Debug.LogException(ex);
+ }
+ finally
+ {
+ AssetDatabase.StopAssetEditing();
+ }
+
+ //After all meshes are imported assign the meshes
+ foreach(var kv in queue)
+ {
+ SetRendererSharedMesh(kv.Key.ownerRenderer, kv.Value);
+ }
+ }
+
+ static void BakeAveragedNormalsToColors(params MeshInfo[] infos)
+ {
+ var queue = new Dictionary<MeshInfo, Mesh>();
+ try
+ {
+ AssetDatabase.StartAssetEditing();
+ foreach(var meshInfo in infos)
+ {
+ if(!meshInfo.sharedMesh)
+ continue;
+
+ Vector3[] verts = meshInfo.bakedVertices;
+ Vector3[] normals = meshInfo.bakedNormals;
+ VertexInfo[] vertInfo = new VertexInfo[verts.Length];
+ for(int i = 0; i < verts.Length; i++)
+ {
+ vertInfo[i] = new VertexInfo()
+ {
+ vertex = verts[i],
+ originalIndex = i,
+ normal = normals[i]
+ };
+ }
+ var groups = vertInfo.GroupBy(x => x.vertex);
+ VertexInfo[] processedVertInfo = new VertexInfo[vertInfo.Length];
+ int index = 0;
+ foreach(IGrouping<Vector3, VertexInfo> group in groups)
+ {
+ Vector3 avgNormal = Vector3.zero;
+ foreach(VertexInfo item in group)
+ avgNormal += item.normal;
+
+ avgNormal /= group.Count();
+ foreach(VertexInfo item in group)
+ {
+ processedVertInfo[index] = new VertexInfo()
+ {
+ vertex = item.vertex,
+ originalIndex = item.originalIndex,
+ normal = item.normal,
+ averagedNormal = avgNormal
+ };
+ index++;
+ }
+ }
+ Color[] colors = new Color[verts.Length];
+ for(int i = 0; i < processedVertInfo.Length; i++)
+ {
+ VertexInfo info = processedVertInfo[i];
+
+ int origIndex = info.originalIndex;
+ Vector3 normal = info.averagedNormal;
+ Color normColor = new Color(normal.x, normal.y, normal.z, 1);
+ colors[origIndex] = normColor;
+ }
+ meshInfo.sharedMesh.colors = colors;
+
+ string name = PoiHelpers.AddSuffix(meshInfo.ownerRenderer.gameObject.name, bakedSuffix_normals);
+ Mesh newMesh = SaveMeshAsset(meshInfo.sharedMesh, name);
+ if(newMesh)
+ queue.Add(meshInfo, newMesh);
+ }
+ }
+ catch(Exception ex)
+ {
+ Debug.LogException(ex);
+ }
+ finally
+ {
+ AssetDatabase.StopAssetEditing();
+ }
+
+ //Assign all new meshes to their renderers
+ foreach(var kv in queue)
+ SetRendererSharedMesh(kv.Key.ownerRenderer, kv.Value);
+ }
+
+ struct MeshInfo
+ {
+ public Renderer ownerRenderer;
+ public Mesh sharedMesh;
+ public Vector3[] bakedVertices;
+ public Vector3[] bakedNormals;
+ }
+
+ struct VertexInfo
+ {
+ public Vector3 vertex;
+ public int originalIndex;
+ public Vector3 normal;
+ public Vector3 averagedNormal;
+ }
+
+ static GameObject _selection;
+ private string _subTitle;
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs.meta
new file mode 100644
index 00000000..d603b15a
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/BakeToVertexColorsEditor.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 3f398d68f8c01b54485d2a04a13c958b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs
new file mode 100644
index 00000000..10063a53
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs
@@ -0,0 +1,567 @@
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using UnityEditor;
+using UnityEngine;
+
+//Made by Dreadrith#3238
+//Version v1.1.0
+//Discord: https://discord.gg/ZsPfrGn
+//Github: https://github.com/Dreadrith/DreadScripts
+//Gumroad: https://gumroad.com/dreadrith
+//Ko-fi: https://ko-fi.com/dreadrith
+
+namespace DreadScripts
+{
+ public class GradientFlood : EditorWindow
+ {
+
+ #region Automated Variables
+ private static Vector2 scroll;
+ private static float modifiedBoundRange;
+ private static Texture2D titleTexture;
+ #endregion
+
+ #region Input
+ public static Texture2D pathTexture;
+ public static Color startPixelsColor = Color.red;
+ public static Color limitPixelsColor = Color.white;
+ public static GradientType gradientType = GradientType.DataGradient;
+
+ public static Color tintColor = Color.white;
+ public static Gradient gradientColor = new Gradient();
+
+ public static float gradientDistribution = 1;
+ public static float startColorTolerance = 0.05f;
+ public static float limitColorTolerance = 0.05f;
+ public static float rangeLowerBound;
+ public static float rangeUpperBound = 255;
+ public static bool invertGradient;
+ public static bool loopGradient;
+ public static bool applyGradientAlpha;
+ #endregion
+
+
+ public enum GradientType
+ {
+ DataGradient,
+ TintedGradient,
+ GradientGradient
+ }
+
+ public enum _FloodBehavior
+ {
+ Side,
+ Diagonal,
+ SideAndDiagonal,
+ Horizontal,
+ Vertical,
+ Custom
+ }
+
+ public static bool foldoutFloodStep;
+ public static _FloodBehavior floodBehavior = _FloodBehavior.SideAndDiagonal;
+ public static List<FloodStep> floodSteps = new List<FloodStep>()
+ {
+ new FloodStep
+ (
+ new Vector2Int(1, 0),
+ new Vector2Int(-1, 0),
+ new Vector2Int(0, 1),
+ new Vector2Int(0, -1),
+ new Vector2Int(1, 1),
+ new Vector2Int(1, -1),
+ new Vector2Int(-1, 1),
+ new Vector2Int(-1, -1)
+
+ )
+ };
+
+
+
+ [MenuItem("Poi/Gradient Flood")]
+ private static void showWindow()
+ {
+ EditorWindow w = GetWindow<GradientFlood>(false, "Gradient Flood", true);
+ if (!titleTexture)
+ {
+ titleTexture = GetColors((Texture2D)EditorGUIUtility.IconContent("Texture2D Icon").image, 16, 16, out _);
+ titleTexture.Apply();
+ }
+
+ w.titleContent.image = titleTexture;
+ w.minSize = new Vector2(423, 253);
+ }
+
+ private void OnGUI()
+ {
+ scroll = EditorGUILayout.BeginScrollView(scroll);
+ GUIStyle centeredTitle = new GUIStyle("boldlabel") {alignment = TextAnchor.MiddleCenter, fontSize = 16};
+ using (new GUILayout.VerticalScope("helpbox"))
+ {
+ GUILayout.Label("Texture", centeredTitle);
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ EditorGUIUtility.labelWidth = 1;
+ pathTexture = (Texture2D) EditorGUILayout.ObjectField(string.Empty, pathTexture, typeof(Texture2D), false, GUILayout.Width(80), GUILayout.Height(80));
+ EditorGUIUtility.labelWidth = 0;
+
+ GUILayout.FlexibleSpace();
+ }
+
+ DrawFloodBehaviorGUI();
+
+ using (new GUILayout.HorizontalScope("box"))
+ gradientType = (GradientType)EditorGUILayout.EnumPopup("Gradient Type", gradientType);
+
+
+ switch (gradientType)
+ {
+ case GradientType.TintedGradient:
+ using (new GUILayout.HorizontalScope("box"))
+ tintColor = EditorGUILayout.ColorField("Tint", tintColor);
+ break;
+ case GradientType.GradientGradient:
+ using (new GUILayout.HorizontalScope("box"))
+ gradientColor = EditorGUILayout.GradientField("Gradient", gradientColor);
+ break;
+ }
+
+
+ if (gradientType > 0)
+ {
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ GUILayout.Label("Color Range");
+
+ EditorGUI.BeginChangeCheck();
+
+ rangeLowerBound = EditorGUILayout.DelayedIntField((int) rangeLowerBound, GUI.skin.label, GUILayout.Width(28));
+ EditorGUILayout.MinMaxSlider(ref rangeLowerBound, ref rangeUpperBound, 0, 255);
+
+ rangeUpperBound = EditorGUILayout.DelayedIntField((int) rangeUpperBound, GUI.skin.label, GUILayout.Width(28));
+
+ if (EditorGUI.EndChangeCheck())
+ {
+ rangeUpperBound = Mathf.Clamp((int) rangeUpperBound, 0, 255);
+ rangeLowerBound = Mathf.Max(0, Mathf.Min(rangeUpperBound, rangeLowerBound));
+ }
+ }
+ }
+
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ using (new GUILayout.HorizontalScope())
+ GUILayout.Label("Tolerance");
+
+ using (new GUILayout.HorizontalScope())
+ {
+ EditorGUIUtility.labelWidth = 40;
+ startColorTolerance = EditorGUILayout.Slider("Start", startColorTolerance, 0, 1);
+ limitColorTolerance = EditorGUILayout.Slider("Limit", limitColorTolerance, 0, 1);
+ EditorGUIUtility.labelWidth = 0;
+ }
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ invertGradient = EditorGUILayout.Toggle("Invert Gradient", invertGradient);
+
+ if (gradientType > 0) applyGradientAlpha = EditorGUILayout.Toggle("Apply Gradient Alpha", applyGradientAlpha);
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ loopGradient = EditorGUILayout.Toggle("Loop Gradient", loopGradient);
+ if (loopGradient) gradientDistribution = EditorGUILayout.FloatField("Distribution", gradientDistribution);
+ }
+
+ using (new EditorGUI.DisabledScope(!pathTexture))
+ if (GUILayout.Button("Fill"))
+ GenerateFilledTexture(pathTexture);
+
+ }
+ Credit();
+
+ EditorGUILayout.EndScrollView();
+ }
+
+ private void DrawFloodBehaviorGUI()
+ {
+ using (var change = new EditorGUI.ChangeCheckScope())
+ {
+ using (new GUILayout.HorizontalScope("box"))
+ floodBehavior = (_FloodBehavior)EditorGUILayout.EnumPopup(new GUIContent("Flood Behavior", "The path to fill in the texture starting from the start pixels"), floodBehavior);
+
+ if (change.changed)
+ {
+ switch (floodBehavior)
+ {
+ case _FloodBehavior.Side:
+ floodSteps.Clear();
+ floodSteps.Add(new FloodStep
+ (
+
+ new Vector2Int(1, 0),
+ new Vector2Int(-1, 0),
+ new Vector2Int(0, 1),
+ new Vector2Int(0, -1)
+
+ ));
+ break;
+ case _FloodBehavior.Diagonal:
+ floodSteps.Clear();
+ floodSteps.Add(new FloodStep
+ (
+ new Vector2Int(1, 1),
+ new Vector2Int(-1, -1),
+ new Vector2Int(1, -1),
+ new Vector2Int(-1, 1)
+ ));
+ break;
+ case _FloodBehavior.SideAndDiagonal:
+ floodSteps.Clear();
+ floodSteps.Add(new FloodStep
+ (
+
+ new Vector2Int(1, 0),
+ new Vector2Int(-1, 0),
+ new Vector2Int(0, 1),
+ new Vector2Int(0, -1),
+ new Vector2Int(1, 1),
+ new Vector2Int(1, -1),
+ new Vector2Int(-1, 1),
+ new Vector2Int(-1, -1)
+
+ ));
+ break;
+ case _FloodBehavior.Horizontal:
+ floodSteps.Clear();
+ floodSteps.Add(new FloodStep
+ (
+ new Vector2Int(1, 0),
+ new Vector2Int(-1, 0)
+ ));
+ break;
+ case _FloodBehavior.Vertical:
+ floodSteps.Clear();
+ floodSteps.Add(new FloodStep
+ (
+ new Vector2Int(0, 1),
+ new Vector2Int(0, -1)
+ ));
+ break;
+ }
+ }
+ }
+ if (floodBehavior != _FloodBehavior.Custom) return;
+
+ using (new GUILayout.VerticalScope("box"))
+ {
+ using (new GUILayout.VerticalScope("helpbox"))
+ {
+ foldoutFloodStep = EditorGUILayout.Foldout(foldoutFloodStep, "Flood Steps");
+ }
+
+ if (foldoutFloodStep)
+ {
+ EditorGUI.indentLevel++;
+ for (int i = 0; i < floodSteps.Count; i++)
+ {
+ DrawFloodStepGUI(floodSteps[i], i);
+ }
+
+ if (GUILayout.Button("Add Step"))
+ floodSteps.Add(new FloodStep());
+ EditorGUI.indentLevel--;
+ }
+ }
+ }
+ private void DrawFloodStepGUI(FloodStep step, int i)
+ {
+ using (new GUILayout.VerticalScope("box"))
+ {
+ using (new GUILayout.HorizontalScope("helpbox"))
+ {
+ step.foldout = EditorGUILayout.Foldout(step.foldout, $"Step {i}:");
+
+ using (new EditorGUI.DisabledGroupScope(floodSteps.Count == 1))
+ if (GUILayout.Button("X", GUILayout.Width(20), GUILayout.Height(18)))
+ {
+ floodSteps.RemoveAt(i);
+ goto Skip;
+ }
+ }
+
+ if (step.foldout)
+ {
+ EditorGUI.indentLevel++;
+ for (int j = 0; j < step.coordinates.Count; j++)
+ {
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ step.coordinates[j] = EditorGUILayout.Vector2IntField(string.Empty, step.coordinates[j]);
+ if (GUILayout.Button("X", GUILayout.Width(20), GUILayout.Height(18)))
+ step.coordinates.RemoveAt(j);
+ }
+
+
+ }
+ if (GUILayout.Button("+", "toolbarbutton")) step.coordinates.Add(new Vector2Int());
+
+ EditorGUI.indentLevel--;
+ }
+ Skip:;
+
+ }
+ }
+
+ public static void GenerateFilledTexture(Texture2D texture)
+ {
+ if (!loopGradient) gradientDistribution = 1;
+ if (gradientType == GradientType.DataGradient)
+ {
+ rangeLowerBound = 1;
+ rangeUpperBound = 255;
+ }
+
+ int width = texture.width;
+ modifiedBoundRange = rangeUpperBound / 255 - rangeLowerBound / 255;
+ Texture2D gradientTexture = GetColors(texture, out Color[] ogColors);
+ GradientFillPixel[] gradientPixels = new GradientFillPixel[ogColors.Length];
+
+ Queue<GradientFillPixel> pixelsToExpand = new Queue<GradientFillPixel>();
+
+ for (int i = 0; i < ogColors.Length; i++)
+ {
+ gradientPixels[i] = new GradientFillPixel(ogColors[i], i);
+ if (!gradientPixels[i].isLimit && gradientPixels[i].isFilled) pixelsToExpand.Enqueue(gradientPixels[i]);
+ }
+
+ if (pixelsToExpand.Count == 0)
+ Debug.LogWarning("<color=red>[GPFiller]</color> No start pixels were found! If start pixels exist, try adjusting the color tolerance.");
+
+ int floodIndex = 0;
+ int currentStackCount = pixelsToExpand.Count;
+ int nextStackCount = 0;
+
+ bool IsValidFillIndex(int index, out GradientFillPixel pixelToFill)
+ {
+ if (index >= 0 && index < ogColors.Length)
+ {
+ pixelToFill = gradientPixels[index];
+ if (!pixelToFill.isLimit && !pixelToFill.isFilled)
+ {
+ pixelsToExpand.Enqueue(pixelToFill);
+ nextStackCount++;
+ return true;
+ }
+ }
+
+ pixelToFill = null;
+ return false;
+ }
+
+ void FillIndex(GradientFillPixel fillerPixel, int index)
+ {
+ if (!IsValidFillIndex(index, out GradientFillPixel nextPixel)) return;
+ nextPixel.gradientValue = fillerPixel.gradientValue + gradientDistribution;
+ nextPixel.isFilled = true;
+ }
+
+
+
+ while (pixelsToExpand.Any())
+ {
+ FloodStep currentStep = floodSteps[floodIndex % floodSteps.Count];
+ var pixel = pixelsToExpand.Dequeue();
+
+ foreach (var coord in currentStep.coordinates)
+ {
+ int finalX = (pixel.arrayIndex % width) + coord.x;
+ if (finalX < 0 || finalX >= width) continue;
+
+ FillIndex(pixel, pixel.arrayIndex + coord.x + width * coord.y);
+ }
+
+ currentStackCount--;
+ if (currentStackCount == 0)
+ {
+ currentStackCount = nextStackCount;
+ nextStackCount = 0;
+ floodIndex++;
+ }
+ }
+
+
+ float maxGradientValue = gradientPixels.Max(p => p.gradientValue);
+ if (gradientType == GradientType.DataGradient) maxGradientValue /= 4;
+
+ for (int i = 0; i < ogColors.Length; i++)
+ {
+ var f = gradientPixels[i].GetFloatValue(maxGradientValue);
+
+ if (f == 0) ogColors[i] = Color.clear;
+ else
+ {
+
+ if (gradientType == GradientType.TintedGradient)
+ ogColors[i] = new Color(f * tintColor.r, f * tintColor.g, f * tintColor.b, gradientPixels[i].isLimit ? 1 : (applyGradientAlpha ? f : 1) * tintColor.a);
+ else if (gradientType == GradientType.GradientGradient)
+ {
+ Color gradColor = gradientColor.Evaluate(f);
+ gradColor.a = gradientPixels[i].isLimit ? 1 : (applyGradientAlpha ? f : 1) * gradColor.a;
+ ogColors[i] = gradColor;
+ }
+ else
+ {
+ if (f <= 1) ogColors[i] = new Color(f % 1, 0, 0, 0);
+
+ else if (f <= 2) ogColors[i] = new Color(1, f%1, 0, 0);
+
+ else if (f <= 3) ogColors[i] = new Color(1, 1, f % 1, 0);
+
+ else ogColors[i] = new Color(1, 1, 1, f % 1);
+
+ }
+ }
+ }
+
+ gradientTexture.SetPixels(ogColors);
+ gradientTexture.Apply();
+
+ string assetPath = AssetDatabase.GetAssetPath(pathTexture);
+ string ext = Path.GetExtension(assetPath);
+ byte[] data;
+ switch (ext)
+ {
+ case ".jpeg" when !applyGradientAlpha && gradientType != GradientType.DataGradient:
+ case ".jpg" when !applyGradientAlpha && gradientType != GradientType.DataGradient:
+ ext = ".jpg";
+ data = gradientTexture.EncodeToJPG(100);
+ break;
+ case ".tga":
+ data = gradientTexture.EncodeToTGA();
+ break;
+ default:
+ ext = ".png";
+ data = gradientTexture.EncodeToPNG();
+ break;
+ }
+
+
+ DestroyImmediate(gradientTexture);
+
+ string savePath = AssetDatabase.GenerateUniqueAssetPath($"{Path.GetDirectoryName(assetPath)}/{pathTexture.name}{ext}");
+ SaveTexture(data, savePath);
+ CopyTextureSettings(assetPath, savePath);
+ }
+
+ public static Texture2D GetColors(Texture2D texture, int width, int height, out Color[] Colors, bool unloadTempTexture = false)
+ {
+ //Thanks to
+ //https://gamedev.stackexchange.com/questions/92285/unity3d-resize-texture-without-corruption
+ texture.filterMode = FilterMode.Point;
+ RenderTexture rt = RenderTexture.GetTemporary(width, height);
+
+ rt.filterMode = FilterMode.Point;
+ RenderTexture.active = rt;
+ Graphics.Blit(texture, rt);
+ Texture2D newTexture = new Texture2D(width, height);
+ newTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
+ Color[] myColors = newTexture.GetPixels();
+ RenderTexture.active = null;
+ /////////////////////
+ Colors = myColors;
+ if (unloadTempTexture)
+ {
+ DestroyImmediate(newTexture);
+ return null;
+ }
+ return newTexture;
+ }
+
+ public static Texture2D GetColors(Texture2D texture, out Color[] Colors, bool unloadTempTexture = false)
+ {
+ return GetColors(texture, texture.width, texture.height, out Colors, unloadTempTexture);
+ }
+
+ private static void CopyTextureSettings(string from, string to)
+ {
+ TextureImporter source = (TextureImporter)AssetImporter.GetAtPath(from);
+ TextureImporterSettings sourceSettings = new TextureImporterSettings();
+ source.ReadTextureSettings(sourceSettings);
+
+ TextureImporter destination = (TextureImporter)AssetImporter.GetAtPath(to);
+ destination.SetTextureSettings(sourceSettings);
+ destination.maxTextureSize = source.maxTextureSize;
+ destination.textureCompression = source.textureCompression;
+ destination.crunchedCompression = source.crunchedCompression;
+ destination.SaveAndReimport();
+ }
+
+ private static void SaveTexture(byte[] textureEncoding, string path)
+ {
+ using (System.IO.FileStream stream = System.IO.File.Create(path))
+ stream.Write(textureEncoding, 0, textureEncoding.Length);
+ AssetDatabase.Refresh();
+ EditorGUIUtility.PingObject(AssetDatabase.LoadMainAssetAtPath(path));
+ }
+
+ public class GradientFillPixel
+ {
+ public readonly bool isLimit;
+ public bool isFilled;
+ public float gradientValue;
+ public int arrayIndex;
+
+ public GradientFillPixel(Color pixelColor, int index)
+ {
+ isLimit = Mathf.Abs(pixelColor.r - limitPixelsColor.r) < limitColorTolerance &&
+ Mathf.Abs(pixelColor.g - limitPixelsColor.g) < limitColorTolerance &&
+ Mathf.Abs(pixelColor.b - limitPixelsColor.b) < limitColorTolerance;
+
+ isFilled = Mathf.Abs(pixelColor.r - startPixelsColor.r) < startColorTolerance &&
+ Mathf.Abs(pixelColor.g - startPixelsColor.g) < startColorTolerance &&
+ Mathf.Abs(pixelColor.b - startPixelsColor.b) < startColorTolerance;
+
+ gradientValue = (int)rangeLowerBound;
+ arrayIndex = index;
+ }
+
+ public float GetFloatValue(float maxGradientValue)
+ {
+ if (isLimit || !isFilled) return 0;
+ float floatValue = !loopGradient ? gradientValue / maxGradientValue : (gradientValue % 255 * (gradientType == GradientType.DataGradient ? 4 : 1)) / 255f;
+ float adjustedValue = floatValue * modifiedBoundRange + rangeLowerBound / 255;
+ return invertGradient ? (gradientType == GradientType.DataGradient ? 4 : 1) - adjustedValue : adjustedValue;
+ }
+ }
+
+ public class FloodStep
+ {
+ public List<Vector2Int> coordinates;
+ public bool foldout;
+
+ public FloodStep(params Vector2Int[] coordinates)
+ {
+ this.coordinates = coordinates.ToList();
+ }
+ }
+
+
+ private static void Credit()
+ {
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("Made By Dreadrith#3238", "boldlabel"))
+ Application.OpenURL("https://linktr.ee/Dreadrith");
+ }
+ }
+ }
+
+
+}
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs.meta
new file mode 100644
index 00000000..7e735a0d
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/GradientFlood (8).cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d47e3b8c6a19a8145bb62e0d933a9679
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs
new file mode 100644
index 00000000..9b72b150
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs
@@ -0,0 +1,211 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using Poiyomi.ModularShaderSystem;
+using UnityEditor;
+using UnityEngine;
+using UnityEngine.UI;
+using UnityEngine.UIElements;
+using Button = UnityEngine.UIElements.Button;
+using Toggle = UnityEngine.UIElements.Toggle;
+
+namespace PoiyomiPatreon.Scripts.poi_tools.Editor
+{
+ public class ModularShadersGeneratorElement : VisualElement
+ {
+ private bool _isSelected;
+
+ public bool IsSelected
+ {
+ get => _isSelected;
+ set
+ {
+ if (_isErrored) return;
+ _isSelected = value;
+ _toggle.SetValueWithoutNotify(_isSelected);
+ }
+ }
+
+ public ModularShader Shader { get; set; }
+
+ private readonly Toggle _toggle;
+ private readonly bool _isErrored;
+ public ModularShadersGeneratorElement(ModularShader shader)
+ {
+ Shader = shader;
+ style.flexDirection = FlexDirection.Row;
+ _toggle = new Toggle();
+ _toggle.RegisterValueChangedCallback(evt => IsSelected = evt.newValue);
+ Add(_toggle);
+ Add(new Label(Shader.Name));
+ var issues = ShaderGenerator.CheckShaderIssues(shader);
+ if (issues.Count > 0)
+ {
+ _isErrored = true;
+ _toggle.SetEnabled(false);
+ VisualElement element = new VisualElement();
+ element.AddToClassList("error");
+ element.tooltip = "Modular shader has the following errors: \n -" + string.Join("\n -", issues);
+ Add(element);
+ }
+ }
+ }
+
+ public class ModularShadersGeneratorWindow : EditorWindow
+ {
+ [MenuItem("Poi/Modular Shaders Generator")]
+ private static void ShowWindow()
+ {
+ var window = GetWindow<ModularShadersGeneratorWindow>();
+ window.titleContent = new GUIContent("Modular Shaders Generator");
+ window.Show();
+ }
+
+ private VisualElement _root;
+ private List<ModularShadersGeneratorElement> _elements;
+ private string _folderPath = "Assets/_poiyomiShaders/Shaders/8.1/Pro";
+
+ private void CreateGUI()
+ {
+ _root = rootVisualElement;
+ try
+ {
+ Reload();
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ }
+ }
+
+ private void Reload()
+ {
+ _root.Clear();
+
+ var styleSheet = Resources.Load<StyleSheet>("Poi/ModularShadersGeneratorStyle");
+ _root.styleSheets.Add(styleSheet);
+
+ var view = new ScrollView(ScrollViewMode.Vertical);
+
+ var selectButtons = new VisualElement();
+ selectButtons.AddToClassList("buttons-area");
+
+ var selectAll = new Button();
+ selectAll.text = "Select all";
+ selectAll.style.flexGrow = 1;
+ selectAll.clicked += () =>
+ {
+ foreach (var element in _elements)
+ element.IsSelected = true;
+ };
+ selectButtons.Add(selectAll);
+
+ var deselectAll = new Button();
+ deselectAll.text = "Deselect all";
+ deselectAll.style.flexGrow = 1;
+ deselectAll.clicked += () =>
+ {
+ foreach (var element in _elements)
+ element.IsSelected = false;
+ };
+ selectButtons.Add(deselectAll);
+
+ var toggleSelections = new Button();
+ toggleSelections.text = "Toggle selections";
+ toggleSelections.style.flexGrow = 1;
+ toggleSelections.clicked += () =>
+ {
+ foreach (var element in _elements)
+ element.IsSelected = !element.IsSelected;
+ };
+ selectButtons.Add(toggleSelections);
+
+ var reloadButton = new Button();
+ reloadButton.text = "Refresh";
+ reloadButton.style.flexGrow = 1;
+ reloadButton.clicked += () =>
+ {
+ Reload();
+ };
+ selectButtons.Add(reloadButton);
+
+ view.Add(selectButtons);
+
+ // Load all modular shaders
+ _elements = new List<ModularShadersGeneratorElement>();
+ foreach (var modularShader in FindAssetsByType<ModularShader>())
+ {
+ var element = new ModularShadersGeneratorElement(modularShader);
+ _elements.Add(element);
+ view.Add(element);
+ }
+
+ var fileSelector = new VisualElement();
+ fileSelector.AddToClassList("folder-selector");
+
+ var folder = new TextField();
+ folder.value = _folderPath;
+ folder.RegisterValueChangedCallback(evt => _folderPath = evt.newValue);
+ folder.style.flexShrink = 1;
+ folder.style.flexGrow = 1;
+ folder.SetEnabled(false);
+ var label = new Label("Destination ");
+ label.style.alignSelf = Align.Center;
+ fileSelector.Add(label);
+ fileSelector.Add(folder);
+ var fileButton = new Button();
+ fileButton.text = "Open";
+ fileButton.clicked += () =>
+ {
+ string path = EditorUtility.OpenFolderPanel("Select folder to use", "Assets", "");
+ if (path.Length == 0)
+ return;
+
+ if (!Directory.Exists(path))
+ {
+ EditorUtility.DisplayDialog("Error", "The folder does not exist", "Ok");
+ return;
+ }
+
+ folder.value = path;
+ };
+ fileSelector.Add(fileButton);
+ view.Add(fileSelector);
+
+ var button = new Button();
+ button.text = "Generate Shaders";
+ button.clicked += GenerateShaders;
+ view.Add(button);
+
+ _root.Add(view);
+ }
+
+ private void GenerateShaders()
+ {
+ if (!Directory.Exists(_folderPath))
+ {
+ EditorUtility.DisplayDialog("Error", "The destination folder does not exist", "Ok");
+ return;
+ }
+
+ foreach (ModularShadersGeneratorElement element in _elements.Where(x => x.IsSelected))
+ ShaderGenerator.GenerateShader(_folderPath, element.Shader);
+ }
+
+ private static T[] FindAssetsByType<T>() where T : UnityEngine.Object
+ {
+ List<T> assets = new List<T>();
+ AssetDatabase.Refresh();
+ string[] guids = AssetDatabase.FindAssets($"t:{typeof(T).ToString().Replace("UnityEngine.", "")}");
+ for (int i = 0; i < guids.Length; i++)
+ {
+ string assetPath = AssetDatabase.GUIDToAssetPath(guids[i]);
+ T asset = AssetDatabase.LoadAssetAtPath<T>(assetPath);
+ if (asset != null)
+ assets.Add(asset);
+ }
+ return assets.ToArray();
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs.meta
new file mode 100644
index 00000000..05c59212
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/ModularShadersGeneratorWindow.cs.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: 628a5d8b8b9a456ca963d43c28fb86c1
+timeCreated: 1638402450 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs
new file mode 100644
index 00000000..7b388701
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs
@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEditor;
+using UnityEngine;
+
+namespace Poi
+{
+ internal static class PoiPaths
+ {
+ public const string defaultResourcesPath = "Library/unity default resources/";
+ public const string poiResourcesPath = "Poi/";
+ }
+
+ internal static class PoiStyles
+ {
+ public static GUIStyle BigButton
+ {
+ get
+ {
+ if(_bigButton == null)
+ _bigButton = new GUIStyle("button")
+ {
+ fixedHeight = 22 * EditorGUIUtility.pixelsPerPoint
+ };
+ return _bigButton;
+ }
+ }
+
+ public static GUIStyle TitleLabel
+ {
+ get
+ {
+ if(_titleLabel == null)
+ _titleLabel = new GUIStyle(EditorStyles.label)
+ {
+ fontSize = 15, stretchHeight = true, clipping = TextClipping.Overflow
+ };
+
+ return _titleLabel;
+ }
+ }
+
+ static GUIStyle _bigButton;
+ static GUIStyle _titleLabel;
+ }
+
+ internal static class PoiIcons
+ {
+ public static Texture2D LinkIcon
+ {
+ get
+ {
+ if(!_linkIcon)
+ {
+ string linkTexPath = EditorGUIUtility.isProSkin ? "icon_link_pro" : "icon_link";
+ _linkIcon = Resources.Load<Texture2D>(PoiPaths.poiResourcesPath + linkTexPath);
+ }
+
+ return _linkIcon;
+ }
+ }
+
+ private static Texture2D _linkIcon;
+ }
+}
+
+
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs.meta
new file mode 100644
index 00000000..2fae90dc
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiData.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8f58036675b906e4797a5c394781b2a0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs
new file mode 100644
index 00000000..2d3d1485
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs
@@ -0,0 +1,190 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using UnityEditor;
+using UnityEngine;
+
+namespace Poi
+{
+ static class PoiHelpers
+ {
+ static readonly string suffixSeparator = "_";
+
+ /// <summary>
+ /// Changes a path in Assets to an absolute windows path
+ /// </summary>
+ /// <param name="localPath"></param>
+ /// <returns></returns>
+ public static string LocalAssetsPathToAbsolutePath(string localPath)
+ {
+ localPath = NormalizePathSlashes(localPath);
+ const string assets = "Assets/";
+ if(localPath.StartsWith(assets))
+ {
+ localPath = localPath.Remove(0, assets.Length);
+ localPath = $"{Application.dataPath}/{localPath}";
+ }
+ return localPath;
+ }
+
+ /// <summary>
+ /// Replaces all forward slashes \ with back slashes /
+ /// </summary>
+ /// <param name="path"></param>
+ /// <returns></returns>
+ public static string NormalizePathSlashes(string path)
+ {
+ if(!string.IsNullOrEmpty(path))
+ path = path.Replace('\\', '/');
+ return path;
+ }
+
+ /// <summary>
+ /// Ensures directory exists inside the assets folder
+ /// </summary>
+ /// <param name="assetPath"></param>
+ public static void EnsurePathExistsInAssets(string assetPath)
+ {
+ Directory.CreateDirectory(LocalAssetsPathToAbsolutePath(assetPath));
+ }
+
+ /// <summary>
+ /// Adds a suffix to the end of the string then returns it
+ /// </summary>
+ /// <param name="str"></param>
+ /// <param name="suffixes"></param>
+ /// <returns></returns>
+ public static string AddSuffix(string str, params string[] suffixes)
+ {
+ bool ignoreSeparatorOnce = string.IsNullOrWhiteSpace(str);
+ StringBuilder sb = new StringBuilder(str);
+ foreach(var suff in suffixes)
+ {
+ if(ignoreSeparatorOnce)
+ {
+ sb.Append(suff);
+ ignoreSeparatorOnce = false;
+ continue;
+ }
+ sb.Append(suffixSeparator + suff);
+ }
+ return sb.ToString();
+ }
+
+ /// <summary>
+ /// Draws a GUI ilne
+ /// </summary>
+ /// <param name="spaceBefore"></param>
+ /// <param name="spaceAfter"></param>
+ internal static void DrawLine(bool spaceBefore = true, bool spaceAfter = true)
+ {
+ float spaceHeight = 3f;
+ if(spaceBefore)
+ GUILayout.Space(spaceHeight);
+
+ Rect rect = EditorGUILayout.GetControlRect(false, 1);
+ rect.height = 1;
+ EditorGUI.DrawRect(rect, new Color(0.5f, 0.5f, 0.5f, 1));
+
+ if(spaceAfter)
+ GUILayout.Space(spaceHeight);
+ }
+
+ /// <summary>
+ /// Destroys an object with DestroyImmediate in object mode and Destroy in play mode
+ /// </summary>
+ /// <param name="obj"></param>
+ internal static void DestroyAppropriate(UnityEngine.Object obj)
+ {
+ if(EditorApplication.isPlaying)
+ UnityEngine.Object.Destroy(obj);
+ else
+ UnityEngine.Object.DestroyImmediate(obj);
+ }
+
+ /// <summary>
+ /// Changes path from full windows path to a local path in the Assets folder
+ /// </summary>
+ /// <param name="path"></param>
+ /// <returns>Path starting with Assets</returns>
+ internal static string AbsolutePathToLocalAssetsPath(string path)
+ {
+ if(path.StartsWith(Application.dataPath))
+ path = "Assets" + path.Substring(Application.dataPath.Length);
+ return path;
+ }
+
+ /// <summary>
+ /// Selects and highlights the asset in your unity Project tab
+ /// </summary>
+ /// <param name="path"></param>
+ internal static void PingAssetAtPath(string path)
+ {
+ var inst = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(path).GetInstanceID();
+ EditorGUIUtility.PingObject(inst);
+ }
+
+ internal static void DrawWithLabelWidth(float width, Action action)
+ {
+ if(action == null)
+ return;
+ float old = EditorGUIUtility.labelWidth;
+ action.Invoke();
+ EditorGUIUtility.labelWidth = old;
+ }
+ }
+
+ internal static class PoiExtensions
+ {
+ public static Shader PackerShader => Shader.Find("Hidden/Poi/TexturePacker");
+
+ public static Shader UnpackerShader => Shader.Find("Hidden/Poi/TextureUnpacker");
+
+ /// <summary>
+ /// Extension method that bakes a material to <paramref name="tex"/>
+ /// </summary>
+ /// <param name="tex">Texture to bake <paramref name="materialToBake"/> to</param>
+ /// <param name="materialToBake">Material to bake to <paramref name="tex"/></param>
+ internal static void BakeMaterialToTexture(this Texture2D tex, Material materialToBake)
+ {
+ var res = new Vector2Int(tex.width, tex.height);
+
+ RenderTexture renderTexture = RenderTexture.GetTemporary(res.x, res.y);
+ Graphics.Blit(null, renderTexture, materialToBake);
+
+ //transfer image from rendertexture to texture
+ RenderTexture.active = renderTexture;
+ tex.ReadPixels(new Rect(Vector2.zero, res), 0, 0);
+ tex.Apply(false, false);
+
+ //clean up variables
+ RenderTexture.active = null;
+ RenderTexture.ReleaseTemporary(renderTexture);
+ }
+
+ /// <summary>
+ /// Rounds vector to closest power of two. Optionally, if above ceiling, square root down by one power of two
+ /// </summary>
+ /// <param name="vec"></param>
+ /// <param name="ceiling">Power of two ceiling. Will be rounded to power of two if not power of two already</param>
+ /// <returns></returns>
+ internal static Vector2Int ClosestPowerOfTwo(this Vector2Int vec, int? ceiling = null)
+ {
+ int x = Mathf.ClosestPowerOfTwo(vec.x);
+ int y = Mathf.ClosestPowerOfTwo(vec.y);
+
+ if(ceiling != null)
+ {
+ int ceil = Mathf.ClosestPowerOfTwo((int) ceiling);
+
+ x = Mathf.Clamp(x, x, ceil);
+ y = Mathf.Clamp(y, y, ceil);
+ }
+
+ return new Vector2Int(x, y);
+ }
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs.meta
new file mode 100644
index 00000000..5326296d
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/PoiHelpers.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 32406f186e960c04ab7448ec0b4ca0e0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs
new file mode 100644
index 00000000..6d487a41
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs
@@ -0,0 +1,1244 @@
+using System.Collections.Generic;
+using UnityEditor;
+using UnityEngine;
+using System.Linq;
+
+//Made by Dreadrith#3238
+//Server: https://discord.gg/ZsPfrGn
+//Github: https://github.com/Dreadrith/DreadScripts
+//Gumroad: https://gumroad.com/dreadrith
+
+namespace Poi.TextureUtility
+{
+ public class TextureUtility : EditorWindow
+ {
+ private readonly string[] DimensionPresets = new string[]
+ {
+ "128x128",
+ "256x256",
+ "512x512",
+ "1024x1024",
+ "2048x2048",
+ "4096x4096",
+ };
+
+ private static GUIContent resetIcon;
+ private static Texture2D titleTexture;
+
+ private static Texture2D mainTexture;
+ private static Texture2D maskTexture;
+
+ private static int jpgQuality = 75;
+ private static int texWidth, texHeight;
+ private static bool copyImport = true;
+ private static bool pingTexture = true;
+
+ private static bool rotating;
+ private static TexRotation rotationType;
+
+ private static bool inverting;
+ private static bool maskInvert=true;
+ private static bool invertRedS = true, invertGreenS = true, invertBlueS = true, invertAlphaS;
+
+ private static bool unpacking=true,packing;
+ private static bool editingTab=true, packingTab,creatingTab;
+
+
+ private static ChannelTexture redChannel = new ChannelTexture("Red", 0);
+ private static ChannelTexture greenChannel = new ChannelTexture("Green", 1);
+ private static ChannelTexture blueChannel = new ChannelTexture("Blue", 2);
+ private static ChannelTexture alphaChannel = new ChannelTexture("Alpha", 0);
+ private static ChannelTexture[] channelTextures = new ChannelTexture[] {redChannel,greenChannel,blueChannel,alphaChannel };
+
+ private static bool hueShifting;
+ private static bool maskHueShift=true;
+ private static float hueShiftFloat;
+
+ private static bool saturating;
+ private static bool maskSaturate=true;
+ private static float saturationFloat;
+
+ private static bool colorizing;
+ private static bool maskColorize=true;
+ private static bool textureColorize;
+ private static bool alphaColorize;
+ private static float colorizeFloat=0.5f;
+ private static Color colorizeColor = Color.black;
+ private static Texture2D colorizeTexture;
+
+ private static Color originalGUIColor;
+
+ private static TexEncoding encoding = TexEncoding.SaveAsPNG;
+ public enum TexEncoding
+ {
+ SaveAsPNG,
+ SaveAsJPG,
+ SaveAsTGA
+ }
+
+ public enum TexRotation
+ {
+ Clockwise90,
+ CClockwise90,
+ Rotate180,
+ FlipHorizontal,
+ FlipVertical
+ }
+
+ #region Creating Tab Variables
+ private static bool creatingCustomSize;
+ private static bool creatingReverse;
+ private static string creatingPath;
+ private static Color solidColor=Color.black;
+ private static Gradient gradientColor = new Gradient() { colorKeys = new GradientColorKey[] { new GradientColorKey(Color.white, 0), new GradientColorKey(Color.black, 1) } };
+
+ private static TextureCreatingMode creatingMode = TextureCreatingMode.SolidColor;
+
+ private enum TextureCreatingMode
+ {
+ SolidColor,
+ HorizontalGradient,
+ VerticalGradient
+ }
+ #endregion
+
+ [MenuItem("Poi/Texture Utility")]
+ private static void showWindow()
+ {
+ EditorWindow w = GetWindow<TextureUtility>(false, "Texture Utility", true);
+ if (!titleTexture)
+ {
+ titleTexture = GetColors((Texture2D)EditorGUIUtility.IconContent("Texture2D Icon").image, 16, 16, out _);
+ titleTexture.Apply();
+ }
+
+ w.titleContent.image = titleTexture;
+ w.minSize = new Vector2(423, 253);
+ }
+
+ private void OnGUI()
+ {
+ originalGUIColor = GUI.backgroundColor;
+ using (new GUILayout.HorizontalScope())
+ {
+ bool c = editingTab;
+
+ SetColorIcon(editingTab);
+ editingTab = GUILayout.Toggle(editingTab, "Editing", "toolbarbutton");
+ if (!c && editingTab)
+ {
+ packingTab = false;
+ creatingTab = false;
+ }
+
+ c = creatingTab;
+
+
+ SetColorIcon(creatingTab);
+ creatingTab = GUILayout.Toggle(creatingTab, "Creating", "toolbarbutton");
+ if (!c && creatingTab)
+ {
+ packingTab = false;
+ editingTab = false;
+ }
+
+ c = packingTab;
+
+ SetColorIcon(packingTab);
+ packingTab = GUILayout.Toggle(packingTab, "Packing", "toolbarbutton");
+ if (!c && packingTab)
+ {
+ editingTab = false;
+ creatingTab = false;
+ }
+ GUI.backgroundColor = originalGUIColor;
+ }
+
+ if (editingTab)
+ {
+ DrawEditingTab();
+ }
+
+ if (creatingTab)
+ {
+ DrawCreatingTab();
+ }
+
+ if (packingTab)
+ {
+ DrawPackingTab();
+ }
+ Credit();
+ }
+
+
+ private void DrawEditingTab()
+ {
+ using (new GUILayout.HorizontalScope())
+ {
+ using (new GUILayout.VerticalScope())
+ {
+ using (new GUILayout.HorizontalScope("box"))
+ DrawDimensionsGUI();
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding, GUILayout.Width(95));
+
+ EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG);
+ EditorGUIUtility.labelWidth = 50;
+ jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100);
+ EditorGUIUtility.labelWidth = 0;
+ EditorGUI.EndDisabledGroup();
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ copyImport = EditorGUILayout.Toggle("Copy Import Settings", copyImport);
+ pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture);
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ if (!rotating)
+ {
+ SetColorIcon(rotating);
+ rotating = GUILayout.Toggle(rotating, "Rotate", "toolbarbutton");
+ GUI.backgroundColor = originalGUIColor;
+ }
+ else
+ {
+ SetColorIcon(rotating);
+ rotating = GUILayout.Toggle(rotating, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
+ GUI.backgroundColor = originalGUIColor;
+
+ EditorGUI.BeginDisabledGroup(true);
+ GUILayout.Toggle(true, "M", EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
+ EditorGUI.EndDisabledGroup();
+
+ GUILayout.Label("Rotate");
+ rotationType = (TexRotation)EditorGUILayout.EnumPopup(GUIContent.none, rotationType);
+ }
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ if (!inverting)
+ {
+ SetColorIcon(inverting);
+ inverting = GUILayout.Toggle(inverting, "Invert", "toolbarbutton");
+ GUI.backgroundColor = originalGUIColor;
+ }
+ else
+ {
+ SetColorIcon(inverting);
+ inverting = GUILayout.Toggle(inverting, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
+ GUI.backgroundColor = originalGUIColor;
+
+ maskInvert = GUILayout.Toggle(maskInvert, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16)); GUILayout.Label("Invert");
+ invertRedS = EditorGUILayout.ToggleLeft("R", invertRedS, GUILayout.Width(30));
+ invertGreenS = EditorGUILayout.ToggleLeft("G", invertGreenS, GUILayout.Width(30));
+ invertBlueS = EditorGUILayout.ToggleLeft("B", invertBlueS, GUILayout.Width(30));
+ invertAlphaS = EditorGUILayout.ToggleLeft("A", invertAlphaS, GUILayout.Width(30));
+
+ }
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ if (!saturating)
+ {
+ SetColorIcon(saturating);
+ saturating = GUILayout.Toggle(saturating, "Saturate", "toolbarbutton");
+ GUI.backgroundColor = originalGUIColor;
+ }
+ else
+ {
+ SetColorIcon(saturating);
+ saturating = GUILayout.Toggle(saturating, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
+ GUI.backgroundColor = originalGUIColor;
+ maskSaturate = GUILayout.Toggle(maskSaturate, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
+ EditorGUIUtility.labelWidth = 65;
+ saturationFloat = EditorGUILayout.Slider("Saturate", saturationFloat, -1, 1);
+ EditorGUIUtility.labelWidth = 0;
+ }
+ }
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ if (!hueShifting)
+ {
+ SetColorIcon(hueShifting);
+ hueShifting = GUILayout.Toggle(hueShifting, "Hue Shift", "toolbarbutton");
+ GUI.backgroundColor = originalGUIColor;
+ }
+ else
+ {
+ SetColorIcon(hueShifting);
+ hueShifting = GUILayout.Toggle(hueShifting, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
+ GUI.backgroundColor = originalGUIColor;
+
+ maskHueShift = GUILayout.Toggle(maskHueShift, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
+ EditorGUIUtility.labelWidth = 65;
+ hueShiftFloat = EditorGUILayout.Slider("Hue Shift", hueShiftFloat, 0, 1);
+ EditorGUIUtility.labelWidth = 0;
+ }
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ if (!colorizing)
+ {
+ SetColorIcon(colorizing);
+ colorizing = GUILayout.Toggle(colorizing, "Colorize", "toolbarbutton");
+ GUI.backgroundColor = originalGUIColor;
+ }
+ else
+ {
+ SetColorIcon(colorizing);
+ colorizing = GUILayout.Toggle(colorizing, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
+ GUI.backgroundColor = originalGUIColor;
+
+ maskColorize = GUILayout.Toggle(maskColorize, new GUIContent("M", "Use Mask"), EditorStyles.miniButton, GUILayout.Width(21), GUILayout.Height(16));
+ EditorGUIUtility.labelWidth = 65;
+ colorizeFloat = EditorGUILayout.Slider("Colorize", colorizeFloat, 0, 1);
+ EditorGUIUtility.labelWidth = 0;
+ if (!textureColorize)
+ colorizeColor = EditorGUILayout.ColorField(new GUIContent(""), colorizeColor, true, alphaColorize, false, GUILayout.Width(70), GUILayout.Height(17));
+ else
+ colorizeTexture = (Texture2D)EditorGUILayout.ObjectField(colorizeTexture, typeof(Texture2D), false, GUILayout.Width(70), GUILayout.Height(17));
+ textureColorize = GUILayout.Toggle(textureColorize, new GUIContent("T", "Use Texture"), EditorStyles.miniButton, GUILayout.Width(19), GUILayout.Height(16));
+ alphaColorize = GUILayout.Toggle(alphaColorize, new GUIContent("A", "Use Alpha"), EditorStyles.miniButton, GUILayout.Width(19), GUILayout.Height(16));
+ }
+ }
+
+ }
+ using (new GUILayout.VerticalScope())
+ {
+ using (new GUILayout.VerticalScope("box"))
+ {
+ EditorGUIUtility.labelWidth = 1;
+ GUILayout.Label("Main", GUILayout.Width(65));
+ EditorGUI.BeginChangeCheck();
+ mainTexture = (Texture2D)EditorGUILayout.ObjectField("", mainTexture, typeof(Texture2D), false, GUILayout.Width(65));
+ if (EditorGUI.EndChangeCheck())
+ ResetDimensions();
+ EditorGUIUtility.labelWidth = 0;
+ }
+ EditorGUI.BeginDisabledGroup(!(hueShifting || saturating || inverting || colorizing));
+ using (new GUILayout.VerticalScope("box"))
+ {
+ EditorGUIUtility.labelWidth = 1;
+ GUILayout.Label("Mask", GUILayout.Width(65));
+ maskTexture = (Texture2D)EditorGUILayout.ObjectField("", maskTexture, typeof(Texture2D), false, GUILayout.Width(65));
+ EditorGUIUtility.labelWidth = 0;
+ }
+ EditorGUI.EndDisabledGroup();
+ }
+ }
+ EditorGUI.BeginDisabledGroup(!mainTexture);
+ if (GUILayout.Button("Apply"))
+ {
+ ApplyTexture();
+ }
+ EditorGUI.EndDisabledGroup();
+ }
+
+ private void DrawCreatingTab()
+ {
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ if (!creatingCustomSize)
+ {
+ SetColorIcon(creatingCustomSize);
+ creatingCustomSize = GUILayout.Toggle(inverting, "Custom Dimensions", "toolbarbutton");
+ GUI.backgroundColor = originalGUIColor;
+ }
+ else
+ {
+ SetColorIcon(creatingCustomSize);
+ creatingCustomSize = GUILayout.Toggle(creatingCustomSize, "", "toolbarbutton", GUILayout.Width(17), GUILayout.Height(17));
+ GUI.backgroundColor = originalGUIColor;
+
+ DrawDimensionsGUI(false);
+ }
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding);
+
+ EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG);
+ EditorGUIUtility.labelWidth = 50;
+ jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100);
+ EditorGUIUtility.labelWidth = 0;
+ EditorGUI.EndDisabledGroup();
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture);
+
+ EditorGUI.BeginDisabledGroup(creatingMode != TextureCreatingMode.HorizontalGradient && creatingMode != TextureCreatingMode.VerticalGradient);
+ creatingReverse = EditorGUILayout.Toggle("Reverse Texture", creatingReverse);
+ EditorGUI.EndDisabledGroup();
+ }
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ creatingMode = (TextureCreatingMode)EditorGUILayout.EnumPopup("Texture Mode", creatingMode);
+ }
+
+ switch ((int)creatingMode)
+ {
+ case 0:
+ solidColor = EditorGUILayout.ColorField(solidColor);
+ break;
+ case 1:
+ case 2:
+ gradientColor = EditorGUILayout.GradientField(gradientColor);
+ break;
+ }
+ if (GUILayout.Button("Create"))
+ {
+ CreateTexture();
+ }
+ AssetFolderPath(ref creatingPath, "Save To", "TextureUtilityCreatingPath");
+ }
+
+ private void DrawPackingTab()
+ {
+
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ encoding = (TexEncoding)EditorGUILayout.EnumPopup(encoding);
+ EditorGUI.BeginDisabledGroup(encoding != TexEncoding.SaveAsJPG);
+ EditorGUIUtility.labelWidth = 50;
+ jpgQuality = EditorGUILayout.IntSlider("Quality", jpgQuality, 1, 100);
+ EditorGUIUtility.labelWidth = 0;
+ EditorGUI.EndDisabledGroup();
+ }
+ using (new GUILayout.HorizontalScope("box"))
+ {
+ copyImport = EditorGUILayout.Toggle("Copy Import Settings", copyImport);
+ pingTexture = EditorGUILayout.Toggle(new GUIContent("Highlight Texture", "Highlight the newly created texture in Assets"), pingTexture);
+ }
+ using (new GUILayout.HorizontalScope())
+ {
+ bool p = unpacking;
+ SetColorIcon(unpacking);
+ unpacking = GUILayout.Toggle(unpacking, "Unpack", "toolbarbutton");
+ if (!p && unpacking)
+ packing = false;
+
+ p = packing;
+ SetColorIcon(packing);
+ packing = GUILayout.Toggle(packing, "Pack", "toolbarbutton");
+ if (!p && packing)
+ unpacking = false;
+
+ GUI.backgroundColor = originalGUIColor;
+ }
+ if (packing)
+ {
+ using (new GUILayout.HorizontalScope())
+ {
+ EditorGUIUtility.labelWidth = 1;
+ redChannel.DrawGUI();
+ greenChannel.DrawGUI();
+ blueChannel.DrawGUI();
+ alphaChannel.DrawGUI();
+ EditorGUIUtility.labelWidth = 0;
+ }
+ EditorGUI.BeginDisabledGroup(!channelTextures.Any(c => c.texture));
+ if (GUILayout.Button("Pack"))
+ {
+ PackTexture(channelTextures);
+ }
+ }
+ if (unpacking)
+ {
+
+ using (new GUILayout.VerticalScope("box"))
+ {
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ GUILayout.Label("Main Texture");
+ GUILayout.FlexibleSpace();
+ }
+
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ EditorGUIUtility.labelWidth = 1;
+ mainTexture = (Texture2D)EditorGUILayout.ObjectField("", mainTexture, typeof(Texture2D), false, GUILayout.Width(66));
+ EditorGUIUtility.labelWidth = 0;
+ GUILayout.FlexibleSpace();
+ }
+ }
+ EditorGUI.BeginDisabledGroup(!mainTexture);
+ if (GUILayout.Button("Unpack"))
+ {
+ UnpackTexture();
+ }
+ EditorGUI.EndDisabledGroup();
+ }
+
+
+ EditorGUI.EndDisabledGroup();
+ }
+
+ private void DrawDimensionsGUI(bool drawReset=true)
+ {
+ GUIStyle iconStyle = new GUIStyle(GUI.skin.label) { padding = new RectOffset(), margin = new RectOffset(), imagePosition = ImagePosition.ImageOnly };
+
+ EditorGUI.BeginDisabledGroup(!mainTexture && !creatingTab);
+ if (drawReset)
+ {
+ if (GUILayout.Button(resetIcon, iconStyle, GUILayout.Height(16), GUILayout.Width(16)))
+ ResetDimensions();
+ }
+ EditorGUIUtility.labelWidth = 20;
+ texWidth = EditorGUILayout.IntField(new GUIContent("W","Width"), texWidth);
+ texHeight = EditorGUILayout.IntField(new GUIContent("H", "Height"), texHeight);
+ EditorGUIUtility.labelWidth = 0;
+
+ int dummy = -1;
+ EditorGUI.BeginChangeCheck();
+ dummy = EditorGUILayout.Popup(dummy, DimensionPresets,GUILayout.Width(17));
+ if (EditorGUI.EndChangeCheck())
+ {
+ string[] dimensions = ((string)DimensionPresets.GetValue(dummy)).Split('x');
+ texWidth = int.Parse(dimensions[0]);
+ texHeight = int.Parse(dimensions[1]);
+ }
+
+ EditorGUI.EndDisabledGroup();
+
+ }
+
+ public static Texture2D GetColors(Texture2D texture, out Color[] Colors, bool unloadTempTexture = false)
+ {
+ return GetColors(texture, texture.width, texture.height, out Colors, unloadTempTexture);
+ }
+
+ public static Texture2D GetColors(Texture2D texture, int width, int height, out Color[] Colors,bool unloadTempTexture = false)
+ {
+ //Thanks to
+ //https://gamedev.stackexchange.com/questions/92285/unity3d-resize-texture-without-corruption
+ texture.filterMode = FilterMode.Point;
+ RenderTexture rt = RenderTexture.GetTemporary(width, height);
+
+ rt.filterMode = FilterMode.Point;
+ RenderTexture.active = rt;
+ Graphics.Blit(texture, rt);
+ Texture2D newTexture = new Texture2D(width, height);
+ newTexture.ReadPixels(new Rect(0, 0, width, height), 0, 0);
+ Color[] myColors = newTexture.GetPixels();
+ RenderTexture.active = null;
+ /////////////////////
+ Colors = myColors;
+ if (unloadTempTexture)
+ {
+ DestroyImmediate(newTexture);
+ return null;
+ }
+ return newTexture;
+ }
+
+ private static void SaveTexture(byte[] textureEncoding, string path, bool refresh=false, bool ping=false)
+ {
+ System.IO.FileStream stream = System.IO.File.Create(path);
+ stream.Write(textureEncoding, 0, textureEncoding.Length);
+ stream.Dispose();
+ if (refresh)
+ {
+ AssetDatabase.Refresh();
+ if (ping)
+ {
+ Ping(path);
+ }
+ }
+
+ }
+ private static void Ping(string path)
+ {
+ EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath<Object>(path));
+ }
+
+ private void ApplyTexture()
+ {
+ if (colorizing && !colorizeTexture && textureColorize)
+ {
+ Debug.LogError("Cannot Colorize using a texture without a texture!");
+ return;
+ }
+
+ string destinationPath = GetDestinationFolder(mainTexture);
+ string texPath = AssetDatabase.GetAssetPath(mainTexture);
+
+ Texture2D newTexture = GetColors(mainTexture, texWidth, texHeight, out Color[] myColors);
+
+ if (rotating)
+ {
+ List<Color> rotatedColors = new List<Color>();
+ switch (rotationType)
+ {
+ case TexRotation.Clockwise90:
+ for (int i = texWidth-1; i >=0; i--)
+ {
+ rotatedColors.AddRange(newTexture.GetPixels(i, 0, 1, texHeight));
+ }
+ myColors = rotatedColors.ToArray();
+ newTexture = new Texture2D(texHeight, texWidth);
+ break;
+
+ case TexRotation.CClockwise90:
+ for (int i = 0; i < texWidth; i++)
+ {
+ rotatedColors.AddRange(ReverseArray(newTexture.GetPixels(i, 0, 1, texHeight)));
+ }
+ myColors = rotatedColors.ToArray();
+ newTexture = new Texture2D(texHeight, texWidth);
+ break;
+
+ case TexRotation.Rotate180:
+ myColors = ReverseArray(myColors);
+ break;
+
+ case TexRotation.FlipHorizontal:
+ for (int i = 0; i < texHeight; i++)
+ {
+ rotatedColors.AddRange(ReverseArray(newTexture.GetPixels(0, i, texWidth, 1)));
+ }
+ myColors = rotatedColors.ToArray();
+ break;
+
+ case TexRotation.FlipVertical:
+ for (int i = texHeight - 1; i >= 0; i--)
+ {
+ rotatedColors.AddRange(newTexture.GetPixels(0, i, texWidth, 1));
+ }
+ myColors = rotatedColors.ToArray();
+ break;
+ }
+
+ }
+
+ bool colorInverting = (invertRedS || invertGreenS || invertBlueS || invertAlphaS) && inverting;
+ bool HSVEditing = hueShifting || saturating;
+ bool colorEditing = HSVEditing || colorizing;
+ bool editing = colorEditing || colorInverting || unpacking;
+ bool masking = ((maskColorize && colorizing) || (maskInvert && colorInverting) || (maskSaturate && saturating) || (maskHueShift && hueShifting)) && maskTexture;
+
+ Color[] maskColors;
+ if (masking)
+ {
+ GetColors(maskTexture, texWidth, texHeight, out maskColors, true);
+ }
+ else
+ maskColors = null;
+
+ Color[] colorizeTextureColors;
+ if (colorizing && textureColorize)
+ {
+ GetColors(colorizeTexture, texWidth, texHeight, out colorizeTextureColors, true);
+ }
+ else
+ colorizeTextureColors = null;
+
+
+ Color[] newColors = new Color[myColors.Length];
+ if (editing)
+ {
+ for (int i = 0; i < myColors.Length; i++)
+ {
+ Color currentColor = myColors[i];
+
+ if (colorEditing)
+ {
+ if (HSVEditing)
+ {
+ Color.RGBToHSV(currentColor, out float h, out float s, out float v);
+ currentColor = Color.HSVToRGB(hueShifting ? (Mathf.Repeat(h + (hueShiftFloat * (maskTexture && maskHueShift ? maskColors[i].r : 1)), 1)) : h, saturating ? (Mathf.Clamp01(s + (saturationFloat * (maskTexture && maskSaturate ? maskColors[i].r : 1)))) : s, v);
+ currentColor.a = myColors[i].a;
+ }
+ if (colorizing)
+ {
+ float oga = currentColor.a;
+ currentColor = Color.Lerp(currentColor, textureColorize ? colorizeTextureColors[i] : colorizeColor, colorizeFloat * (maskColorize && maskTexture ? maskColors[i].r : 1));
+
+ if (!alphaColorize)
+ currentColor.a = oga;
+ }
+ }
+
+ float r = colorInverting && invertRedS ? currentColor.r - ((currentColor.r - (1 - currentColor.r)) * (maskInvert && maskTexture ? maskColors[i].r : 1)) : currentColor.r;
+ float g = colorInverting && invertGreenS ? currentColor.g - ((currentColor.g - (1 - currentColor.g)) * (maskInvert && maskTexture ? maskColors[i].g : 1)) : currentColor.g;
+ float b = colorInverting && invertBlueS ? currentColor.b - ((currentColor.b - (1 - currentColor.b)) * (maskInvert && maskTexture ? maskColors[i].b : 1)) : currentColor.b;
+ float a = colorInverting && invertAlphaS ? currentColor.a - ((currentColor.a - (1 - currentColor.a)) * (maskInvert && maskTexture ? maskColors[i].a : 1)) : currentColor.a;
+
+ newColors[i] = new Color(r, g, b, a);
+ }
+ }
+ newTexture.SetPixels(editing ? newColors : myColors);
+ newTexture.Apply();
+
+ GetEncoding(newTexture, encoding, out byte[] data, out string ext);
+
+ string newTexturePath = AssetDatabase.GenerateUniqueAssetPath(destinationPath + "/" + mainTexture.name
+ + (colorInverting ? " Inverted" : "") + ext);
+
+ SaveTexture(data, newTexturePath, true, pingTexture);
+
+ if (copyImport)
+ {
+ CopyTextureSettings(texPath, newTexturePath);
+ }
+ }
+
+ private static void GetEncoding(Texture2D texture, TexEncoding encodingType, out byte[] data, out string ext)
+ {
+ switch ((int)encodingType)
+ {
+ default:
+ ext = ".png";
+ data = texture.EncodeToPNG();
+ break;
+ case 1:
+ ext = ".jpg";
+ data = texture.EncodeToJPG(jpgQuality);
+ break;
+ case 2:
+ ext = ".tga";
+ data = texture.EncodeToTGA();
+ break;
+ }
+ }
+
+
+ private void CreateTexture()
+ {
+ Texture2D newTexture = null;
+ int w = creatingCustomSize ? texWidth : 0;
+ int h = creatingCustomSize ? texHeight : 0;
+
+ Color[] myColors = null;
+ switch ((int)creatingMode)
+ {
+ case 0:
+ if (!creatingCustomSize)
+ {
+ w = h = 4;
+ }
+ newTexture = new Texture2D(w, h);
+
+ myColors = CreateFilledArray(solidColor, w * h);
+ newTexture.SetPixels(0, 0, w, h, myColors);
+ break;
+ case 1:
+ {
+ if (!creatingCustomSize)
+ {
+ w = 256;
+ h = 4;
+ }
+ newTexture = new Texture2D(w, h);
+
+ int i = creatingReverse ? w - 1 : 0;
+ int istep = creatingReverse ? -1 : 1;
+
+ float xstepValue = (1f / w);
+ float xcurrentStep = 0;
+ for (; i < w && i >= 0; i += istep)
+ {
+ newTexture.SetPixels(i, 0, 1, h, CreateFilledArray(gradientColor.Evaluate(xcurrentStep), h));
+ xcurrentStep += xstepValue;
+ }
+ }
+ break;
+ case 2:
+ {
+ if (!creatingCustomSize)
+ {
+ w = 4;
+ h = 256;
+ }
+ newTexture = new Texture2D(w, h);
+
+ int i = creatingReverse ? h - 1 : 0;
+ int istep = creatingReverse ? -1 : 1;
+
+ float ystepValue = 1f / h;
+ float ycurrentStep = 0;
+ for (; i < h && i >= 0; i += istep)
+ {
+ newTexture.SetPixels(0, i, w, 1, CreateFilledArray(gradientColor.Evaluate(ycurrentStep), w));
+ ycurrentStep += ystepValue;
+ }
+ }
+ break;
+ }
+
+ GetEncoding(newTexture, encoding, out byte[] data, out string ext);
+
+ RecreateFolders(creatingPath);
+ SaveTexture(data, AssetDatabase.GenerateUniqueAssetPath(creatingPath +"/Generated Texture"+ext), true, pingTexture);
+ }
+
+ private void UnpackTexture()
+ {
+ string destinationPath = GetDestinationFolder(mainTexture);
+ string texPath = AssetDatabase.GetAssetPath(mainTexture);
+ int x = mainTexture.width, y = mainTexture.height;
+ Texture2D newTexture = GetColors(mainTexture, x, y, out Color[] myColors);
+ List<System.Tuple<string, string>> copyFromTo = new List<System.Tuple<string, string>>();
+
+ bool isRedPass = true, isGreenPass, isBluePass, isAlphaPass;
+ isGreenPass = isBluePass = isAlphaPass = false;
+ try
+ {
+ AssetDatabase.StartAssetEditing();
+
+ do
+ {
+ Color[] newColors = new Color[myColors.Length];
+
+ bool hasAlpha = false;
+ for (int i = 0; i < myColors.Length; i++)
+ {
+ Color currentColor = myColors[i];
+
+ float r = currentColor.r;
+ float g = currentColor.g;
+ float b = currentColor.b;
+ float a = currentColor.a;
+
+ if (isRedPass)
+ {
+ g = b = r;
+ a = 1;
+ }
+ if (isGreenPass)
+ {
+ r = b = g;
+ a = 1;
+ }
+ if (isBluePass)
+ {
+ r = g = b;
+ a = 1;
+ }
+ if (isAlphaPass)
+ {
+ r = g = b = a;
+ if (a != 1)
+ hasAlpha = true;
+ }
+
+ newColors[i] = new Color(r, g, b, a);
+ }
+
+ if (isAlphaPass && !hasAlpha)
+ {
+ isAlphaPass = false;
+ goto Skip;
+ }
+
+ newTexture.SetPixels(newColors);
+ newTexture.Apply();
+
+ GetEncoding(newTexture, encoding, out byte[] data, out string ext);
+
+ string newTexturePath = AssetDatabase.GenerateUniqueAssetPath(destinationPath + "/" + mainTexture.name
+ + (isRedPass ? "-Red" : isGreenPass ? "-Green" : isBluePass ? "-Blue" : "-Alpha") + ext);
+
+ SaveTexture(data, newTexturePath);
+
+ if (copyImport)
+ {
+ copyFromTo.Add(new System.Tuple<string, string>(texPath, newTexturePath));
+ }
+
+ if (isAlphaPass)
+ isAlphaPass = false;
+ if (isBluePass)
+ {
+ isBluePass = false;
+ isAlphaPass = true;
+ }
+ if (isGreenPass)
+ {
+ isGreenPass = false;
+ isBluePass = true;
+ }
+ if (isRedPass)
+ {
+ isRedPass = false;
+ isGreenPass = true;
+ }
+
+ if (unpacking)
+ newTexture = new Texture2D(x, y);
+
+ Skip:;
+
+ } while (isRedPass || isGreenPass || isBluePass || isAlphaPass);
+ }
+ finally
+ {
+ AssetDatabase.StopAssetEditing();
+ }
+ AssetDatabase.Refresh();
+ if (copyImport)
+ {
+ for (int i = 0; i < copyFromTo.Count; i++)
+ {
+ CopyTextureSettings(copyFromTo[i].Item1, copyFromTo[i].Item2);
+ }
+ }
+ }
+
+ public void PackTexture(ChannelTexture[] channels)
+ {
+ int firstIndex = 0;
+ for (int i = 3; i >= 0; i--)
+ {
+ if (channels[i].texture)
+ firstIndex = i;
+ }
+ ChannelTexture firstChannel = channels[firstIndex];
+ int w = firstChannel.texture.width;
+ int h = firstChannel.texture.height;
+ PackTexture(channels, AssetDatabase.GetAssetPath(firstChannel.texture), w, h, encoding);
+ }
+
+ public static string PackTexture(ChannelTexture[] channels, TexEncoding encodingType, bool refresh=true, bool copyImportSettings=true)
+ {
+ int firstIndex = -1;
+ for (int i = 3; i >= 0; i--)
+ {
+ if (channels[i].texture)
+ firstIndex = i;
+ }
+ if (firstIndex < 0)
+ return string.Empty;
+ ChannelTexture firstChannel = channels[firstIndex];
+ int w = firstChannel.texture.width;
+ int h = firstChannel.texture.height;
+ return PackTexture(channels, AssetDatabase.GetAssetPath(firstChannel.texture), w, h, encodingType,refresh,false,copyImportSettings);
+ }
+
+ public static string PackTexture(ChannelTexture[] channels, string destination,int width, int height, TexEncoding encodingType, bool refresh=true,bool overwrite=false, bool copyImportSettings=true)
+ {
+ int firstIndex = -1;
+ for (int i = 3; i >= 0; i--)
+ {
+ if (channels[i].texture)
+ firstIndex = i;
+ }
+ if (firstIndex < 0)
+ return string.Empty;
+
+ ChannelTexture firstChannel = channels[firstIndex];
+
+
+ Texture2D newTexture = new Texture2D(width, height);
+ channels[0].GetChannelColors(width, height, out float[] reds, true);
+ channels[1].GetChannelColors(width, height, out float[] greens, true);
+ channels[2].GetChannelColors(width, height, out float[] blues, true);
+ channels[3].GetChannelColors(width, height, out float[] alphas, true);
+ Color[] finalColors = new Color[width*height];
+
+ for (int i=0;i< finalColors.Length;i++)
+ {
+ finalColors[i].r = (reds!=null) ? reds[i] : 0;
+ finalColors[i].g = (greens != null) ? greens[i] : 0;
+ finalColors[i].b = (blues != null) ? blues[i] : 0;
+ finalColors[i].a = (alphas != null) ? alphas[i] : 1;
+ }
+ newTexture.SetPixels(finalColors);
+ newTexture.Apply();
+
+ GetEncoding(newTexture, encodingType, out byte[] data, out string ext);
+
+ string newTexturePath = GetDestinationFolder(destination)+"/"+System.IO.Path.GetFileNameWithoutExtension(destination)+ext;
+ if (!overwrite)
+ newTexturePath = AssetDatabase.GenerateUniqueAssetPath(newTexturePath);
+ SaveTexture(data, newTexturePath);
+ DestroyImmediate(newTexture);
+ if (refresh)
+ AssetDatabase.Refresh();
+
+
+ if (copyImportSettings)
+ {
+ CopyTextureSettings(AssetDatabase.GetAssetPath(firstChannel.texture), newTexturePath);
+ }
+ return newTexturePath;
+ }
+
+ private static void CopyTextureSettings(string from, string to)
+ {
+ TextureImporter source = (TextureImporter)AssetImporter.GetAtPath(from);
+ TextureImporterSettings sourceSettings = new TextureImporterSettings();
+ source.ReadTextureSettings(sourceSettings);
+
+ TextureImporter destination = (TextureImporter)AssetImporter.GetAtPath(to);
+ destination.SetTextureSettings(sourceSettings);
+ destination.maxTextureSize = source.maxTextureSize;
+ destination.textureCompression = source.textureCompression;
+ destination.crunchedCompression = source.crunchedCompression;
+ destination.SaveAndReimport();
+ }
+
+ private static string GetDestinationFolder(Object o)
+ {
+ string path = AssetDatabase.GetAssetPath(o);
+ return GetDestinationFolder(path);
+ }
+ private static string GetDestinationFolder(string path)
+ {
+ return path.Substring(0, path.LastIndexOf('/'));
+ }
+
+ private void ResetDimensions()
+ {
+ if (mainTexture)
+ {
+ texHeight = mainTexture.height;
+ texWidth = mainTexture.width;
+ }
+ }
+
+ private void SetColorIcon(bool value)
+ {
+ if (value)
+ GUI.backgroundColor = Color.green;
+ else
+ GUI.backgroundColor = Color.grey;
+ }
+
+ private void OnEnable()
+ {
+ resetIcon = new GUIContent(EditorGUIUtility.IconContent("d_Refresh")) { tooltip = "Reset Dimensions" };
+ creatingPath = PlayerPrefs.GetString("TextureUtilityCreatingPath", "Assets/DreadScripts/Texture Utility/Generated Assets");
+
+ for (int i=0;i<channelTextures.Length;i++)
+ {
+ channelTextures[i].SetMode(EditorPrefs.GetInt("TextureUtilityChannel" + channelTextures[i].name, (int)channelTextures[i].mode));
+ }
+ }
+
+ private static T[] CreateFilledArray<T>(T variable,int length)
+ {
+ T[] myArray = new T[length];
+ for (int i=0;i< myArray.Length;i++)
+ {
+ myArray[i] = variable;
+ }
+ return myArray;
+ }
+
+ private static T[] ReverseArray<T>(T[] array)
+ {
+ T[] reversed = new T[array.Length];
+ int index = array.Length - 1;
+ for (int i = 0; i < reversed.Length; i++)
+ {
+ reversed[i] = array[index];
+ index--;
+ }
+ return reversed;
+ }
+
+ #region Extracted From DS_CommonMethods
+ public static void AssetFolderPath(ref string variable, string title, string playerpref)
+ {
+ EditorGUILayout.BeginHorizontal();
+ EditorGUI.BeginDisabledGroup(true);
+ EditorGUILayout.TextField(title, variable);
+ EditorGUI.EndDisabledGroup();
+ if (GUILayout.Button("...", GUILayout.Width(30)))
+ {
+ string dummyPath = EditorUtility.OpenFolderPanel(title, variable, "");
+ if (string.IsNullOrEmpty(dummyPath))
+ return;
+
+ if (!dummyPath.Contains("Assets"))
+ {
+ Debug.LogWarning("New Path must be a folder within Assets!");
+ return;
+ }
+ variable = FileUtil.GetProjectRelativePath(dummyPath);
+ PlayerPrefs.SetString(playerpref, variable);
+ }
+ EditorGUILayout.EndHorizontal();
+ }
+
+ public static void RecreateFolders(string fullPath)
+ {
+ string[] folderNames = fullPath.Split('/');
+ string[] folderPaths = new string[folderNames.Length];
+ for (int i = 0; i < folderNames.Length; i++)
+ {
+ folderPaths[i] = folderNames[0];
+ for (int j = 1; j <= i; j++)
+ {
+ folderPaths[i] = folderPaths[i] + "/" + folderNames[j];
+ }
+ }
+ for (int i = 0; i < folderPaths.Length; i++)
+ {
+ if (!AssetDatabase.IsValidFolder(folderPaths[i]))
+ {
+ AssetDatabase.CreateFolder(folderPaths[i].Substring(0, folderPaths[i].LastIndexOf('/')), folderPaths[i].Substring(folderPaths[i].LastIndexOf('/') + 1, folderPaths[i].Length - folderPaths[i].LastIndexOf('/') - 1));
+ }
+
+ }
+ }
+ #endregion
+
+ private static void Credit()
+ {
+ GUIStyle creditLabelStyle = new GUIStyle(GUI.skin.label) { richText = true };
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ if (GUILayout.Button("<b>Made by Dreadrith#3238</b>",creditLabelStyle))
+ {
+ Application.OpenURL("https://github.com/Dreadrith/DreadScripts");
+ }
+
+ }
+ }
+ }
+
+ [System.Serializable]
+ public class ChannelTexture
+ {
+ public string name;
+ public Texture2D texture;
+ public bool invert;
+ public ColorMode mode = ColorMode.Red;
+ public enum ColorMode
+ {
+ Red,
+ Green,
+ Blue,
+ Alpha
+ }
+ public ChannelTexture(string n, int mode)
+ {
+ name = n;
+ SetMode(mode, true);
+ }
+
+ public void SetMode(int i, bool ignoreSave = false)
+ {
+ switch (i)
+ {
+ case 0:
+ mode = ColorMode.Red;
+ break;
+ case 1:
+ mode = ColorMode.Green;
+ break;
+ case 2:
+ mode = ColorMode.Blue;
+ break;
+ case 3:
+ mode = ColorMode.Alpha;
+ break;
+ }
+ if (!ignoreSave)
+ {
+ EditorPrefs.SetInt("TextureUtilityChannel" + name, i);
+ }
+ }
+
+ public Texture2D GetChannelColors(int width, int height, out float[] colors, bool unloadTempTexture)
+ {
+ if (!texture)
+ {
+ colors = null;
+ return null;
+ }
+ else
+ {
+ Texture2D newTexture = TextureUtility.GetColors(texture, width, height, out Color[] myColors, unloadTempTexture);
+ colors = myColors.Select(c =>
+ {
+ if (mode == ColorMode.Red)
+ return c.r;
+ if (mode == ColorMode.Green)
+ return c.g;
+ if (mode == ColorMode.Blue)
+ return c.b;
+
+ return c.a;
+ }).ToArray();
+ if (invert)
+ {
+ for (int i = 0; i < colors.Length; i++)
+ {
+ colors[i] = 1 - colors[i];
+ }
+ }
+ return newTexture;
+ }
+ }
+
+ public void DrawGUI()
+ {
+ GUIStyle buttonGroupStyle = new GUIStyle(GUI.skin.GetStyle("toolbarbutton")) { padding = new RectOffset(1, 1, 1, 1), margin = new RectOffset(0, 0, 1, 1) };
+ using (new GUILayout.VerticalScope("box"))
+ {
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ GUILayout.Label(name, "boldlabel");
+ GUILayout.FlexibleSpace();
+ }
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ bool dummy;
+ EditorGUI.BeginChangeCheck();
+ dummy = GUILayout.Toggle(mode == ColorMode.Red, "R", buttonGroupStyle, GUILayout.Width(16));
+ if (EditorGUI.EndChangeCheck())
+ if (dummy)
+ SetMode(0);
+
+ EditorGUI.BeginChangeCheck();
+ dummy = GUILayout.Toggle(mode == ColorMode.Green, "G", buttonGroupStyle, GUILayout.Width(16));
+ if (EditorGUI.EndChangeCheck())
+ if (dummy)
+ SetMode(1);
+
+ EditorGUI.BeginChangeCheck();
+ dummy = GUILayout.Toggle(mode == ColorMode.Blue, "B", buttonGroupStyle, GUILayout.Width(16));
+ if (EditorGUI.EndChangeCheck())
+ if (dummy)
+ SetMode(2);
+
+ EditorGUI.BeginChangeCheck();
+ dummy = GUILayout.Toggle(mode == ColorMode.Alpha, "A", buttonGroupStyle, GUILayout.Width(16));
+ if (EditorGUI.EndChangeCheck())
+ if (dummy)
+ SetMode(3);
+ GUILayout.FlexibleSpace();
+ }
+ using (new GUILayout.HorizontalScope())
+ {
+ GUILayout.FlexibleSpace();
+ texture = (Texture2D)EditorGUILayout.ObjectField("", texture, typeof(Texture2D), false, GUILayout.Width(66));
+ GUILayout.FlexibleSpace();
+ }
+ invert = GUILayout.Toggle(invert, "Invert", "toolbarbutton");
+ }
+ }
+
+
+ }
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs.meta
new file mode 100644
index 00000000..8752585e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Editor/TextureUtility.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cb8d94d5a72732e4b8b754b8138f95d8
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources.meta
new file mode 100644
index 00000000..604e4ea7
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 362826441ef464c458314d76942a2c67
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi.meta
new file mode 100644
index 00000000..903cc2d6
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 2526eb19e2b785f43934a75ebbdfb35e
+folderAsset: yes
+DefaultImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss
new file mode 100644
index 00000000..a1df90f1
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss
@@ -0,0 +1,26 @@
+.error
+{
+ background-image: resource("CollabError");
+ margin-top: 2px;
+ margin-left: 6px;
+ height: 12px;
+ width: 12px;
+}
+
+.buttons-area
+{
+ flex-direction: row;
+ margin-bottom: 10px;
+}
+
+.folder-selector
+{
+ flex-direction: row;
+ margin-top: 10px;
+ margin-left: 4px;
+}
+
+ModularShadersGeneratorElement
+{
+ margin-left: 4px;
+} \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss.meta
new file mode 100644
index 00000000..36d9b656
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/ModularShadersGeneratorStyle.uss.meta
@@ -0,0 +1,3 @@
+fileFormatVersion: 2
+guid: a77a12c151c44847b8de5c6c7be71d8e
+timeCreated: 1638406657 \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader
new file mode 100644
index 00000000..2f366a9e
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader
@@ -0,0 +1,169 @@
+// Made with Amplify Shader Editor
+// Available at the Unity Asset Store - http://u3d.as/y3X
+Shader "Hidden/Poi/TexturePacker"
+{
+ Properties
+ {
+ _Invert_Red("Invert_Red", Float) = 0
+ _Invert_Green("Invert_Green", Float) = 0
+ _Invert_Blue("Invert_Blue", Float) = 0
+ _Invert_Alpha("Invert_Alpha", Float) = 0
+ _Red("Red", 2D) = "white" {}
+ _Green("Green", 2D) = "white" {}
+ _Blue("Blue", 2D) = "white" {}
+ _Alpha("Alpha", 2D) = "white" {}
+ [HideInInspector] _texcoord( "", 2D ) = "white" {}
+ }
+
+ SubShader
+ {
+ Tags { "RenderType"="Opaque" }
+ LOD 100
+ CGINCLUDE
+ #pragma target 3.0
+ ENDCG
+ Blend Off
+ Cull Back
+ ColorMask RGBA
+ ZWrite On
+ ZTest LEqual
+ Offset 0 , 0
+
+
+
+ Pass
+ {
+ Name "Unlit"
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #pragma multi_compile_instancing
+ #include "UnityCG.cginc"
+
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ UNITY_VERTEX_INPUT_INSTANCE_ID
+ float4 ase_texcoord : TEXCOORD0;
+ };
+
+ struct v2f
+ {
+ float4 vertex : SV_POSITION;
+ float4 ase_texcoord : TEXCOORD0;
+ UNITY_VERTEX_OUTPUT_STEREO
+ UNITY_VERTEX_INPUT_INSTANCE_ID
+ };
+
+ uniform sampler2D _Red;
+ uniform float4 _Red_ST;
+ uniform float _Invert_Red;
+ uniform sampler2D _Green;
+ uniform float4 _Green_ST;
+ uniform float _Invert_Green;
+ uniform sampler2D _Blue;
+ uniform float4 _Blue_ST;
+ uniform float _Invert_Blue;
+ uniform sampler2D _Alpha;
+ uniform float4 _Alpha_ST;
+ uniform float _Invert_Alpha;
+
+ v2f vert ( appdata v )
+ {
+ v2f o;
+ UNITY_SETUP_INSTANCE_ID(v);
+ UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
+ UNITY_TRANSFER_INSTANCE_ID(v, o);
+
+ o.ase_texcoord.xy = v.ase_texcoord.xy;
+
+ //setting value to unused interpolator channels and avoid initialization warnings
+ o.ase_texcoord.zw = 0;
+
+ v.vertex.xyz += float3(0,0,0) ;
+ o.vertex = UnityObjectToClipPos(v.vertex);
+ return o;
+ }
+
+ fixed4 frag (v2f i ) : SV_Target
+ {
+ UNITY_SETUP_INSTANCE_ID(i);
+ fixed4 finalColor;
+ float2 uv_Red = i.ase_texcoord.xy * _Red_ST.xy + _Red_ST.zw;
+ float4 tex2DNode28 = tex2D( _Red, uv_Red );
+ float4 temp_cast_0 = (_Invert_Red).xxxx;
+ float4 lerpResult27 = lerp( tex2DNode28 , ( temp_cast_0 - tex2DNode28 ) , _Invert_Red);
+ float2 uv_Green = i.ase_texcoord.xy * _Green_ST.xy + _Green_ST.zw;
+ float4 tex2DNode12 = tex2D( _Green, uv_Green );
+ float4 temp_cast_2 = (_Invert_Green).xxxx;
+ float4 lerpResult20 = lerp( tex2DNode12 , ( temp_cast_2 - tex2DNode12 ) , _Invert_Green);
+ float2 uv_Blue = i.ase_texcoord.xy * _Blue_ST.xy + _Blue_ST.zw;
+ float4 tex2DNode14 = tex2D( _Blue, uv_Blue );
+ float4 temp_cast_4 = (_Invert_Blue).xxxx;
+ float4 lerpResult21 = lerp( tex2DNode14 , ( temp_cast_4 - tex2DNode14 ) , _Invert_Blue);
+ float2 uv_Alpha = i.ase_texcoord.xy * _Alpha_ST.xy + _Alpha_ST.zw;
+ float4 tex2DNode13 = tex2D( _Alpha, uv_Alpha );
+ float4 temp_cast_6 = (_Invert_Alpha).xxxx;
+ float4 lerpResult19 = lerp( tex2DNode13 , ( temp_cast_6 - tex2DNode13 ) , _Invert_Alpha);
+ float4 appendResult30 = (float4(lerpResult27.r , lerpResult20.r , lerpResult21.r , lerpResult19.r));
+
+
+ finalColor = appendResult30;
+ return finalColor;
+ }
+ ENDCG
+ }
+ }
+ CustomEditor "ASEMaterialInspector"
+
+
+}
+/*ASEBEGIN
+Version=15902
+0;0;1368;850;1368.399;595.2781;1;True;False
+Node;AmplifyShaderEditor.SamplerNode;14;-1193.289,314.7757;Float;True;Property;_Blue;Blue;6;0;Create;True;0;0;False;0;None;None;True;0;False;white;Auto;False;Object;-1;Auto;Texture2D;6;0;SAMPLER2D;;False;1;FLOAT2;0,0;False;2;FLOAT;0;False;3;FLOAT2;0,0;False;4;FLOAT2;0,0;False;5;FLOAT;1;False;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
+Node;AmplifyShaderEditor.RangedFloatNode;25;-815.7044,759.9294;Float;False;Property;_Invert_Alpha;Invert_Alpha;3;0;Create;True;0;0;False;0;0;0;0;0;0;1;FLOAT;0
+Node;AmplifyShaderEditor.RangedFloatNode;15;-819.5868,472.4816;Float;False;Property;_Invert_Blue;Invert_Blue;2;0;Create;True;0;0;False;0;0;0;0;0;0;1;FLOAT;0
+Node;AmplifyShaderEditor.RangedFloatNode;31;-803.4256,177.2413;Float;False;Property;_Invert_Green;Invert_Green;1;0;Create;True;0;0;False;0;0;0;0;0;0;1;FLOAT;0
+Node;AmplifyShaderEditor.RangedFloatNode;29;-795.8423,-109.6157;Float;False;Property;_Invert_Red;Invert_Red;0;0;Create;True;0;0;False;0;0;0;0;0;0;1;FLOAT;0
+Node;AmplifyShaderEditor.SamplerNode;28;-1189.017,-285.634;Float;True;Property;_Red;Red;4;0;Create;True;0;0;False;0;None;None;True;0;False;white;Auto;False;Object;-1;Auto;Texture2D;6;0;SAMPLER2D;;False;1;FLOAT2;0,0;False;2;FLOAT;0;False;3;FLOAT2;0,0;False;4;FLOAT2;0,0;False;5;FLOAT;1;False;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
+Node;AmplifyShaderEditor.SamplerNode;12;-1199.358,5.317238;Float;True;Property;_Green;Green;5;0;Create;True;0;0;False;0;None;None;True;0;False;white;Auto;False;Object;-1;Auto;Texture2D;6;0;SAMPLER2D;;False;1;FLOAT2;0,0;False;2;FLOAT;0;False;3;FLOAT2;0,0;False;4;FLOAT2;0,0;False;5;FLOAT;1;False;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
+Node;AmplifyShaderEditor.SamplerNode;13;-1182.523,665.4475;Float;True;Property;_Alpha;Alpha;7;0;Create;True;0;0;False;0;None;None;True;0;False;white;Auto;False;Object;-1;Auto;Texture2D;6;0;SAMPLER2D;;False;1;FLOAT2;0,0;False;2;FLOAT;0;False;3;FLOAT2;0,0;False;4;FLOAT2;0,0;False;5;FLOAT;1;False;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
+Node;AmplifyShaderEditor.SimpleSubtractOpNode;16;-610.2974,-218.5994;Float;False;2;0;FLOAT;0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.SimpleSubtractOpNode;26;-570.7031,710.9296;Float;False;2;0;FLOAT;0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.SimpleSubtractOpNode;17;-612.9231,67.14128;Float;False;2;0;FLOAT;0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.SimpleSubtractOpNode;18;-589.0041,392.5837;Float;False;2;0;FLOAT;0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.LerpOp;19;-279.5903,619.9736;Float;False;3;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;2;FLOAT;0;False;1;COLOR;0
+Node;AmplifyShaderEditor.LerpOp;27;-318.2486,-275.2707;Float;False;3;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;2;FLOAT;0;False;1;COLOR;0
+Node;AmplifyShaderEditor.LerpOp;20;-299.71,16.80488;Float;False;3;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;2;FLOAT;0;False;1;COLOR;0
+Node;AmplifyShaderEditor.LerpOp;21;-296.069,300.6409;Float;False;3;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;2;FLOAT;0;False;1;COLOR;0
+Node;AmplifyShaderEditor.DynamicAppendNode;30;98.28339,102.1202;Float;False;FLOAT4;4;0;FLOAT;0;False;1;FLOAT;0;False;2;FLOAT;0;False;3;FLOAT;0;False;1;FLOAT4;0
+Node;AmplifyShaderEditor.TemplateMultiPassMasterNode;0;369.802,98.57185;Float;False;True;2;Float;ASEMaterialInspector;0;1;Hidden/Poi/TexturePacker;0770190933193b94aaa3065e307002fa;0;0;Unlit;2;True;0;1;False;-1;0;False;-1;0;1;False;-1;0;False;-1;True;0;False;-1;0;False;-1;True;0;False;-1;True;True;True;True;True;0;False;-1;True;False;255;False;-1;255;False;-1;255;False;-1;7;False;-1;1;False;-1;1;False;-1;1;False;-1;7;False;-1;1;False;-1;1;False;-1;1;False;-1;True;1;False;-1;True;3;False;-1;True;True;0;False;-1;0;False;-1;True;1;RenderType=Opaque=RenderType;True;2;0;False;False;False;False;False;False;False;False;False;False;0;;0;0;Standard;0;2;0;FLOAT4;0,0,0,0;False;1;FLOAT3;0,0,0;False;0
+WireConnection;16;0;29;0
+WireConnection;16;1;28;0
+WireConnection;26;0;25;0
+WireConnection;26;1;13;0
+WireConnection;17;0;31;0
+WireConnection;17;1;12;0
+WireConnection;18;0;15;0
+WireConnection;18;1;14;0
+WireConnection;19;0;13;0
+WireConnection;19;1;26;0
+WireConnection;19;2;25;0
+WireConnection;27;0;28;0
+WireConnection;27;1;16;0
+WireConnection;27;2;29;0
+WireConnection;20;0;12;0
+WireConnection;20;1;17;0
+WireConnection;20;2;31;0
+WireConnection;21;0;14;0
+WireConnection;21;1;18;0
+WireConnection;21;2;15;0
+WireConnection;30;0;27;0
+WireConnection;30;1;20;0
+WireConnection;30;2;21;0
+WireConnection;30;3;19;0
+WireConnection;0;0;30;0
+ASEEND*/
+//CHKSM=2C30DB01285F07958B9316BD81CB0A64AD7E3B0E \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader.meta
new file mode 100644
index 00000000..1658d888
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTexturePacker.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 71129bd3774e04d48827a25fc98d45a7
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader
new file mode 100644
index 00000000..736465be
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader
@@ -0,0 +1,156 @@
+// Made with Amplify Shader Editor
+// Available at the Unity Asset Store - http://u3d.as/y3X
+Shader "Hidden/Poi/TextureUnpacker"
+{
+ Properties
+ {
+ _MainTex("MainTex", 2D) = "white" {}
+ _Mode("Mode", Range( 0 , 3)) = 3
+ _Invert("Invert", Float) = 0
+ [HideInInspector] _texcoord( "", 2D ) = "white" {}
+ }
+
+ SubShader
+ {
+ Tags { "RenderType"="Opaque" }
+ LOD 100
+ CGINCLUDE
+ #pragma target 3.0
+ ENDCG
+ Blend Off
+ Cull Back
+ ColorMask RGBA
+ ZWrite On
+ ZTest LEqual
+ Offset 0 , 0
+
+
+
+ Pass
+ {
+ Name "Unlit"
+ CGPROGRAM
+ #pragma vertex vert
+ #pragma fragment frag
+ #pragma multi_compile_instancing
+ #include "UnityCG.cginc"
+
+
+ struct appdata
+ {
+ float4 vertex : POSITION;
+ UNITY_VERTEX_INPUT_INSTANCE_ID
+ float4 ase_texcoord : TEXCOORD0;
+ };
+
+ struct v2f
+ {
+ float4 vertex : SV_POSITION;
+ float4 ase_texcoord : TEXCOORD0;
+ UNITY_VERTEX_OUTPUT_STEREO
+ UNITY_VERTEX_INPUT_INSTANCE_ID
+ };
+
+ uniform float _Mode;
+ uniform sampler2D _MainTex;
+ uniform float4 _MainTex_ST;
+ uniform float _Invert;
+
+ v2f vert ( appdata v )
+ {
+ v2f o;
+ UNITY_SETUP_INSTANCE_ID(v);
+ UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(o);
+ UNITY_TRANSFER_INSTANCE_ID(v, o);
+
+ o.ase_texcoord.xy = v.ase_texcoord.xy;
+
+ //setting value to unused interpolator channels and avoid initialization warnings
+ o.ase_texcoord.zw = 0;
+
+ v.vertex.xyz += float3(0,0,0) ;
+ o.vertex = UnityObjectToClipPos(v.vertex);
+ return o;
+ }
+
+ fixed4 frag (v2f i ) : SV_Target
+ {
+ UNITY_SETUP_INSTANCE_ID(i);
+ fixed4 finalColor;
+ float2 uv_MainTex = i.ase_texcoord.xy * _MainTex_ST.xy + _MainTex_ST.zw;
+ float4 tex2DNode32 = tex2D( _MainTex, uv_MainTex );
+ float ifLocalVar34 = 0;
+ if( _Mode == 0.0 )
+ ifLocalVar34 = tex2DNode32.r;
+ float ifLocalVar35 = 0;
+ if( _Mode == 1.0 )
+ ifLocalVar35 = tex2DNode32.g;
+ float ifLocalVar36 = 0;
+ if( _Mode == 2.0 )
+ ifLocalVar36 = tex2DNode32.b;
+ float ifLocalVar37 = 0;
+ if( _Mode == 3.0 )
+ ifLocalVar37 = tex2DNode32.a;
+ float4 ifLocalVar42 = 0;
+ if( _Mode < 0.0 )
+ ifLocalVar42 = tex2DNode32;
+ float4 ifLocalVar43 = 0;
+ if( _Mode > 3.0 )
+ ifLocalVar43 = tex2DNode32;
+ float4 temp_output_40_0 = ( ifLocalVar34 + ifLocalVar35 + ifLocalVar36 + ifLocalVar37 + ifLocalVar42 + ifLocalVar43 );
+ float4 temp_cast_0 = (_Invert).xxxx;
+ float4 lerpResult46 = lerp( temp_output_40_0 , ( temp_cast_0 - temp_output_40_0 ) , _Invert);
+
+
+ finalColor = lerpResult46;
+ return finalColor;
+ }
+ ENDCG
+ }
+ }
+ CustomEditor "ASEMaterialInspector"
+
+
+}
+/*ASEBEGIN
+Version=15902
+0;0;1368;850;930.0129;673.0209;1.753676;True;False
+Node;AmplifyShaderEditor.SamplerNode;32;-446.011,1.547681;Float;True;Property;_MainTex;MainTex;0;0;Create;True;0;0;False;0;None;None;True;0;False;white;Auto;False;Object;-1;Auto;Texture2D;6;0;SAMPLER2D;;False;1;FLOAT2;0,0;False;2;FLOAT;0;False;3;FLOAT2;0,0;False;4;FLOAT2;0,0;False;5;FLOAT;1;False;5;COLOR;0;FLOAT;1;FLOAT;2;FLOAT;3;FLOAT;4
+Node;AmplifyShaderEditor.RangedFloatNode;33;-414.2798,-86.22936;Float;False;Property;_Mode;Mode;1;0;Create;True;0;0;False;0;3;0;0;3;0;1;FLOAT;0
+Node;AmplifyShaderEditor.ConditionalIfNode;35;17.04439,123.3313;Float;False;False;5;0;FLOAT;0;False;1;FLOAT;1;False;2;FLOAT;0;False;3;FLOAT;0;False;4;FLOAT;0;False;1;FLOAT;0
+Node;AmplifyShaderEditor.ConditionalIfNode;36;17.16646,287.5046;Float;False;False;5;0;FLOAT;0;False;1;FLOAT;2;False;2;FLOAT;0;False;3;FLOAT;0;False;4;FLOAT;0;False;1;FLOAT;0
+Node;AmplifyShaderEditor.ConditionalIfNode;37;15.75801,456.534;Float;False;False;5;0;FLOAT;0;False;1;FLOAT;3;False;2;FLOAT;0;False;3;FLOAT;0;False;4;FLOAT;0;False;1;FLOAT;0
+Node;AmplifyShaderEditor.ConditionalIfNode;34;17.15299,-44.90865;Float;False;False;5;0;FLOAT;0;False;1;FLOAT;0;False;2;FLOAT;0;False;3;FLOAT;0;False;4;FLOAT;0;False;1;FLOAT;0
+Node;AmplifyShaderEditor.ConditionalIfNode;42;19.07808,-276.4948;Float;False;False;5;0;FLOAT;0;False;1;FLOAT;0;False;2;FLOAT;0;False;3;FLOAT;0;False;4;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.ConditionalIfNode;43;19.07608,697.2275;Float;False;False;5;0;FLOAT;0;False;1;FLOAT;3;False;2;COLOR;0,0,0,0;False;3;FLOAT;0;False;4;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.SimpleAddOpNode;40;370.6085,1.924235;Float;True;6;6;0;FLOAT;0;False;1;FLOAT;0;False;2;FLOAT;0;False;3;FLOAT;0;False;4;COLOR;0,0,0,0;False;5;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.RangedFloatNode;44;440.5474,232.555;Float;False;Property;_Invert;Invert;2;0;Create;True;0;0;False;0;0;0;0;0;0;1;FLOAT;0
+Node;AmplifyShaderEditor.SimpleSubtractOpNode;45;609.8499,63.25506;Float;False;2;0;FLOAT;0;False;1;COLOR;0,0,0,0;False;1;COLOR;0
+Node;AmplifyShaderEditor.LerpOp;46;780.463,-0.6814048;Float;False;3;0;COLOR;0,0,0,0;False;1;COLOR;0,0,0,0;False;2;FLOAT;0;False;1;COLOR;0
+Node;AmplifyShaderEditor.TemplateMultiPassMasterNode;0;975.2405,-1.718735;Float;False;True;2;Float;ASEMaterialInspector;0;1;Hidden/Poi/TextureUnpacker;0770190933193b94aaa3065e307002fa;0;0;Unlit;2;True;0;1;False;-1;0;False;-1;0;1;False;-1;0;False;-1;True;0;False;-1;0;False;-1;True;0;False;-1;True;True;True;True;True;0;False;-1;True;False;255;False;-1;255;False;-1;255;False;-1;7;False;-1;1;False;-1;1;False;-1;1;False;-1;7;False;-1;1;False;-1;1;False;-1;1;False;-1;True;1;False;-1;True;3;False;-1;True;True;0;False;-1;0;False;-1;True;1;RenderType=Opaque=RenderType;True;2;0;False;False;False;False;False;False;False;False;False;False;0;;0;0;Standard;0;2;0;FLOAT4;0,0,0,0;False;1;FLOAT3;0,0,0;False;0
+WireConnection;35;0;33;0
+WireConnection;35;3;32;2
+WireConnection;36;0;33;0
+WireConnection;36;3;32;3
+WireConnection;37;0;33;0
+WireConnection;37;3;32;4
+WireConnection;34;0;33;0
+WireConnection;34;3;32;1
+WireConnection;42;0;33;0
+WireConnection;42;4;32;0
+WireConnection;43;0;33;0
+WireConnection;43;2;32;0
+WireConnection;40;0;34;0
+WireConnection;40;1;35;0
+WireConnection;40;2;36;0
+WireConnection;40;3;37;0
+WireConnection;40;4;42;0
+WireConnection;40;5;43;0
+WireConnection;45;0;44;0
+WireConnection;45;1;40;0
+WireConnection;46;0;40;0
+WireConnection;46;1;45;0
+WireConnection;46;2;44;0
+WireConnection;0;0;46;0
+ASEEND*/
+//CHKSM=FB476DC839C9D986CDFBE64BF68940FC3E2666AE \ No newline at end of file
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader.meta
new file mode 100644
index 00000000..d7c2c86d
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/PoiTextureUnpacker.shader.meta
@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 245e67c21ccaa9a43ad7e84d1c7bb5fc
+ShaderImporter:
+ externalObjects: {}
+ defaultTextures: []
+ nonModifiableTextures: []
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.png
new file mode 100755
index 00000000..f2221935
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.png.meta
new file mode 100644
index 00000000..2534f427
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link.png.meta
@@ -0,0 +1,99 @@
+fileFormatVersion: 2
+guid: bf576c4a5c9c7d6408d714bfc0779a3f
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: 1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.png b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.png
new file mode 100755
index 00000000..c6454537
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.png
Binary files differ
diff --git a/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.png.meta b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.png.meta
new file mode 100644
index 00000000..1c244949
--- /dev/null
+++ b/VRCSDK3Avatars/Assets/_PoiyomiShaders/Scripts/poi-tools/Resources/Poi/icon_link_pro.png.meta
@@ -0,0 +1,99 @@
+fileFormatVersion: 2
+guid: e5afc9f6ee88c964cbc59accc832fbbe
+TextureImporter:
+ fileIDToRecycleName: {}
+ externalObjects: {}
+ serializedVersion: 9
+ mipmaps:
+ mipMapMode: 0
+ enableMipMap: 0
+ sRGBTexture: 1
+ linearTexture: 0
+ fadeOut: 0
+ borderMipMap: 0
+ mipMapsPreserveCoverage: 0
+ alphaTestReferenceValue: 0.5
+ mipMapFadeDistanceStart: 1
+ mipMapFadeDistanceEnd: 3
+ bumpmap:
+ convertToNormalMap: 0
+ externalNormalMap: 0
+ heightScale: 0.25
+ normalMapFilter: 0
+ isReadable: 0
+ streamingMipmaps: 0
+ streamingMipmapsPriority: 0
+ grayScaleToAlpha: 0
+ generateCubemap: 6
+ cubemapConvolution: 0
+ seamlessCubemap: 0
+ textureFormat: 1
+ maxTextureSize: 2048
+ textureSettings:
+ serializedVersion: 2
+ filterMode: -1
+ aniso: 1
+ mipBias: -100
+ wrapU: 1
+ wrapV: 1
+ wrapW: -1
+ nPOTScale: 1
+ lightmap: 0
+ compressionQuality: 50
+ spriteMode: 0
+ spriteExtrude: 1
+ spriteMeshType: 1
+ alignment: 0
+ spritePivot: {x: 0.5, y: 0.5}
+ spritePixelsToUnits: 100
+ spriteBorder: {x: 0, y: 0, z: 0, w: 0}
+ spriteGenerateFallbackPhysicsShape: 1
+ alphaUsage: 1
+ alphaIsTransparency: 1
+ spriteTessellationDetail: -1
+ textureType: 2
+ textureShape: 1
+ singleChannelComponent: 0
+ maxTextureSizeSet: 0
+ compressionQualitySet: 0
+ textureFormatSet: 0
+ platformSettings:
+ - serializedVersion: 2
+ buildTarget: DefaultTexturePlatform
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ - serializedVersion: 2
+ buildTarget: Standalone
+ maxTextureSize: 2048
+ resizeAlgorithm: 0
+ textureFormat: -1
+ textureCompression: 1
+ compressionQuality: 50
+ crunchedCompression: 0
+ allowsAlphaSplitting: 0
+ overridden: 0
+ androidETC2FallbackOverride: 0
+ spriteSheet:
+ serializedVersion: 2
+ sprites: []
+ outline: []
+ physicsShape: []
+ bones: []
+ spriteID:
+ vertices: []
+ indices:
+ edges: []
+ weights: []
+ spritePackingTag:
+ pSDRemoveMatte: 0
+ pSDShowRemoveMatteOption: 0
+ userData:
+ assetBundleName:
+ assetBundleVariant: