| using UnityEngine; |
| using UnityEditor; |
|
|
| namespace TMPro.EditorUtilities |
| { |
| |
| public abstract class TMP_BaseShaderGUI : ShaderGUI |
| { |
| |
| |
| protected class ShaderFeature |
| { |
| public string undoLabel; |
|
|
| public GUIContent label; |
|
|
| |
| public GUIContent[] keywordLabels; |
|
|
| |
| public string[] keywords; |
|
|
| int m_State; |
|
|
| public bool Active |
| { |
| get { return m_State >= 0; } |
| } |
|
|
| public int State |
| { |
| get { return m_State; } |
| } |
|
|
| public void ReadState(Material material) |
| { |
| for (int i = 0; i < keywords.Length; i++) |
| { |
| if (material.IsKeywordEnabled(keywords[i])) |
| { |
| m_State = i; |
| return; |
| } |
| } |
|
|
| m_State = -1; |
| } |
|
|
| public void SetActive(bool active, Material material) |
| { |
| m_State = active ? 0 : -1; |
| SetStateKeywords(material); |
| } |
|
|
| public void DoPopup(MaterialEditor editor, Material material) |
| { |
| EditorGUI.BeginChangeCheck(); |
| int selection = EditorGUILayout.Popup(label, m_State + 1, keywordLabels); |
| if (EditorGUI.EndChangeCheck()) |
| { |
| m_State = selection - 1; |
| editor.RegisterPropertyChangeUndo(undoLabel); |
| SetStateKeywords(material); |
| } |
| } |
|
|
| void SetStateKeywords(Material material) |
| { |
| for (int i = 0; i < keywords.Length; i++) |
| { |
| if (i == m_State) |
| { |
| material.EnableKeyword(keywords[i]); |
| } |
| else |
| { |
| material.DisableKeyword(keywords[i]); |
| } |
| } |
| } |
| } |
|
|
| static GUIContent s_TempLabel = new GUIContent(); |
|
|
| protected static bool s_DebugExtended; |
|
|
| static int s_UndoRedoCount, s_LastSeenUndoRedoCount; |
|
|
| static float[][] s_TempFloats = |
| { |
| null, new float[1], new float[2], new float[3], new float[4] |
| }; |
|
|
| protected static GUIContent[] s_XywhVectorLabels = |
| { |
| new GUIContent("X"), |
| new GUIContent("Y"), |
| new GUIContent("W", "Width"), |
| new GUIContent("H", "Height") |
| }; |
|
|
| protected static GUIContent[] s_LbrtVectorLabels = |
| { |
| new GUIContent("L", "Left"), |
| new GUIContent("B", "Bottom"), |
| new GUIContent("R", "Right"), |
| new GUIContent("T", "Top") |
| }; |
|
|
| protected static GUIContent[] s_CullingTypeLabels = |
| { |
| new GUIContent("Off"), |
| new GUIContent("Front"), |
| new GUIContent("Back") |
| }; |
|
|
| static TMP_BaseShaderGUI() |
| { |
| |
| Undo.undoRedoPerformed += () => s_UndoRedoCount += 1; |
| } |
|
|
| bool m_IsNewGUI = true; |
|
|
| float m_DragAndDropMinY; |
|
|
| protected MaterialEditor m_Editor; |
|
|
| protected Material m_Material; |
|
|
| protected MaterialProperty[] m_Properties; |
|
|
| void PrepareGUI() |
| { |
| m_IsNewGUI = false; |
| ShaderUtilities.GetShaderPropertyIDs(); |
|
|
| |
| |
| if (s_LastSeenUndoRedoCount != s_UndoRedoCount) |
| { |
| |
| |
| TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material as Material); |
| } |
|
|
| s_LastSeenUndoRedoCount = s_UndoRedoCount; |
| } |
|
|
| public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) |
| { |
| m_Editor = materialEditor; |
| m_Material = materialEditor.target as Material; |
| this.m_Properties = properties; |
|
|
| if (m_IsNewGUI) |
| { |
| PrepareGUI(); |
| } |
|
|
| DoDragAndDropBegin(); |
| EditorGUI.BeginChangeCheck(); |
| DoGUI(); |
| if (EditorGUI.EndChangeCheck()) |
| { |
| TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); |
| } |
|
|
| DoDragAndDropEnd(); |
| } |
|
|
| |
| protected abstract void DoGUI(); |
|
|
| static string[] s_PanelStateLabel = new string[] { "\t- <i>Click to collapse</i> -", "\t- <i>Click to expand</i> -" }; |
|
|
| protected bool BeginPanel(string panel, bool expanded) |
| { |
| EditorGUI.indentLevel = 0; |
|
|
| EditorGUILayout.BeginVertical(EditorStyles.helpBox); |
| Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); |
| r.x += 20; |
| r.width += 6; |
|
|
| bool enabled = GUI.enabled; |
| GUI.enabled = true; |
| expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); |
| r.width -= 30; |
| EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); |
| GUI.enabled = enabled; |
|
|
| EditorGUI.indentLevel += 1; |
| EditorGUI.BeginDisabledGroup(false); |
|
|
| return expanded; |
| } |
|
|
| protected bool BeginPanel(string panel, ShaderFeature feature, bool expanded, bool readState = true) |
| { |
| EditorGUI.indentLevel = 0; |
|
|
| if (readState) |
| { |
| feature.ReadState(m_Material); |
| } |
|
|
| EditorGUI.BeginChangeCheck(); |
|
|
| EditorGUILayout.BeginVertical(EditorStyles.helpBox); |
| GUILayout.BeginHorizontal(); |
|
|
| Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 20, GUILayout.Width(20f))); |
| bool active = EditorGUI.Toggle(r, feature.Active); |
|
|
| if (EditorGUI.EndChangeCheck()) |
| { |
| m_Editor.RegisterPropertyChangeUndo(feature.undoLabel); |
| feature.SetActive(active, m_Material); |
| } |
|
|
| r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); |
| r.width += 6; |
|
|
| bool enabled = GUI.enabled; |
| GUI.enabled = true; |
| expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); |
| r.width -= 10; |
| EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); |
| GUI.enabled = enabled; |
|
|
| GUILayout.EndHorizontal(); |
|
|
| EditorGUI.indentLevel += 1; |
| EditorGUI.BeginDisabledGroup(!active); |
|
|
| return expanded; |
| } |
|
|
| public void EndPanel() |
| { |
| EditorGUI.EndDisabledGroup(); |
| EditorGUI.indentLevel -= 1; |
| EditorGUILayout.EndVertical(); |
| } |
|
|
| MaterialProperty BeginProperty(string name) |
| { |
| MaterialProperty property = FindProperty(name, m_Properties); |
| EditorGUI.BeginChangeCheck(); |
| EditorGUI.showMixedValue = property.hasMixedValue; |
| m_Editor.BeginAnimatedCheck(Rect.zero, property); |
|
|
| return property; |
| } |
|
|
| bool EndProperty() |
| { |
| m_Editor.EndAnimatedCheck(); |
| EditorGUI.showMixedValue = false; |
| return EditorGUI.EndChangeCheck(); |
| } |
|
|
| protected void DoPopup(string name, string label, GUIContent[] options) |
| { |
| MaterialProperty property = BeginProperty(name); |
| s_TempLabel.text = label; |
| int index = EditorGUILayout.Popup(s_TempLabel, (int)property.floatValue, options); |
| if (EndProperty()) |
| { |
| property.floatValue = index; |
| } |
| } |
|
|
| protected void DoCubeMap(string name, string label) |
| { |
| DoTexture(name, label, typeof(Cubemap)); |
| } |
|
|
| protected void DoTexture2D(string name, string label, bool withTilingOffset = false, string[] speedNames = null) |
| { |
| DoTexture(name, label, typeof(Texture2D), withTilingOffset, speedNames); |
| } |
|
|
| void DoTexture(string name, string label, System.Type type, bool withTilingOffset = false, string[] speedNames = null) |
| { |
| float objFieldSize = 60f; |
| bool smallLayout = EditorGUIUtility.currentViewWidth <= 440f && (withTilingOffset || speedNames != null); |
| float controlHeight = smallLayout ? objFieldSize * 2 : objFieldSize; |
|
|
| MaterialProperty property = FindProperty(name, m_Properties); |
| m_Editor.BeginAnimatedCheck(Rect.zero, property); |
|
|
| Rect rect = EditorGUILayout.GetControlRect(true, controlHeight); |
| float totalWidth = rect.width; |
| rect.width = EditorGUIUtility.labelWidth + objFieldSize; |
| rect.height = objFieldSize; |
| s_TempLabel.text = label; |
|
|
| EditorGUI.BeginChangeCheck(); |
| Object tex = EditorGUI.ObjectField(rect, s_TempLabel, property.textureValue, type, false); |
| if (EditorGUI.EndChangeCheck()) |
| { |
| property.textureValue = tex as Texture; |
| } |
|
|
| float additionalHeight = controlHeight - objFieldSize; |
| float xOffset = smallLayout ? rect.width - objFieldSize : rect.width; |
|
|
| rect.y += additionalHeight; |
| rect.x += xOffset; |
| rect.width = totalWidth - xOffset; |
| rect.height = EditorGUIUtility.singleLineHeight; |
|
|
| if (withTilingOffset) |
| { |
| DoTilingOffset(rect, property); |
| rect.y += (rect.height + 2f) * 2f; |
| } |
|
|
| m_Editor.EndAnimatedCheck(); |
|
|
| if (speedNames != null) |
| { |
| DoUVSpeed(rect, speedNames); |
| } |
| } |
|
|
| void DoTilingOffset(Rect rect, MaterialProperty property) |
| { |
| float labelWidth = EditorGUIUtility.labelWidth; |
| int indentLevel = EditorGUI.indentLevel; |
| EditorGUI.indentLevel = 0; |
| EditorGUIUtility.labelWidth = Mathf.Min(37f, rect.width * 0.40f); |
|
|
| Vector4 vector = property.textureScaleAndOffset; |
|
|
| bool changed = false; |
| float[] values = s_TempFloats[2]; |
|
|
| s_TempLabel.text = "Tiling"; |
| Rect vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); |
| values[0] = vector.x; |
| values[1] = vector.y; |
|
|
| EditorGUI.BeginChangeCheck(); |
| EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); |
| if (EditorGUI.EndChangeCheck()) |
| { |
| vector.x = values[0]; |
| vector.y = values[1]; |
| changed = true; |
| } |
|
|
| rect.y += rect.height + 2f; |
| s_TempLabel.text = "Offset"; |
| vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); |
| values[0] = vector.z; |
| values[1] = vector.w; |
|
|
| EditorGUI.BeginChangeCheck(); |
| EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); |
| if (EditorGUI.EndChangeCheck()) |
| { |
| vector.z = values[0]; |
| vector.w = values[1]; |
| changed = true; |
| } |
|
|
| if (changed) |
| { |
| property.textureScaleAndOffset = vector; |
| } |
|
|
| EditorGUIUtility.labelWidth = labelWidth; |
| EditorGUI.indentLevel = indentLevel; |
| } |
|
|
| protected void DoUVSpeed(Rect rect, string[] names) |
| { |
| float labelWidth = EditorGUIUtility.labelWidth; |
| int indentLevel = EditorGUI.indentLevel; |
| EditorGUI.indentLevel = 0; |
| EditorGUIUtility.labelWidth = Mathf.Min(37f, rect.width * 0.40f); |
|
|
| s_TempLabel.text = "Speed"; |
| rect = EditorGUI.PrefixLabel(rect, s_TempLabel); |
|
|
| EditorGUIUtility.labelWidth = 10f; |
| rect.width = rect.width * 0.5f - 2f; |
|
|
| if (names.Length == 1) |
| { |
| DoFloat2(rect, names[0]); |
| } |
| else |
| { |
| DoFloat(rect, names[0], "X"); |
| rect.x += rect.width + 4f; |
| DoFloat(rect, names[1], "Y"); |
| } |
|
|
| EditorGUIUtility.labelWidth = labelWidth; |
| EditorGUI.indentLevel = indentLevel; |
| } |
|
|
| protected void DoToggle(string name, string label) |
| { |
| MaterialProperty property = BeginProperty(name); |
| s_TempLabel.text = label; |
| bool value = EditorGUILayout.Toggle(s_TempLabel, property.floatValue == 1f); |
| if (EndProperty()) |
| { |
| property.floatValue = value ? 1f : 0f; |
| } |
| } |
|
|
| protected void DoFloat(string name, string label) |
| { |
| MaterialProperty property = BeginProperty(name); |
| Rect rect = EditorGUILayout.GetControlRect(); |
| rect.width = EditorGUIUtility.labelWidth + 55f; |
| s_TempLabel.text = label; |
| float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); |
| if (EndProperty()) |
| { |
| property.floatValue = value; |
| } |
| } |
|
|
| protected void DoColor(string name, string label) |
| { |
| MaterialProperty property = BeginProperty(name); |
| s_TempLabel.text = label; |
| Color value = EditorGUI.ColorField(EditorGUILayout.GetControlRect(), s_TempLabel, property.colorValue, false, true, true); |
| if (EndProperty()) |
| { |
| property.colorValue = value; |
| } |
| } |
|
|
| void DoFloat(Rect rect, string name, string label) |
| { |
| MaterialProperty property = BeginProperty(name); |
| s_TempLabel.text = label; |
| float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); |
| if (EndProperty()) |
| { |
| property.floatValue = value; |
| } |
| } |
|
|
| void DoFloat2(Rect rect, string name) |
| { |
| MaterialProperty property = BeginProperty(name); |
|
|
| float x = EditorGUI.FloatField(rect, "X", property.vectorValue.x); |
| rect.x += rect.width + 4f; |
| float y = EditorGUI.FloatField(rect, "Y", property.vectorValue.y); |
|
|
| if (EndProperty()) |
| { |
| property.vectorValue = new Vector2(x, y); |
| } |
| } |
|
|
| protected void DoSlider(string name, string label) |
| { |
| MaterialProperty property = BeginProperty(name); |
| Vector2 range = property.rangeLimits; |
| s_TempLabel.text = label; |
| float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); |
| if (EndProperty()) |
| { |
| property.floatValue = value; |
| } |
| } |
|
|
| protected void DoSlider(string propertyName, string propertyField, string label) |
| { |
| MaterialProperty property = BeginProperty(propertyName); |
| Vector2 range = property.rangeLimits; |
| s_TempLabel.text = label; |
|
|
| Vector4 value = property.vectorValue; |
|
|
| switch (propertyField) |
| { |
| case "X": |
| value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); |
| break; |
| case "Y": |
| value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); |
| break; |
| case "Z": |
| value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); |
| break; |
| case "W": |
| value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); |
| break; |
| } |
|
|
| if (EndProperty()) |
| { |
| property.vectorValue = value; |
| } |
| } |
|
|
| protected void DoVector2(string name, string label) |
| { |
| MaterialProperty property = BeginProperty(name); |
| s_TempLabel.text = label; |
| Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); |
| if (EndProperty()) |
| { |
| property.vectorValue = value; |
| } |
| } |
|
|
| protected void DoVector3(string name, string label) |
| { |
| MaterialProperty property = BeginProperty(name); |
| s_TempLabel.text = label; |
| Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); |
| if (EndProperty()) |
| { |
| property.vectorValue = value; |
| } |
| } |
|
|
| protected void DoVector(string name, string label, GUIContent[] subLabels) |
| { |
| MaterialProperty property = BeginProperty(name); |
| Rect rect = EditorGUILayout.GetControlRect(); |
| s_TempLabel.text = label; |
| rect = EditorGUI.PrefixLabel(rect, s_TempLabel); |
| Vector4 vector = property.vectorValue; |
|
|
| float[] values = s_TempFloats[subLabels.Length]; |
| for (int i = 0; i < subLabels.Length; i++) |
| { |
| values[i] = vector[i]; |
| } |
|
|
| EditorGUI.MultiFloatField(rect, subLabels, values); |
| if (EndProperty()) |
| { |
| for (int i = 0; i < subLabels.Length; i++) |
| { |
| vector[i] = values[i]; |
| } |
|
|
| property.vectorValue = vector; |
| } |
| } |
|
|
| void DoDragAndDropBegin() |
| { |
| m_DragAndDropMinY = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)).y; |
| } |
|
|
| void DoDragAndDropEnd() |
| { |
| Rect rect = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); |
| Event evt = Event.current; |
| if (evt.type == EventType.DragUpdated) |
| { |
| DragAndDrop.visualMode = DragAndDropVisualMode.Generic; |
| evt.Use(); |
| } |
| else if ( |
| evt.type == EventType.DragPerform && |
| Rect.MinMaxRect(rect.xMin, m_DragAndDropMinY, rect.xMax, rect.yMax).Contains(evt.mousePosition) |
| ) |
| { |
| DragAndDrop.AcceptDrag(); |
| evt.Use(); |
| Material droppedMaterial = DragAndDrop.objectReferences[0] as Material; |
| if (droppedMaterial && droppedMaterial != m_Material) |
| { |
| PerformDrop(droppedMaterial); |
| } |
| } |
| } |
|
|
| void PerformDrop(Material droppedMaterial) |
| { |
| Texture droppedTex = droppedMaterial.GetTexture(ShaderUtilities.ID_MainTex); |
| if (!droppedTex) |
| { |
| return; |
| } |
|
|
| Texture currentTex = m_Material.GetTexture(ShaderUtilities.ID_MainTex); |
| TMP_FontAsset requiredFontAsset = null; |
| if (droppedTex != currentTex) |
| { |
| requiredFontAsset = TMP_EditorUtility.FindMatchingFontAsset(droppedMaterial); |
| if (!requiredFontAsset) |
| { |
| return; |
| } |
| } |
|
|
| foreach (GameObject o in Selection.gameObjects) |
| { |
| if (requiredFontAsset) |
| { |
| TMP_Text textComponent = o.GetComponent<TMP_Text>(); |
| if (textComponent) |
| { |
| Undo.RecordObject(textComponent, "Font Asset Change"); |
| textComponent.font = requiredFontAsset; |
| } |
| } |
|
|
| TMPro_EventManager.ON_DRAG_AND_DROP_MATERIAL_CHANGED(o, m_Material, droppedMaterial); |
| EditorUtility.SetDirty(o); |
| } |
| } |
| } |
| } |
|
|