Files
Continentis/Assets/OtherPlugins/Sprite Shaders Ultimate/Scripts/Editor/SSUShaderGUI.cs
SoulliesOfficial ad4948207e 推进度!
2025-11-25 21:49:03 -05:00

2093 lines
90 KiB
C#

#if UNITY_EDITOR
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UI;
namespace SpriteShadersUltimate
{
public class SSUShaderGUI : ShaderGUI
{
//Toggles:
static bool showMasking = false;
static bool showNoise = false;
static bool showTime = false;
//GUI Resources:
GUIStyle labelStyle;
GUIStyle labelCenterStyle;
GUIStyle buttonStyle;
static Color warnColor = new Color(1, 0.7f, 0.65f, 0.7f);
static Color lightWarnColor = new Color(1f, 0.8f, 0.65f, 0.7f);
static Color hintColor = new Color(1, 1, 1, 0.7f);
Shader shader;
Material defaultMaterial;
GameObject gameObject;
Dictionary<string, ShaderHintSSU> allHints;
ShaderHintSSU currentHint;
//Internal:
HashSet<string> enabledShaders;
HashSet<string> toggleProperties;
HashSet<string> hidingProperties;
HashSet<string> enableProperties;
HashSet<string> alwaysHiddenProperties;
HashSet<string> linesAboveProperties;
List<string> shaderList;
Dictionary<string, int> shaderDictionary;
Shader lastShader;
bool newCategory; //Used to avoid drawing lines at the beginning of a new category.
bool isDisabled; //Skip shaders.
bool isHidden; //Used to skip hidden properties.
bool skipGUI; //Skip GUI refresh after changing the shader.
float shaderSpace; //Used to skip hidden properties.
string spaceName; //Used to skip hidden properties.
float shaderFading; //Used to skip hidden properties.
int currentBoxColor; //Shader Rainbow Color
int shaderAmount; //Counter
int enabledAmount; //Counter
int textureAmount; //Samples
float performanceBenchmark;
float lastTitleHeight; //For Category Lines
Sprite lastSSF; //Sprite for last SSF.
static int bakeStackAmount = 1;
//Status:
static Material[] materials;
bool wasWarned;
bool requiresFullRectMesh, requiresSpriteSheetFix, requiresInstancing, requiresTiling;
public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties)
{
Initialize(materialEditor, properties);
DrawStatus(materialEditor);
if(skipGUI)
{
skipGUI = false;
return;
}
//Properties:
enabledShaders = new HashSet<string>();
isDisabled = false;
isHidden = false;
EditorGUILayout.BeginVertical();
for (int n = 0; n < properties.Length; n++)
{
newCategory = false;
MaterialProperty prop = properties[n];
//Always Skipped:
if(alwaysHiddenProperties.Contains(prop.name))
{
continue;
}
//Space Skipped:
if (prop.name == "_PixelsPerUnit" && !(shaderSpace < 0.5f || (shaderSpace > 4.5f && shaderSpace < 5.5f))) continue;
if (prop.name == "_ScreenWidthUnits" && !(shaderSpace > 5.5f)) continue;
if ((prop.name == "_RectHeight" || prop.name == "_RectWidth") && !(shaderSpace > 4.5f && shaderSpace < 5.5f)) continue;
//Fading Skipped:
if (prop.name == "_FadingFade" && shaderFading < 0.5f) continue;
if (prop.name == "_FadingMask" && Mathf.RoundToInt(shaderFading) != 2) continue;
if ((prop.name == "_FadingPosition" || prop.name == "_FadingNoiseFactor") && Mathf.RoundToInt(shaderFading) != 4) continue;
if ((prop.name == "_FadingWidth" || prop.name == "_FadingNoiseScale") && Mathf.RoundToInt(shaderFading) != 4 && Mathf.RoundToInt(shaderFading) != 3) continue;
//Basic:
if (prop.name == "_MetallicMap" && materials[0].GetFloat("_MetallicMapToggle") < 0.5f) continue;
bool isKeyword = toggleProperties.Contains(prop.name);
//Enable:
if (enableProperties.Contains(prop.name))
{
isDisabled = DrawShaderToggle(materialEditor, prop);
isHidden = false;
continue; //Dont display shader toggle twice.
}
else
{
if (isDisabled)
{
continue; //Skip disabled properties.
}
}
string displayName = prop.displayName;
//Categories:
if (prop.name == "_MainTex")
{
DrawShaderCategory("Main");
displayName = "Sprite Texture";
}
else if (prop.name == "_ShaderSpace")
{
DrawShaderCategory("Space");
shaderSpace = prop.floatValue;
switch (Mathf.RoundToInt(shaderSpace))
{
case (0):
spaceName = "UV";
break;
case (1):
spaceName = "UV Raw";
break;
case (2):
spaceName = "Object";
requiresInstancing = true;
break;
case (3):
spaceName = "Scaled Object";
requiresInstancing = true;
break;
case (4):
spaceName = "World";
break;
case (5):
spaceName = "UI Rect";
break;
case (6):
spaceName = "Screen";
break;
}
}
else if (prop.name == "_ToggleUnscaledTime")
{
DrawShaderCategory("Time", ref showTime);
}
else if (prop.name == "_ShaderFading")
{
//Space Hints:
switch (Mathf.RoundToInt(shaderSpace))
{
case (0):
DisplayHint("- Uses the <b>UV</b> position with size adjustment.");
break;
case (1):
DisplayHint("- Uses the raw <b>UV</b> position.");
break;
case (2):
DisplayHint("- Uses the <b>local position</b> of the object.");
break;
case (3):
DisplayHint("- Uses the <b>local position</b> with scale adjustment.");
break;
case (4):
DisplayHint("- Uses the <b>world position</b> (good for scene effects).");
break;
case (5):
DisplayHint("- Use this for <b>UI images</b>.");
DisplayHint("- The <b>ImageSSU</b> component auto-updates <b>rect size</b>.");
//Add component:
if (gameObject != null && gameObject.GetComponent<RectTransform>() != null && gameObject.GetComponent<Image>() != null && gameObject.GetComponent<ImageSSU>() == null)
{
EditorGUILayout.Space();
GUI.color = new Color(0.8f, 1f, 0.8f);
if (GUILayout.Button("Add Helper Component"))
{
if (gameObject.GetComponent<InstancerSSU>() != null)
{
MonoBehaviour.DestroyImmediate(gameObject.GetComponent<InstancerSSU>());
}
gameObject.AddComponent<ImageSSU>();
}
GUI.color = Color.white;
}
break;
case (6):
DisplayHint("- Use this for non-moving <b>UI Images</b> or <b>fullscreen</b> effects..");
break;
}
DrawShaderCategory("Fading");
shaderFading = prop.floatValue;
}
else if (prop.name == "_UberNoiseTexture")
{
DrawShaderCategory("Noise", ref showNoise);
}
else if (prop.name == "_VertexTintFirst")
{
DrawShaderCategory("Settings");
}
else if (prop.name == "_IsText")
{
DrawShaderCategory("GUI Settings");
}
else if (prop.name == "_StencilComp")
{
DrawShaderCategory("UI Masking", ref showMasking);
}
if (isKeyword && !newCategory && prop.name != "PixelSnap" && prop.name != "_UseUIAlphaClip" && prop.name != "_MetallicMapToggle")
{
//Space:
if (prop.name == "_TogglePixelArt" && shaderSpace > 1.1f)
{
continue;
}
//GUI:
if (prop.name == "_IsTextMeshPro" && materials[0].GetFloat("_IsText") < 0.5f)
{
isHidden = true;
continue;
}
//Time:
if(showTime == false)
{
if(prop.name == "_ToggleCustomTime" || prop.name == "_ToggleTimeSpeed" || prop.name == "_ToggleTimeFPS" || prop.name == "_ToggleTimeFrequency")
{
continue;
}
}
//Lines:
Lines();
//Hiding:
if (hidingProperties.Contains(prop.name))
{
isHidden = prop.floatValue < 0.5f;
}
}
else if (isHidden)
{
if (prop.name == "_EnchantedLowColor" || prop.name == "_EnchantedHighColor" || prop.name == "_ShiftingColorA" || prop.name == "_ShiftingColorB")
{
//No Skipping
}
else
{
continue; //Skip hidden properties.
}
}
else
{
if (prop.name == "_EnchantedLowColor" || prop.name == "_EnchantedHighColor" || prop.name == "_ShiftingColorA" || prop.name == "_ShiftingColorB")
{
continue; //Skipping if not Hidden
}
}
//Lines Above:
if (linesAboveProperties.Contains(prop.name))
{
Lines();
}
//Name:
string[] splitName = displayName.Split(':');
if (splitName.Length > 1)
{
displayName = splitName[1];
if (displayName[0] == ' ')
{
displayName = displayName.Substring(1);
}
}
GUIContent displayContent = new GUIContent(displayName, isKeyword ? "" : prop.name + " (C#)");
//Display:
EditorGUILayout.BeginHorizontal();
if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Texture)
{
prop.textureValue = (Texture)EditorGUILayout.ObjectField(displayContent, prop.textureValue, typeof(Texture), false, GUILayout.Height(50));
}
else if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Vector)
{
if(prop.name == "_SpriteSheetRect")
{
prop.vectorValue = EditorGUI.Vector4Field(PropertyLabel(displayContent), GUIContent.none, prop.vectorValue);
}
else
{
prop.vectorValue = EditorGUI.Vector2Field(PropertyLabel(displayContent), GUIContent.none, prop.vectorValue);
}
}
else if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Range)
{
bool isSlider = true;
if (prop.name == "_FadingFade" && Mathf.RoundToInt(shaderFading) == 4)
{
isSlider = false;
}
if (isSlider)
{
prop.floatValue = EditorGUI.Slider(GetPropertySize(prop, isKeyword), displayContent, prop.floatValue, prop.rangeLimits.x, prop.rangeLimits.y);
}
else
{
prop.floatValue = EditorGUI.FloatField(GetPropertySize(prop, isKeyword), displayContent, prop.floatValue);
}
}
else if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Color)
{
EditorGUI.BeginChangeCheck();
EditorGUI.showMixedValue = prop.hasMixedValue;
bool showEyedropper = false;
bool showAlpha = false;
bool showContrast = false;
if (prop.name.StartsWith("_Recolor"))
{
showAlpha = true;
showContrast = true;
}
if (prop.name == "_ColorReplaceFromColor")
{
showEyedropper = true;
}
Color color = EditorGUILayout.ColorField(displayContent, prop.colorValue, showEyedropper, showAlpha, true);
if (showContrast)
{
Rect lastRect = GUILayoutUtility.GetLastRect();
lastRect.y -= 1;
GUI.color = new Color(1, 1, 1, 0.5f);
GUI.Label(lastRect, "<color=#00000000>" + displayContent.text + "</color> <b><size=9>| " + Mathf.RoundToInt(prop.colorValue.a * 200) + "% Contrast</size></b>", labelStyle);
GUI.color = Color.white;
}
EditorGUI.showMixedValue = false;
if (EditorGUI.EndChangeCheck())
{
prop.colorValue = color;
}
}
else
{
materialEditor.ShaderProperty(GetPropertySize(prop, isKeyword), prop, displayContent);
}
if (!isKeyword)
{
ResetButton(prop);
HelpButton(prop, displayContent);
}
EditorGUILayout.EndHorizontal();
//Hints:
if (prop.name == "_ToggleUnscaledTime" && prop.floatValue > 0.5f)
{
DisplayHint("- Requires <b>one</b> active <b>UnscaledTimeSSU</b> component in your scene.");
}
if (prop.name == "_TimeFPS")
{
DisplayHint("- Limits shader animations to <b>" + Mathf.RoundToInt(prop.floatValue) + "</b> frames per second.");
}
if (prop.name == "_TimeRange")
{
DisplayHint("- Time flows <b>back</b> and <b>forth</b>.");
}
if(prop.name == "_VertexTintFirst" && prop.floatValue > 0.5f)
{
DisplayHint("- Applies the vertex tint <b>before</b> the applying shaders.");
}
if (prop.name == "_TilingFix" && prop.floatValue > 0.5f)
{
DisplayHint("- Fixes issues with <b>tiling</b> shaders.");
DisplayHint("- This is only required on <b>sprite sheets</b>.");
}
if (prop.name == "_PixelPerfectSpace" && prop.floatValue > 0.5f)
{
DisplayHint("- Snaps the <b>shader space</b> to the sprite's pixels.");
DisplayHint("- Only works with <b>UV</b> shader space.");
DisplayHint("- Does not work well with <b>Smooth Pixel Art</b>, use one or the other.");
}
if (prop.name == "_PixelPerfectUV" && prop.floatValue > 0.5f)
{
DisplayHint("- Snaps the <b>UV manipulation</b> to the sprite's pixels.");
DisplayHint("- This works best with <b>Point No Filter</b> and <b>Pixel Snap</b>.");
DisplayHint("- Does not work well with <b>Smooth Pixel Art</b>, use one or the other.");
}
if (prop.name == "_BakedMaterial" && prop.floatValue > 0.5f)
{
DisplayHint("- Enabled while baking shaders to textures.");
DisplayHint("- You can <b>ignore</b> this.");
}
if (prop.name == "_ForceAlpha" && prop.floatValue > 0.5f)
{
DisplayHint("- Forces the alpha to always be <b>100%</b>.");
DisplayHint("- You can <b>ignore</b> this.");
}
if(prop.name == "_WindLocalWind" && prop.floatValue < 0.5f)
{
DisplayHint("- Uses and requires <b>WindManagerSSU</b> for <b>global</b> wind.");
}
if (prop.name == "_WindMaxIntensity")
{
DisplayHint("- Uses <b>local</b> wind settings.");
}
if (prop.name == "_WindHighQualityNoise" && prop.floatValue > 0.5f)
{
DisplayHint("- Generates less <b>repetitive</b> noise, but costs more performance.");
}
if (prop.name == "_SpriteSheetRect")
{
DisplayHint("- Requires the <b>SpriteSheetSSU</b> component.");
DisplayHint("- Fixes sprite sheet issues for shaders like the <b>Wind</b> shader.");
Sprite targetSprite = null;
EditorGUILayout.BeginHorizontal();
GUI.color = new Color(1, 1, 1, 0.7f);
EditorGUILayout.PrefixLabel("- Manual Rect Calculation");
targetSprite = (Sprite) EditorGUILayout.ObjectField(targetSprite, typeof(Sprite), true);
if (targetSprite != null)
{
foreach(Material mat in materials)
{
mat.SetVector("_SpriteSheetRect", SpriteSheetSSU.GetSheetVector(targetSprite));
}
}
EditorGUILayout.EndHorizontal();
GUI.color = Color.white;
//Apply to Sprite Renderer:
if (Selection.activeGameObject != null)
{
SpriteRenderer spriteRenderer = Selection.activeGameObject.GetComponent<SpriteRenderer>();
if(spriteRenderer != null && spriteRenderer.sharedMaterial == materials[0])
{
if(spriteRenderer.HasPropertyBlock() && spriteRenderer.sprite != null && spriteRenderer.sprite != lastSSF)
{
lastSSF = spriteRenderer.sprite;
MaterialPropertyBlock mpb = new MaterialPropertyBlock();
spriteRenderer.GetPropertyBlock(mpb);
mpb.SetVector("_SpriteSheetRect", SpriteSheetSSU.GetSheetVector(lastSSF));
spriteRenderer.SetPropertyBlock(mpb);
}
}
}
}
if (prop.name == "_WiggleFixedGroundToggle" && prop.floatValue > 0.5f)
{
DisplayHint("- Prevents the sprite from <b>sliding</b> on the ground.");
}
if(prop.name == "_TMPSmoothness")
{
DisplayHint("- Many <b>distortion</b> shaders will not work.");
DisplayHint("- <b>Bold</b> markups will not work.");
}
//Other:
if (currentHint != null)
{
if(currentHint.hints != null)
{
for(int s = 0; s < currentHint.hints.Count; s++)
{
HintText suffix = currentHint.hints[s];
if(suffix.property == prop.name)
{
DisplayHint(suffix.text);
break;
}
}
}
if(currentHint.spaceHint != null && currentHint.spaceHint == prop.name)
{
DisplaySpaceHint();
}
if (currentHint.lines != null)
{
for (int l = 0; l < currentHint.lines.Count; l++)
{
string line = currentHint.lines[l];
if (line == prop.name)
{
Lines();
}
}
}
}
}
EditorGUILayout.EndVertical();
//Final Category Close:
ShaderTitle("Close");
//Additional:
AdditionalMaterialProperties(materialEditor);
}
void Initialize(MaterialEditor materialEditor, MaterialProperty[] properties)
{
gameObject = Selection.activeGameObject;
if(allHints == null)
{
allHints = new Dictionary<string, ShaderHintSSU>();
}
if(enabledShaders == null)
{
enabledShaders = new HashSet<string>();
}
if(shaderList == null || shaderList.Count == 0)
{
shaderList = new List<string>();
shaderList.Add("Sprite Shaders Ultimate/Standard SSU");
shaderList.Add("Sprite Shaders Ultimate/Additive SSU");
shaderList.Add("Sprite Shaders Ultimate/GUI SSU");
shaderList.Add("Sprite Shaders Ultimate/Additive GUI SSU");
shaderList.Add("Sprite Shaders Ultimate/2D Lit URP SSU");
shaderList.Add("Sprite Shaders Ultimate/3D Lit URP SSU");
shaderList.Add("Sprite Shaders Ultimate/3D Lit BuiltIn SSU");
shaderList.Add("Sprite Shaders Ultimate/Multiplicative SSU");
shaderList.Add("Sprite Shaders Ultimate/3D Lit Cutout URP SSU");
shaderList.Add("Sprite Shaders Ultimate/3D Lit Cutout BuiltIn SSU");
shaderDictionary = new Dictionary<string, int>();
for(int n = 0; n < shaderList.Count; n++)
{
shaderDictionary.Add(shaderList[n], n);
}
}
labelStyle = new GUIStyle(GUI.skin.label);
labelStyle.richText = true;
labelCenterStyle = new GUIStyle(labelStyle);
labelCenterStyle.alignment = TextAnchor.MiddleCenter;
buttonStyle = new GUIStyle(GUI.skin.button);
buttonStyle.richText = true;
buttonStyle.alignment = TextAnchor.MiddleCenter;
shader = ((Material) materialEditor.target).shader;
if (defaultMaterial == null || defaultMaterial.shader != shader)
{
defaultMaterial = new Material(shader);
}
if (lastShader != shader)
{
lastShader = shader;
toggleProperties = new HashSet<string>();
foreach (MaterialProperty prop in properties)
{
if (IsKeyword(prop))
{
toggleProperties.Add(prop.name);
}
}
hidingProperties = new HashSet<string>();
foreach (MaterialProperty prop in properties)
{
if (prop.name.StartsWith("_Toggle") || prop.name.EndsWith("Toggle") || prop.name == "_IsTextMeshPro" || prop.name == "_WindLocalWind" || prop.name == "_WindIsParallax" || prop.name == "_SpriteSheetFix")
{
hidingProperties.Add(prop.name);
}
}
enableProperties = new HashSet<string>();
foreach (MaterialProperty prop in properties)
{
if (prop.name.StartsWith("_Enable"))
{
enableProperties.Add(prop.name);
}
}
alwaysHiddenProperties = new HashSet<string>();
alwaysHiddenProperties.Add("_AlphaTex");
alwaysHiddenProperties.Add("_texcoord");
alwaysHiddenProperties.Add("_EmissionColor");
alwaysHiddenProperties.Add("_AlphaCutoff");
alwaysHiddenProperties.Add("_UIVertexColorAlwaysGammaSpace");
linesAboveProperties = new HashSet<string>();
linesAboveProperties.Add("_MaskMap");
linesAboveProperties.Add("_Smoothness");
linesAboveProperties.Add("_NormalMap");
linesAboveProperties.Add("_ShadowClip");
linesAboveProperties.Add("_AlphaClip");
}
materials = new Material[materialEditor.targets.Length];
for(int m = 0; m < materials.Length; m++)
{
materials[m] = (Material) materialEditor.targets[m];
}
}
void DrawStatus(MaterialEditor materialEditor)
{
//Top:
GUI.color = Color.white;
EditorGUILayout.BeginVertical("Helpbox");
//Shaders Toolbar:
int selected = -1;
if(shaderDictionary.ContainsKey(shader.name))
{
selected = shaderDictionary[shader.name];
}
int newSelection = GUILayout.Toolbar(selected, new string[] { "Standard", "Additive", "GUI", "Additive GUI" });
int secondSelection = GUILayout.Toolbar(selected - 4, new string[] { "2D Lit URP", "3D Lit URP", "3D Lit Built-In", "Multiplicative" });
int thirdSelection = GUILayout.Toolbar(selected - 8, new string[] { "3D Lit Cutout URP", "3D Lit Cutout Built-In"});
if (secondSelection > -1 && secondSelection != selected - 4)
{
newSelection = secondSelection + 4;
}
if (thirdSelection > -1 && thirdSelection != selected - 8)
{
newSelection = thirdSelection + 8;
}
if (newSelection != selected)
{
Undo.RecordObjects(materials, "Changed SSU Shader");
skipGUI = true;
foreach(Material mat in materials)
{
mat.shader = Shader.Find(shaderList[newSelection]);
}
}
EditorGUILayout.Space();
//Status:
GUI.color = new Color(0.7f, 1f, 0.7f, EditorGUIUtility.isProSkin ? 1f : 0.7f);
EditorGUILayout.BeginVertical(GUI.skin.box);
GUI.color = hintColor;
EditorGUILayout.LabelField("- Enabled <b>" + enabledAmount + "</b> out of <b>" + shaderAmount + "</b> shaders.", labelStyle);
//Fading:
switch(Mathf.RoundToInt(shaderFading))
{
case (0):
//No Cost
break;
case (1):
performanceBenchmark += 400;
break;
case (2):
performanceBenchmark += 600;
textureAmount++;
break;
case (3):
performanceBenchmark += 950;
textureAmount++;
break;
case (4):
performanceBenchmark += 1150;
textureAmount++;
break;
}
//Performance:
/*if(performanceBenchmark <= 1)
{
EditorGUILayout.LabelField("- GPU Performance: " + "<b>" + Mathf.RoundToInt(performanceBenchmark * 0.1f) + "</b> (<size=11>same as unity's built-in shader</size>)", labelStyle);
}
else
{
EditorGUILayout.LabelField("- GPU Performance: " + "<b>" + Mathf.RoundToInt(performanceBenchmark * 0.1f) + "</b>", labelStyle);
}
if (textureAmount == 1)
{
EditorGUILayout.LabelField("- Texture Samples: <b>" + textureAmount + "</b> (<size=11>the sprite texture</size>)", labelStyle);
}
else
{
EditorGUILayout.LabelField("- Texture Samples: <b>" + textureAmount + "</b>", labelStyle);
}*/
EditorGUILayout.EndVertical();
wasWarned = false;
//Color Space:
if (PlayerSettings.colorSpace != ColorSpace.Linear)
{
StartWarning(true);
EditorGUILayout.LabelField("- The <b>default</b> shader variables are <b>adjusted</b> for <b>Linear</b> color space.", labelStyle);
EditorGUILayout.LabelField("- Switch to <b>Linear</b> for higher <b>quality</b> and better <b>default</b> settings.", labelStyle);
if (GUILayout.Button("Switch to <b>Linear</b> (recommended)", buttonStyle))
{
Undo.RecordObjects(materials, "Enabled Linear Color Space");
PlayerSettings.colorSpace = ColorSpace.Linear;
}
EditorGUILayout.EndVertical();
}
//Conflict Warnings:
if (enabledShaders.Contains("World Tiling") && enabledShaders.Contains("Screen Tiling"))
{
StartWarning();
EditorGUILayout.LabelField("- <b>World</b> and <b>Screen Tiling</b> aren't compatible.", labelStyle);
EditorGUILayout.EndVertical();
}
if (enabledShaders.Contains("Smooth Pixel Art") && enabledShaders.Contains("Gaussian Blur"))
{
StartWarning();
EditorGUILayout.LabelField("- <b>Smooth Pixel Art</b> and <b>Gaussian Blur</b> aren't compatible.", labelStyle);
EditorGUILayout.EndVertical();
}
//Texture Warnings:
Texture activeTexture = GetTexture(materialEditor);
Sprite activeSprite = GetSprite();
TextureImporter textureImporter = GetTextureImporter(activeTexture);
if (textureImporter != null)
{
TextureImporterSettings textureSettings = new TextureImporterSettings();
textureImporter.ReadTextureSettings(textureSettings);
if (textureImporter != null)
{
//Tiling and Sheet Conflict:
if(requiresTiling && textureImporter.spriteImportMode == SpriteImportMode.Multiple && materials[0].GetFloat("_TilingFix") < 0.5f)
{
StartWarning();
EditorGUILayout.LabelField("- <b>Tiling</b> shaders cause problems with <b>sprite sheets</b>.", labelStyle);
EditorGUILayout.LabelField("- Please enable <b>Tiling Fix</b> to fix these problems.", labelStyle);
EditorGUILayout.LabelField("- Also make sure <b>Sprite Sheet Fix</b> is enabled.", labelStyle);
if (GUILayout.Button("Enable <b>Tiling Fix</b>", buttonStyle))
{
Undo.RecordObjects(materials, "Enabled Tiling Fix Option");
foreach (Material mat in materials)
{
mat.EnableKeyword("_TILINGFIX_ON");
mat.SetFloat("_TilingFix", 1f);
}
}
EditorGUILayout.EndVertical();
}
//Full Rect Mesh:
if (requiresFullRectMesh && textureSettings.spriteMeshType != SpriteMeshType.FullRect)
{
StartWarning();
EditorGUILayout.LabelField("- Set <b>Mesh Type</b> to <b>Full Rect</b> to avoid pixel clipping.", labelStyle);
if (GUILayout.Button("Set <b>Mesh Type</b> to <b>Full Rect</b>", buttonStyle))
{
textureSettings.spriteMeshType = SpriteMeshType.FullRect;
Undo.RecordObject(textureImporter, "Changed Mesh Type");
textureImporter.SetTextureSettings(textureSettings);
textureImporter.SaveAndReimport();
}
EditorGUILayout.EndVertical();
}
//Tiling Fix:
if (requiresTiling && textureSettings.wrapMode == TextureWrapMode.Clamp)
{
StartWarning();
EditorGUILayout.LabelField("- Some shaders require <b>Wrap Mode</b> set to <b>Repeat</b>.", labelStyle);
EditorGUILayout.LabelField("- <b>Tiling</b> won't work properly without this setting.", labelStyle);
if (GUILayout.Button("Set <b>Wrap Mode</b> to <b>Repeat</b>", buttonStyle))
{
textureSettings.wrapMode = TextureWrapMode.Repeat;
Undo.RecordObject(textureImporter, "Changed Wrap Mode");
textureImporter.SetTextureSettings(textureSettings);
textureImporter.SaveAndReimport();
}
EditorGUILayout.EndVertical();
}
//Sprite Sheet Fix:
if (enabledShaders.Contains("Wiggle") && materials[0].GetFloat("_WiggleFixedGroundToggle") > 0.5f)
{
requiresSpriteSheetFix = true;
}
if((requiresSpriteSheetFix || requiresTiling) && textureImporter.spriteImportMode == SpriteImportMode.Multiple && materials[0].GetFloat("_SpriteSheetFix") < 0.5f && activeSprite != null)
{
StartWarning();
EditorGUILayout.LabelField("- Some shaders require the <b>Sprite Sheet Fix</b> option.", labelStyle);
if (GUILayout.Button("Enable <b>Sprite Sheet Fix</b>", buttonStyle))
{
Undo.RecordObjects(materials, "Enabled Sprite Sheet Fix Option");
foreach (Material mat in materials)
{
mat.EnableKeyword("_SPRITESHEETFIX_ON");
mat.SetFloat("_SpriteSheetFix", 1f);
mat.SetVector("_SpriteSheetRect", SpriteSheetSSU.GetSheetVector(activeSprite));
}
}
EditorGUILayout.EndVertical();
}
//Sprite Sheet Component:
if (materials[0].GetFloat("_SpriteSheetFix") > 0.5f && Selection.activeGameObject != null && Selection.activeGameObject.GetComponent<SpriteSheetSSU>() == false)
{
StartWarning();
EditorGUILayout.LabelField("- You might need the <b>SpriteSheetSSU</b> component.", labelStyle);
EditorGUILayout.LabelField("- It updates the <b>Rect</b> variable depending on the <b>Sprite</b>.", labelStyle);
if (GUILayout.Button("Add <b>SpriteSheetSSU</b>", buttonStyle))
{
Undo.AddComponent(Selection.activeGameObject, typeof(SpriteSheetSSU));
}
Material mat = materials[0];
if(activeSprite != null)
{
mat.SetVector("_SpriteSheetRect", SpriteSheetSSU.GetSheetVector(activeSprite));
}
EditorGUILayout.EndVertical();
}
//Instance Required:
if (requiresInstancing && Selection.activeGameObject != null && Selection.activeGameObject.GetComponent<InstancerSSU>() == null)
{
StartWarning();
if (Mathf.RoundToInt(shaderSpace) == 2 || Mathf.RoundToInt(shaderSpace) == 3)
{
EditorGUILayout.LabelField("- <b>Object</b> space requires <b>unique</b> material <b>instances</b>.", labelStyle);
}
else
{
EditorGUILayout.LabelField("- Some shaders require <b>unique</b> material <b>instances</b>.", labelStyle);
}
EditorGUILayout.LabelField("- <b>Instantiate</b> the material at <b>runtime</b> to fix this.", labelStyle);
if (Selection.activeGameObject.GetComponent<SpriteRenderer>() != null)
{
EditorGUILayout.LabelField("- <b>Modifying</b> the material at <b>runtime</b> will <b>instantiate</b> it.", labelStyle);
}
bool multiple = false;
if (enabledShaders.Contains("Wind"))
{
multiple = true;
if (GUILayout.Button("Add <b>InteractiveWindSSU</b>", buttonStyle))
{
Undo.AddComponent(Selection.activeGameObject, typeof(InteractiveWindSSU));
}
}
if (GUILayout.Button("Add <b>MaterialInstancerSSU</b>", buttonStyle))
{
Undo.AddComponent(Selection.activeGameObject, typeof(MaterialInstancerSSU));
}
if (multiple)
{
EditorGUILayout.LabelField("- You only need <b>one</b> of these components.", labelStyle);
}
EditorGUILayout.EndVertical();
}
//Bilinear:
if (enabledShaders.Contains("Smooth Pixel Art") && textureSettings.filterMode == FilterMode.Point)
{
StartWarning();
EditorGUILayout.LabelField("- <b>Smooth Pixel Art</b> requires <b>Bilinear</b> filtering.", labelStyle);
if (GUILayout.Button("Set <b>Filter Mode</b> to <b>Bilinear</b>", buttonStyle))
{
textureSettings.filterMode = FilterMode.Bilinear;
Undo.RecordObject(textureImporter, "Changed Filter Mode");
textureImporter.SetTextureSettings(textureSettings);
textureImporter.SaveAndReimport();
}
EditorGUILayout.EndVertical();
}
if(enabledShaders.Contains("Pixelate"))
{
if (textureSettings.mipmapEnabled)
{
StartWarning();
EditorGUILayout.LabelField("- <b>Pixelate</b> does not work with <b>mip maps</b>.", labelStyle);
if (GUILayout.Button("Disable <b>Mip Maps</b>", buttonStyle))
{
textureSettings.mipmapEnabled = false;
Undo.RecordObject(textureImporter, "Disabled Mip Maps");
textureImporter.SetTextureSettings(textureSettings);
textureImporter.SaveAndReimport();
}
EditorGUILayout.EndVertical();
}
}
}
}
//WindParallaxSSU Required:
if(enabledShaders.Contains("Wind") && materials[0].GetFloat("_WindIsParallax") > 0.5f && Selection.activeGameObject != null && Selection.activeGameObject.GetComponent<WindParallaxSSU>() == null)
{
StartWarning();
EditorGUILayout.LabelField("- <b>Is Parallax</b> requires the <b>WindParallaxSSU</b> component.", labelStyle);
EditorGUILayout.LabelField("- This will fix any issues with <b>moving</b> the sprite.", labelStyle);
if (GUILayout.Button("Add <b>WindParallaxSSU</b>", buttonStyle))
{
Undo.AddComponent(Selection.activeGameObject, typeof(WindParallaxSSU));
}
EditorGUILayout.EndVertical();
}
if(!wasWarned)
{
GUI.color = new Color(0.7f, 1, 1f, EditorGUIUtility.isProSkin ? 1f : 0.7f);
EditorGUILayout.BeginVertical(GUI.skin.box);
GUI.color = hintColor;
EditorGUILayout.LabelField("- No <b>issues</b> were detected.", labelStyle);
EditorGUILayout.LabelField("- Detected issues will be <b>displayed here</b>.", labelStyle);
EditorGUILayout.EndVertical();
}
//Reset Requirements:
requiresSpriteSheetFix = requiresFullRectMesh = requiresInstancing = requiresTiling = false;
//Support Box:
GUI.color = new Color(0.7f, 0.77f, 1f, EditorGUIUtility.isProSkin ? 1f : 0.7f);
EditorGUILayout.BeginVertical(GUI.skin.box);
GUI.color = Color.white;
DisplaySupportInformation();
EditorGUILayout.EndVertical();
//Export Sprite Feature:
GUI.color = new Color(0.9f, 0.7f, 1f, EditorGUIUtility.isProSkin ? 1f : 0.7f);
EditorGUILayout.BeginVertical(GUI.skin.box);
GUI.color = new Color(0.95f, 0.85f, 1, 1f);
if (GUILayout.Button("<b>Bake Shader</b> to Texture and <b>Export</b>", buttonStyle))
{
ExportSprite(materialEditor, bakeStackAmount);
}
bakeStackAmount = Mathf.Clamp(EditorGUILayout.IntField("Stack Amount", bakeStackAmount), 1, 20);
GUI.color = hintColor;
EditorGUILayout.LabelField("- Use a <b>stack amount</b> of <b>10</b> for smooth <b>gaussian blur</b>.", labelStyle);
GUI.color = Color.white;
EditorGUILayout.EndVertical();
EditorGUILayout.EndVertical();
}
void StartWarning(bool isLight = false)
{
wasWarned = true;
GUI.color = isLight ? lightWarnColor : warnColor;
EditorGUILayout.BeginVertical(GUI.skin.box);
}
void AdditionalMaterialProperties(MaterialEditor materialEditor)
{
if (UnityEngine.Rendering.SupportedRenderingFeatures.active.editableMaterialRenderQueue)
{
EditorGUILayout.Space();
EditorGUILayout.Space();
materialEditor.RenderQueueField();
}
}
void DrawShaderCategory(string title)
{
newCategory = true;
isHidden = false;
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.BeginVertical("Helpbox");
GUI.color = new Color(1, 1, 1, 0.9f);
GUILayout.Label("<b><size=14>" + title + "</size></b>", labelStyle);
Lines();
}
void DrawShaderCategory(string title, ref bool toggleVariable)
{
newCategory = true;
isHidden = false;
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.BeginVertical("Helpbox");
GUI.color = new Color(1, 1, 1, 0.9f);
GUILayout.Label("<b><size=14>" + title + "</size></b>", labelStyle);
//Toggle:
Rect buttonRect = GUILayoutUtility.GetLastRect();
buttonRect.x += buttonRect.width - 20;
buttonRect.width = 20;
if(GUI.Button(buttonRect, !toggleVariable ? "<size=12>▶</size>" : "<size=10>▼</size>", buttonStyle))
{
toggleVariable = !toggleVariable;
}
if(toggleVariable)
{
Lines();
}
else
{
isHidden = true;
}
}
void DisplayHint(string text)
{
GUI.color = hintColor;
EditorGUILayout.LabelField(text, labelStyle);
GUI.color = Color.white;
}
void DisplaySpaceHint()
{
GUI.color = hintColor;
EditorGUILayout.LabelField("- Uses <b>" + spaceName + " Space</b> as configured above.", labelStyle);
GUI.color = Color.white;
}
bool DrawShaderToggle(MaterialEditor materialEditor, MaterialProperty prop)
{
newCategory = true;
isHidden = false;
EditorGUILayout.EndVertical();
switch (prop.name)
{
case ("_EnableStrongTint"):
ShaderTitle("Color");
break;
case ("_EnableHologram"):
ShaderTitle("Effect");
break;
case ("_EnableFullAlphaDissolve"):
ShaderTitle("Fading");
break;
case ("_EnablePixelate"):
ShaderTitle("Transformation");
break;
case ("_EnableWind"):
ShaderTitle("Interactive");
break;
case ("_EnableCheckerboard"):
ShaderTitle("Other");
break;
}
shaderAmount++;
bool isEnabled = prop.floatValue > 0.5f;
bool isCollapsed = prop.floatValue == 1.1f;
//Box:
Color color = Color.HSVToRGB((currentBoxColor * 0.05f) % 1, isEnabled ? 0.7f : 0.2f + (EditorGUIUtility.isProSkin ? 0.4f : 0), EditorGUIUtility.isProSkin ? (isEnabled ? 1.8f : 1f) : 1);
color.a = isEnabled ? 1f : 0.7f;
GUI.color = color;
currentBoxColor++;
EditorGUILayout.BeginVertical("Helpbox");
string shaderName = prop.displayName.Replace("Enable ", "");
EditorGUILayout.BeginHorizontal();
GUI.color = new Color(1, 1, 1, 0.5f);
GUILayout.Label(shaderAmount + ".", GUILayout.Width(24f));
GUI.color = new Color(1, 1, 1, isEnabled ? 0.9f : 0.7f);
GUILayout.Label("<b><size=14>" + shaderName + "</size></b>", labelStyle);
//Track:
if (isEnabled)
{
enabledShaders.Add(shaderName);
}
Rect toggleRect = GUILayoutUtility.GetLastRect();
//Enabled:
currentHint = null;
if (isEnabled)
{
enabledAmount++;
string resourcePath = "SSU/Hints/" + shaderName;
if (allHints.ContainsKey(resourcePath))
{
currentHint = allHints[resourcePath];
}
else
{
currentHint = Resources.Load<ShaderHintSSU>(resourcePath);
if (currentHint != null)
{
allHints.Add(resourcePath, currentHint);
}
}
DrawShadow("<b><size=14>" + shaderName + "</size></b>");
}
toggleRect.x += toggleRect.width -= 37;
toggleRect.width = 37;
materialEditor.ShaderProperty(toggleRect, prop, GUIContent.none);
if (isEnabled)
{
Rect lastRect = GUILayoutUtility.GetLastRect();
lastRect.x += lastRect.width - 20;
lastRect.width = 20;
if (GUI.Button(lastRect, isCollapsed ? "<size=12>▶</size>" : "<size=10>▼</size>", buttonStyle))
{
isCollapsed = !isCollapsed;
if (isCollapsed)
{
prop.floatValue = 1.1f;
}
else
{
prop.floatValue = 1f;
}
}
if (currentHint != null)
{
if (currentHint.requiresFullRectMesh)
{
requiresFullRectMesh = true;
}
if (currentHint.requiresSpriteSheetFix)
{
requiresSpriteSheetFix = true;
}
if (currentHint.requiresTiling)
{
requiresTiling = true;
}
if (currentHint.requiresInstancing)
{
requiresInstancing = true;
}
if (currentHint.benchmarkValue > 0)
{
performanceBenchmark += currentHint.benchmarkValue;
}
if (currentHint.textureSamples > 0)
{
textureAmount += currentHint.textureSamples;
}
if (currentHint.textureToggle != "" && currentHint.textureToggle != null && materials[0].GetFloat(currentHint.textureToggle) > 0.5f)
{
textureAmount++;
}
if (currentHint.textureToggleExtra != "" && currentHint.textureToggleExtra != null && materials[0].GetFloat(currentHint.textureToggleExtra) > 0.5f)
{
textureAmount++;
}
}
}
GUI.color = Color.white;
EditorGUILayout.EndHorizontal();
if (isEnabled && !isCollapsed)
{
if (currentHint != null && currentHint.shaderDescription != null && currentHint.shaderDescription != "")
{
string[] descriptionLines = currentHint.shaderDescription.Split('\n');
for (int d = 0; d < descriptionLines.Length; d++)
{
DisplayHint(descriptionLines[d]);
}
string performanceText = "Relatively Lower";
if (currentHint.benchmarkValue > 600)
{
performanceText = currentHint.benchmarkValue < 1700 ? "Average" : "Relatively Higher";
}
DisplayHint("- GPU Usage: <b>" + performanceText + "</b>");
}
if (prop.name == "_EnableSmoothPixelArt")
{
Texture activeTexture = GetTexture(materialEditor);
TextureImporter textureImporter = GetTextureImporter(activeTexture);
if (textureImporter != null)
{
if (textureImporter.filterMode == FilterMode.Point)
{
GUI.color = warnColor;
if (GUILayout.Button("Set <b>" + activeTexture.name + "'s</b> filter mode to <b>Bilinear</b>", buttonStyle))
{
TextureImporterSettings textureSettings = new TextureImporterSettings();
textureImporter.ReadTextureSettings(textureSettings);
textureSettings.filterMode = FilterMode.Bilinear;
Undo.RecordObject(textureImporter, "Changed Filter Mode");
textureImporter.SetTextureSettings(textureSettings);
textureImporter.SaveAndReimport();
}
GUI.color = Color.white;
}
}
}
else
{
Lines();
/*if (prop.name == "_EnableRecolorPalette")
{
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("Generate Source"))
{
Texture activeTexture = GetTexture(materialEditor);
if (activeTexture != null)
{
//Blit to Render Texture:
RenderTexture rt = new RenderTexture(activeTexture.width, activeTexture.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(activeTexture, rt);
//Read RenderTexture to Texture:
Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
tex.Apply();
//Get Colors:
Dictionary<Vector3, float> colorWeights = new Dictionary<Vector3, float>();
for (int x = 0; x < tex.width; x++)
{
for (int y = 0; y < tex.height; y++)
{
Color pixel = paletteBilinear ? tex.GetPixelBilinear((float)x / (float)tex.width, (float)y / (float)tex.height) : tex.GetPixel(x, y);
Vector3 colorKey = new Vector3(pixel.r, pixel.g, pixel.b);
if (colorWeights.ContainsKey(colorKey))
{
colorWeights[colorKey] += pixel.a;
}
else
{
colorWeights.Add(colorKey, pixel.a);
}
}
EditorUtility.DisplayProgressBar("Generating Palette Texture", "Loading Pixels", 0f);
}
//Get Top Colors:
List<Vector3> paletteColors = new List<Vector3>();
Dictionary<Vector3, int> colorDictionary = new Dictionary<Vector3, int>(); ;
int totalColors = paletteSize * paletteSize;
if(colorWeights.Count > totalColors)
{
while (paletteColors.Count < totalColors && colorWeights.Count > 0)
{
float highestValue = 0;
Vector3 highestColor = Vector3.zero;
foreach (KeyValuePair<Vector3, float> colorWeight in colorWeights)
{
if (highestValue < colorWeight.Value)
{
highestValue = colorWeight.Value;
highestColor = colorWeight.Key;
}
}
paletteColors.Add(highestColor);
colorDictionary.Add(highestColor, paletteColors.Count - 1);
colorWeights.Remove(highestColor);
EditorUtility.DisplayProgressBar("Generating Palette Texture", "Sorting colors.", 0.2f);
}
}
else
{
foreach (KeyValuePair<Vector3, float> colorWeight in colorWeights)
{
paletteColors.Add(colorWeight.Key);
colorDictionary.Add(colorWeight.Key, paletteColors.Count - 1);
}
}
/*Sort Top Colors:
List<Vector3> sortedColors = new List<Vector3>();
sortedColors.Add(topColors[0]);
topColors.RemoveAt(0);
while (topColors.Count > 0)
{
float closestDistance = 100f;
int closestIndex = -1;
for (int c = 0; c < topColors.Count; c++)
{
float distance = (sortedColors[sortedColors.Count - 1] - topColors[c]).sqrMagnitude;
if (distance < closestDistance)
{
closestDistance = distance;
closestIndex = c;
}
}
sortedColors.Add(topColors[closestIndex]);
topColors.RemoveAt(closestIndex);
EditorUtility.DisplayProgressBar("Generating Palette Texture", "Sorting color palette.", 0.5f);
}
//Creating Texture:
for (int x = 0; x < tex.width; x++)
{
for (int y = 0; y < tex.height; y++)
{
Color pixel = paletteBilinear ? tex.GetPixelBilinear((float)x / (float)tex.width, (float)y / (float)tex.height) : tex.GetPixel(x, y);
Vector3 colorKey = new Vector3(pixel.r, pixel.g, pixel.b);
int colorIndex = 0;
if (colorDictionary.ContainsKey(colorKey))
{
colorIndex = colorDictionary[colorKey];
}
else
{
float closestDistance = 100f;
for (int c = 0; c < paletteColors.Count; c++)
{
float distance = (paletteColors[c] - colorKey).sqrMagnitude;
if (distance < closestDistance)
{
closestDistance = distance;
colorIndex = c;
}
}
}
float rValue = (float) (colorIndex % paletteSize) / paletteSize;
float gValue = Mathf.Floor(colorIndex / paletteSize) / paletteSize;
tex.SetPixel(x, y, new Color(rValue, gValue, 0, 1));
}
EditorUtility.DisplayProgressBar("Generating Palette Texture", "Mapping colors.", 0.8f);
}
//Export:
EditorUtility.ClearProgressBar();
string oldPath = AssetDatabase.GetAssetPath(activeTexture);
if (oldPath == "")
{
oldPath = Application.dataPath + "/";
}
string[] fileEnding = oldPath.Split('.');
string newPath = oldPath.Replace("." + fileEnding[fileEnding.Length - 1], "");
string folderPath = "";
string[] folders = oldPath.Split('/');
for (int n = 0; n < folders.Length - 1; n++)
{
folderPath += folders[n] + "/";
}
string fileName = activeTexture.name;
newPath = EditorUtility.SaveFilePanel("Save Texture", folderPath, activeTexture.name + " (Source)", "png");
if (newPath != "")
{
newPath = newPath.Substring(Application.dataPath.Length - 9);
while (newPath.Length > 1 && newPath.StartsWith("Assets") == false)
{
newPath = newPath.Substring(1);
}
//Save Texture:
byte[] bytes = tex.EncodeToPNG();
bool newFile = AssetDatabase.LoadAssetAtPath(newPath, typeof(Texture)) == null;
if (newFile)
{
AssetDatabase.CopyAsset(oldPath, newPath);
}
System.IO.File.WriteAllBytes(newPath, bytes);
if (newFile)
{
AssetDatabase.ImportAsset(newPath);
}
//Import new Texture:
AssetDatabase.Refresh();
//Ping:
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(newPath, typeof(Texture)));
}
//Clear:
if (RenderTexture.active == rt)
{
RenderTexture.active = null;
}
Object.DestroyImmediate(rt);
Object.DestroyImmediate(tex);
}
else
{
EditorUtility.DisplayDialog("No texture found.", "Select a SpriteRenderer or Image with this material.\nOr assign a texture to this material.", "Alright");
}
}
if (GUILayout.Button("Generate Palette"))
{
Texture activeTexture = GetTexture(materialEditor);
if (activeTexture != null)
{
//Open Source:
string currentFile = AssetDatabase.GetAssetPath(activeTexture);
string[] splitPath = currentFile.Split('/');
string openPath = EditorUtility.OpenFilePanel("Open Source Texture", currentFile.Substring(0, currentFile.Length - splitPath[splitPath.Length - 1].Length), "png");
string[] openPathSplit = openPath.Split('/');
openPath = "";
bool ignore = true;
for(int i = 0; i < openPathSplit.Length; i++)
{
if(openPathSplit[i] == "Assets")
{
ignore = false;
}
if(!ignore)
{
openPath += openPathSplit[i] + (i == openPathSplit.Length - 1 ? "" : "/");
}
}
Texture sourceTexture = AssetDatabase.LoadAssetAtPath<Texture>(openPath);
//Source Texture:
if (sourceTexture != null)
{
RenderTexture sourceRT = new RenderTexture(sourceTexture.width, sourceTexture.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(sourceTexture, sourceRT);
Texture2D sourceTex = new Texture2D(sourceRT.width, sourceRT.height, TextureFormat.ARGB32, false);
sourceTex.ReadPixels(new Rect(0, 0, sourceRT.width, sourceRT.height), 0, 0);
sourceTex.Apply();
//Recolor Texture
RenderTexture rt = new RenderTexture(activeTexture.width, activeTexture.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(activeTexture, rt);
Texture2D tex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
tex.Apply();
//Creating Palette:
Texture2D paletteTex = new Texture2D(paletteSize, paletteSize);
for (int x = 0; x < tex.width; x++)
{
for (int y = 0; y < tex.height; y++)
{
Color pixel = paletteBilinear ? tex.GetPixelBilinear((float)x / (float)tex.width, (float)y / (float)tex.height) : tex.GetPixel(x, y);
Color pixelSource = paletteBilinear ? sourceTex.GetPixelBilinear((float)x / (float)tex.width, (float)y / (float)tex.height) : tex.GetPixel(x, y);
paletteTex.SetPixel(Mathf.RoundToInt(pixelSource.r * paletteSize), Mathf.RoundToInt(pixelSource.g * paletteSize), pixel);
}
EditorUtility.DisplayProgressBar("Generating Palette Texture", "Saving Pixels", 0f);
}
paletteTex.Apply();
//Export:
EditorUtility.ClearProgressBar();
string oldPath = AssetDatabase.GetAssetPath(activeTexture);
if (oldPath == "")
{
oldPath = Application.dataPath + "/";
}
string[] fileEnding = oldPath.Split('.');
string newPath = oldPath.Replace("." + fileEnding[fileEnding.Length - 1], "");
string folderPath = "";
string[] folders = oldPath.Split('/');
for (int n = 0; n < folders.Length - 1; n++)
{
folderPath += folders[n] + "/";
}
string fileName = activeTexture.name;
newPath = EditorUtility.SaveFilePanel("Save Texture", folderPath, activeTexture.name + " (Source)", "png");
if (newPath != "")
{
newPath = newPath.Substring(Application.dataPath.Length - 9);
while (newPath.Length > 1 && newPath.StartsWith("Assets") == false)
{
newPath = newPath.Substring(1);
}
//Save Texture:
byte[] bytes = paletteTex.EncodeToPNG();
bool newFile = AssetDatabase.LoadAssetAtPath(newPath, typeof(Texture)) == null;
if (newFile)
{
AssetDatabase.CopyAsset(oldPath, newPath);
}
System.IO.File.WriteAllBytes(newPath, bytes);
if (newFile)
{
AssetDatabase.ImportAsset(newPath);
}
//Import new Texture:
AssetDatabase.Refresh();
//Ping:
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(newPath, typeof(Texture)));
}
//Clear:
if (RenderTexture.active == rt || RenderTexture.active == sourceRT)
{
RenderTexture.active = null;
}
Object.DestroyImmediate(rt);
Object.DestroyImmediate(tex);
Object.DestroyImmediate(sourceRT);
Object.DestroyImmediate(sourceTex);
Object.DestroyImmediate(paletteTex);
}
}
else
{
EditorUtility.DisplayDialog("No texture found.", "Select a SpriteRenderer or Image with this material.\nOr assign a texture to this material.", "Alright");
}
}
EditorGUILayout.EndHorizontal();
paletteSize = EditorGUILayout.IntField("Palette Colors", paletteSize);
paletteBilinear = EditorGUILayout.Toggle("Bilinear Filter", paletteBilinear);
GUI.color = hintColor;
EditorGUILayout.LabelField("- Use these to easily generate palette textures.", labelStyle);
Lines();
}*/
}
}
return !isEnabled || isCollapsed;
}
static Texture GetTexture(MaterialEditor materialEditor)
{
Texture activeTexture = null;
if (Selection.activeGameObject != null)
{
SpriteRenderer spriteRenderer = Selection.activeGameObject.GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
if(spriteRenderer.sprite != null)
{
activeTexture = spriteRenderer.sprite.texture;
}
}
else
{
Image image = Selection.activeGameObject.GetComponent<Image>();
if (image != null && image.sprite != null)
{
activeTexture = image.sprite.texture;
}
}
}
else
{
foreach(Material mat in materials)
{
if (mat != null)
{
activeTexture = mat.GetTexture("_MainTex");
if(activeTexture != null)
{
break;
}
}
}
}
return activeTexture;
}
public static TextureImporter GetTextureImporter(Texture activeTexture)
{
try
{
if (activeTexture != null)
{
string path = AssetDatabase.GetAssetPath(activeTexture);
if (path != null)
{
TextureImporter textureImporter = (TextureImporter)AssetImporter.GetAtPath(path);
return textureImporter;
}
}
}
catch
{
return null;
}
return null;
}
Sprite GetSprite()
{
if (Selection.activeGameObject != null)
{
SpriteRenderer spriteRenderer = Selection.activeGameObject.GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
return spriteRenderer.sprite;
}
else
{
Image image = Selection.activeGameObject.GetComponent<Image>();
if (image != null)
{
return image.sprite;
}
}
}
return null;
}
void DrawShadow(string textContent)
{
for (int x = -1; x <= 1; x += 2)
{
for (int y = -1; y <= 1; y += 2)
{
Rect lastRect = GUILayoutUtility.GetLastRect();
lastRect.x += x;
lastRect.y += y;
GUI.color = new Color(1, 1, 1, 0.12f);
EditorGUI.LabelField(lastRect, new GUIContent(textContent), labelStyle);
}
}
GUI.color = Color.white;
}
void ShaderTitle(string title)
{
if(title != "Close")
{
if(title != "Color")
{
EditorGUILayout.Space();
EditorGUILayout.Space();
}
EditorGUILayout.Space();
EditorGUILayout.Space();
GUI.color = new Color(1, 1, 1, 0.55f);
EditorGUILayout.LabelField("<size=18><b>" + title + "</b></size>", labelStyle, GUILayout.Height(22));
GUI.color = new Color(1, 1, 1, 0.1f);
for (int x = -1; x <= 1; x += 2)
{
for (int y = -1; y <= 1; y += 2)
{
Rect lastRect = GUILayoutUtility.GetLastRect();
lastRect.y += x;
lastRect.x += y;
EditorGUI.LabelField(lastRect, "<size=18><b>" + title + "</b></size>", labelStyle);
}
}
GUI.color = Color.white;
}
float currentHeight = (title != "Close") ? GUILayoutUtility.GetLastRect().y : GUILayoutUtility.GetLastRect().y + 59;
if (title == "Color")
{
shaderAmount = enabledAmount = currentBoxColor = 0;
performanceBenchmark = 0f;
textureAmount = 1;
}
else
{
Rect lineRect = GUILayoutUtility.GetLastRect();
lineRect.x -= 8;
lineRect.width = 2;
lineRect.y = lastTitleHeight + 4;
lineRect.height = currentHeight - lastTitleHeight - 32;
if(EditorGUIUtility.isProSkin)
{
GUI.color = new Color(1, 1, 1, 0.5f);
lineRect.x -= 3;
GUI.Box(lineRect, GUIContent.none, GUI.skin.verticalSlider);
lineRect.x -= 1;
GUI.Box(lineRect, GUIContent.none, GUI.skin.verticalSlider);
}
else
{
GUI.color = new Color(0, 0, 0, 0.3f);
GUI.Box(lineRect, GUIContent.none);
lineRect.x += 1;
GUI.Box(lineRect, GUIContent.none);
GUI.color = Color.white;
}
}
lastTitleHeight = currentHeight;
EditorGUILayout.Space();
}
void ResetButton(MaterialProperty prop)
{
GUIContent resetButton = new GUIContent();
resetButton.text = "R";
resetButton.tooltip = "Resets this property.";
if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Color)
{
Color defaultValue = defaultMaterial.GetColor(prop.name);
if (prop.colorValue == defaultValue)
{
GUI.enabled = false;
}
if (GUILayout.Button(resetButton, GUILayout.Width(20)))
{
prop.colorValue = defaultValue;
}
}
else if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Vector)
{
Vector4 defaultValue = defaultMaterial.GetVector(prop.name);
if (prop.vectorValue == defaultValue)
{
GUI.enabled = false;
}
if (GUILayout.Button(resetButton, GUILayout.Width(20)))
{
prop.vectorValue = defaultValue;
}
}
else if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Float || prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Range)
{
float defaultValue = defaultMaterial.GetFloat(prop.name);
if (prop.floatValue == defaultValue)
{
GUI.enabled = false;
}
if (GUILayout.Button(resetButton, GUILayout.Width(20)))
{
prop.floatValue = defaultValue;
}
}
else if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Texture)
{
Texture defaultValue = defaultMaterial.GetTexture(prop.name);
if (prop.textureValue == defaultValue)
{
GUI.enabled = false;
}
if (GUILayout.Button(resetButton, GUILayout.Width(20), GUILayout.Height(50)))
{
prop.textureValue = defaultValue;
}
}
GUI.enabled = true;
}
void HelpButton(MaterialProperty prop, GUIContent displayContent)
{
GUIContent infoButton = new GUIContent();
infoButton.text = "<size=1> </size>C<size=10>#</size>";
infoButton.tooltip = "Useful information for programmers.";
if (GUILayout.Button(infoButton, buttonStyle, GUILayout.Width(26), GUILayout.Height((prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Texture) ? 50 : 20)))
{
CodingHelper.Open(displayContent, prop, shader, EditorGUIUtility.currentViewWidth);
}
}
Rect PropertyLabel(GUIContent labelContent)
{
EditorGUILayout.LabelField(" ");
Rect labelRect = GUILayoutUtility.GetLastRect();
Rect fieldRect = new Rect(labelRect);
if (labelRect.width > 320)
{
labelRect.width -= 160;
}
else
{
labelRect.width = labelRect.width / 2;
}
fieldRect.width -= labelRect.width;
fieldRect.x += labelRect.width;
EditorGUI.PrefixLabel(labelRect, labelContent);
return fieldRect;
}
Rect GetPropertySize(MaterialProperty prop, bool isKeyword)
{
EditorGUILayout.LabelField(" ");
Rect fullRect = GUILayoutUtility.GetLastRect();
Rect labelRect = new Rect(fullRect);
Rect fieldRect = new Rect(labelRect);
if (labelRect.width > 320)
{
labelRect.width -= 160;
}
else
{
labelRect.width = labelRect.width / 2;
}
if(isKeyword) {
labelRect.width -= 52;
}
fieldRect.width -= labelRect.width;
fieldRect.x += labelRect.width;
EditorGUIUtility.fieldWidth = fieldRect.width;
EditorGUIUtility.labelWidth = labelRect.width;
if (prop.propertyType == UnityEngine.Rendering.ShaderPropertyType.Range)
{
EditorGUIUtility.fieldWidth = 50;
EditorGUIUtility.labelWidth = labelRect.width;
}
return fullRect;
}
bool IsKeyword(MaterialProperty prop)
{
return IsKeyword(prop.name);
}
public static bool IsKeyword(string propertyName)
{
if (propertyName.StartsWith("_Toggle") || propertyName.EndsWith("Toggle") || propertyName.EndsWith("Invert") || propertyName == "PixelSnap" || propertyName == "_ShaderSpace" || propertyName == "_ShaderFading" || propertyName == "_BakedMaterial" || propertyName == "_SmokeVertexSeed" || propertyName == "_SpriteSheetFix" || propertyName == "_UseUIAlphaClip" || propertyName == "_IsText" || propertyName == "_IsTextMeshPro" || propertyName == "_TilingFix" || propertyName == "_ForceAlpha" || propertyName == "_VertexTintFirst" || propertyName == "_PixelPerfectSpace" || propertyName == "_PixelPerfectUV" || propertyName == "_WindLocalWind" || propertyName == "_WindHighQualityNoise" || propertyName == "_WindIsParallax" || propertyName == "_WindFlip" || propertyName == "_SquishFlip")
{
return true;
}
return false;
}
public static void Lines()
{
GUI.color = new Color(1, 1, 1, 0.5f);
EditorGUILayout.LabelField("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ", GUILayout.Height(9));
GUI.color = new Color(1, 1, 1, 1);
}
public static void DisplaySupportInformation()
{
GUIStyle labelStyle = new GUIStyle(GUI.skin.label);
labelStyle.richText = true;
GUIStyle linkStyle = new GUIStyle(GUI.skin.label);
linkStyle.richText = true;
linkStyle.alignment = TextAnchor.MiddleLeft;
linkStyle.normal.textColor = linkStyle.focused.textColor = linkStyle.hover.textColor = EditorGUIUtility.isProSkin ? new Color(0.8f, 0.9f, 1f, 1) : new Color(0.1f, 0.2f, 0.4f, 1);
linkStyle.active.textColor = EditorGUIUtility.isProSkin ? new Color(0.6f, 0.8f, 1f, 1) : new Color(0.15f, 0.4f, 0.6f, 1);
DisplayLink("Documentation", "https://ekincantas.com/sprite-shaders-ultimate/", "https://ekincantas.com/sprite-shaders-ultimate/", labelStyle, linkStyle);
DisplayLink("Discord", "https://discord.gg/nWbRkN8Zxr", "https://discord.gg/nWbRkN8Zxr", labelStyle, linkStyle);
DisplayLink("Email", "ekincantascontact@gmail.com", "", labelStyle, linkStyle);
}
private static void DisplayLink(string title, string link, string url, GUIStyle labelStyle, GUIStyle linkStyle)
{
GUI.color = new Color(1, 1, 1, 0.7f);
EditorGUILayout.BeginHorizontal();
GUILayout.Label("<b>" + title + ": </b>", labelStyle);
Rect lastRect = GUILayoutUtility.GetLastRect();
lastRect.x += 100;
lastRect.width -= 100;
GUI.color = Color.white;
if (url == "")
{
EditorGUI.SelectableLabel(lastRect, link, linkStyle);
}
else
{
if(GUI.Button(lastRect,link, linkStyle))
{
Application.OpenURL(url);
}
}
EditorGUILayout.EndHorizontal();
}
public static void ExportSprite(MaterialEditor materialEditor, int count = 1)
{
Material material = (Material)materialEditor.target;
Texture texture = GetTexture(materialEditor);
if (material != null && texture != null)
{
SaveShadedTexture(material, texture, count);
}
else
{
EditorUtility.DisplayDialog("No texture found.", "Select a SpriteRenderer or Image with this material.\nOr assign a texture to this material.", "Alright");
}
}
public static void SaveShadedTexture(Material spriteMaterial, Texture spriteTexture, int count = 1)
{
//Enable Baked Material:
Undo.RecordObject(spriteMaterial, "Switched baked material setting.");
Shader previousShader = spriteMaterial.shader;
spriteMaterial.shader = Shader.Find("Sprite Shaders Ultimate/Standard SSU");
spriteMaterial.EnableKeyword("_BAKEDMATERIAL_ON");
spriteMaterial.SetFloat("_BakedMaterial", 1f);
Texture2D tex = (Texture2D) spriteTexture;
bool first = true;
for (int n = 0; n < count; n++)
{
//Blit to Render Texture:
RenderTexture rt = new RenderTexture(tex.width, tex.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(tex, rt, spriteMaterial);
//Destroy Previous Texture:
if (!first)
{
Object.DestroyImmediate(tex);
}
first = false;
//Read RenderTexture to Texture:
tex = new Texture2D(rt.width, rt.height, TextureFormat.ARGB32, false);
tex.ReadPixels(new Rect(0, 0, rt.width, rt.height), 0, 0);
tex.Apply();
//Clear RenderTexture:
if (RenderTexture.active == rt)
{
RenderTexture.active = null;
}
Object.DestroyImmediate(rt);
}
//Disable Baked Material:
spriteMaterial.DisableKeyword("_BAKEDMATERIAL_ON");
spriteMaterial.SetFloat("_BakedMaterial", 0f);
spriteMaterial.shader = previousShader;
//Get Paths:
string oldPath = AssetDatabase.GetAssetPath(spriteTexture);
if (oldPath == "")
{
oldPath = Application.dataPath + "/";
}
string[] fileEnding = oldPath.Split('.');
string newPath = oldPath.Replace("." + fileEnding[fileEnding.Length - 1], "");
string folderPath = "";
string[] folders = oldPath.Split('/');
for (int n = 0; n < folders.Length - 1; n++)
{
folderPath += folders[n] + "/";
}
string fileName = spriteTexture.name;
int number = 1;
while (AssetDatabase.LoadAssetAtPath(newPath + " (Baked " + number + ").png", typeof(Texture)) != null)
{
number++;
}
newPath = EditorUtility.SaveFilePanel("Save Texture", folderPath, spriteTexture.name + " (Baked " + number + ")", "png");
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginVertical();
EditorGUILayout.BeginVertical();
if (newPath != "")
{
newPath = newPath.Substring(Application.dataPath.Length - 9);
while (newPath.Length > 1 && newPath.StartsWith("Assets") == false)
{
newPath = newPath.Substring(1);
}
//Save Texture:
byte[] bytes = tex.EncodeToPNG();
bool newFile = AssetDatabase.LoadAssetAtPath(newPath, typeof(Texture)) == null;
if (newFile)
{
AssetDatabase.CopyAsset(oldPath, newPath);
}
System.IO.File.WriteAllBytes(newPath, bytes);
if (newFile)
{
AssetDatabase.ImportAsset(newPath);
}
//Import new Texture:
AssetDatabase.Refresh();
//Ping:
EditorGUIUtility.PingObject(AssetDatabase.LoadAssetAtPath(newPath, typeof(Texture)));
}
//Clean Up:
Object.DestroyImmediate(tex);
}
}
}
#endif