A game about forced loneliness, made by TACStudios
at master 697 lines 24 kB view raw
1using UnityEngine; 2using UnityEditor; 3 4namespace TMPro.EditorUtilities 5{ 6 /// <summary>Base class for TextMesh Pro shader GUIs.</summary> 7 public abstract class TMP_BaseShaderGUI : ShaderGUI 8 { 9 /// <summary>Representation of a #pragma shader_feature.</summary> 10 /// <description>It is assumed that the first feature option is for no keyword (underscores).</description> 11 protected class ShaderFeature 12 { 13 public string undoLabel; 14 15 public GUIContent label; 16 17 /// <summary>The keyword labels, for display. Include the no-keyword as the first option.</summary> 18 public GUIContent[] keywordLabels; 19 20 /// <summary>The shader keywords. Exclude the no-keyword option.</summary> 21 public string[] keywords; 22 23 int m_State; 24 25 public bool Active 26 { 27 get { return m_State >= 0; } 28 } 29 30 public int State 31 { 32 get { return m_State; } 33 } 34 35 public void ReadState(Material material) 36 { 37 for (int i = 0; i < keywords.Length; i++) 38 { 39 if (material.IsKeywordEnabled(keywords[i])) 40 { 41 m_State = i; 42 return; 43 } 44 } 45 46 m_State = -1; 47 } 48 49 public void SetActive(bool active, Material material) 50 { 51 m_State = active ? 0 : -1; 52 SetStateKeywords(material); 53 } 54 55 public void DoPopup(MaterialEditor editor, Material material) 56 { 57 EditorGUI.BeginChangeCheck(); 58 int selection = EditorGUILayout.Popup(label, m_State + 1, keywordLabels); 59 if (EditorGUI.EndChangeCheck()) 60 { 61 m_State = selection - 1; 62 editor.RegisterPropertyChangeUndo(undoLabel); 63 SetStateKeywords(material); 64 } 65 } 66 67 void SetStateKeywords(Material material) 68 { 69 for (int i = 0; i < keywords.Length; i++) 70 { 71 if (i == m_State) 72 { 73 material.EnableKeyword(keywords[i]); 74 } 75 else 76 { 77 material.DisableKeyword(keywords[i]); 78 } 79 } 80 } 81 } 82 83 static GUIContent s_TempLabel = new GUIContent(); 84 85 protected static bool s_DebugExtended; 86 87 static int s_UndoRedoCount, s_LastSeenUndoRedoCount; 88 89 static float[][] s_TempFloats = 90 { 91 null, new float[1], new float[2], new float[3], new float[4] 92 }; 93 94 protected static GUIContent[] s_XywhVectorLabels = 95 { 96 new GUIContent("X"), 97 new GUIContent("Y"), 98 new GUIContent("W", "Width"), 99 new GUIContent("H", "Height") 100 }; 101 102 protected static GUIContent[] s_LbrtVectorLabels = 103 { 104 new GUIContent("L", "Left"), 105 new GUIContent("B", "Bottom"), 106 new GUIContent("R", "Right"), 107 new GUIContent("T", "Top") 108 }; 109 110 protected static GUIContent[] s_CullingTypeLabels = 111 { 112 new GUIContent("Off"), 113 new GUIContent("Front"), 114 new GUIContent("Back") 115 }; 116 117 static TMP_BaseShaderGUI() 118 { 119 // Keep track of how many undo/redo events happened. 120 Undo.undoRedoPerformed += () => s_UndoRedoCount += 1; 121 } 122 123 bool m_IsNewGUI = true; 124 125 float m_DragAndDropMinY; 126 127 protected MaterialEditor m_Editor; 128 129 protected Material m_Material; 130 private int m_ShaderID; 131 132 protected MaterialProperty[] m_Properties; 133 134 void PrepareGUI() 135 { 136 m_IsNewGUI = false; 137 ShaderUtilities.GetShaderPropertyIDs(); 138 139 // New GUI just got constructed. This happens in response to a selection, 140 // but also after undo/redo events. 141 if (s_LastSeenUndoRedoCount != s_UndoRedoCount) 142 { 143 // There's been at least one undo/redo since the last time this GUI got constructed. 144 // Maybe the undo/redo was for this material? Assume that is was. 145 TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); 146 } 147 148 s_LastSeenUndoRedoCount = s_UndoRedoCount; 149 } 150 151 public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] properties) 152 { 153 m_Editor = materialEditor; 154 m_Material = materialEditor.target as Material; 155 this.m_Properties = properties; 156 157 if (m_IsNewGUI) 158 PrepareGUI(); 159 160 DoDragAndDropBegin(); 161 EditorGUI.BeginChangeCheck(); 162 DoGUI(); 163 if (EditorGUI.EndChangeCheck()) 164 { 165 TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); 166 } 167 168 DoDragAndDropEnd(); 169 } 170 171 public override void AssignNewShaderToMaterial(Material material, Shader oldShader, Shader newShader) 172 { 173 base.AssignNewShaderToMaterial(material, oldShader, newShader); 174 175 TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, material); 176 } 177 178 /// <summary>Override this method to create the specific shader GUI.</summary> 179 protected abstract void DoGUI(); 180 181 static string[] s_PanelStateLabel = new string[] { "\t- <i>Click to collapse</i> -", "\t- <i>Click to expand</i> -" }; 182 183 protected bool BeginPanel(string panel, bool expanded) 184 { 185 EditorGUI.indentLevel = 0; 186 187 EditorGUILayout.BeginVertical(EditorStyles.helpBox); 188 Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); 189 r.x += 20; 190 r.width += 6; 191 192 bool enabled = GUI.enabled; 193 GUI.enabled = true; 194 expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); 195 r.width -= 30; 196 EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); 197 GUI.enabled = enabled; 198 199 EditorGUI.indentLevel += 1; 200 EditorGUI.BeginDisabledGroup(false); 201 202 return expanded; 203 } 204 205 protected bool BeginPanel(string panel, ShaderFeature feature, bool expanded, bool readState = true) 206 { 207 EditorGUI.indentLevel = 0; 208 209 if (readState) 210 { 211 feature.ReadState(m_Material); 212 } 213 214 EditorGUI.BeginChangeCheck(); 215 216 EditorGUILayout.BeginVertical(EditorStyles.helpBox); 217 GUILayout.BeginHorizontal(); 218 219 Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 20, GUILayout.Width(20f))); 220 bool active = EditorGUI.Toggle(r, feature.Active); 221 222 if (EditorGUI.EndChangeCheck()) 223 { 224 m_Editor.RegisterPropertyChangeUndo(feature.undoLabel); 225 feature.SetActive(active, m_Material); 226 } 227 228 r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); 229 r.width += 6; 230 231 bool enabled = GUI.enabled; 232 GUI.enabled = true; 233 expanded = TMP_EditorUtility.EditorToggle(r, expanded, new GUIContent(panel), TMP_UIStyleManager.panelTitle); 234 r.width -= 10; 235 EditorGUI.LabelField(r, new GUIContent(expanded ? s_PanelStateLabel[0] : s_PanelStateLabel[1]), TMP_UIStyleManager.rightLabel); 236 GUI.enabled = enabled; 237 238 GUILayout.EndHorizontal(); 239 240 EditorGUI.indentLevel += 1; 241 EditorGUI.BeginDisabledGroup(!active); 242 243 return expanded; 244 } 245 246 public void EndPanel() 247 { 248 EditorGUI.EndDisabledGroup(); 249 EditorGUI.indentLevel -= 1; 250 EditorGUILayout.EndVertical(); 251 } 252 253 MaterialProperty BeginProperty(string name) 254 { 255 MaterialProperty property = FindProperty(name, m_Properties); 256 EditorGUI.BeginChangeCheck(); 257 EditorGUI.showMixedValue = property.hasMixedValue; 258 m_Editor.BeginAnimatedCheck(Rect.zero, property); 259 260 return property; 261 } 262 263 bool EndProperty() 264 { 265 m_Editor.EndAnimatedCheck(); 266 EditorGUI.showMixedValue = false; 267 return EditorGUI.EndChangeCheck(); 268 } 269 270 protected void DoPopup(string name, string label, GUIContent[] options) 271 { 272 MaterialProperty property = BeginProperty(name); 273 s_TempLabel.text = label; 274 int index = EditorGUILayout.Popup(s_TempLabel, (int)property.floatValue, options); 275 if (EndProperty()) 276 { 277 property.floatValue = index; 278 } 279 } 280 281 protected void DoCubeMap(string name, string label) 282 { 283 DoTexture(name, label, typeof(Cubemap)); 284 } 285 286 protected void DoTexture2D(string name, string label, bool withTilingOffset = false, string[] speedNames = null) 287 { 288 DoTexture(name, label, typeof(Texture2D), withTilingOffset, speedNames); 289 } 290 291 void DoTexture(string name, string label, System.Type type, bool withTilingOffset = false, string[] speedNames = null) 292 { 293 float objFieldSize = 60f; 294 bool smallLayout = EditorGUIUtility.currentViewWidth <= 330f && (withTilingOffset || speedNames != null); 295 float controlHeight = smallLayout ? objFieldSize * 2 : objFieldSize; 296 297 MaterialProperty property = FindProperty(name, m_Properties); 298 m_Editor.BeginAnimatedCheck(Rect.zero, property); 299 300 Rect rect = EditorGUILayout.GetControlRect(true, controlHeight); 301 float totalWidth = rect.width; 302 rect.width = EditorGUIUtility.labelWidth + objFieldSize; 303 rect.height = objFieldSize; 304 s_TempLabel.text = label; 305 306 EditorGUI.BeginChangeCheck(); 307 Object tex = EditorGUI.ObjectField(rect, s_TempLabel, property.textureValue, type, false); 308 if (EditorGUI.EndChangeCheck()) 309 { 310 property.textureValue = tex as Texture; 311 } 312 313 float additionalHeight = controlHeight - objFieldSize; 314 float xOffset = smallLayout ? rect.width - objFieldSize : rect.width; 315 316 rect.y += additionalHeight; 317 rect.x += xOffset; 318 rect.width = totalWidth - xOffset; 319 rect.height = EditorGUIUtility.singleLineHeight; 320 321 if (withTilingOffset) 322 { 323 DoTilingOffset(rect, property); 324 rect.y += (rect.height + 2f) * 2f; 325 } 326 327 m_Editor.EndAnimatedCheck(); 328 329 if (speedNames != null) 330 { 331 DoUVSpeed(rect, speedNames); 332 } 333 } 334 335 void DoTilingOffset(Rect rect, MaterialProperty property) 336 { 337 float labelWidth = EditorGUIUtility.labelWidth; 338 int indentLevel = EditorGUI.indentLevel; 339 EditorGUI.indentLevel = 0; 340 EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); 341 342 Vector4 vector = property.textureScaleAndOffset; 343 344 bool changed = false; 345 float[] values = s_TempFloats[2]; 346 347 s_TempLabel.text = "Tiling"; 348 Rect vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); 349 values[0] = vector.x; 350 values[1] = vector.y; 351 352 EditorGUI.BeginChangeCheck(); 353 EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); 354 if (EditorGUI.EndChangeCheck()) 355 { 356 vector.x = values[0]; 357 vector.y = values[1]; 358 changed = true; 359 } 360 361 rect.y += rect.height + 2f; 362 s_TempLabel.text = "Offset"; 363 vectorRect = EditorGUI.PrefixLabel(rect, s_TempLabel); 364 values[0] = vector.z; 365 values[1] = vector.w; 366 367 EditorGUI.BeginChangeCheck(); 368 EditorGUI.MultiFloatField(vectorRect, s_XywhVectorLabels, values); 369 if (EditorGUI.EndChangeCheck()) 370 { 371 vector.z = values[0]; 372 vector.w = values[1]; 373 changed = true; 374 } 375 376 if (changed) 377 { 378 property.textureScaleAndOffset = vector; 379 } 380 381 EditorGUIUtility.labelWidth = labelWidth; 382 EditorGUI.indentLevel = indentLevel; 383 } 384 385 protected void DoUVSpeed(Rect rect, string[] names) 386 { 387 float labelWidth = EditorGUIUtility.labelWidth; 388 int indentLevel = EditorGUI.indentLevel; 389 EditorGUI.indentLevel = 0; 390 EditorGUIUtility.labelWidth = Mathf.Min(40f, rect.width * 0.40f); 391 392 s_TempLabel.text = "Speed"; 393 rect = EditorGUI.PrefixLabel(rect, s_TempLabel); 394 395 EditorGUIUtility.labelWidth = 10f; 396 rect.width = rect.width * 0.5f - 2f; 397 398 if (names.Length == 1) 399 { 400 DoFloat2(rect, names[0]); 401 } 402 else 403 { 404 DoFloat(rect, names[0], "X"); 405 rect.x += rect.width + 4f; 406 DoFloat(rect, names[1], "Y"); 407 } 408 409 EditorGUIUtility.labelWidth = labelWidth; 410 EditorGUI.indentLevel = indentLevel; 411 } 412 413 protected void DoToggle(string name, string label) 414 { 415 MaterialProperty property = BeginProperty(name); 416 s_TempLabel.text = label; 417 bool value = EditorGUILayout.Toggle(s_TempLabel, property.floatValue == 1f); 418 if (EndProperty()) 419 { 420 property.floatValue = value ? 1f : 0f; 421 } 422 } 423 424 protected void DoFloat(string name, string label) 425 { 426 MaterialProperty property = BeginProperty(name); 427 Rect rect = EditorGUILayout.GetControlRect(); 428 rect.width = EditorGUIUtility.labelWidth + 55f; 429 s_TempLabel.text = label; 430 float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); 431 if (EndProperty()) 432 { 433 property.floatValue = value; 434 } 435 } 436 437 protected void DoColor(string name, string label) 438 { 439 MaterialProperty property = BeginProperty(name); 440 s_TempLabel.text = label; 441 Color value = EditorGUI.ColorField(EditorGUILayout.GetControlRect(), s_TempLabel, property.colorValue, false, true, false); 442 if (EndProperty()) 443 { 444 property.colorValue = value; 445 } 446 } 447 448 void DoFloat(Rect rect, string name, string label) 449 { 450 MaterialProperty property = BeginProperty(name); 451 s_TempLabel.text = label; 452 float value = EditorGUI.FloatField(rect, s_TempLabel, property.floatValue); 453 if (EndProperty()) 454 { 455 property.floatValue = value; 456 } 457 } 458 459 void DoFloat2(Rect rect, string name) 460 { 461 MaterialProperty property = BeginProperty(name); 462 463 float x = EditorGUI.FloatField(rect, "X", property.vectorValue.x); 464 rect.x += rect.width + 4f; 465 float y = EditorGUI.FloatField(rect, "Y", property.vectorValue.y); 466 467 if (EndProperty()) 468 { 469 property.vectorValue = new Vector2(x, y); 470 } 471 } 472 473 protected void DoOffset(string name, string label) 474 { 475 MaterialProperty property = BeginProperty(name); 476 s_TempLabel.text = label; 477 Vector2 value = EditorGUI.Vector2Field(EditorGUILayout.GetControlRect(), s_TempLabel, property.vectorValue); 478 if (EndProperty()) 479 { 480 property.vectorValue = value; 481 } 482 } 483 484 protected void DoSlider(string name, string label) 485 { 486 MaterialProperty property = BeginProperty(name); 487 Vector2 range = property.rangeLimits; 488 s_TempLabel.text = label; 489 float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); 490 if (EndProperty()) 491 { 492 property.floatValue = value; 493 } 494 } 495 496 protected void DoSlider(string name, Vector2 range, string label) 497 { 498 MaterialProperty property = BeginProperty(name); 499 s_TempLabel.text = label; 500 float value = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, property.floatValue, range.x, range.y); 501 if (EndProperty()) 502 { 503 property.floatValue = value; 504 } 505 } 506 507 protected void DoSlider(string propertyName, string propertyField, string label) 508 { 509 MaterialProperty property = BeginProperty(propertyName); 510 Vector2 range = property.rangeLimits; 511 s_TempLabel.text = label; 512 513 Vector4 value = property.vectorValue; 514 515 switch (propertyField) 516 { 517 case "X": 518 value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); 519 break; 520 case "Y": 521 value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); 522 break; 523 case "Z": 524 value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); 525 break; 526 case "W": 527 value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); 528 break; 529 } 530 531 if (EndProperty()) 532 { 533 property.vectorValue = value; 534 } 535 } 536 537 protected void DoSlider(string propertyName, string propertyField, Vector2 range, string label) 538 { 539 MaterialProperty property = BeginProperty(propertyName); 540 s_TempLabel.text = label; 541 542 Vector4 value = property.vectorValue; 543 544 switch (propertyField) 545 { 546 case "X": 547 value.x = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.x, range.x, range.y); 548 break; 549 case "Y": 550 value.y = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.y, range.x, range.y); 551 break; 552 case "Z": 553 value.z = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.z, range.x, range.y); 554 break; 555 case "W": 556 value.w = EditorGUI.Slider(EditorGUILayout.GetControlRect(), s_TempLabel, value.w, range.x, range.y); 557 break; 558 } 559 560 if (EndProperty()) 561 { 562 property.vectorValue = value; 563 } 564 } 565 566 protected void DoVector2(string name, string label) 567 { 568 MaterialProperty property = BeginProperty(name); 569 s_TempLabel.text = label; 570 Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); 571 if (EndProperty()) 572 { 573 property.vectorValue = value; 574 } 575 } 576 577 protected void DoVector3(string name, string label) 578 { 579 MaterialProperty property = BeginProperty(name); 580 s_TempLabel.text = label; 581 Vector4 value = EditorGUILayout.Vector3Field(s_TempLabel, property.vectorValue); 582 if (EndProperty()) 583 { 584 property.vectorValue = value; 585 } 586 } 587 588 protected void DoVector(string name, string label, GUIContent[] subLabels) 589 { 590 MaterialProperty property = BeginProperty(name); 591 Rect rect = EditorGUILayout.GetControlRect(); 592 s_TempLabel.text = label; 593 rect = EditorGUI.PrefixLabel(rect, s_TempLabel); 594 Vector4 vector = property.vectorValue; 595 596 float[] values = s_TempFloats[subLabels.Length]; 597 for (int i = 0; i < subLabels.Length; i++) 598 { 599 values[i] = vector[i]; 600 } 601 602 EditorGUI.MultiFloatField(rect, subLabels, values); 603 if (EndProperty()) 604 { 605 for (int i = 0; i < subLabels.Length; i++) 606 { 607 vector[i] = values[i]; 608 } 609 610 property.vectorValue = vector; 611 } 612 } 613 614 bool IsNewShader() 615 { 616 if (m_Material == null) 617 return false; 618 619 int currentShaderID = m_Material.shader.GetInstanceID(); 620 621 if (m_ShaderID == currentShaderID) 622 return false; 623 624 m_ShaderID = currentShaderID; 625 626 return true; 627 } 628 629 void DoDragAndDropBegin() 630 { 631 m_DragAndDropMinY = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)).y; 632 } 633 634 void DoDragAndDropEnd() 635 { 636 Rect rect = GUILayoutUtility.GetRect(0f, 0f, GUILayout.ExpandWidth(true)); 637 Event evt = Event.current; 638 639 if (evt.type == EventType.DragUpdated) 640 { 641 DragAndDrop.visualMode = DragAndDropVisualMode.Generic; 642 evt.Use(); 643 } 644 else if (evt.type == EventType.DragPerform && Rect.MinMaxRect(rect.xMin, m_DragAndDropMinY, rect.xMax, rect.yMax).Contains(evt.mousePosition)) 645 { 646 DragAndDrop.AcceptDrag(); 647 evt.Use(); 648 Material droppedMaterial = DragAndDrop.objectReferences[0] as Material; 649 if (droppedMaterial && droppedMaterial != m_Material) 650 { 651 PerformDrop(droppedMaterial); 652 } 653 } 654 else if (evt.type == EventType.DragExited) 655 { 656 if (IsNewShader()) 657 TMPro_EventManager.ON_MATERIAL_PROPERTY_CHANGED(true, m_Material); 658 } 659 } 660 661 void PerformDrop(Material droppedMaterial) 662 { 663 Texture droppedTex = droppedMaterial.GetTexture(ShaderUtilities.ID_MainTex); 664 if (!droppedTex) 665 { 666 return; 667 } 668 669 Texture currentTex = m_Material.GetTexture(ShaderUtilities.ID_MainTex); 670 TMP_FontAsset requiredFontAsset = null; 671 if (droppedTex != currentTex) 672 { 673 requiredFontAsset = TMP_EditorUtility.FindMatchingFontAsset(droppedMaterial); 674 if (!requiredFontAsset) 675 { 676 return; 677 } 678 } 679 680 foreach (GameObject o in Selection.gameObjects) 681 { 682 if (requiredFontAsset) 683 { 684 TMP_Text textComponent = o.GetComponent<TMP_Text>(); 685 if (textComponent) 686 { 687 Undo.RecordObject(textComponent, "Font Asset Change"); 688 textComponent.font = requiredFontAsset; 689 } 690 } 691 692 TMPro_EventManager.ON_DRAG_AND_DROP_MATERIAL_CHANGED(o, m_Material, droppedMaterial); 693 EditorUtility.SetDirty(o); 694 } 695 } 696 } 697}