483 lines
18 KiB
C#
483 lines
18 KiB
C#
|
using UnityEngine;
|
|||
|
using UnityEditor;
|
|||
|
using System.Collections.Generic;
|
|||
|
using System.IO;
|
|||
|
using System.Reflection;
|
|||
|
using System;
|
|||
|
using UnityEditorInternal;
|
|||
|
|
|||
|
namespace XSToonDynamicPenetration
|
|||
|
{
|
|||
|
public class XSGradientEditor : EditorWindow
|
|||
|
{
|
|||
|
public List<int> gradients_index = new List<int>(new int[1] { 0 });
|
|||
|
public List<Gradient> gradients = new List<Gradient>(5);
|
|||
|
public Texture2D tex;
|
|||
|
|
|||
|
private string finalFilePath;
|
|||
|
|
|||
|
private bool isLinear = false;
|
|||
|
private bool manualMaterial = false;
|
|||
|
private enum Resolutions
|
|||
|
{
|
|||
|
Tiny64x8 = 64,
|
|||
|
Small128x8 = 128,
|
|||
|
Medium256x8 = 256,
|
|||
|
Large512x8 = 512
|
|||
|
}
|
|||
|
private Resolutions res = Resolutions.Tiny64x8;
|
|||
|
public static Material focusedMat;
|
|||
|
private Material oldFocusedMat;
|
|||
|
private Texture oldTexture;
|
|||
|
private string rampProperty = "_Ramp";
|
|||
|
private ReorderableList grad_index_reorderable;
|
|||
|
private bool reorder;
|
|||
|
private static GUIContent iconToolbarPlus;
|
|||
|
private static GUIContent iconToolbarMinus;
|
|||
|
private static GUIStyle preButton;
|
|||
|
private static GUIStyle buttonBackground;
|
|||
|
private bool changed;
|
|||
|
private int loadGradIndex;
|
|||
|
private XSMultiGradient xsmg;
|
|||
|
private Vector2 scrollPos;
|
|||
|
|
|||
|
private bool dHelpText = false;
|
|||
|
//private bool dAdvanced = false;
|
|||
|
|
|||
|
[MenuItem("Tools/Xiexe/XSToon/Gradient Editor")]
|
|||
|
static public void Init()
|
|||
|
{
|
|||
|
XSGradientEditor window = EditorWindow.GetWindow<XSGradientEditor>(false, "XSToon: Gradient Editor", true);
|
|||
|
window.minSize = new Vector2(450, 390);
|
|||
|
}
|
|||
|
|
|||
|
public void OnGUI()
|
|||
|
{
|
|||
|
changed = false;
|
|||
|
if (focusedMat != null)
|
|||
|
{
|
|||
|
XSStyles.ShurikenHeader("Current Material: " + focusedMat.name);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
XSStyles.ShurikenHeader("Current Material: None");
|
|||
|
}
|
|||
|
|
|||
|
if (preButton == null)
|
|||
|
{
|
|||
|
iconToolbarPlus = EditorGUIUtility.IconContent("Toolbar Plus", "Add Gradient");
|
|||
|
iconToolbarMinus = EditorGUIUtility.IconContent("Toolbar Minus", "Remove Gradient");
|
|||
|
preButton = new GUIStyle("RL FooterButton");
|
|||
|
buttonBackground = new GUIStyle("RL Header");
|
|||
|
}
|
|||
|
|
|||
|
if (gradients.Count == 0)
|
|||
|
{
|
|||
|
gradients.Add(new Gradient());
|
|||
|
gradients.Add(new Gradient());
|
|||
|
gradients.Add(new Gradient());
|
|||
|
gradients.Add(new Gradient());
|
|||
|
gradients.Add(new Gradient());
|
|||
|
}
|
|||
|
|
|||
|
if (grad_index_reorderable == null)
|
|||
|
{
|
|||
|
makeReorderedList();
|
|||
|
}
|
|||
|
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
GUILayout.FlexibleSpace();
|
|||
|
Rect r = EditorGUILayout.GetControlRect();
|
|||
|
float rightEdge = r.xMax;
|
|||
|
float leftEdge = rightEdge - 48f;
|
|||
|
r = new Rect(leftEdge, r.y, rightEdge - leftEdge, r.height);
|
|||
|
if (Event.current.type == EventType.Repaint) buttonBackground.Draw(r, false, false, false, false);
|
|||
|
leftEdge += 18f;
|
|||
|
EditorGUI.BeginDisabledGroup(gradients_index.Count == 5);
|
|||
|
bool addE = GUI.Button(new Rect(leftEdge + 4, r.y, 25, 13), iconToolbarPlus, preButton);
|
|||
|
EditorGUI.EndDisabledGroup();
|
|||
|
EditorGUI.BeginDisabledGroup(gradients_index.Count == 1);
|
|||
|
bool removeE = GUI.Button(new Rect(leftEdge - 19, r.y, 25, 13), iconToolbarMinus, preButton);
|
|||
|
EditorGUI.EndDisabledGroup();
|
|||
|
|
|||
|
if (addE)
|
|||
|
{
|
|||
|
grad_index_reorderable.index++;
|
|||
|
int wat = 0;
|
|||
|
for (int i = 0; i < 5; i++)
|
|||
|
{
|
|||
|
if (!gradients_index.Contains(i))
|
|||
|
{
|
|||
|
wat = i;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
gradients_index.Add(wat);
|
|||
|
changed = true;
|
|||
|
}
|
|||
|
if (removeE)
|
|||
|
{
|
|||
|
gradients_index.Remove(gradients_index[gradients_index.Count - 1]);
|
|||
|
grad_index_reorderable.index--;
|
|||
|
changed = true;
|
|||
|
}
|
|||
|
|
|||
|
GUIStyle button = new GUIStyle(EditorStyles.miniButton);
|
|||
|
button.normal = !reorder ? EditorStyles.miniButton.normal : EditorStyles.miniButton.onNormal;
|
|||
|
if (GUILayout.Button(new GUIContent("Reorder", "Don't use Reorder if you want to undo a gradient change"), button, GUILayout.ExpandWidth(false)))
|
|||
|
{
|
|||
|
reorder = !reorder;
|
|||
|
}
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
|
|||
|
SerializedObject serializedObject = new SerializedObject(this);
|
|||
|
if (reorder)
|
|||
|
{
|
|||
|
grad_index_reorderable.DoLayoutList();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
SerializedProperty colorGradients = serializedObject.FindProperty("gradients");
|
|||
|
if (colorGradients.arraySize == 5)
|
|||
|
{
|
|||
|
for (int i = 0; i < gradients_index.Count; i++)
|
|||
|
{
|
|||
|
Rect _r = EditorGUILayout.GetControlRect();
|
|||
|
_r.x += 16f;
|
|||
|
_r.width -= 2f + 16f;
|
|||
|
_r.height += 5f;
|
|||
|
_r.y += 2f + (3f * i);
|
|||
|
EditorGUI.PropertyField(_r, colorGradients.GetArrayElementAtIndex(gradients_index[i]), new GUIContent(""));
|
|||
|
}
|
|||
|
GUILayout.Space(Mathf.Lerp(9f, 24f, gradients_index.Count / 5f));
|
|||
|
}
|
|||
|
}
|
|||
|
if (serializedObject.ApplyModifiedProperties()) changed = true;
|
|||
|
|
|||
|
if (oldFocusedMat != focusedMat)
|
|||
|
{
|
|||
|
changed = true;
|
|||
|
if (this.oldTexture != null)
|
|||
|
{
|
|||
|
if (this.oldTexture == EditorGUIUtility.whiteTexture) this.oldTexture = null;
|
|||
|
oldFocusedMat.SetTexture(rampProperty, this.oldTexture);
|
|||
|
this.oldTexture = null;
|
|||
|
}
|
|||
|
oldFocusedMat = focusedMat;
|
|||
|
}
|
|||
|
|
|||
|
Resolutions oldRes = res;
|
|||
|
res = (Resolutions)EditorGUILayout.EnumPopup("Resolution: ", res);
|
|||
|
if (oldRes != res) changed = true;
|
|||
|
|
|||
|
int width = (int)res;
|
|||
|
int height = 30;
|
|||
|
if (gradients_index.Count == 1)
|
|||
|
{
|
|||
|
height = 8;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
height = 150;
|
|||
|
}
|
|||
|
if (tex == null)
|
|||
|
{
|
|||
|
tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
|||
|
}
|
|||
|
|
|||
|
bool old_isLinear = isLinear;
|
|||
|
drawAdvancedOptions();
|
|||
|
if (old_isLinear != isLinear)
|
|||
|
{
|
|||
|
changed = true;
|
|||
|
}
|
|||
|
|
|||
|
if (manualMaterial)
|
|||
|
{
|
|||
|
focusedMat = (Material)EditorGUILayout.ObjectField(new GUIContent("", ""), focusedMat, typeof(Material), true);
|
|||
|
}
|
|||
|
|
|||
|
if (focusedMat != null)
|
|||
|
{
|
|||
|
if (focusedMat.HasProperty("_Ramp"))
|
|||
|
{
|
|||
|
rampProperty = "_Ramp";
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
rampProperty = EditorGUILayout.TextField("Ramp Property Name", rampProperty);
|
|||
|
if (!focusedMat.HasProperty(rampProperty))
|
|||
|
{
|
|||
|
GUILayout.Label("Property not found!");
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (changed)
|
|||
|
{
|
|||
|
updateTexture(width, height);
|
|||
|
if (focusedMat != null)
|
|||
|
{
|
|||
|
if (focusedMat.HasProperty(rampProperty))
|
|||
|
{
|
|||
|
if (this.oldTexture == null)
|
|||
|
{
|
|||
|
if (focusedMat.GetTexture(rampProperty) == null)
|
|||
|
{
|
|||
|
this.oldTexture = EditorGUIUtility.whiteTexture;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
this.oldTexture = focusedMat.GetTexture(rampProperty);
|
|||
|
}
|
|||
|
}
|
|||
|
tex.wrapMode = TextureWrapMode.Clamp;
|
|||
|
tex.Apply(false, false);
|
|||
|
focusedMat.SetTexture(rampProperty, tex);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
XSStyles.Separator();
|
|||
|
drawMGInputOutput();
|
|||
|
|
|||
|
|
|||
|
if (GUILayout.Button("Save Ramp"))
|
|||
|
{
|
|||
|
finalFilePath = XSStyles.findAssetPath(finalFilePath);
|
|||
|
string path = EditorUtility.SaveFilePanel("Save Ramp as PNG", finalFilePath + "/Textures/Shadow Ramps/Generated", "gradient", "png");
|
|||
|
if (path.Length != 0)
|
|||
|
{
|
|||
|
updateTexture(width, height);
|
|||
|
bool success = GenTexture(tex, path);
|
|||
|
if (success)
|
|||
|
{
|
|||
|
if (focusedMat != null)
|
|||
|
{
|
|||
|
string s = path.Substring(path.IndexOf("Assets"));
|
|||
|
Texture ramp = AssetDatabase.LoadAssetAtPath<Texture>(s);
|
|||
|
if (ramp != null)
|
|||
|
{
|
|||
|
focusedMat.SetTexture(rampProperty, ramp);
|
|||
|
this.oldTexture = null;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
drawHelpText();
|
|||
|
}
|
|||
|
|
|||
|
Gradient reflessGradient(Gradient old_grad)
|
|||
|
{
|
|||
|
Gradient grad = new Gradient();
|
|||
|
grad.SetKeys(old_grad.colorKeys, old_grad.alphaKeys);
|
|||
|
grad.mode = old_grad.mode;
|
|||
|
return grad;
|
|||
|
}
|
|||
|
|
|||
|
List<int> reflessIndexes(List<int> old_indexes)
|
|||
|
{
|
|||
|
List<int> indexes = new List<int>();
|
|||
|
for (int i = 0; i < old_indexes.Count; i++)
|
|||
|
{
|
|||
|
indexes.Add(old_indexes[i]);
|
|||
|
}
|
|||
|
return indexes;
|
|||
|
}
|
|||
|
|
|||
|
void makeReorderedList()
|
|||
|
{
|
|||
|
grad_index_reorderable = new ReorderableList(gradients_index, typeof(int), true, false, false, false);
|
|||
|
grad_index_reorderable.headerHeight = 0f;
|
|||
|
grad_index_reorderable.footerHeight = 0f;
|
|||
|
grad_index_reorderable.showDefaultBackground = true;
|
|||
|
|
|||
|
grad_index_reorderable.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
|
|||
|
{
|
|||
|
if (gradients.Count == 5)
|
|||
|
{
|
|||
|
Type editorGui = typeof(EditorGUI);
|
|||
|
MethodInfo mi = editorGui.GetMethod("GradientField", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[2] { typeof(Rect), typeof(Gradient) }, null);
|
|||
|
mi.Invoke(this, new object[2] { rect, gradients[gradients_index[index]] });
|
|||
|
if (Event.current.type == EventType.Repaint)
|
|||
|
{
|
|||
|
changed = true;
|
|||
|
}
|
|||
|
}
|
|||
|
};
|
|||
|
|
|||
|
grad_index_reorderable.onChangedCallback = (ReorderableList list) =>
|
|||
|
{
|
|||
|
changed = true;
|
|||
|
};
|
|||
|
}
|
|||
|
|
|||
|
void OnDestroy()
|
|||
|
{
|
|||
|
if (focusedMat != null)
|
|||
|
{
|
|||
|
if (this.oldTexture != null)
|
|||
|
{
|
|||
|
if (this.oldTexture == EditorGUIUtility.whiteTexture)
|
|||
|
{
|
|||
|
this.oldTexture = null;
|
|||
|
}
|
|||
|
focusedMat.SetTexture(rampProperty, this.oldTexture);
|
|||
|
this.oldTexture = null;
|
|||
|
}
|
|||
|
focusedMat = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void updateTexture(int width, int height)
|
|||
|
{
|
|||
|
tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
|||
|
for (int y = 0; y < height; y++)
|
|||
|
{
|
|||
|
for (int x = 0; x < width; x++)
|
|||
|
{
|
|||
|
if (gradients_index.Count != 1)
|
|||
|
{
|
|||
|
int gradNum = Mathf.FloorToInt(y / 30f);
|
|||
|
gradNum = Mathf.Abs(gradNum - 5) - 1;
|
|||
|
if (gradNum >= gradients_index.Count)
|
|||
|
{
|
|||
|
tex.SetPixel(x, y, Color.white);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (gradients[gradients_index[gradNum]] != null)
|
|||
|
{
|
|||
|
Color grad_col = gradients[gradients_index[gradNum]].Evaluate((float)x / (float)width);
|
|||
|
tex.SetPixel(x, y, isLinear ? grad_col.gamma : grad_col);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
tex.SetPixel(x, y, Color.white);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Color grad_col = gradients[gradients_index[0]].Evaluate((float)x / (float)width);
|
|||
|
tex.SetPixel(x, y, isLinear ? grad_col.gamma : grad_col);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool GenTexture(Texture2D tex, string path)
|
|||
|
{
|
|||
|
var pngData = tex.EncodeToPNG();
|
|||
|
if (pngData != null)
|
|||
|
{
|
|||
|
File.WriteAllBytes(path, pngData);
|
|||
|
AssetDatabase.Refresh();
|
|||
|
return ChangeImportSettings(path);
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
bool ChangeImportSettings(string path)
|
|||
|
{
|
|||
|
|
|||
|
string s = path.Substring(path.LastIndexOf("Assets"));
|
|||
|
TextureImporter texture = (TextureImporter)TextureImporter.GetAtPath(s);
|
|||
|
if (texture != null)
|
|||
|
{
|
|||
|
texture.wrapMode = TextureWrapMode.Clamp;
|
|||
|
texture.maxTextureSize = 512;
|
|||
|
texture.mipmapEnabled = false;
|
|||
|
texture.textureCompression = TextureImporterCompression.Uncompressed;
|
|||
|
|
|||
|
// texture.sRGBTexture = !isLinear; // We already do the conversion in tex.SetPixel
|
|||
|
|
|||
|
texture.SaveAndReimport();
|
|||
|
AssetDatabase.Refresh();
|
|||
|
return true;
|
|||
|
|
|||
|
// shadowRamp = (Texture)Resources.Load(path);
|
|||
|
// Debug.LogWarning(shadowRamp.ToString());
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
Debug.Log("Asset Path is Null, can't set to Clamped.\n You'll need to do it manually.");
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
void drawMGInputOutput()
|
|||
|
{
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
XSMultiGradient old_xsmg = xsmg;
|
|||
|
xsmg = (XSMultiGradient)EditorGUILayout.ObjectField("MultiGradient Preset", xsmg, typeof(XSMultiGradient), false, null);
|
|||
|
if (xsmg != old_xsmg)
|
|||
|
{
|
|||
|
if (xsmg != null)
|
|||
|
{
|
|||
|
this.gradients = xsmg.gradients;
|
|||
|
this.gradients_index = xsmg.order;
|
|||
|
makeReorderedList();
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
List<Gradient> new_Grads = new List<Gradient>();
|
|||
|
for (int i = 0; i < this.gradients.Count; i++)
|
|||
|
{
|
|||
|
new_Grads.Add(reflessGradient(this.gradients[i]));
|
|||
|
}
|
|||
|
this.gradients = new_Grads;
|
|||
|
this.gradients_index = reflessIndexes(this.gradients_index);
|
|||
|
makeReorderedList();
|
|||
|
}
|
|||
|
changed = true;
|
|||
|
}
|
|||
|
|
|||
|
if (GUILayout.Button("Save New", EditorStyles.miniButton, GUILayout.ExpandWidth(false)))
|
|||
|
{
|
|||
|
finalFilePath = XSStyles.findAssetPath(finalFilePath);
|
|||
|
string path = EditorUtility.SaveFilePanel("Save MultiGradient", (finalFilePath + "/Textures/Shadow Ramps/MGPresets"), "MultiGradient", "asset");
|
|||
|
if (path.Length != 0)
|
|||
|
{
|
|||
|
path = path.Substring(Application.dataPath.Length - "Assets".Length);
|
|||
|
XSMultiGradient _xsmg = ScriptableObject.CreateInstance<XSMultiGradient>();
|
|||
|
_xsmg.uniqueName = Path.GetFileNameWithoutExtension(path);
|
|||
|
foreach (Gradient grad in gradients)
|
|||
|
{
|
|||
|
_xsmg.gradients.Add(reflessGradient(grad));
|
|||
|
}
|
|||
|
_xsmg.order.AddRange(gradients_index.ToArray());
|
|||
|
xsmg = _xsmg;
|
|||
|
AssetDatabase.CreateAsset(_xsmg, path);
|
|||
|
this.gradients = xsmg.gradients;
|
|||
|
this.gradients_index = xsmg.order;
|
|||
|
makeReorderedList();
|
|||
|
AssetDatabase.SaveAssets();
|
|||
|
}
|
|||
|
}
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
}
|
|||
|
|
|||
|
void drawAdvancedOptions()
|
|||
|
{
|
|||
|
GUILayout.BeginHorizontal();
|
|||
|
isLinear = GUILayout.Toggle(isLinear, "Make Linear Texture");
|
|||
|
manualMaterial = GUILayout.Toggle(manualMaterial, "Manual Material");
|
|||
|
GUILayout.EndHorizontal();
|
|||
|
}
|
|||
|
|
|||
|
void drawHelpText()
|
|||
|
{
|
|||
|
XSStyles.Separator();
|
|||
|
dHelpText = XSStyles.ShurikenFoldout("Information", dHelpText);
|
|||
|
if(dHelpText)
|
|||
|
{
|
|||
|
scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
|
|||
|
XSStyles.HelpBox("You can use this to create a custom shadow ramp in realtime. \nIf you do not save, the ramp will be reverted back to what it was previously. \n\n - Click the Gradient box. \n - Choose resolution of the texture. \n - Save.", MessageType.Info);
|
|||
|
XSStyles.HelpBox("Ramp textures support up to 5 ramps in one texture. That means you can have up to 5 ramps on a single material. You will need to author a ramp mask to choose which ramp to sample from. \n\nA texture that is fully black would sample from the bottom ramp, a texture that is fully white would sample from the top ramp, and a texture that is half gray would sample from the middle ramp. \n\n A quick tip would be that you can sample from each of the 5 ramps with 0, 0.25, 0.5, 0.75, and 1 on the texture. \n\nThe order of the gradients on the UI is the order that they will be on the texture.", MessageType.Info);
|
|||
|
EditorGUILayout.EndScrollView();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|