gerberz

ter

Feb 21st, 2019
119
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 1.51 KB | None | 0 0
  1. C:\Windows\System32\cmd.exe /c "set LAUNCHER_PATH=dotnet&&set LAUNCHER_ARGS=.\bin\Debug\netcoreapp2.2\mysite.dll&& C:\iisexpress10_64\iisexpress.exe /path:C:\dev\mysite\web /port:8083 /trace:error"
  2.  
  3. C:\Windows\System32\cmd.exe /c "cd C:\Program Files (x86)\IIS Express\&& iisexpress.exe /path:C:\dev\mysite\web /port:8084 /trace:error"
  4.  
  5.  
  6. (?:(?<!^)\G|((?:(?<!^)\G"|^)[^"]*"))(?:[^"]|(?<=[^\\]|[^\\]\\|[^\\]\\{3}|[^\\]\\{5})")
  7.  
  8. have to reverse string to use this:
  9. (?:(?<!^)\G|((?:(?<!^)\G"|^)[^"]*"))(?:[^"]|"(?=\\(?:\\{2})*(?!\\)))
  10.  
  11. loop through this to remove bottom-level brackets:
  12. ^((?:[^{}"']|"(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*'|\{(?!(?:[^{}"']|"(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*')*+\}))*+)\{(?:[^{}"']|"(?:[^\\"]|\\.)*"|'(?:[^\\']|\\.)*')*+\}
  13.  
  14. https://medium.com/planet-stories/a-gentle-introduction-to-gdal-part-4-working-with-satellite-data-d3835b5e2971
  15.  
  16. gdalinfo -mm canyon.img
  17.  
  18. gdal_translate -ot UInt16 -scale 757.586 2711.519 0 65535 -of ENVI canyon.img canyon.raw
  19.  
  20.  
  21.  
  22.  
  23.  
  24. @{
  25.  
  26.  
  27.  
  28.        var str = "{adsfasdf \"asdf{ }asd\"{asdf\"asdfas{}\"{}asdfasdf}}";
  29.  
  30.         var c = 0;
  31.         string Key;
  32.         Match TheMatch;
  33.         var Pattern = "^((?>(?:[^{}\\[\\]\"']|\"(?:[^\\\\\"]|\\\\.)*\"|'(?:[^\\\\']|\\\\.)*'|\\{(?!(?>(?:[^{}\\[\\]\"']|\"(?:[^\\\\\"]|\\\\.)*\"|'(?:[^\\\\']|\\\\.)*')*)\\})|\\[(?!(?>(?:[^{}\\[\\]\"']|\"(?:[^\\\\\"]|\\\\.)*\"|'(?:[^\\\\']|\\\\.)*')*)\\]))*))(\\{(?>(?:[^{}\\[\\]\"']|\"(?:[^\\\\\"]|\\\\.)*\"|'(?:[^\\\\']|\\\\.)*')*)\\}|\\[(?>(?:[^{}\\[\\]\"']|\"(?:[^\\\\\"]|\\\\.)*\"|'(?:[^\\\\']|\\\\.)*')*)\\])(.*)$";
  34.         var TheRegex = new Regex(Pattern, RegexOptions.Singleline);
  35.         var NestedObjects = new StringDictionary();
  36.         while ((TheMatch = TheRegex.Match(str)).Success)
  37.         {
  38.             Key = "@" + c;
  39.             NestedObjects.Add(Key, TheMatch.Groups[2].Value);
  40.             str = TheMatch.Result("$1" + Key + "$3");
  41.             c++;
  42.         }
  43.         <div style="background-color:aquamarine;padding:10px;">
  44.             @str
  45.         </div>
  46.         <div>
  47.             @TheRegex.Replace("{adsfasdf \"asdf{ }asd\"{asdf\"asdfas{}\"{}asdfasdf}}", "$1@0")
  48.         </div>
  49.  
  50.         <div>
  51.             @JsonTools.get_json_depth("{{[{asdfasdf}]{{{{asdfsdaf}}}}}}")
  52.         </div>
  53.  
  54. }
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61. using System;
  62. using System.IO;
  63. using System.Collections;
  64. using System.Collections.Generic;
  65. using System.Collections.Specialized;
  66. using System.Runtime.Serialization.Formatters.Binary;
  67. using System.Linq;
  68. using System.Linq.Expressions;
  69. using System.Text.RegularExpressions;
  70. using UnityEditor;
  71. using UnityEngine;
  72. using UnityEngine.SceneManagement;
  73. using System.Reflection;
  74. using static TerraLab.GenericHelpers;
  75. using static TerraLab.TerraLabHelpers;
  76.  
  77. namespace TerraLab
  78. {
  79.     public class TerraLab : ScriptableObject
  80.     {
  81.         public string Prop1;
  82.         [HideInInspector]
  83.         public string Params;
  84.         private static TerraLab TheInstance;
  85.         private static readonly string TerraLabFolder = "Assets/Editor/TerraLab";
  86.         private static readonly string AssetPath = TerraLabFolder + "/TerraLabAssets.asset";
  87.         [MenuItem("Terrain/TerraLabNEW")]
  88.         private static TerraLab Init()
  89.         {
  90.             if (TheInstance == null && (TheInstance = AssetDatabase.LoadMainAssetAtPath(AssetPath) as TerraLab) == null)
  91.             {
  92.                 var FullAssetPath = Regex.Replace(Application.dataPath, "Assets$", "") + AssetPath;
  93.                 if (File.Exists(FullAssetPath))
  94.                 {
  95.                     var FileName = Regex.Replace(AssetPath, ".*/", "");
  96.                     throw new Exception("No object could be loaded from " + FileName + ". Try restarting Unity.");
  97.                 }
  98.                 TheInstance = CreateInstance<TerraLab>();
  99.                 //set hideFlags = HideFlags.None or else you get an error
  100.                 //https://issuetracker.unity3d.com/issues/creating-asset-through-createasset-with-hideflags-dot-hideanddontsave-throws-error
  101.                 TheInstance.hideFlags = HideFlags.None;
  102.                 AssetDatabase.CreateAsset(TheInstance, AssetPath);
  103.             }
  104.             EditorWindow.GetWindow<TerraLabWindow>("TerraLab", typeof(Editor).Assembly.GetType("UnityEditor.InspectorWindow"));
  105.             return TheInstance;
  106.         }
  107.         private class TerraLabWindow : EditorWindow
  108.         {
  109.             private string ScriptPath;
  110.             private AssetBucket TheAssetBucket;
  111.             private LayoutCSS TheLayout;
  112.             private bool ScriptInRightPlace = false;
  113.             //##########################################
  114.             private bool SelectedTerrainHasNoData = false;
  115.             private bool SelectedLayerCountsAreDifferent = false;
  116.             private System.Random RNG = new System.Random();
  117.             private int RandomInt32 { get { return RNG.Next(1000000000, 2147483647); } }
  118.             private Terrain[] TerrainsInScene = new Terrain[0];
  119.             private Terrain[] SelectedTerrains = new Terrain[0];
  120.             void OnEnable()
  121.             {
  122.                 //OnEnable is called by the object's constructor, so many
  123.                 //object properties may not be available from inside here
  124.                 //try and do post-instantiation config in the Init method
  125.                 Init();
  126.                 autoRepaintOnSceneChange = true;
  127.                 TheLayout = new LayoutCSS(this);
  128.                 TheAssetBucket = new AssetBucket(TheInstance);
  129.                 ScriptPath = AssetDatabase.GetAssetPath(MonoScript.FromScriptableObject(TheInstance));
  130.                 ScriptInRightPlace = Regex.IsMatch(ScriptPath, "^" + TerraLabFolder + "/TerraLab\\.cs$", RegexOptions.IgnoreCase);
  131.                 OnSelectionChange();
  132.             }
  133.             private void OnFocus()
  134.             {
  135.                 //OnSelectionChange();
  136.                 //Debug.Log("OnFocus()");
  137.             }
  138.             private void OnHierarchyChange()
  139.             {
  140.                 OnSelectionChange();
  141.                 Debug.Log("OnHierarchyChange()");
  142.             }
  143.             private void OnProjectChange()
  144.             {
  145.                 OnSelectionChange();
  146.                 Debug.Log("OnProjectChange()");
  147.             }
  148.             private void OnValidate()
  149.             {
  150.                 OnSelectionChange();
  151.                 Debug.Log("OnValidate()");
  152.             }
  153.             private void OnSelectionChange()
  154.             {
  155.                 //##########################################
  156.                 //update the SelectedTerrains variable
  157.                 Terrain TheTerrain;
  158.                 TerrainData TData;
  159.                 var TerrainList = new List<Terrain>();
  160.                 SelectedTerrainHasNoData = false;
  161.                 //###############
  162.                 SelectedLayerCountsAreDifferent = false;
  163.                 TerrainLayer[] LastTerrainLayers = null;
  164.                 //###############
  165.                 var i = 0;
  166.                 foreach (var TheObject in Selection.objects)
  167.                 {
  168.                     var TheGameObject = TheObject as GameObject;
  169.                     if (TheGameObject != null)
  170.                     {
  171.                         TheTerrain = TheGameObject.GetComponent<Terrain>();
  172.                         if (TheTerrain != null)
  173.                         {
  174.                             if (TheTerrain.terrainData == null)
  175.                             {
  176.                                 SelectedTerrainHasNoData = true;
  177.                             }
  178.                             else
  179.                             {
  180.                                 TData = TheTerrain.terrainData;
  181.                                 if (i == 0)
  182.                                 {
  183.                                     LastTerrainLayers = TData.terrainLayers;
  184.                                 }
  185.                                 if (LastTerrainLayers?.Length != TData.terrainLayers?.Length)
  186.                                 {
  187.                                     SelectedLayerCountsAreDifferent = true;
  188.                                 }
  189.                                 LastTerrainLayers = TData.terrainLayers;
  190.                                 TerrainList.Add(TheTerrain);
  191.                                 i++;
  192.                             }
  193.                         }
  194.                     }
  195.                 }
  196.                 SelectedTerrains = TerrainList.ToArray();
  197.                 //##########################################
  198.                 //update the TerrainsInScene variable
  199.                 TerrainList = new List<Terrain>();
  200.                 var SceneGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
  201.                 foreach (var TheGameObject in SceneGameObjects)
  202.                 {
  203.                     TheTerrain = TheGameObject.GetComponent<Terrain>();
  204.                     if (TheTerrain != null)
  205.                     {
  206.                         if (TheTerrain.terrainData != null)
  207.                         {
  208.                             TerrainList.Add(TheTerrain);
  209.                         }
  210.                     }
  211.                 }
  212.                 TerrainsInScene = TerrainList.ToArray();
  213.                 //##########################################
  214.                 RefreshLayersPanel(SelectedTerrains);
  215.                 //##########################################
  216.                 Repaint();
  217.             }
  218.             //##############################################################################
  219.             //##############################################################################
  220.             private static class MainPanel
  221.             {
  222.                 public static int PanelInt = 0;
  223.             }
  224.             public class Truth
  225.             {
  226.                 private string comparisonStr;
  227.                 private string variable;
  228.                 private string operate;
  229.                 private float constant;
  230.                 private Func<Truth, Dictionary<string, float>, bool> Compare;
  231.                 private Truth[] ANDS;
  232.                 private Truth[] ORS;
  233.                 private Truth(Truth[] ANDS, Truth[] ORS)
  234.                 {
  235.                     this.ANDS = ANDS;
  236.                     this.ORS = ORS;
  237.                 }
  238.                 private Truth(string comparisonStr, string variable, string operate, float constant, bool variableOnLeft)
  239.                 {
  240.                     this.comparisonStr = comparisonStr;
  241.                     this.variable = variable;
  242.                     this.operate = operate;
  243.                     this.constant = constant;
  244.                     if (variableOnLeft)
  245.                     {
  246.                         Compare = delegate (Truth obj, Dictionary<string, float> Values)
  247.                         {
  248.                             var value = Values[obj.variable];
  249.                             var result = false;
  250.                             if (obj.operate == ">=")
  251.                             {
  252.                                 result = value >= obj.constant;
  253.                             }
  254.                             else if (obj.operate == "<=")
  255.                             {
  256.                                 result = value <= obj.constant;
  257.                             }
  258.                             else if (obj.operate == ">")
  259.                             {
  260.                                 result = value > obj.constant;
  261.                             }
  262.                             else if (obj.operate == "<")
  263.                             {
  264.                                 result = value < obj.constant;
  265.                             }
  266.                             else if (obj.operate == "==")
  267.                             {
  268.                                 result = value == obj.constant;
  269.                             }
  270.                             return result;
  271.                         };
  272.                     }
  273.                     else
  274.                     {
  275.                         Compare = delegate (Truth obj, Dictionary<string, float> Values)
  276.                         {
  277.                             var value = Values[obj.variable];
  278.                             var result = false;
  279.                             if (obj.operate == ">=")
  280.                             {
  281.                                 result = obj.constant >= value;
  282.                             }
  283.                             else if (obj.operate == "<=")
  284.                             {
  285.                                 result = obj.constant <= value;
  286.                             }
  287.                             else if (obj.operate == ">")
  288.                             {
  289.                                 result = obj.constant > value;
  290.                             }
  291.                             else if (obj.operate == "<")
  292.                             {
  293.                                 result = obj.constant < value;
  294.                             }
  295.                             else if (obj.operate == "==")
  296.                             {
  297.                                 result = obj.constant == value;
  298.                             }
  299.                             return result;
  300.                         };
  301.                     }
  302.                 }
  303.                 public bool Evaluate(Dictionary<string, float> Values)
  304.                 {
  305.                     bool result;
  306.                     if (Compare != null)
  307.                     {
  308.                         result = Compare(this, Values);
  309.                     }
  310.                     else if (ANDS != null)
  311.                     {
  312.                         result = true;
  313.                         foreach (var TheTruth in ANDS)
  314.                         {
  315.                             if (!TheTruth.Evaluate(Values))
  316.                             {
  317.                                 result = false;
  318.                                 break;
  319.                             }
  320.                         }
  321.                     }
  322.                     else
  323.                     {
  324.                         result = false;
  325.                         foreach (var TheTruth in ORS)
  326.                         {
  327.                             if (TheTruth.Evaluate(Values))
  328.                             {
  329.                                 result = true;
  330.                                 break;
  331.                             }
  332.                         }
  333.                     }
  334.                     return result;
  335.                 }
  336.                 public static Truth Compile(string input, char[] variables, out string Errors)
  337.                 {
  338.                     Errors = "";
  339.                     Match TheMatch;
  340.                     Truth TheTruth;
  341.                     GroupCollection Groups;
  342.                     var ReplacementPrefix = "@";
  343.                     input = ApplyPrecedence(Regex.Replace((input ?? "").ToLower(), "\\s+", ""), ReplacementPrefix);
  344.                     input = ExtractParentheses(input, ReplacementPrefix, out string[] parenContent);
  345.                     float constant;
  346.                     string GroupErrors;
  347.                     var UseAnd = true;
  348.                     var RegexVarStr = Regex.Escape(new string(variables));
  349.                     string variable, operate;
  350.                     var TruthList = new List<Truth>();
  351.                     var Matches = Regex.Matches(input, "(?:^|\\G(?<!^)(\\&\\&|\\|\\|))(?:(?:([" + RegexVarStr + "])(>=|<=|>|<|==)(-?(?:[0-9]*\\.[0-9]+|[0-9]+))|(-?(?:[0-9]*\\.[0-9]+|[0-9]+))(>=|<=|>|<|==)([" + RegexVarStr + "]))|\\(@([0-9]+)\\))(?=(?:(?:\\&\\&|\\|\\|)(?:(?:[" + RegexVarStr + "](?:>=|<=|>|<|==)-?(?:[0-9]*\\.[0-9]+|[0-9]+)|-?(?:[0-9]*\\.[0-9]+|[0-9]+)(?:>=|<=|>|<|==)[" + RegexVarStr + "])|\\(@[0-9]+\\)))*$)");
  352.                     if (Matches.Count == 0)
  353.                     {
  354.                         Errors += "Invalid comparison string: " + input;
  355.                     }
  356.                     for (var i = 0; i < Matches.Count; i++)
  357.                     {
  358.                         TheTruth = null;
  359.                         TheMatch = Matches[i];
  360.                         Groups = TheMatch.Groups;
  361.                         UseAnd = (Groups[1].Value == "||") ? false : UseAnd;
  362.                         if (!string.IsNullOrEmpty(Groups[8].Value))
  363.                         {
  364.                             TheTruth = Compile(parenContent[int.Parse(Groups[8].Value)], variables, out GroupErrors);
  365.                             if (GroupErrors != "")
  366.                             {
  367.                                 Errors += GroupErrors;
  368.                                 break;
  369.                             }
  370.                         }
  371.                         else if (!string.IsNullOrEmpty(Groups[2].Value))
  372.                         {
  373.                             variable = Groups[2].Value;
  374.                             operate = Groups[3].Value;
  375.                             constant = float.Parse(Groups[4].Value);
  376.                             TheTruth = new Truth(TheMatch.Value, variable, operate, constant, true);
  377.                         }
  378.                         else if (!string.IsNullOrEmpty(Groups[5].Value))
  379.                         {
  380.                             constant = float.Parse(Groups[5].Value);
  381.                             operate = Groups[6].Value;
  382.                             variable = Groups[7].Value;
  383.                             TheTruth = new Truth(TheMatch.Value, variable, operate, constant, false);
  384.                         }
  385.                         else
  386.                         {
  387.                             Errors += "Invalid comparison element: " + TheMatch.Value;
  388.                             break;
  389.                         }
  390.                         TruthList.Add(TheTruth);
  391.                     }
  392.                     if (Errors == "")
  393.                     {
  394.                         return UseAnd ? new Truth(TruthList.ToArray(), null) : new Truth(null, TruthList.ToArray());
  395.                     }
  396.                     else
  397.                     {
  398.                         return null;
  399.                     }
  400.                 }
  401.                 private static string ApplyPrecedence(string input, string replacementPrefix)
  402.                 {
  403.                     //this method puts parentheses around comparisons needing left-to-right precedence
  404.                     //for example, h == 10 || s <= 323.22 && s == 3 becomes (h == 10 || s <= 323.22) && s == 3
  405.                     //first, take out all the parentheses content so the precedence regex can do its job
  406.                     input = ExtractParentheses(input, replacementPrefix, out string[] parenContent);
  407.                     //apply the parentheses where needed using a regex
  408.                     input = Regex.Replace(input, "(?<=\\|\\|)((?:[^|&]*&&)+[^|&]+)(?=\\|\\||$)|(?<=^|\\|\\|)((?:[^|&]*&&)+[^|&]+)(?=\\|\\|)|(?<=&&)((?:[^|&]*\\|\\|)+[^|&]+)(?=&&|$)|(?<=^|&&)((?:[^|&]*\\|\\|)+[^|&]+)(?=&&)", "($1$2$3$4)");
  409.                     //re-insert the parentheses content before returning
  410.                     for (var i = 0; i < parenContent.Length; i++)
  411.                     {
  412.                         input = input.Replace(replacementPrefix + i, parenContent[i]);
  413.                     }
  414.                     return input;
  415.                 }
  416.                 private static string ExtractParentheses(string inputStr, string replacementPrefix, out string[] parenContent)
  417.                 {
  418.                     char x;
  419.                     var Count = 0;
  420.                     var newStr = "";
  421.                     var IsOpen = false;
  422.                     var CurParenGroup = "";
  423.                     var ParenGroupList = new List<string>();
  424.                     var CharArr = (inputStr ?? "").ToCharArray();
  425.                     for (var i = 0; i < CharArr.Length; i++)
  426.                     {
  427.                         x = CharArr[i];
  428.                         if (x == '(')
  429.                         {
  430.                             if (!IsOpen)
  431.                             {
  432.                                 CurParenGroup = "";
  433.                                 newStr += x;
  434.                             }
  435.                             else
  436.                             {
  437.                                 CurParenGroup += x;
  438.                                 newStr += (replacementPrefix == null) ? " " : "";
  439.                             }
  440.                             Count++;
  441.                             IsOpen = true;
  442.                         }
  443.                         else
  444.                         {
  445.                             if (IsOpen)
  446.                             {
  447.                                 if (x == ')')
  448.                                 {
  449.                                     Count--;
  450.                                     if (Count == 0)
  451.                                     {
  452.                                         IsOpen = false;
  453.                                         newStr += ((replacementPrefix == null) ? "" : (replacementPrefix + ParenGroupList.Count)) + x;
  454.                                         ParenGroupList.Add(CurParenGroup);
  455.                                     }
  456.                                     else
  457.                                     {
  458.                                         CurParenGroup += x;
  459.                                         newStr += (replacementPrefix == null) ? " " : "";
  460.                                     }
  461.                                 }
  462.                                 else
  463.                                 {
  464.                                     CurParenGroup += x;
  465.                                     newStr += (replacementPrefix == null) ? " " : "";
  466.                                 }
  467.                             }
  468.                             else
  469.                             {
  470.                                 newStr += x;
  471.                             }
  472.                         }
  473.                     }
  474.                     parenContent = ParenGroupList.ToArray();
  475.                     return newStr;
  476.                 }
  477.             }
  478.             private void OnGUI()
  479.             {
  480.                 //var FontStyle = "font-size:14px;font-family:'Arial';";
  481.                 //var FontStyle = "font-size:14px;font-family:'Monaco','Consolas','Menlo','Lucida Console';";
  482.                 var FontStyle = "font-size:14px;font-family:'Arial';";
  483.                 TheLayout.SetDefaultRowSpace(5);
  484.                 TheLayout.SetBoxStyle(GUI.skin.box, "margin:0;border:0;padding:0;stretch-width:false;" + FontStyle + "");
  485.                 TheLayout.SetButtonStyle(GUI.skin.button, "margin:0;padding:4px 4px;vertical-align:top;min-height:text;stretch-width:false;" + FontStyle + "");
  486.                 TheLayout.SetToolbarStyle(GUI.skin.button, "margin:0;stretch-width:true;" + FontStyle + "");
  487.                 TheLayout.SetLabelStyle(GUI.skin.label, "margin:0px;border:0;padding:0px 4px;vertical-align:middle;min-height:text;stretch-width:false;white-space:nowrap;" + FontStyle + "");
  488.                 TheLayout.SetTextAreaStyle(GUI.skin.textArea, "margin:0;stretch-width:false;" + FontStyle + "");
  489.                 TheLayout.SetTextFieldStyle(GUI.skin.textField, "margin:0px;padding:2px 4px;vertical-align:middle;min-height:text;stretch-width:false;" + FontStyle + "");
  490.                 TheLayout.SetToggleStyle(GUI.skin.toggle, "margin:0;stretch-width:false;");
  491.                 TheLayout.SetDropdownStyle(EditorStyles.popup, "margin:0;");
  492.                 TheLayout.SetHorizontalStyle(new GUIStyle(), "margin:0;border:0;padding:0;stretch-width:false;" + FontStyle + "");
  493.                 TheLayout.SetVerticalStyle(new GUIStyle(), "margin:0;border:0;padding:0;stretch-width:false;" + FontStyle + "");
  494.                 TheLayout.BeginVertical("padding:10px;stretch-height:true;");
  495.                 TheLayout.StartRowSpace();
  496.                 if (!ScriptInRightPlace)
  497.                 {
  498.                     var ErrorMessage = "TerraLab is not installed correctly. Make sure the file \"TerraLab.cs\" resides in the directory \"" + TerraLabFolder + "\"";
  499.                     TheLayout.Label(ErrorMessage, "font-size:30px;background-color:rgba(255,0,0,0.75);");
  500.                 }
  501.                 else
  502.                 {
  503.                     if (SelectedTerrainHasNoData)
  504.                     {
  505.                         TheLayout.Label("One or more selected terrains has no TerrainData.", "background-color:rgba(255,0,0,0.75);");
  506.                     }
  507.                     MainPanel.PanelInt = TheLayout.Toolbar(MainPanel.PanelInt, new[] { "Create", "Arrange", "Heightmap", "Sew", "Smooth", "Layers", "Properties", "Debug" });
  508.                     GUILayout.Space(10);
  509.                     if (MainPanel.PanelInt == 0)
  510.                     {
  511.                         PaintCreatePanel();
  512.                     }
  513.                     else if (MainPanel.PanelInt == 1)
  514.                     {
  515.                         PaintArrangePanel();
  516.                     }
  517.                     else if (MainPanel.PanelInt == 2)
  518.                     {
  519.                         PaintHeightmapPanel();
  520.                     }
  521.                     else if (MainPanel.PanelInt == 3)
  522.                     {
  523.                         PaintSewPanel();
  524.                     }
  525.                     else if (MainPanel.PanelInt == 4)
  526.                     {
  527.                         PaintSmoothPanel();
  528.                     }
  529.                     else if (MainPanel.PanelInt == 5)
  530.                     {
  531.                         PaintLayersPanel();
  532.                     }
  533.                     else if (MainPanel.PanelInt == 6)
  534.                     {
  535.                         PaintPropertiesPanel();
  536.                     }
  537.                     else if (MainPanel.PanelInt == 7)
  538.                     {
  539.                         PaintDebugPanel();
  540.                     }
  541.                     if (MainPanel.PanelInt != 6)
  542.                     {
  543.                         DebugPanel.DebugMsg = "";
  544.                     }
  545.                 }
  546.                 TheLayout.EndRowSpace();
  547.                 TheLayout.EndVertical();
  548.             }
  549.             //##############################################################################
  550.             //##############################################################################
  551.             private static class CreatePanel
  552.             {
  553.                 public static string AmountStr = "4";
  554.                 public static string LengthStr = "128";
  555.                 public static string WidthStr = "128";
  556.                 public static string HeightStr = "128";
  557.                 public static string ResolutionStr = "32";
  558.             }
  559.             private void PaintCreatePanel()
  560.             {
  561.                 var Errors = "";
  562.                 var MaxAmount = 256;
  563.                 if (!int.TryParse(CreatePanel.AmountStr, out int Amount) || Amount < 1)
  564.                 {
  565.                     Errors += "Amount must be an integer greater than 0.\n";
  566.                 }
  567.                 else
  568.                 {
  569.                     Amount = Math.Min(MaxAmount, Amount);
  570.                     CreatePanel.AmountStr = Amount.ToString();
  571.                 }
  572.                 if (!int.TryParse(CreatePanel.LengthStr, out int Length) || Length < 1)
  573.                 {
  574.                     Errors += "Length must be an integer greater than 0.\n";
  575.                 }
  576.                 if (!int.TryParse(CreatePanel.WidthStr, out int Width) || Width < 1)
  577.                 {
  578.                     Errors += "Width must be an integer greater than 0.\n";
  579.                 }
  580.                 if (!int.TryParse(CreatePanel.HeightStr, out int Height) || Height < 0)
  581.                 {
  582.                     Errors += "Height must be an integer greater than 0.\n";
  583.                 }
  584.                 if (!int.TryParse(CreatePanel.ResolutionStr, out int Resolution) || Resolution < 32 || Resolution > 4096)
  585.                 {
  586.                     Errors += "Resolution must be an integer between 32 and 4096.\n";
  587.                 }
  588.                 TheLayout.BeginHorizontal();
  589.                 TheLayout.BeginVertical("width:500px;background-color:rgba(0,0,0,0.15);padding:5px;");
  590.                 TheLayout.BeginVertical();
  591.                 TheLayout.BeginHorizontal();
  592.                 TheLayout.Label("Amount", "width:128px;");
  593.                 CreatePanel.AmountStr = TheLayout.TextField(CreatePanel.AmountStr, "width:100px;");
  594.                 TheLayout.EndHorizontal();
  595.                 TheLayout.BeginHorizontal();
  596.                 TheLayout.Label("Length", "width:128px;");
  597.                 CreatePanel.LengthStr = TheLayout.TextField(CreatePanel.LengthStr, "width:100px;");
  598.                 TheLayout.EndHorizontal();
  599.                 TheLayout.BeginHorizontal();
  600.                 TheLayout.Label("Width", "width:128px;");
  601.                 CreatePanel.WidthStr = TheLayout.TextField(CreatePanel.WidthStr, "width:100px;");
  602.                 TheLayout.EndHorizontal();
  603.                 TheLayout.BeginHorizontal();
  604.                 TheLayout.Label("Height", "width:128px;");
  605.                 CreatePanel.HeightStr = TheLayout.TextField(CreatePanel.HeightStr, "width:100px;");
  606.                 TheLayout.EndHorizontal();
  607.                 TheLayout.BeginHorizontal();
  608.                 TheLayout.Label("Resolution", "width:128px;");
  609.                 CreatePanel.ResolutionStr = TheLayout.TextField(CreatePanel.ResolutionStr, "width:100px;");
  610.                 TheLayout.EndHorizontal();
  611.                 GUI.enabled = (Errors == "");
  612.                 if (TheLayout.Button("Create Terrain" + (Amount == 1 ? "" : "s"), "width:200px;margin-top:5px;"))
  613.                 {
  614.                     CreateTerrains(Amount, Length, Width, Height, Resolution);
  615.                 }
  616.                 GUI.enabled = true;
  617.                 TheLayout.EndVertical();
  618.                 TheLayout.EndVertical();
  619.                 if (Errors != "")
  620.                 {
  621.                     TheLayout.BeginHorizontal("background-color:rgba(255,255,0,0.75);");
  622.                     TheLayout.Label(Errors);
  623.                     TheLayout.EndHorizontal();
  624.                 }
  625.                 TheLayout.EndHorizontal();
  626.             }
  627.             private void CreateTerrains(int Amount, int Length, int Width, int Height, int Resolution)
  628.             {
  629.                 var UnixNow = DateTime.Now.ToUtcUnixTimeSeconds();
  630.                 var TerrainNum = Math.Max(int.TryParse(TheAssetBucket.GetKey("TerrainNum"), out int intResult) ? intResult : -1, -1) + 1;
  631.                 var LayerNum = Math.Max(int.TryParse(TheAssetBucket.GetKey("LayerNum"), out intResult) ? intResult : -1, -1) + 1;
  632.                 var TerrainTime = long.TryParse(TheAssetBucket.GetKey("TerrainTime"), out long longResult) ? longResult : 0;
  633.                 TerrainTime = (TerrainTime == UnixNow) ? UnixNow + 1 : UnixNow;
  634.                 var AlphaMapResolution = 16;
  635.                 Terrain TheTerrainComponent;
  636.                 TerrainData TheTerrainData;
  637.                 GameObject TheGameObject;
  638.                 string PaddedNum;
  639.                 var LastLayerNum = LayerNum + 1;
  640.                 var LastTerrainNum = 0;
  641.                 var NewTerrains = new GameObject[Amount];
  642.                 var NewTerrainDatas = new TerrainData[Amount];
  643.                 //AssetDatabase.Refresh();
  644.                 //the Texture2D needs to be made into an asset for it to save properly
  645.                 var DiffuseTexture = (Texture2D)TheAssetBucket.Get("DefaultTerrainTexture");
  646.                 if (DiffuseTexture == null)
  647.                 {
  648.                     DiffuseTexture = GetWhiteGridTexture(Color.blue, 0, 0.1);
  649.                     DiffuseTexture.name = "DefaultTerrainTexture";
  650.                     TheAssetBucket.Add(DiffuseTexture, false);
  651.                 }
  652.                 //beige
  653.                 //DiffuseTexture = GetWhiteGridTexture(0.886, 0.847, 0.733, 0, 0.5);
  654.                 //dark blue
  655.                 var TheTerrainLayer = new TerrainLayer
  656.                 {
  657.                     name = "Terrain_" + PadLeft(LastLayerNum, '0', 7) + "_Layer_" + TerrainTime,
  658.                     diffuseTexture = DiffuseTexture,
  659.                     maskMapTexture = null,
  660.                     normalMapTexture = null,
  661.                     metallic = 0,
  662.                     smoothness = 0,
  663.                     tileOffset = new Vector2(0, 0),
  664.                     tileSize = new Vector2(Width / (float)Resolution, Length / (float)Resolution)
  665.                 };
  666.                 TheAssetBucket.Add(TheTerrainLayer, false);
  667.                 var AlphaMap = new float[AlphaMapResolution, AlphaMapResolution, 1];
  668.                 //need to set all the vertices to opaque for layer 0
  669.                 for (var x = 0; x < AlphaMapResolution; x++)
  670.                 {
  671.                     for (var y = 0; y < AlphaMapResolution; y++)
  672.                     {
  673.                         AlphaMap[x, y, 0] = 1;
  674.                     }
  675.                 }
  676.                 for (var i = 0; i < Amount; i++)
  677.                 {
  678.                     //TerrainData is what the asset uses
  679.                     //GameObject is what the scene uses
  680.                     //CANNOT CREATE ASSETS OUT OF
  681.                     //GAMEOBJECTS OR COMPONENTS
  682.                     TheTerrainData = new TerrainData();
  683.                     //the TerrainData needs to be created as an asset before
  684.                     //modifying it so that all the property changes save properly
  685.                     TheAssetBucket.Add(TheTerrainData, false);
  686.                     LastTerrainNum = TerrainNum + i;
  687.                     PaddedNum = PadLeft(LastTerrainNum, '0', 7);
  688.                     TheTerrainData.name = "Terrain_" + PaddedNum + "_Data_" + TerrainTime;
  689.                     TheTerrainData.heightmapResolution = Resolution;
  690.                     TheTerrainData.alphamapResolution = AlphaMapResolution;
  691.                     //SET THE TERRAIN SIZE AFTER SETTING THE HEIGHTMAP RESOLUTION
  692.                     //OR ELSE THE SIZE WILL BE RESET
  693.                     TheTerrainData.size = new Vector3(Width, Height, Length);
  694.                     TheTerrainData.terrainLayers = new[] { TheTerrainLayer };
  695.                     TheTerrainData.alphamapTextures[0].name = "Terrain_" + PaddedNum + "_Alpha_" + TerrainTime;
  696.                     //TERRAINDATAS NEED TO BE
  697.                     //SAVED AS ASSETS BEFORE CALLING SETALPHAMAPS
  698.                     //OR ELSE THE TEXTURE WON'T APPEAR ON THE TERRAINS
  699.                     TheTerrainData.SetAlphamaps(0, 0, AlphaMap);
  700.                     TheGameObject = Terrain.CreateTerrainGameObject(TheTerrainData);
  701.                     TheGameObject.name = "Terrain_" + PaddedNum + "_" + TerrainTime;
  702.                     Undo.RegisterCreatedObjectUndo(TheGameObject, "TerraLab create terrain");
  703.                     TheTerrainComponent = TheGameObject.GetComponent<Terrain>();
  704.                     TheTerrainComponent.name = "Terrain_" + PaddedNum + "_Component_" + TerrainTime;
  705.                     TheTerrainComponent.heightmapPixelError = 1;
  706.                     TheTerrainComponent.basemapDistance = 1000000;
  707.                     TheTerrainComponent.allowAutoConnect = true;
  708.                     TheTerrainComponent.groupingID = 0;
  709.                     NewTerrains[i] = TheGameObject;
  710.                     NewTerrainDatas[i] = TheTerrainData;
  711.                 }
  712.                 TheAssetBucket.Save();
  713.                 TheAssetBucket.SetKey("TerrainNum", LastTerrainNum.ToString());
  714.                 TheAssetBucket.SetKey("TerrainTime", TerrainTime.ToString());
  715.                 Selection.objects = NewTerrains;
  716.             }
  717.             //##############################################################################
  718.             //##############################################################################
  719.             private static class ArrangePanel
  720.             {
  721.                 public static string yCoordStr = "0";
  722.                 public static bool Rotate90 = false;
  723.                 public static int SortMethod = 0;
  724.                 public static PositionOptions PositionEnum = PositionOptions.MiddleCenter;
  725.                 public enum PositionOptions
  726.                 {
  727.                     TopLeft = 0,
  728.                     TopCenter = 1,
  729.                     TopRight = 2,
  730.                     MiddleLeft = 3,
  731.                     MiddleCenter = 4,
  732.                     MiddleRight = 5,
  733.                     BottomLeft = 6,
  734.                     BottomCenter = 7,
  735.                     BottomRight = 8
  736.                 }
  737.             }
  738.             private void PaintArrangePanel()
  739.             {
  740.                 if (empty(SelectedTerrains))
  741.                 {
  742.                     TheLayout.Label("No terrains selected.");
  743.                 }
  744.                 else
  745.                 {
  746.                     TheLayout.BeginVertical("width:500px;background-color:rgba(0,0,0,0.15);padding:5px;");
  747.                     var Errors = "";
  748.                     var LastWidthHeight = SelectedTerrains[0].terrainData.size;
  749.                     foreach (var Terrain in SelectedTerrains)
  750.                     {
  751.                         if (LastWidthHeight != Terrain.terrainData.size)
  752.                         {
  753.                             Errors += "Cannot arrange terrains of different sizes.";
  754.                             break;
  755.                         }
  756.                     }
  757.                     if (Errors != "")
  758.                     {
  759.                         TheLayout.Label(Errors);
  760.                     }
  761.                     else
  762.                     {
  763.                         var Count = SelectedTerrains.Length;
  764.                         TheLayout.Label(Count + " terrain" + ((Count == 1) ? "" : "s") + " selected.", "margin-bottom:5px;");
  765.                         TheLayout.BeginHorizontal();
  766.                         TheLayout.Label("Y Coordinate:", "width:140px;");
  767.                         ArrangePanel.yCoordStr = TheLayout.TextField(ArrangePanel.yCoordStr, "width:110px;");
  768.                         TheLayout.EndHorizontal();
  769.                         TheLayout.BeginHorizontal();
  770.                         TheLayout.Label("Position:", "width:140px;");
  771.                         ArrangePanel.PositionEnum = TheLayout.Dropdown(ArrangePanel.PositionEnum, "width:210px;");
  772.                         TheLayout.EndHorizontal();
  773.                         TheLayout.BeginHorizontal();
  774.                         TheLayout.Label("Rotate 90°:", "width:140px;");
  775.                         ArrangePanel.Rotate90 = TheLayout.Toggle(ArrangePanel.Rotate90);
  776.                         TheLayout.EndHorizontal();
  777.                         TheLayout.BeginHorizontal();
  778.                         TheLayout.Label("Sort By:", "width:140px;");
  779.                         ArrangePanel.SortMethod = TheLayout.Toolbar(ArrangePanel.SortMethod, new[] { "Ascending", "Descending", "Random" });
  780.                         TheLayout.EndHorizontal();
  781.                         var yCoordIsValid = float.TryParse(ArrangePanel.yCoordStr, out float yCoord);
  782.                         var Factors = new Dictionary<int, int>();
  783.                         decimal Multiple;
  784.                         for (var i = 1; i <= (Count / 2) + 1; i++)
  785.                         {
  786.                             if (IsInteger(Multiple = Count / (decimal)i) && !Factors.ContainsKey((int)Multiple))
  787.                             {
  788.                                 Factors.Add(i, (int)Multiple);
  789.                             }
  790.                         }
  791.                         foreach (var Factor in Factors)
  792.                         {
  793.                             if (TheLayout.Button(Factor.Key + " x " + Factor.Value, "width:128px;margin-top:5px;"))
  794.                             {
  795.                                 if (yCoordIsValid)
  796.                                 {
  797.                                     ArrangeTerrains(SelectedTerrains, Factor.Value, Factor.Key, ArrangePanel.SortMethod, yCoord);
  798.                                 }
  799.                                 else
  800.                                 {
  801.                                     ArrangeTerrains(SelectedTerrains, Factor.Value, Factor.Key, ArrangePanel.SortMethod);
  802.                                 }
  803.                             }
  804.                         }
  805.                     }
  806.                     TheLayout.EndVertical();
  807.                 }
  808.             }
  809.             private void ArrangeTerrains(Terrain[] Terrains, int xNum, int zNum, int SortMethod, float yCoord = 0)
  810.             {
  811.                 if (SortMethod == 2)
  812.                 {
  813.                     Terrains = Terrains.OrderBy(x => RandomInt32).ToArray();
  814.                 }
  815.                 else if (SortMethod == 1)
  816.                 {
  817.                     Terrains = Terrains.OrderByDescending(x => x.name).ToArray();
  818.                 }
  819.                 else
  820.                 {
  821.                     Terrains = Terrains.OrderBy(x => x.name).ToArray();
  822.                 }
  823.                 if (!empty(Terrains) && xNum > 0 && zNum > 0 && xNum * zNum == Terrains.Length)
  824.                 {
  825.                     var xPos = -0.5F;
  826.                     var yPos = 0.5F;
  827.                     var ThePosition = ArrangePanel.PositionEnum;
  828.                     if (ThePosition == ArrangePanel.PositionOptions.TopLeft)
  829.                     {
  830.                         xPos = -1F;
  831.                         yPos = 1F;
  832.                     }
  833.                     else if (ThePosition == ArrangePanel.PositionOptions.TopCenter)
  834.                     {
  835.                         xPos = -0.5F;
  836.                         yPos = 1F;
  837.                     }
  838.                     else if (ThePosition == ArrangePanel.PositionOptions.TopRight)
  839.                     {
  840.                         xPos = 0F;
  841.                         yPos = 1F;
  842.                     }
  843.                     else if (ThePosition == ArrangePanel.PositionOptions.MiddleLeft)
  844.                     {
  845.                         xPos = -1F;
  846.                         yPos = 0.5F;
  847.                     }
  848.                     else if (ThePosition == ArrangePanel.PositionOptions.MiddleCenter)
  849.                     {
  850.                         xPos = -0.5F;
  851.                         yPos = 0.5F;
  852.                     }
  853.                     else if (ThePosition == ArrangePanel.PositionOptions.MiddleRight)
  854.                     {
  855.                         xPos = 0F;
  856.                         yPos = 0.5F;
  857.                     }
  858.                     else if (ThePosition == ArrangePanel.PositionOptions.BottomLeft)
  859.                     {
  860.                         xPos = -1F;
  861.                         yPos = 0F;
  862.                     }
  863.                     else if (ThePosition == ArrangePanel.PositionOptions.BottomCenter)
  864.                     {
  865.                         xPos = -0.5F;
  866.                         yPos = 0F;
  867.                     }
  868.                     else if (ThePosition == ArrangePanel.PositionOptions.BottomRight)
  869.                     {
  870.                         xPos = 0F;
  871.                         yPos = 0F;
  872.                     }
  873.                     if (ArrangePanel.Rotate90)
  874.                     {
  875.                         var Temp = xNum;
  876.                         xNum = zNum;
  877.                         zNum = Temp;
  878.                     }
  879.                     var Size = Terrains[0].terrainData.size;
  880.                     var xCoord = xNum * Size.x * xPos;
  881.                     //subtract one z-length from zCoord because
  882.                     //unlike with the x axis where we go from negative to positive,
  883.                     //with the z axis we go from positive to negative
  884.                     var zCoord = (zNum * Size.z * yPos) - Size.z;
  885.                     Terrain TheTerrain;
  886.                     var c = 0;
  887.                     for (var z = 0; z < zNum; z++)
  888.                     {
  889.                         for (var x = 0; x < xNum; x++)
  890.                         {
  891.                             TheTerrain = Terrains[c];
  892.                             Undo.RecordObject(TheTerrain.transform, "TerraLab arrange terrains");
  893.                             TheTerrain.transform.position = new Vector3(xCoord + (x * Size.x), yCoord, zCoord - (z * Size.z));
  894.                             c++;
  895.                         }
  896.                     }
  897.                 }
  898.             }
  899.             //##############################################################################
  900.             //##############################################################################
  901.             private static class HeightmapPanel
  902.             {
  903.                 public static HeightmapInfo TheHeightmap = null;
  904.                 public static string LoadHeightmapErrors = "";
  905.                 public static string ApplyHeightmapErrors = "";
  906.                 public static string ResetHeightmapErrors = "";
  907.                 public static bool ReverseBytes = false;
  908.                 public static bool Use8Bit = false;
  909.                 public static bool FlipX = false;
  910.                 public static bool FlipZ = false;
  911.             }
  912.             private class HeightmapInfo
  913.             {
  914.                 public readonly long Edge = -1;
  915.                 public readonly long Length = -1;
  916.                 public readonly bool Is8Bit = false;
  917.                 public readonly bool Is16Bit = false;
  918.                 public readonly bool IsImage = false;
  919.                 public readonly string FilePath = null;
  920.                 public static HeightmapInfo CreateInstance(string Path, out string Errors)
  921.                 {
  922.                     Errors = "";
  923.                     HeightmapInfo TheHeightmapInfo = null;
  924.                     if (!File.Exists(Path))
  925.                     {
  926.                         Errors += "Invalid file path.\n";
  927.                     }
  928.                     else
  929.                     {
  930.                         var FileName = Regex.Replace(Path, ".*/", "");
  931.                         long Length = -1;
  932.                         decimal Edge = -1;
  933.                         var Is8Bit = false;
  934.                         var Is16Bit = false;
  935.                         var IsImage = false;
  936.                         string FilePath = null;
  937.                         using (var TheStream = File.OpenRead(Path))
  938.                         {
  939.                             using (var TheReader = new BinaryReader(TheStream))
  940.                             {
  941.                                 FilePath = Path;
  942.                                 Length = TheStream.Length;
  943.                                 Edge = (decimal)Math.Sqrt(Length / 2);
  944.                                 if (IsInteger(Edge))
  945.                                 {
  946.                                     Is16Bit = true;
  947.                                 }
  948.                                 else
  949.                                 {
  950.                                     Edge = (decimal)Math.Sqrt(Length);
  951.                                     if (IsInteger(Edge))
  952.                                     {
  953.                                         Is8Bit = true;
  954.                                     }
  955.                                     else
  956.                                     {
  957.                                         Edge = -1;
  958.                                     }
  959.                                 }
  960.                             }
  961.                         }
  962.                         if (Edge != 32 && Edge != 64 && Edge != 128 && Edge != 256 && Edge != 512 && Edge != 1024 && Edge != 2048 && Edge != 4096 && Edge != 8192 && Edge != 16384)
  963.                         {
  964.                             Errors += "\"" + FileName + "\"\n";
  965.                             Errors += "Could not determine heightmap resolution.\n";
  966.                             Errors += "Only these resolutions are supported: 32x32, 64x64, 128x128, 256x256, 512x512, 1024x1024, 2048x2048, 4096x4096, 8192x8192, 16384x16384\n";
  967.                         }
  968.                         if (Errors == "")
  969.                         {
  970.                             TheHeightmapInfo = new HeightmapInfo((int)Edge, Length, Is8Bit, Is16Bit, IsImage, FilePath);
  971.                         }
  972.                     }
  973.                     return TheHeightmapInfo;
  974.                 }
  975.                 private HeightmapInfo(int Edge, long Length, bool Is8Bit, bool Is16Bit, bool IsImage, string FilePath)
  976.                 {
  977.                     this.Edge = Edge;
  978.                     this.Length = Length;
  979.                     this.Is8Bit = Is8Bit;
  980.                     this.Is16Bit = Is16Bit;
  981.                     this.IsImage = IsImage;
  982.                     this.FilePath = FilePath;
  983.                 }
  984.             }
  985.             private void PaintHeightmapPanel()
  986.             {
  987.                 TheLayout.BeginVertical();
  988.                 if (empty(SelectedTerrains))
  989.                 {
  990.                     TheLayout.Label("No terrains selected.");
  991.                 }
  992.                 else
  993.                 {
  994.                     var Errors = "";
  995.                     var TheTerrain = SelectedTerrains[0];
  996.                     //var Neighbors = new NeighborGroup(TheTerrain, TerrainsInScene, out string Errors);
  997.                     if (Errors != "")
  998.                     {
  999.                         TheLayout.Label(Errors);
  1000.                     }
  1001.                     else
  1002.                     {
  1003.                         if (HeightmapPanel.TheHeightmap == null)
  1004.                         {
  1005.                             Errors += "No heightmap file has been selected.\n";
  1006.                         }
  1007.                         TheLayout.BeginHorizontal();
  1008.                         TheLayout.BeginVertical("width:500px;background-color:rgba(0,0,0,0.15);padding:5px;");
  1009.                         TheLayout.BeginHorizontal();
  1010.                         TheLayout.Label("Select Heightmap File:", "width:200px;");
  1011.                         var FileName = (HeightmapPanel.TheHeightmap == null) ? null : Regex.Replace(HeightmapPanel.TheHeightmap.FilePath, ".*/", "");
  1012.                         if (TheLayout.Button(empty(FileName) ? "Browse" : FileName))
  1013.                         {
  1014.                             HeightmapPanel.TheHeightmap = HeightmapInfo.CreateInstance(EditorUtility.OpenFilePanel("Heightmap File", "", ""), out HeightmapPanel.LoadHeightmapErrors);
  1015.                             HeightmapPanel.Use8Bit = (HeightmapPanel.TheHeightmap == null) ? false : HeightmapPanel.TheHeightmap.Is8Bit;
  1016.                         }
  1017.                         TheLayout.EndHorizontal();
  1018.                         TheLayout.BeginHorizontal();
  1019.                         TheLayout.Label("Heightmap Details:", "width:200px;");
  1020.                         var HeightmapDetails = "";
  1021.                         if (empty(HeightmapPanel.LoadHeightmapErrors))
  1022.                         {
  1023.                             if (HeightmapPanel.TheHeightmap == null)
  1024.                             {
  1025.                                 HeightmapDetails += "No heightmap selected.";
  1026.                             }
  1027.                             else
  1028.                             {
  1029.                                 var HM = HeightmapPanel.TheHeightmap;
  1030.                                 HeightmapDetails += "Bit Depth: " + (HM.Is16Bit ? "16" : "8") + "\nResolution: " + HM.Edge + "x" + HM.Edge + "\nSize:" + AddCommas(HM.Length) + " bytes";
  1031.                             }
  1032.                         }
  1033.                         else
  1034.                         {
  1035.                             HeightmapDetails += Regex.Replace(HeightmapPanel.LoadHeightmapErrors, "[\\s\\r\\n]*$", "");
  1036.                         }
  1037.                         TheLayout.Label(HeightmapDetails);
  1038.                         TheLayout.EndHorizontal();
  1039.                         TheLayout.BeginHorizontal();
  1040.                         TheLayout.Label("Reverse Byte Order:", "width:200px;");
  1041.                         HeightmapPanel.ReverseBytes = TheLayout.Toggle(HeightmapPanel.ReverseBytes);
  1042.                         TheLayout.EndHorizontal();
  1043.                         TheLayout.BeginHorizontal();
  1044.                         TheLayout.Label("Heightmap Is 8-bit:", "width:200px;");
  1045.                         HeightmapPanel.Use8Bit = TheLayout.Toggle(HeightmapPanel.Use8Bit);
  1046.                         TheLayout.EndHorizontal();
  1047.                         TheLayout.BeginHorizontal();
  1048.                         TheLayout.Label("Flip X:", "width:200px;");
  1049.                         HeightmapPanel.FlipX = TheLayout.Toggle(HeightmapPanel.FlipX);
  1050.                         TheLayout.EndHorizontal();
  1051.                         TheLayout.BeginHorizontal();
  1052.                         TheLayout.Label("Flip Z:", "width:200px;");
  1053.                         HeightmapPanel.FlipZ = TheLayout.Toggle(HeightmapPanel.FlipZ);
  1054.                         TheLayout.EndHorizontal();
  1055.                         GUI.enabled = (Errors == "");
  1056.                         if (TheLayout.Button("Apply Heightmap", "width:200px;margin-top:5px;"))
  1057.                         {
  1058.                             ApplyHeightmapMultiple(SelectedTerrains, HeightmapPanel.TheHeightmap, HeightmapPanel.ReverseBytes, HeightmapPanel.Use8Bit, HeightmapPanel.FlipX, HeightmapPanel.FlipZ, out HeightmapPanel.ApplyHeightmapErrors);
  1059.                         }
  1060.                         if (HeightmapPanel.ApplyHeightmapErrors != "")
  1061.                         {
  1062.                             Errors += HeightmapPanel.ApplyHeightmapErrors;
  1063.                         }
  1064.                         GUI.enabled = true;
  1065.                         if (TheLayout.Button("Reset Heightmap", "width:200px;margin-top:5px;"))
  1066.                         {
  1067.                             ResetHeightmap(SelectedTerrains, out HeightmapPanel.ResetHeightmapErrors);
  1068.                         }
  1069.                         if (HeightmapPanel.ResetHeightmapErrors != "")
  1070.                         {
  1071.                             Errors += HeightmapPanel.ResetHeightmapErrors;
  1072.                         }
  1073.                         TheLayout.EndVertical();
  1074.                         if (Errors != "")
  1075.                         {
  1076.                             Errors = Regex.Replace(Errors, "[\\s\\r\\n]*$", "");
  1077.                             TheLayout.BeginHorizontal("background-color:rgba(255,255,0,0.75);");
  1078.                             TheLayout.Label(Errors);
  1079.                             TheLayout.EndHorizontal();
  1080.                         }
  1081.                         TheLayout.EndHorizontal();
  1082.                     }
  1083.                 }
  1084.                 TheLayout.EndVertical();
  1085.             }
  1086.             private void ApplyHeightmapMultiple(Terrain[] Terrains, HeightmapInfo TheHeightmap, bool ReverseBytes, bool Use8Bit, bool FlipX, bool FlipZ, out string Errors)
  1087.             {
  1088.                 Errors = "";
  1089.                 if (empty(Terrains))
  1090.                 {
  1091.                     Errors += "No terrains were provided.\n";
  1092.                 }
  1093.                 else if (TheHeightmap == null)
  1094.                 {
  1095.                     Errors += "No heightmap was provided.\n";
  1096.                 }
  1097.                 else
  1098.                 {
  1099.                     var EdgeCount = Math.Sqrt(Terrains.Length);
  1100.                     var NotSquareMsg = "Selected terrains must form a square (e.g. 2x2, 3x3, 4x4).\nMake sure the edges of each terrain are perfectly lined up with their neighbors.\n";
  1101.                     if (!IsInteger((decimal)EdgeCount))
  1102.                     {
  1103.                         Errors += NotSquareMsg;
  1104.                     }
  1105.                     else
  1106.                     {
  1107.                         var TerrainEdge = (Terrains[0].terrainData.heightmapWidth - 1) * EdgeCount;
  1108.                         if (TerrainEdge > TheHeightmap.Edge)
  1109.                         {
  1110.                             Errors += "The total terrain resolution is greater than the heightmap file's resolution (" + TerrainEdge + "x" + TerrainEdge + " versus " + TheHeightmap.Edge + "x" + TheHeightmap.Edge + ").\n";
  1111.                         }
  1112.                         else if (TerrainEdge < TheHeightmap.Edge)
  1113.                         {
  1114.                             Errors += "The total terrain resolution is less than the heightmap file's resolution (" + TerrainEdge + "x" + TerrainEdge + " versus " + TheHeightmap.Edge + "x" + TheHeightmap.Edge + ").\n";
  1115.                         }
  1116.                         if (Errors == "")
  1117.                         {
  1118.                             var StartingTerrain = Terrains[0];
  1119.                             var LowestX = StartingTerrain.transform.position.x;
  1120.                             var LowestZ = StartingTerrain.transform.position.z;
  1121.                             var LastX = StartingTerrain.terrainData.heightmapWidth - 1;
  1122.                             var LastZ = StartingTerrain.terrainData.heightmapHeight - 1;
  1123.                             var NeighborGroupCollection = new Dictionary<Terrain, NeighborGroup>();
  1124.                             var _1000 = 0;
  1125.                             var _0100 = 0;
  1126.                             var _0010 = 0;
  1127.                             var _0001 = 0;
  1128.                             var _1100 = 0;
  1129.                             var _0110 = 0;
  1130.                             var _0011 = 0;
  1131.                             var _1001 = 0;
  1132.                             var _1111 = 0;
  1133.                             NeighborGroup TheNeighborGroup;
  1134.                             string NeighborErrors;
  1135.                             foreach (var TheTerrain in Terrains)
  1136.                             {
  1137.                                 TheNeighborGroup = new NeighborGroup(TheTerrain, Terrains, out NeighborErrors);
  1138.                                 NeighborGroupCollection.Add(TheTerrain, TheNeighborGroup);
  1139.                                 if (NeighborErrors != "")
  1140.                                 {
  1141.                                     Errors += NeighborErrors;
  1142.                                     break;
  1143.                                 }
  1144.                                 else
  1145.                                 {
  1146.                                     if (TheTerrain.transform.position.x < LowestX)
  1147.                                     {
  1148.                                         StartingTerrain = TheTerrain;
  1149.                                         LowestX = TheTerrain.transform.position.x;
  1150.                                     }
  1151.                                     if (TheTerrain.transform.position.z < LowestZ)
  1152.                                     {
  1153.                                         StartingTerrain = TheTerrain;
  1154.                                         LowestZ = TheTerrain.transform.position.z;
  1155.                                     }
  1156.                                     _1000 += (TheNeighborGroup.Top == null && TheNeighborGroup.Right != null && TheNeighborGroup.Bottom != null && TheNeighborGroup.Left != null) ? 1 : 0;
  1157.                                     _0100 += (TheNeighborGroup.Top != null && TheNeighborGroup.Right == null && TheNeighborGroup.Bottom != null && TheNeighborGroup.Left != null) ? 1 : 0;
  1158.                                     _0010 += (TheNeighborGroup.Top != null && TheNeighborGroup.Right != null && TheNeighborGroup.Bottom == null && TheNeighborGroup.Left != null) ? 1 : 0;
  1159.                                     _0001 += (TheNeighborGroup.Top != null && TheNeighborGroup.Right != null && TheNeighborGroup.Bottom != null && TheNeighborGroup.Left == null) ? 1 : 0;
  1160.                                     _1100 += (TheNeighborGroup.Top != null && TheNeighborGroup.Right != null && TheNeighborGroup.Bottom == null && TheNeighborGroup.Left == null) ? 1 : 0;
  1161.                                     _0110 += (TheNeighborGroup.Top == null && TheNeighborGroup.Right != null && TheNeighborGroup.Bottom != null && TheNeighborGroup.Left == null) ? 1 : 0;
  1162.                                     _0011 += (TheNeighborGroup.Top == null && TheNeighborGroup.Right == null && TheNeighborGroup.Bottom != null && TheNeighborGroup.Left != null) ? 1 : 0;
  1163.                                     _1001 += (TheNeighborGroup.Top != null && TheNeighborGroup.Right == null && TheNeighborGroup.Bottom == null && TheNeighborGroup.Left != null) ? 1 : 0;
  1164.                                     _1111 += (TheNeighborGroup.Top != null && TheNeighborGroup.Right != null && TheNeighborGroup.Bottom != null && TheNeighborGroup.Left != null) ? 1 : 0;
  1165.                                 }
  1166.                             }
  1167.                             /*
  1168.                             */
  1169.                             var Test = "";
  1170.                             Test += "1000: " + _1000 + ", ";
  1171.                             Test += "0100: " + _0100 + ", ";
  1172.                             Test += "0010: " + _0010 + ", ";
  1173.                             Test += "0001: " + _0001 + ", ";
  1174.                             Test += "1100: " + _1100 + ", ";
  1175.                             Test += "0110: " + _0110 + ", ";
  1176.                             Test += "0011: " + _0011 + ", ";
  1177.                             Test += "1001: " + _1001 + ", ";
  1178.                             Test += "1111: " + _1111 + "";
  1179.                             Debug.Log(Test);
  1180.                             var Minus2 = EdgeCount - 2;
  1181.                             if (EdgeCount != 1 && ((EdgeCount > 2 && (_1000 != Minus2 || _0100 != Minus2 || _0010 != Minus2 || _0001 != Minus2 || _1111 != Math.Pow(Minus2, 2))) || _1100 != 1 || _0110 != 1 || _0011 != 1 || _1001 != 1))
  1182.                             {
  1183.                                 Errors += NotSquareMsg;
  1184.                             }
  1185.                             if (Errors == "")
  1186.                             {
  1187.                                 //###################################
  1188.                                 //pre-load heightmap values into arrays
  1189.                                 //to make it easier to flip it horizontally or vertically
  1190.                                 float[] H_Array;
  1191.                                 var V_Array = new float[TheHeightmap.Edge + 1][];
  1192.                                 using (var TheStream = File.OpenRead(TheHeightmap.FilePath))
  1193.                                 {
  1194.                                     using (var TheReader = new BinaryReader(TheStream))
  1195.                                     {
  1196.                                         for (var i = 0; i < V_Array.Length; i++)
  1197.                                         {
  1198.                                             if (i == V_Array.Length - 1)
  1199.                                             {
  1200.                                                 V_Array[i] = V_Array[i - 1];
  1201.                                             }
  1202.                                             else
  1203.                                             {
  1204.                                                 H_Array = new float[TheHeightmap.Edge + 1];
  1205.                                                 for (var t = 0; t < H_Array.Length; t++)
  1206.                                                 {
  1207.                                                     if (t == H_Array.Length - 1)
  1208.                                                     {
  1209.                                                         H_Array[t] = H_Array[t - 1];
  1210.                                                     }
  1211.                                                     else
  1212.                                                     {
  1213.                                                         if (Use8Bit)
  1214.                                                         {
  1215.                                                             H_Array[t] = (float)TheReader.ReadByte() / 0xFF;
  1216.                                                         }
  1217.                                                         else
  1218.                                                         {
  1219.                                                             if (ReverseBytes)
  1220.                                                             {
  1221.                                                                 H_Array[t] = (float)BitConverter.ToUInt16((byte[])TheReader.ReadBytes(2).Reverse(), 0) / 0xFFFF;
  1222.                                                             }
  1223.                                                             else
  1224.                                                             {
  1225.                                                                 H_Array[t] = (float)TheReader.ReadUInt16() / 0xFFFF;
  1226.                                                             }
  1227.                                                         }
  1228.                                                     }
  1229.                                                 }
  1230.                                                 if (FlipX)
  1231.                                                 {
  1232.                                                     Array.Reverse(H_Array);
  1233.                                                 }
  1234.                                                 V_Array[i] = H_Array;
  1235.                                             }
  1236.                                         }
  1237.                                     }
  1238.                                 }
  1239.                                 if (FlipZ)
  1240.                                 {
  1241.                                     Array.Reverse(V_Array);
  1242.                                 }
  1243.                                 //###################################
  1244.                                 float v;
  1245.                                 var x = 0;
  1246.                                 var z = 0;
  1247.                                 var RowStartNeighborGroup = NeighborGroupCollection[StartingTerrain];
  1248.                                 var CurrentNeighborGroup = RowStartNeighborGroup;
  1249.                                 for (var VIndex = 0; VIndex < V_Array.Length; VIndex++)
  1250.                                 {
  1251.                                     H_Array = V_Array[VIndex];
  1252.                                     for (var HIndex = 0; HIndex < H_Array.Length; HIndex++)
  1253.                                     {
  1254.                                         v = H_Array[HIndex];
  1255.                                         CurrentNeighborGroup.MainHeights[z, x] = v;
  1256.                                         if (x == LastX && CurrentNeighborGroup.Right != null)
  1257.                                         {
  1258.                                             NeighborGroupCollection[CurrentNeighborGroup.Right].MainHeights[z, 0] = v;
  1259.                                         }
  1260.                                         if (z == LastZ && CurrentNeighborGroup.Top != null)
  1261.                                         {
  1262.                                             NeighborGroupCollection[CurrentNeighborGroup.Top].MainHeights[0, x] = v;
  1263.                                         }
  1264.                                         //####################################
  1265.                                         //increment x and z values
  1266.                                         x++;
  1267.                                         if (x > LastX)
  1268.                                         {
  1269.                                             if (CurrentNeighborGroup.Right != null)
  1270.                                             {
  1271.                                                 x = 1;
  1272.                                                 CurrentNeighborGroup = NeighborGroupCollection[CurrentNeighborGroup.Right];
  1273.                                             }
  1274.                                             else
  1275.                                             {
  1276.                                                 z++;
  1277.                                                 x = 0;
  1278.                                                 CurrentNeighborGroup = RowStartNeighborGroup;
  1279.                                                 if (z > LastZ)
  1280.                                                 {
  1281.                                                     if (CurrentNeighborGroup.Top != null)
  1282.                                                     {
  1283.                                                         z = 1;
  1284.                                                         RowStartNeighborGroup = CurrentNeighborGroup = NeighborGroupCollection[RowStartNeighborGroup.Top];
  1285.                                                     }
  1286.                                                     else
  1287.                                                     {
  1288.                                                         break;
  1289.                                                     }
  1290.                                                 }
  1291.                                             }
  1292.                                         }
  1293.                                     }
  1294.                                 }
  1295.                                 if (Errors == "")
  1296.                                 {
  1297.                                     foreach (var Item in NeighborGroupCollection)
  1298.                                     {
  1299.                                         Undo.RegisterCompleteObjectUndo(Item.Key.terrainData, "TerraLab apply heightmap");
  1300.                                         Item.Key.terrainData.SetHeights(0, 0, Item.Value.MainHeights);
  1301.                                     }
  1302.                                 }
  1303.                             }
  1304.                         }
  1305.                     }
  1306.                 }
  1307.             }
  1308.             private void ResetHeightmap(Terrain[] Terrains, out string Errors)
  1309.             {
  1310.                 Errors = "";
  1311.                 if (empty(Terrains))
  1312.                 {
  1313.                     Errors += "No terrains were provided.";
  1314.                 }
  1315.                 else
  1316.                 {
  1317.                     foreach (var TheTerrain in Terrains)
  1318.                     {
  1319.                         if (TheTerrain == null || TheTerrain.terrainData == null)
  1320.                         {
  1321.                             Errors += "The Terrain object has no TerrainData.";
  1322.                             break;
  1323.                         }
  1324.                     }
  1325.                     if (Errors == "")
  1326.                     {
  1327.                         int h, w;
  1328.                         float[,] TheHeights;
  1329.                         foreach (var TheTerrain in Terrains)
  1330.                         {
  1331.                             h = TheTerrain.terrainData.heightmapHeight;
  1332.                             w = TheTerrain.terrainData.heightmapWidth;
  1333.                             TheHeights = TheTerrain.terrainData.GetHeights(0, 0, w, h);
  1334.                             for (int z = 0; z < h; z++)
  1335.                             {
  1336.                                 for (int x = 0; x < w; x++)
  1337.                                 {
  1338.                                     TheHeights[z, x] = 0;
  1339.                                 }
  1340.                             }
  1341.                             Undo.RegisterCompleteObjectUndo(TheTerrain.terrainData, "TerraLab reset heightmaps");
  1342.                             TheTerrain.terrainData.SetHeights(0, 0, TheHeights);
  1343.                         }
  1344.                     }
  1345.                 }
  1346.             }
  1347.             private void ApplyHeightmap(Terrain TheTerrain, string PathToHeightmap, bool ReverseBytes, bool Use8Bit, out string Errors)
  1348.             {
  1349.                 Errors = "";
  1350.                 PathToHeightmap = PathToHeightmap ?? "";
  1351.                 if (!File.Exists(PathToHeightmap))
  1352.                 {
  1353.                     Errors += "The path to the heightmap is invalid.";
  1354.                 }
  1355.                 if (TheTerrain == null || TheTerrain.terrainData == null)
  1356.                 {
  1357.                     Errors += "The Terrain object has no TerrainData.";
  1358.                 }
  1359.                 if (Errors == "")
  1360.                 {
  1361.                     long len;
  1362.                     float v;
  1363.                     var h = TheTerrain.terrainData.heightmapHeight;
  1364.                     var w = TheTerrain.terrainData.heightmapWidth;
  1365.                     var TheHeights = TheTerrain.terrainData.GetHeights(0, 0, w, h);
  1366.                     using (var TheStream = File.OpenRead(PathToHeightmap))
  1367.                     {
  1368.                         using (var TheReader = new BinaryReader(TheStream))
  1369.                         {
  1370.                             len = TheReader.BaseStream.Length;
  1371.                             if (false)
  1372.                             {
  1373.                                 for (int z = 0; z < h; z++)
  1374.                                 {
  1375.                                     for (int x = 0; x < w; x++)
  1376.                                     {
  1377.                                         if (x == w - 1 && z == h - 1)
  1378.                                         {
  1379.                                             v = (TheHeights[z, x - 1] + TheHeights[z - 1, x]) / 2;
  1380.                                         }
  1381.                                         else if (x == w - 1)
  1382.                                         {
  1383.                                             v = TheHeights[z, x - 1];
  1384.                                         }
  1385.                                         else if (z == h - 1)
  1386.                                         {
  1387.                                             v = TheHeights[z - 1, x];
  1388.                                         }
  1389.                                         else
  1390.                                         {
  1391.                                             if (TheReader.BaseStream.Position < TheReader.BaseStream.Length)
  1392.                                             {
  1393.                                                 if (Use8Bit)
  1394.                                                 {
  1395.                                                     v = (float)TheReader.ReadByte() / 0xFF;
  1396.                                                 }
  1397.                                                 else
  1398.                                                 {
  1399.                                                     if (ReverseBytes)
  1400.                                                     {
  1401.                                                         v = (float)BitConverter.ToUInt16((byte[])TheReader.ReadBytes(2).Reverse(), 0) / 0xFFFF;
  1402.                                                     }
  1403.                                                     else
  1404.                                                     {
  1405.                                                         v = (float)TheReader.ReadUInt16() / 0xFFFF;
  1406.                                                     }
  1407.                                                 }
  1408.                                             }
  1409.                                             else
  1410.                                             {
  1411.                                                 v = 0;
  1412.                                             }
  1413.                                         }
  1414.                                         TheHeights[z, x] = v;
  1415.                                     }
  1416.                                 }
  1417.                             }
  1418.                         }
  1419.                     }
  1420.                     Debug.Log(len);
  1421.                     TheTerrain.terrainData.SetHeights(0, 0, TheHeights);
  1422.                 }
  1423.             }
  1424.             //##############################################################################
  1425.             //##############################################################################
  1426.             private static class SmoothPanel
  1427.             {
  1428.                 public static string RadiusStr = "3";
  1429.                 public static bool IgnoreNeighbors = false;
  1430.                 public static string SmoothErrors = "";
  1431.             }
  1432.             private void PaintSmoothPanel()
  1433.             {
  1434.                 TheLayout.BeginVertical();
  1435.                 if (empty(SelectedTerrains))
  1436.                 {
  1437.                     TheLayout.Label("No terrains selected.");
  1438.                 }
  1439.                 else
  1440.                 {
  1441.                     var Errors = "";
  1442.                     var TheTerrain = SelectedTerrains[0];
  1443.                     //var Neighbors = new NeighborGroup(TheTerrain, TerrainsInScene, out string Errors);
  1444.                     if (Errors != "")
  1445.                     {
  1446.                         TheLayout.Label(Errors);
  1447.                     }
  1448.                     else
  1449.                     {
  1450.                         var Resolution = TheTerrain.terrainData.heightmapResolution - 1;
  1451.                         var RadiusLimit = (Resolution / 2) - 1;
  1452.                         if (!int.TryParse(SmoothPanel.RadiusStr, out int Radius) || Radius < 0 || Radius > RadiusLimit)
  1453.                         {
  1454.                             Errors += "Radius must be between 0 and half the heightmap resolution minus 1 (the current resolution is " + Resolution + ").\n";
  1455.                         }
  1456.                         TheLayout.BeginHorizontal();
  1457.                         TheLayout.BeginVertical("width:500px;background-color:rgba(0,0,0,0.15);padding:5px;");
  1458.                         TheLayout.BeginHorizontal();
  1459.                         TheLayout.Label("Radius:", "width:200px;");
  1460.                         SmoothPanel.RadiusStr = TheLayout.TextField(SmoothPanel.RadiusStr, "width:100px;");
  1461.                         TheLayout.EndHorizontal();
  1462.                         TheLayout.BeginHorizontal();
  1463.                         TheLayout.Label("Ignore Neighbors:", "width:200px;");
  1464.                         SmoothPanel.IgnoreNeighbors = TheLayout.Toggle(SmoothPanel.IgnoreNeighbors);
  1465.                         TheLayout.EndHorizontal();
  1466.                         GUI.enabled = (Errors == "");
  1467.                         if (TheLayout.Button("Smooth Selected Terrains", "width:250px;margin-top:5px;"))
  1468.                         {
  1469.                             SmoothTerrains(SelectedTerrains, out SmoothPanel.SmoothErrors, Radius, SmoothPanel.IgnoreNeighbors);
  1470.                         }
  1471.                         if (SmoothPanel.SmoothErrors != "")
  1472.                         {
  1473.                             TheLayout.Label(SmoothPanel.SmoothErrors);
  1474.                         }
  1475.                         GUI.enabled = true;
  1476.                         TheLayout.EndVertical();
  1477.                         if (Errors != "")
  1478.                         {
  1479.                             Errors = Regex.Replace(Errors, "[\\s\\r\\n]*$", "");
  1480.                             TheLayout.BeginHorizontal("background-color:rgba(255,255,0,0.75);");
  1481.                             TheLayout.Label(Errors);
  1482.                             TheLayout.EndHorizontal();
  1483.                         }
  1484.                         TheLayout.EndHorizontal();
  1485.                     }
  1486.                 }
  1487.                 TheLayout.EndVertical();
  1488.             }
  1489.             private void SmoothTerrains(Terrain[] CurrentSelection, out string Errors, int Radius = 5, bool IgnoreNeighbors = false)
  1490.             {
  1491.                 Errors = "";
  1492.                 var NeighborGroupCollection = new List<NeighborGroup>();
  1493.                 string NeighborErrors;
  1494.                 foreach (var TerrainItem in CurrentSelection)
  1495.                 {
  1496.                     NeighborGroupCollection.Add(new NeighborGroup(TerrainItem, CurrentSelection, out NeighborErrors));
  1497.                     if (NeighborErrors != "")
  1498.                     {
  1499.                         Errors += NeighborErrors;
  1500.                         break;
  1501.                     }
  1502.                 }
  1503.                 if (Radius < 0)
  1504.                 {
  1505.                     Errors += "Radius cannot be negative.\n";
  1506.                 }
  1507.                 if (Errors == "")
  1508.                 {
  1509.                     float[,] HeightsTemp;
  1510.                     var HeightsCollection = new Dictionary<Terrain, float[,]>();
  1511.                     int HeightMapWidth, HeightMapHeight, LastX, LastZ, x, z;
  1512.                     foreach (var TheNeighborGroup in NeighborGroupCollection)
  1513.                     {
  1514.                         HeightsTemp = (float[,])TheNeighborGroup.MainHeights.Clone();
  1515.                         HeightMapWidth = TheNeighborGroup.Main.terrainData.heightmapWidth;
  1516.                         HeightMapHeight = TheNeighborGroup.Main.terrainData.heightmapHeight;
  1517.                         LastX = HeightMapWidth - 1;
  1518.                         LastZ = HeightMapHeight - 1;
  1519.                         //##############################################################
  1520.                         for (z = 0; z < HeightMapHeight; z++)
  1521.                         {
  1522.                             for (x = 0; x < HeightMapWidth; x++)
  1523.                             {
  1524.                                 HeightsTemp[z, x] = GetAverageHeightValue(TheNeighborGroup, x, z, Radius, IgnoreNeighbors);
  1525.                             }
  1526.                         }
  1527.                         //##############################################################
  1528.                         HeightsCollection.Add(TheNeighborGroup.Main, HeightsTemp);
  1529.                     }
  1530.                     foreach (var Item in HeightsCollection)
  1531.                     {
  1532.                         Undo.RegisterCompleteObjectUndo(Item.Key.terrainData, "TerraLab smooth terrains");
  1533.                         Item.Key.terrainData.SetHeights(0, 0, Item.Value);
  1534.                     }
  1535.                 }
  1536.             }
  1537.             //##############################################################################
  1538.             //##############################################################################
  1539.             private static class SewPanel
  1540.             {
  1541.                 public static int Method = 0;
  1542.                 public static string DistanceStr = "4";
  1543.                 public static string RadiusStr = "4";
  1544.                 public static string BlendPowerStr = "4";
  1545.                 public static string SewErrors = "";
  1546.             }
  1547.             private class NeighborGroup
  1548.             {
  1549.                 public NeighborGroup(Terrain TheTerrain, Terrain[] CurrentSelection, out string Errors)
  1550.                 {
  1551.                     Errors = "";
  1552.                     Main = TheTerrain;
  1553.                     if (TheTerrain.terrainData == null)
  1554.                     {
  1555.                         Errors += "The reference terrain has no TerrainData.\n";
  1556.                     }
  1557.                     if (Errors == "")
  1558.                     {
  1559.                         var x = TheTerrain.transform.position.x;
  1560.                         var y = TheTerrain.transform.position.y;
  1561.                         var z = TheTerrain.transform.position.z;
  1562.                         var width = TheTerrain.terrainData.size.x;
  1563.                         var height = TheTerrain.terrainData.size.y;
  1564.                         var length = TheTerrain.terrainData.size.z;
  1565.                         var HeightMapWidth = Main.terrainData.heightmapWidth;
  1566.                         var HeightMapHeight = Main.terrainData.heightmapHeight;
  1567.                         MainHeights = Main.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1568.                         float itemX, itemY, itemZ, itemWidth, itemHeight, itemLength;
  1569.                         foreach (var Item in CurrentSelection)
  1570.                         {
  1571.                             if (Item.terrainData == null)
  1572.                             {
  1573.                                 Errors += "One or more selected terrains has no TerrainData.\n";
  1574.                                 break;
  1575.                             }
  1576.                             else if (Item.terrainData.heightmapResolution != TheTerrain.terrainData.heightmapResolution)
  1577.                             {
  1578.                                 Errors += "One or more selected terrains have different heightmap resolutions.\n";
  1579.                                 Errors += "A neighbor scan cannot take place until all the selected terrains have matching heightmap resolutions.\n";
  1580.                                 break;
  1581.                             }
  1582.                             else
  1583.                             {
  1584.                                 itemX = Item.transform.position.x;
  1585.                                 itemY = Item.transform.position.y;
  1586.                                 itemZ = Item.transform.position.z;
  1587.                                 itemWidth = Item.terrainData.size.x;
  1588.                                 itemHeight = Item.terrainData.size.y;
  1589.                                 itemLength = Item.terrainData.size.z;
  1590.                                 if (TopLeft == null && itemY == y && itemHeight == height && (itemX + itemWidth == x && itemZ == z + length))
  1591.                                 {
  1592.                                     TopLeft = Item;
  1593.                                     TopLeftHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1594.                                 }
  1595.                                 else if (Top == null && itemY == y && itemHeight == height && (itemX == x && itemZ == z + length))
  1596.                                 {
  1597.                                     Top = Item;
  1598.                                     TopHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1599.                                 }
  1600.                                 else if (TopRight == null && itemY == y && itemHeight == height && (itemX == x + width && itemZ == z + length))
  1601.                                 {
  1602.                                     TopRight = Item;
  1603.                                     TopRightHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1604.                                 }
  1605.                                 else if (Left == null && itemY == y && itemHeight == height && (itemX + itemWidth == x && itemZ == z))
  1606.                                 {
  1607.                                     Left = Item;
  1608.                                     LeftHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1609.                                 }
  1610.                                 else if (Right == null && itemY == y && itemHeight == height && (itemX == x + width && itemZ == z))
  1611.                                 {
  1612.                                     Right = Item;
  1613.                                     RightHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1614.                                 }
  1615.                                 else if (BottomLeft == null && itemY == y && itemHeight == height && (itemX + itemWidth == x && itemZ + itemLength == z))
  1616.                                 {
  1617.                                     BottomLeft = Item;
  1618.                                     BottomLeftHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1619.                                 }
  1620.                                 else if (Bottom == null && itemY == y && itemHeight == height && (itemX == x && itemZ + itemLength == z))
  1621.                                 {
  1622.                                     Bottom = Item;
  1623.                                     BottomHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1624.                                 }
  1625.                                 else if (BottomRight == null && itemY == y && itemHeight == height && (itemX == x + width && itemZ + itemLength == z))
  1626.                                 {
  1627.                                     BottomRight = Item;
  1628.                                     BottomRightHeights = Item.terrainData.GetHeights(0, 0, HeightMapWidth, HeightMapHeight);
  1629.                                 }
  1630.                             }
  1631.                         }
  1632.                     }
  1633.                 }
  1634.                 public Terrain Main;
  1635.                 public Terrain TopLeft;
  1636.                 public Terrain Top;
  1637.                 public Terrain TopRight;
  1638.                 public Terrain Left;
  1639.                 public Terrain Right;
  1640.                 public Terrain BottomLeft;
  1641.                 public Terrain Bottom;
  1642.                 public Terrain BottomRight;
  1643.                 public float[,] MainHeights;
  1644.                 public float[,] TopLeftHeights;
  1645.                 public float[,] TopHeights;
  1646.                 public float[,] TopRightHeights;
  1647.                 public float[,] LeftHeights;
  1648.                 public float[,] RightHeights;
  1649.                 public float[,] BottomLeftHeights;
  1650.                 public float[,] BottomHeights;
  1651.                 public float[,] BottomRightHeights;
  1652.             }
  1653.             private void PaintSewPanel()
  1654.             {
  1655.                 TheLayout.BeginVertical();
  1656.                 //TheLayout.Label("Terrains in scene: " + TerrainsInScene.Length);
  1657.                 if (empty(SelectedTerrains))
  1658.                 {
  1659.                     TheLayout.Label("No terrains selected.");
  1660.                 }
  1661.                 else
  1662.                 {
  1663.                     var Errors = "";
  1664.                     var TheTerrain = SelectedTerrains[0];
  1665.                     //var Neighbors = new NeighborGroup(TheTerrain, TerrainsInScene, out string Errors);
  1666.                     if (Errors != "")
  1667.                     {
  1668.                         TheLayout.Label(Errors);
  1669.                     }
  1670.                     else
  1671.                     {
  1672.                         /*
  1673.                         TheLayout.Label("TopLeft: " + ((Neighbors.TopLeft == null) ? "" : "yes"));
  1674.                         TheLayout.Label("Top: " + ((Neighbors.Top == null) ? "" : "yes"));
  1675.                         TheLayout.Label("TopRight: " + ((Neighbors.TopRight == null) ? "" : "yes"));
  1676.                         TheLayout.Label("Left: " + ((Neighbors.Left == null) ? "" : "yes"));
  1677.                         TheLayout.Label("Right: " + ((Neighbors.Right == null) ? "" : "yes"));
  1678.                         TheLayout.Label("BottomLeft: " + ((Neighbors.BottomLeft == null) ? "" : "yes"));
  1679.                         TheLayout.Label("Bottom: " + ((Neighbors.Bottom == null) ? "" : "yes"));
  1680.                         TheLayout.Label("BottomRight: " + ((Neighbors.BottomRight == null) ? "" : "yes"));
  1681.                         */
  1682.                         var UseAveraging = SewPanel.Method == 1;
  1683.                         var UseSimple = SewPanel.Method == 2;
  1684.                         var Resolution = TheTerrain.terrainData.heightmapResolution - 1;
  1685.                         var RadiusLimit = (Resolution / 2) - 1;
  1686.                         if (!int.TryParse(SewPanel.RadiusStr, out int Radius) || Radius < 0 || Radius > RadiusLimit)
  1687.                         {
  1688.                             Errors += "Radius must be between 0 and half the heightmap resolution minus 1 (the current resolution is " + Resolution + ").\n";
  1689.                         }
  1690.                         var DistanceLimit = (Resolution / 2) - 1;
  1691.                         if (!int.TryParse(SewPanel.DistanceStr, out int Distance) || Distance < 0 || Distance > DistanceLimit)
  1692.                         {
  1693.                             Errors += "Distance must be between 0 and half the heightmap resolution minus 1 (the current resolution is " + Resolution + ").\n";
  1694.                         }
  1695.                         if (!float.TryParse(SewPanel.BlendPowerStr, out float BlendPower) || BlendPower < 0 || BlendPower > 32)
  1696.                         {
  1697.                             Errors += "Blend Power must be between 0 and 32.\n";
  1698.                         }
  1699.                         TheLayout.BeginHorizontal();
  1700.                         TheLayout.BeginVertical("width:500px;background-color:rgba(0,0,0,0.15);padding:5px;");
  1701.                         TheLayout.BeginHorizontal();
  1702.                         TheLayout.Label("Method:", "width:128px;");
  1703.                         SewPanel.Method = TheLayout.Toolbar(SewPanel.Method, new[] { "Difference", "Average", "Simple" });
  1704.                         TheLayout.EndHorizontal();
  1705.                         TheLayout.BeginHorizontal();
  1706.                         TheLayout.Label("Radius:", "width:128px;");
  1707.                         if (SewPanel.Method == 2)
  1708.                         {
  1709.                             TheLayout.Label("(no effect when using Simple)");
  1710.                         }
  1711.                         else if (SewPanel.Method == 0)
  1712.                         {
  1713.                             TheLayout.Label("(no effect when using Difference)");
  1714.                         }
  1715.                         else
  1716.                         {
  1717.                             SewPanel.RadiusStr = TheLayout.TextField(SewPanel.RadiusStr, "width:100px;");
  1718.                         }
  1719.                         TheLayout.EndHorizontal();
  1720.                         TheLayout.BeginHorizontal();
  1721.                         TheLayout.Label("Distance:", "width:128px;");
  1722.                         if (SewPanel.Method == 2)
  1723.                         {
  1724.                             TheLayout.Label("(no effect when using Simple)");
  1725.                         }
  1726.                         else
  1727.                         {
  1728.                             SewPanel.DistanceStr = TheLayout.TextField(SewPanel.DistanceStr, "width:100px;");
  1729.                         }
  1730.                         TheLayout.EndHorizontal();
  1731.                         TheLayout.BeginHorizontal();
  1732.                         TheLayout.Label("Blend Power:", "width:128px;");
  1733.                         if (SewPanel.Method == 2)
  1734.                         {
  1735.                             TheLayout.Label("(no effect when using Simple)");
  1736.                         }
  1737.                         else
  1738.                         {
  1739.                             SewPanel.BlendPowerStr = TheLayout.TextField(SewPanel.BlendPowerStr, "width:100px;");
  1740.                         }
  1741.                         TheLayout.EndHorizontal();
  1742.                         GUI.enabled = (Errors == "");
  1743.                         if (TheLayout.Button("Sew Selected Terrains", "width:200px;margin-top:5px;"))
  1744.                         {
  1745.                             SewTerrains(SelectedTerrains, out SewPanel.SewErrors, UseAveraging, UseSimple ? 0 : Radius, UseSimple ? 0 : Distance, BlendPower);
  1746.                         }
  1747.                         if (SewPanel.SewErrors != "")
  1748.                         {
  1749.                             TheLayout.Label(SewPanel.SewErrors);
  1750.                         }
  1751.                         GUI.enabled = true;
  1752.                         TheLayout.EndVertical();
  1753.                         if (Errors != "")
  1754.                         {
  1755.                             Errors = Regex.Replace(Errors, "[\\s\\r\\n]*$", "");
  1756.                             TheLayout.BeginHorizontal("background-color:rgba(255,255,0,0.75);");
  1757.                             TheLayout.Label(Errors);
  1758.                             TheLayout.EndHorizontal();
  1759.                         }
  1760.                         TheLayout.EndHorizontal();
  1761.                     }
  1762.                 }
  1763.                 TheLayout.EndVertical();
  1764.             }
  1765.             private void SewTerrains(Terrain[] CurrentSelection, out string Errors, bool UseAverage = false, int Radius = 5, int Distance = 5, float BlendPower = 4)
  1766.             {
  1767.                 Errors = "";
  1768.                 var NeighborGroupCollection = new List<NeighborGroup>();
  1769.                 string NeighborErrors;
  1770.                 foreach (var TerrainItem in CurrentSelection)
  1771.                 {
  1772.                     NeighborGroupCollection.Add(new NeighborGroup(TerrainItem, CurrentSelection, out NeighborErrors));
  1773.                     if (NeighborErrors != "")
  1774.                     {
  1775.                         Errors += NeighborErrors;
  1776.                         break;
  1777.                     }
  1778.                 }
  1779.                 if (Radius < 0)
  1780.                 {
  1781.                     Errors += "Radius cannot be negative.\n";
  1782.                 }
  1783.                 if (BlendPower < 0 || BlendPower > 16)
  1784.                 {
  1785.                     Errors += "Blend Power must be between 0 and 16.\n";
  1786.                 }
  1787.                 if (Errors == "")
  1788.                 {
  1789.                     //Tier 0 = full weight
  1790.                     Radius = UseAverage ? Radius : Distance;
  1791.                     float Tier;
  1792.                     float[,] HeightsTemp;
  1793.                     string CornerBlendKey;
  1794.                     float[] CornerBlendVal;
  1795.                     float[] SeamHeights = null;
  1796.                     bool SharpSmoothing = true;
  1797.                     Dictionary<string, float[]> CornerBlend;
  1798.                     float OriginalHeight, Weight, WeightedAverage;
  1799.                     int HeightMapWidth, HeightMapHeight, LastX, LastZ, x, z;
  1800.                     foreach (var TheNeighborGroup in NeighborGroupCollection)
  1801.                     {
  1802.                         HeightsTemp = (float[,])TheNeighborGroup.MainHeights.Clone();
  1803.                         HeightMapWidth = TheNeighborGroup.Main.terrainData.heightmapWidth;
  1804.                         HeightMapHeight = TheNeighborGroup.Main.terrainData.heightmapHeight;
  1805.                         LastX = HeightMapWidth - 1;
  1806.                         LastZ = HeightMapHeight - 1;
  1807.                         CornerBlend = new Dictionary<string, float[]>();
  1808.                         //##############################################################
  1809.                         //BottomLeft
  1810.                         if (TheNeighborGroup.BottomLeft != null)
  1811.                         {
  1812.                             for (z = 0; z < Distance + 1; z++)
  1813.                             {
  1814.                                 for (x = 0; x < Distance + 1; x++)
  1815.                                 {
  1816.                                     Tier = (float)Math.Sqrt(Math.Pow(x, 2) + Math.Pow(z, 2));
  1817.                                     Weight = Math.Max(0, ((Distance - Tier) + 1) / (Distance + 1));
  1818.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  1819.                                     HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  1820.                                 }
  1821.                             }
  1822.                         }
  1823.                         //BottomRight
  1824.                         if (TheNeighborGroup.BottomRight != null)
  1825.                         {
  1826.                             for (z = 0; z < Distance + 1; z++)
  1827.                             {
  1828.                                 for (x = LastX - Distance; x < HeightMapWidth; x++)
  1829.                                 {
  1830.                                     Tier = (float)Math.Sqrt(Math.Pow(LastX - x, 2) + Math.Pow(z, 2));
  1831.                                     Weight = Math.Max(0, ((Distance - Tier) + 1) / (Distance + 1));
  1832.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  1833.                                     HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  1834.                                 }
  1835.                             }
  1836.                         }
  1837.                         //TopLeft
  1838.                         if (TheNeighborGroup.TopLeft != null)
  1839.                         {
  1840.                             for (z = LastZ - Distance; z < HeightMapHeight; z++)
  1841.                             {
  1842.                                 for (x = 0; x < Distance + 1; x++)
  1843.                                 {
  1844.                                     Tier = (float)Math.Sqrt(Math.Pow(x, 2) + Math.Pow(LastZ - z, 2));
  1845.                                     Weight = Math.Max(0, ((Distance - Tier) + 1) / (Distance + 1));
  1846.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  1847.                                     HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  1848.                                 }
  1849.                             }
  1850.                         }
  1851.                         //TopRight
  1852.                         if (TheNeighborGroup.TopRight != null)
  1853.                         {
  1854.                             for (z = LastZ - Distance; z < HeightMapHeight; z++)
  1855.                             {
  1856.                                 for (x = LastX - Distance; x < HeightMapWidth; x++)
  1857.                                 {
  1858.                                     Tier = (float)Math.Sqrt(Math.Pow(LastX - x, 2) + Math.Pow(LastZ - z, 2));
  1859.                                     Weight = Math.Max(0, ((Distance - Tier) + 1) / (Distance + 1));
  1860.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  1861.                                     HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  1862.                                 }
  1863.                             }
  1864.                         }
  1865.                         //##############################################################
  1866.                         //Top
  1867.                         if (TheNeighborGroup.Top != null)
  1868.                         {
  1869.                             if (!UseAverage)
  1870.                             {
  1871.                                 SeamHeights = new float[HeightMapWidth];
  1872.                                 for (x = 0; x < HeightMapWidth; x++)
  1873.                                 {
  1874.                                     SeamHeights[x] = GetAverageHeightValue(TheNeighborGroup, x, LastZ, 0);
  1875.                                 }
  1876.                             }
  1877.                             for (z = LastZ - Distance; z < HeightMapHeight; z++)
  1878.                             {
  1879.                                 for (x = 0; x < HeightMapWidth; x++)
  1880.                                 {
  1881.                                     Tier = LastZ - z;
  1882.                                     if (UseAverage)
  1883.                                     {
  1884.                                         if (TheNeighborGroup.Left != null && x < Tier)
  1885.                                         {
  1886.                                             Tier = x;
  1887.                                         }
  1888.                                         else if (TheNeighborGroup.Right != null && LastX - x < Tier)
  1889.                                         {
  1890.                                             Tier = LastX - x;
  1891.                                         }
  1892.                                     }
  1893.                                     Weight = SharpSmoothing ? ((Distance - Tier) + 1) / (Distance + 1) : Math.Min(((Distance - Tier) + 1) / Distance, 1);
  1894.                                     Weight = (float)Math.Pow(Weight, BlendPower);
  1895.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  1896.                                     if (UseAverage)
  1897.                                     {
  1898.                                         HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  1899.                                     }
  1900.                                     else
  1901.                                     {
  1902.                                         if (z == LastZ)
  1903.                                         {
  1904.                                             HeightsTemp[z, x] = SeamHeights[x];
  1905.                                         }
  1906.                                         else if ((x > 0 && x < LastX) || (TheNeighborGroup.Left == null && x == 0) || (TheNeighborGroup.Right == null && x == LastX))
  1907.                                         {
  1908.                                             HeightsTemp[z, x] = OriginalHeight + ((SeamHeights[x] - OriginalHeight) * Weight);
  1909.                                         }
  1910.                                         if (z < LastZ && ((x > 0 && x < Distance + 1 && TheNeighborGroup.Left != null) || (x > LastX - (Distance + 1) && x < LastX && TheNeighborGroup.Right != null)))
  1911.                                         {
  1912.                                             CornerBlendKey = z + "," + x;
  1913.                                             if (CornerBlend.TryGetValue(CornerBlendKey, out CornerBlendVal))
  1914.                                             {
  1915.                                                 WeightedAverage = ((HeightsTemp[z, x] * Weight) + (CornerBlendVal[0] * CornerBlendVal[1])) / (Weight + CornerBlendVal[1]);
  1916.                                                 CornerBlend[CornerBlendKey] = new[] { WeightedAverage };
  1917.                                             }
  1918.                                             else
  1919.                                             {
  1920.                                                 CornerBlend.Add(CornerBlendKey, new[] { HeightsTemp[z, x], Weight });
  1921.                                             }
  1922.                                         }
  1923.                                     }
  1924.                                 }
  1925.                             }
  1926.                         }
  1927.                         //##############################################################
  1928.                         //Bottom
  1929.                         if (TheNeighborGroup.Bottom != null)
  1930.                         {
  1931.                             if (!UseAverage)
  1932.                             {
  1933.                                 SeamHeights = new float[HeightMapWidth];
  1934.                                 for (x = 0; x < HeightMapWidth; x++)
  1935.                                 {
  1936.                                     SeamHeights[x] = GetAverageHeightValue(TheNeighborGroup, x, 0, 0);
  1937.                                 }
  1938.                             }
  1939.                             for (z = 0; z < Distance + 1; z++)
  1940.                             {
  1941.                                 for (x = 0; x < HeightMapWidth; x++)
  1942.                                 {
  1943.                                     Tier = z;
  1944.                                     if (UseAverage)
  1945.                                     {
  1946.                                         if (TheNeighborGroup.Left != null && x < Tier)
  1947.                                         {
  1948.                                             Tier = x;
  1949.                                         }
  1950.                                         else if (TheNeighborGroup.Right != null && LastX - x < Tier)
  1951.                                         {
  1952.                                             Tier = LastX - x;
  1953.                                         }
  1954.                                     }
  1955.                                     Weight = SharpSmoothing ? ((Distance - Tier) + 1) / (Distance + 1) : Math.Min(((Distance - Tier) + 1) / Distance, 1);
  1956.                                     Weight = (float)Math.Pow(Weight, BlendPower);
  1957.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  1958.                                     if (UseAverage)
  1959.                                     {
  1960.                                         HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  1961.                                     }
  1962.                                     else
  1963.                                     {
  1964.                                         if (z == 0)
  1965.                                         {
  1966.                                             HeightsTemp[z, x] = SeamHeights[x];
  1967.                                         }
  1968.                                         else if ((x > 0 && x < LastX) || (TheNeighborGroup.Left == null && x == 0) || (TheNeighborGroup.Right == null && x == LastX))
  1969.                                         {
  1970.                                             HeightsTemp[z, x] = OriginalHeight + ((SeamHeights[x] - OriginalHeight) * Weight);
  1971.                                         }
  1972.                                         if (z > 0 && ((x > 0 && x < Distance + 1 && TheNeighborGroup.Left != null) || (x > LastX - (Distance + 1) && x < LastX && TheNeighborGroup.Right != null)))
  1973.                                         {
  1974.                                             CornerBlendKey = z + "," + x;
  1975.                                             if (CornerBlend.TryGetValue(CornerBlendKey, out CornerBlendVal))
  1976.                                             {
  1977.                                                 WeightedAverage = ((HeightsTemp[z, x] * Weight) + (CornerBlendVal[0] * CornerBlendVal[1])) / (Weight + CornerBlendVal[1]);
  1978.                                                 CornerBlend[CornerBlendKey] = new[] { WeightedAverage };
  1979.                                             }
  1980.                                             else
  1981.                                             {
  1982.                                                 CornerBlend.Add(CornerBlendKey, new[] { HeightsTemp[z, x], Weight });
  1983.                                             }
  1984.                                         }
  1985.                                     }
  1986.                                 }
  1987.                             }
  1988.                         }
  1989.                         //##############################################################
  1990.                         //Left
  1991.                         if (TheNeighborGroup.Left != null)
  1992.                         {
  1993.                             if (!UseAverage)
  1994.                             {
  1995.                                 SeamHeights = new float[HeightMapHeight];
  1996.                                 for (z = 0; z < HeightMapHeight; z++)
  1997.                                 {
  1998.                                     SeamHeights[z] = GetAverageHeightValue(TheNeighborGroup, 0, z, 0);
  1999.                                 }
  2000.                             }
  2001.                             for (x = 0; x < Distance + 1; x++)
  2002.                             {
  2003.                                 for (z = 0; z < HeightMapHeight; z++)
  2004.                                 {
  2005.                                     Tier = x;
  2006.                                     if (UseAverage)
  2007.                                     {
  2008.                                         if (TheNeighborGroup.Top != null && LastZ - z < Tier)
  2009.                                         {
  2010.                                             Tier = LastZ - z;
  2011.                                         }
  2012.                                         else if (TheNeighborGroup.Bottom != null && z < Tier)
  2013.                                         {
  2014.                                             Tier = z;
  2015.                                         }
  2016.                                     }
  2017.                                     Weight = SharpSmoothing ? ((Distance - Tier) + 1) / (Distance + 1) : Math.Min(((Distance - Tier) + 1) / Distance, 1);
  2018.                                     Weight = (float)Math.Pow(Weight, BlendPower);
  2019.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  2020.                                     if (UseAverage)
  2021.                                     {
  2022.                                         HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  2023.                                     }
  2024.                                     else
  2025.                                     {
  2026.                                         if (x == 0)
  2027.                                         {
  2028.                                             HeightsTemp[z, x] = SeamHeights[z];
  2029.                                         }
  2030.                                         else if ((z > 0 && z < LastZ) || (TheNeighborGroup.Top == null && z == LastZ) || (TheNeighborGroup.Bottom == null && z == 0))
  2031.                                         {
  2032.                                             HeightsTemp[z, x] = OriginalHeight + ((SeamHeights[z] - OriginalHeight) * Weight);
  2033.                                         }
  2034.                                         if (x > 0 && ((z > 0 && z < Distance + 1 && TheNeighborGroup.Bottom != null) || (z > LastZ - (Distance + 1) && z < LastZ && TheNeighborGroup.Top != null)))
  2035.                                         {
  2036.                                             CornerBlendKey = z + "," + x;
  2037.                                             if (CornerBlend.TryGetValue(CornerBlendKey, out CornerBlendVal))
  2038.                                             {
  2039.                                                 WeightedAverage = ((HeightsTemp[z, x] * Weight) + (CornerBlendVal[0] * CornerBlendVal[1])) / (Weight + CornerBlendVal[1]);
  2040.                                                 CornerBlend[CornerBlendKey] = new[] { WeightedAverage };
  2041.                                             }
  2042.                                             else
  2043.                                             {
  2044.                                                 CornerBlend.Add(CornerBlendKey, new[] { HeightsTemp[z, x], Weight });
  2045.                                             }
  2046.                                         }
  2047.                                     }
  2048.                                 }
  2049.                             }
  2050.                         }
  2051.                         //##############################################################
  2052.                         //Right
  2053.                         if (TheNeighborGroup.Right != null)
  2054.                         {
  2055.                             if (!UseAverage)
  2056.                             {
  2057.                                 SeamHeights = new float[HeightMapHeight];
  2058.                                 for (z = 0; z < HeightMapHeight; z++)
  2059.                                 {
  2060.                                     SeamHeights[z] = GetAverageHeightValue(TheNeighborGroup, LastX, z, 0);
  2061.                                 }
  2062.                             }
  2063.                             for (x = LastX - Distance; x < HeightMapWidth; x++)
  2064.                             {
  2065.                                 for (z = 0; z < HeightMapHeight; z++)
  2066.                                 {
  2067.                                     Tier = LastX - x;
  2068.                                     if (UseAverage)
  2069.                                     {
  2070.                                         if (TheNeighborGroup.Top != null && LastZ - z < Tier)
  2071.                                         {
  2072.                                             Tier = LastZ - z;
  2073.                                         }
  2074.                                         else if (TheNeighborGroup.Bottom != null && z < Tier)
  2075.                                         {
  2076.                                             Tier = z;
  2077.                                         }
  2078.                                     }
  2079.                                     Weight = SharpSmoothing ? ((Distance - Tier) + 1) / (Distance + 1) : Math.Min(((Distance - Tier) + 1) / Distance, 1);
  2080.                                     Weight = (float)Math.Pow(Weight, BlendPower);
  2081.                                     OriginalHeight = TheNeighborGroup.MainHeights[z, x];
  2082.                                     if (UseAverage)
  2083.                                     {
  2084.                                         HeightsTemp[z, x] = OriginalHeight + ((GetAverageHeightValue(TheNeighborGroup, x, z, Radius) - OriginalHeight) * Weight);
  2085.                                     }
  2086.                                     else
  2087.                                     {
  2088.                                         if (x == LastX)
  2089.                                         {
  2090.                                             HeightsTemp[z, x] = SeamHeights[z];
  2091.                                         }
  2092.                                         else if ((z > 0 && z < LastZ) || (TheNeighborGroup.Top == null && z == LastZ) || (TheNeighborGroup.Bottom == null && z == 0))
  2093.                                         {
  2094.                                             HeightsTemp[z, x] = OriginalHeight + ((SeamHeights[z] - OriginalHeight) * Weight);
  2095.                                         }
  2096.                                         if (x < LastX && ((z > 0 && z < Distance + 1 && TheNeighborGroup.Bottom != null) || (z > LastZ - (Distance + 1) && z < LastZ && TheNeighborGroup.Top != null)))
  2097.                                         {
  2098.                                             CornerBlendKey = z + "," + x;
  2099.                                             if (CornerBlend.TryGetValue(CornerBlendKey, out CornerBlendVal))
  2100.                                             {
  2101.                                                 WeightedAverage = ((HeightsTemp[z, x] * Weight) + (CornerBlendVal[0] * CornerBlendVal[1])) / (Weight + CornerBlendVal[1]);
  2102.                                                 CornerBlend[CornerBlendKey] = new[] { WeightedAverage };
  2103.                                             }
  2104.                                             else
  2105.                                             {
  2106.                                                 CornerBlend.Add(CornerBlendKey, new[] { HeightsTemp[z, x], Weight });
  2107.                                             }
  2108.                                         }
  2109.                                     }
  2110.                                 }
  2111.                             }
  2112.                         }
  2113.                         //##############################################################
  2114.                         if (!UseAverage)
  2115.                         {
  2116.                             foreach (var Item in CornerBlend)
  2117.                             {
  2118.                                 HeightsTemp[int.Parse(Regex.Replace(Item.Key, ",.*", "")), int.Parse(Regex.Replace(Item.Key, ".*,", ""))] = Item.Value[0];
  2119.                             }
  2120.                         }
  2121.                         //##############################################################
  2122.                         Undo.RecordObject(TheNeighborGroup.Main.terrainData, "TerraLab sew terrains");
  2123.                         TheNeighborGroup.Main.terrainData.SetHeights(0, 0, HeightsTemp);
  2124.                     }
  2125.                 }
  2126.             }
  2127.             private float GetAverageHeightValue(NeighborGroup TheNeighborGroup, int x, int z, int Radius, bool IgnoreNeighbors = false)
  2128.             {
  2129.                 //---    ---    ---    ---    ---    ---    x--    -x-    --x
  2130.                 //--- -> --- -> --- -> x-- -> -x- -> --x -> --- -> --- -> ---
  2131.                 //x--    -x-    --x    ---    ---    ---    ---    ---    ---
  2132.                 var LastX = TheNeighborGroup.Main.terrainData.heightmapWidth - 1;
  2133.                 var LastZ = TheNeighborGroup.Main.terrainData.heightmapHeight - 1;
  2134.                 float Average, Value, ExactPointCount, AverageCount, Sum;
  2135.                 bool ValueExists;
  2136.                 Sum = 0;
  2137.                 AverageCount = 0;
  2138.                 for (var RadZ = z - Radius; RadZ < z + Radius + 1; RadZ++)
  2139.                 {
  2140.                     for (var RadX = x - Radius; RadX < x + Radius + 1; RadX++)
  2141.                     {
  2142.                         Value = 0;
  2143.                         ValueExists = false;
  2144.                         if (IgnoreNeighbors)
  2145.                         {
  2146.                             if (RadX >= 0 && RadX <= LastX && RadZ >= 0 && RadZ <= LastZ)
  2147.                             {
  2148.                                 ValueExists = true;
  2149.                                 Value = TheNeighborGroup.MainHeights[RadZ, RadX];
  2150.                             }
  2151.                         }
  2152.                         else
  2153.                         {
  2154.                             if (RadX < 0 && RadZ > LastZ)
  2155.                             {
  2156.                                 //TopLeft Neighbor
  2157.                                 if (TheNeighborGroup.TopLeft != null)
  2158.                                 {
  2159.                                     ValueExists = true;
  2160.                                     Value = TheNeighborGroup.TopLeftHeights[RadZ - LastZ, LastX + RadX];
  2161.                                 }
  2162.                             }
  2163.                             else if (RadX > LastX && RadZ > LastZ)
  2164.                             {
  2165.                                 //TopRight Neighbor
  2166.                                 if (TheNeighborGroup.TopRight != null)
  2167.                                 {
  2168.                                     ValueExists = true;
  2169.                                     Value = TheNeighborGroup.TopRightHeights[RadZ - LastZ, RadX - LastX];
  2170.                                 }
  2171.                             }
  2172.                             else if (RadX < 0 && RadZ < 0)
  2173.                             {
  2174.                                 //BottomLeft Neighbor
  2175.                                 if (TheNeighborGroup.BottomLeft != null)
  2176.                                 {
  2177.                                     ValueExists = true;
  2178.                                     Value = TheNeighborGroup.BottomLeftHeights[LastZ + RadZ, LastX + RadX];
  2179.                                 }
  2180.                             }
  2181.                             else if (RadX > LastX && RadZ < 0)
  2182.                             {
  2183.                                 //BottomRight Neighbor
  2184.                                 if (TheNeighborGroup.BottomRight != null)
  2185.                                 {
  2186.                                     ValueExists = true;
  2187.                                     Value = TheNeighborGroup.BottomRightHeights[LastZ + RadZ, RadX - LastX];
  2188.                                 }
  2189.                             }
  2190.                             else
  2191.                             {
  2192.                                 ExactPointCount = 0;
  2193.                                 if (RadZ > LastZ)
  2194.                                 {
  2195.                                     //Top Neighbor
  2196.                                     if (TheNeighborGroup.Top != null)
  2197.                                     {
  2198.                                         ValueExists = true;
  2199.                                         Value += TheNeighborGroup.TopHeights[RadZ - LastZ, RadX];
  2200.                                         ExactPointCount++;
  2201.                                     }
  2202.                                     if (TheNeighborGroup.TopLeft != null && RadX == 0)
  2203.                                     {
  2204.                                         ValueExists = true;
  2205.                                         Value += TheNeighborGroup.TopLeftHeights[RadZ - LastZ, LastX];
  2206.                                         ExactPointCount++;
  2207.                                     }
  2208.                                     if (TheNeighborGroup.TopRight != null && RadX == LastX)
  2209.                                     {
  2210.                                         ValueExists = true;
  2211.                                         Value += TheNeighborGroup.TopRightHeights[RadZ - LastZ, 0];
  2212.                                         ExactPointCount++;
  2213.                                     }
  2214.                                 }
  2215.                                 else if (RadZ < 0)
  2216.                                 {
  2217.                                     //Bottom Neighbor
  2218.                                     if (TheNeighborGroup.Bottom != null)
  2219.                                     {
  2220.                                         ValueExists = true;
  2221.                                         Value += TheNeighborGroup.BottomHeights[LastZ + RadZ, RadX];
  2222.                                         ExactPointCount++;
  2223.                                     }
  2224.                                     if (TheNeighborGroup.BottomLeft != null && RadX == 0)
  2225.                                     {
  2226.                                         ValueExists = true;
  2227.                                         Value += TheNeighborGroup.BottomLeftHeights[LastZ + RadZ, LastX];
  2228.                                         ExactPointCount++;
  2229.                                     }
  2230.                                     if (TheNeighborGroup.BottomRight != null && RadX == LastX)
  2231.                                     {
  2232.                                         ValueExists = true;
  2233.                                         Value += TheNeighborGroup.BottomRightHeights[LastZ + RadZ, 0];
  2234.                                         ExactPointCount++;
  2235.                                     }
  2236.                                 }
  2237.                                 else if (RadX < 0)
  2238.                                 {
  2239.                                     //Left Neighbor
  2240.                                     if (TheNeighborGroup.Left != null)
  2241.                                     {
  2242.                                         ValueExists = true;
  2243.                                         Value += TheNeighborGroup.LeftHeights[RadZ, LastX + RadX];
  2244.                                         ExactPointCount++;
  2245.                                     }
  2246.                                     if (TheNeighborGroup.TopLeft != null && RadZ == LastZ)
  2247.                                     {
  2248.                                         ValueExists = true;
  2249.                                         Value += TheNeighborGroup.TopLeftHeights[0, LastX + RadX];
  2250.                                         ExactPointCount++;
  2251.                                     }
  2252.                                     if (TheNeighborGroup.BottomLeft != null && RadZ == 0)
  2253.                                     {
  2254.                                         ValueExists = true;
  2255.                                         Value += TheNeighborGroup.BottomLeftHeights[LastZ, LastX + RadX];
  2256.                                         ExactPointCount++;
  2257.                                     }
  2258.                                 }
  2259.                                 else if (RadX > LastX)
  2260.                                 {
  2261.                                     //Right Neighbor
  2262.                                     if (TheNeighborGroup.Right != null)
  2263.                                     {
  2264.                                         ValueExists = true;
  2265.                                         Value += TheNeighborGroup.RightHeights[RadZ, RadX - LastX];
  2266.                                         ExactPointCount++;
  2267.                                     }
  2268.                                     if (TheNeighborGroup.TopRight != null && RadZ == LastZ)
  2269.                                     {
  2270.                                         ValueExists = true;
  2271.                                         Value += TheNeighborGroup.TopRightHeights[0, RadX - LastX];
  2272.                                         ExactPointCount++;
  2273.                                     }
  2274.                                     if (TheNeighborGroup.BottomRight != null && RadZ == 0)
  2275.                                     {
  2276.                                         ValueExists = true;
  2277.                                         Value += TheNeighborGroup.BottomRightHeights[LastZ, RadX - LastX];
  2278.                                         ExactPointCount++;
  2279.                                     }
  2280.                                 }
  2281.                                 else
  2282.                                 {
  2283.                                     //point is inside the terrain
  2284.                                     ValueExists = true;
  2285.                                     ExactPointCount = 1;
  2286.                                     Value = TheNeighborGroup.MainHeights[RadZ, RadX];
  2287.                                     if (RadX == 0 && RadZ == LastZ)
  2288.                                     {
  2289.                                         //TopLeft Exact
  2290.                                         if (TheNeighborGroup.Left != null)
  2291.                                         {
  2292.                                             Value += TheNeighborGroup.LeftHeights[LastZ, LastX];
  2293.                                             ExactPointCount++;
  2294.                                         }
  2295.                                         if (TheNeighborGroup.TopLeft != null)
  2296.                                         {
  2297.                                             Value += TheNeighborGroup.TopLeftHeights[0, LastX];
  2298.                                             ExactPointCount++;
  2299.                                         }
  2300.                                         if (TheNeighborGroup.Top != null)
  2301.                                         {
  2302.                                             Value += TheNeighborGroup.TopHeights[0, 0];
  2303.                                             ExactPointCount++;
  2304.                                         }
  2305.                                     }
  2306.                                     else if (RadX == LastX && RadZ == LastZ)
  2307.                                     {
  2308.                                         //TopRight Exact
  2309.                                         if (TheNeighborGroup.Top != null)
  2310.                                         {
  2311.                                             Value += TheNeighborGroup.TopHeights[0, LastX];
  2312.                                             ExactPointCount++;
  2313.                                         }
  2314.                                         if (TheNeighborGroup.TopRight != null)
  2315.                                         {
  2316.                                             Value += TheNeighborGroup.TopRightHeights[0, 0];
  2317.                                             ExactPointCount++;
  2318.                                         }
  2319.                                         if (TheNeighborGroup.Right != null)
  2320.                                         {
  2321.                                             Value += TheNeighborGroup.RightHeights[LastZ, 0];
  2322.                                             ExactPointCount++;
  2323.                                         }
  2324.                                     }
  2325.                                     else if (RadX == 0 && RadZ == 0)
  2326.                                     {
  2327.                                         //BottomLeft Exact
  2328.                                         if (TheNeighborGroup.Bottom != null)
  2329.                                         {
  2330.                                             Value += TheNeighborGroup.BottomHeights[LastZ, 0];
  2331.                                             ExactPointCount++;
  2332.                                         }
  2333.                                         if (TheNeighborGroup.BottomLeft != null)
  2334.                                         {
  2335.                                             Value += TheNeighborGroup.BottomLeftHeights[LastZ, LastX];
  2336.                                             ExactPointCount++;
  2337.                                         }
  2338.                                         if (TheNeighborGroup.Left != null)
  2339.                                         {
  2340.                                             Value += TheNeighborGroup.LeftHeights[0, LastX];
  2341.                                             ExactPointCount++;
  2342.                                         }
  2343.                                     }
  2344.                                     else if (RadX == LastX && RadZ == 0)
  2345.                                     {
  2346.                                         //BottomRight Exact
  2347.                                         if (TheNeighborGroup.Right != null)
  2348.                                         {
  2349.                                             Value += TheNeighborGroup.RightHeights[0, 0];
  2350.                                             ExactPointCount++;
  2351.                                         }
  2352.                                         if (TheNeighborGroup.BottomRight != null)
  2353.                                         {
  2354.                                             Value += TheNeighborGroup.BottomRightHeights[LastZ, 0];
  2355.                                             ExactPointCount++;
  2356.                                         }
  2357.                                         if (TheNeighborGroup.Bottom != null)
  2358.                                         {
  2359.                                             Value += TheNeighborGroup.BottomHeights[LastZ, LastX];
  2360.                                             ExactPointCount++;
  2361.                                         }
  2362.                                     }
  2363.                                     else if (RadZ == LastZ)
  2364.                                     {
  2365.                                         //Top Exact
  2366.                                         if (TheNeighborGroup.Top != null)
  2367.                                         {
  2368.                                             Value += TheNeighborGroup.TopHeights[0, RadX];
  2369.                                             ExactPointCount++;
  2370.                                         }
  2371.                                     }
  2372.                                     else if (RadZ == 0)
  2373.                                     {
  2374.                                         //Bottom Exact
  2375.                                         if (TheNeighborGroup.Bottom != null)
  2376.                                         {
  2377.                                             Value += TheNeighborGroup.BottomHeights[LastZ, RadX];
  2378.                                             ExactPointCount++;
  2379.                                         }
  2380.                                     }
  2381.                                     else if (RadX == 0)
  2382.                                     {
  2383.                                         //Left Exact
  2384.                                         if (TheNeighborGroup.Left != null)
  2385.                                         {
  2386.                                             Value += TheNeighborGroup.LeftHeights[RadZ, LastX];
  2387.                                             ExactPointCount++;
  2388.                                         }
  2389.                                     }
  2390.                                     else if (RadX == LastX)
  2391.                                     {
  2392.                                         //Right Exact
  2393.                                         if (TheNeighborGroup.Right != null)
  2394.                                         {
  2395.                                             Value += TheNeighborGroup.RightHeights[RadZ, 0];
  2396.                                             ExactPointCount++;
  2397.                                         }
  2398.                                     }
  2399.                                 }
  2400.                                 Value = Value / ExactPointCount;
  2401.                             }
  2402.                         }
  2403.                         if (ValueExists)
  2404.                         {
  2405.                             Sum += Value;
  2406.                             AverageCount++;
  2407.                         }
  2408.                     }
  2409.                 }
  2410.                 Average = Sum / AverageCount;
  2411.                 return Average;
  2412.             }
  2413.             //##############################################################################
  2414.             //##############################################################################
  2415.             private static class LayersPanel
  2416.             {
  2417.                 public static string[] PaintString = null;
  2418.                 public static string[] LayerPaintErrors = null;
  2419.                 public static Vector2 ScrollVector = new Vector2(0, 0);
  2420.                 public static int alphamapWidth;
  2421.                 public static int alphamapHeight;
  2422.                 public static int heightmapWidth;
  2423.                 public static int heightmapHeight;
  2424.                 public static bool Different_alphamapWidth;
  2425.                 public static bool Different_alphamapHeight;
  2426.                 public static bool Different_heightmapWidth;
  2427.                 public static bool Different_heightmapHeight;
  2428.                 //####################################
  2429.                 public static TerrainLayer[][] LayerGroups = null;
  2430.                 public static string[] LayerEditErrors = null;
  2431.                 public static string[] nameStr = null;
  2432.                 public static Texture2D[] diffuseTexture = null;
  2433.                 public static Texture2D[] maskMapTexture = null;
  2434.                 public static Texture2D[] normalMapTexture = null;
  2435.                 public static string[] metallicStr = null;
  2436.                 public static string[] smoothnessStr = null;
  2437.                 public static string[] tileOffsetXStr = null;
  2438.                 public static string[] tileOffsetYStr = null;
  2439.                 public static string[] tileSizeXStr = null;
  2440.                 public static string[] tileSizeYStr = null;
  2441.                 public static string[] diffuseRemapMaxWStr = null;
  2442.                 public static string[] diffuseRemapMaxXStr = null;
  2443.                 public static string[] diffuseRemapMaxYStr = null;
  2444.                 public static string[] diffuseRemapMaxZStr = null;
  2445.                 public static string[] diffuseRemapMinWStr = null;
  2446.                 public static string[] diffuseRemapMinXStr = null;
  2447.                 public static string[] diffuseRemapMinYStr = null;
  2448.                 public static string[] diffuseRemapMinZStr = null;
  2449.                 public static string[] maskMapRemapMaxWStr = null;
  2450.                 public static string[] maskMapRemapMaxXStr = null;
  2451.                 public static string[] maskMapRemapMaxYStr = null;
  2452.                 public static string[] maskMapRemapMaxZStr = null;
  2453.                 public static string[] maskMapRemapMinWStr = null;
  2454.                 public static string[] maskMapRemapMinXStr = null;
  2455.                 public static string[] maskMapRemapMinYStr = null;
  2456.                 public static string[] maskMapRemapMinZStr = null;
  2457.                 public static string[] normalScaleStr = null;
  2458.                 public static string[] specularRStr = null;
  2459.                 public static string[] specularGStr = null;
  2460.                 public static string[] specularBStr = null;
  2461.                 public static string[] specularAStr = null;
  2462.                 //####################################
  2463.                 public static bool[] NullLayerExists;
  2464.                 public static bool[] Different_name;
  2465.                 public static bool[] Different_diffuseTexture;
  2466.                 public static bool[] Different_maskMapTexture;
  2467.                 public static bool[] Different_normalMapTexture;
  2468.                 public static bool[] Different_metallic;
  2469.                 public static bool[] Different_smoothness;
  2470.                 public static bool[] Different_tileOffsetX;
  2471.                 public static bool[] Different_tileOffsetY;
  2472.                 public static bool[] Different_tileSizeX;
  2473.                 public static bool[] Different_tileSizeY;
  2474.                 public static bool[] Different_diffuseRemapMaxW;
  2475.                 public static bool[] Different_diffuseRemapMaxX;
  2476.                 public static bool[] Different_diffuseRemapMaxY;
  2477.                 public static bool[] Different_diffuseRemapMaxZ;
  2478.                 public static bool[] Different_diffuseRemapMinW;
  2479.                 public static bool[] Different_diffuseRemapMinX;
  2480.                 public static bool[] Different_diffuseRemapMinY;
  2481.                 public static bool[] Different_diffuseRemapMinZ;
  2482.                 public static bool[] Different_maskMapRemapMaxW;
  2483.                 public static bool[] Different_maskMapRemapMaxX;
  2484.                 public static bool[] Different_maskMapRemapMaxY;
  2485.                 public static bool[] Different_maskMapRemapMaxZ;
  2486.                 public static bool[] Different_maskMapRemapMinW;
  2487.                 public static bool[] Different_maskMapRemapMinX;
  2488.                 public static bool[] Different_maskMapRemapMinY;
  2489.                 public static bool[] Different_maskMapRemapMinZ;
  2490.                 public static bool[] Different_normalScale;
  2491.                 public static bool[] Different_specularR;
  2492.                 public static bool[] Different_specularG;
  2493.                 public static bool[] Different_specularB;
  2494.                 public static bool[] Different_specularA;
  2495.                 //####################################
  2496.             }
  2497.             private void RefreshLayersPanel(Terrain[] Terrains)
  2498.             {
  2499.                 if (!SelectedLayerCountsAreDifferent && Terrains.Length > 0)
  2500.                 {
  2501.                     List<TerrainLayer> LayerGroup;
  2502.                     TerrainLayer TheLayer, LastLayer;
  2503.                     var FirstTerrain = Terrains[0];
  2504.                     var LayerCount = empty(FirstTerrain.terrainData.terrainLayers) ? 0 : FirstTerrain.terrainData.terrainLayers.Length;
  2505.                     if (LayersPanel.PaintString == null || LayersPanel.PaintString.Length < LayerCount)
  2506.                     {
  2507.                         Array.Resize(ref LayersPanel.PaintString, LayerCount);
  2508.                     }
  2509.                     if (LayersPanel.LayerPaintErrors == null || LayersPanel.LayerPaintErrors.Length < LayerCount)
  2510.                     {
  2511.                         Array.Resize(ref LayersPanel.LayerPaintErrors, LayerCount);
  2512.                     }
  2513.                     //########################################################
  2514.                     LayersPanel.alphamapWidth = 0;
  2515.                     LayersPanel.alphamapHeight = 0;
  2516.                     LayersPanel.heightmapWidth = 0;
  2517.                     LayersPanel.heightmapHeight = 0;
  2518.                     LayersPanel.Different_alphamapWidth = false;
  2519.                     LayersPanel.Different_alphamapHeight = false;
  2520.                     LayersPanel.Different_heightmapWidth = false;
  2521.                     LayersPanel.Different_heightmapHeight = false;
  2522.                     //########################################################
  2523.                     TerrainData TheData;
  2524.                     TerrainData LastData = null;
  2525.                     var c = 0;
  2526.                     foreach (var TerrainComponent in Terrains)
  2527.                     {
  2528.                         TheData = TerrainComponent.terrainData;
  2529.                         if (c == 0)
  2530.                         {
  2531.                             LastData = TheData;
  2532.                         }
  2533.                         //###############
  2534.                         LayersPanel.Different_alphamapWidth = (TheData.alphamapWidth != LastData.alphamapWidth) ? true : LayersPanel.Different_alphamapWidth;
  2535.                         LayersPanel.Different_alphamapHeight = (TheData.alphamapHeight != LastData.alphamapHeight) ? true : LayersPanel.Different_alphamapHeight;
  2536.                         LayersPanel.Different_heightmapWidth = (TheData.heightmapWidth != LastData.heightmapWidth) ? true : LayersPanel.Different_heightmapWidth;
  2537.                         LayersPanel.Different_heightmapHeight = (TheData.heightmapHeight != LastData.heightmapHeight) ? true : LayersPanel.Different_heightmapHeight;
  2538.                         //###############
  2539.                         LayersPanel.alphamapWidth = LayersPanel.Different_alphamapWidth ? 0 : TheData.alphamapWidth;
  2540.                         LayersPanel.alphamapHeight = LayersPanel.Different_alphamapHeight ? 0 : TheData.alphamapHeight;
  2541.                         LayersPanel.heightmapWidth = LayersPanel.Different_heightmapWidth ? 0 : TheData.heightmapWidth;
  2542.                         LayersPanel.heightmapHeight = LayersPanel.Different_heightmapHeight ? 0 : TheData.heightmapHeight;
  2543.                         //###############
  2544.                         LastData = TheData;
  2545.                         c++;
  2546.                     }
  2547.                     //########################################################
  2548.                     LayersPanel.LayerGroups = new TerrainLayer[LayerCount][];
  2549.                     LayersPanel.LayerEditErrors = new string[LayerCount];
  2550.                     LayersPanel.nameStr = new string[LayerCount];
  2551.                     LayersPanel.diffuseTexture = new Texture2D[LayerCount];
  2552.                     LayersPanel.maskMapTexture = new Texture2D[LayerCount];
  2553.                     LayersPanel.normalMapTexture = new Texture2D[LayerCount];
  2554.                     LayersPanel.metallicStr = new string[LayerCount];
  2555.                     LayersPanel.smoothnessStr = new string[LayerCount];
  2556.                     LayersPanel.tileOffsetXStr = new string[LayerCount];
  2557.                     LayersPanel.tileOffsetYStr = new string[LayerCount];
  2558.                     LayersPanel.tileSizeXStr = new string[LayerCount];
  2559.                     LayersPanel.tileSizeYStr = new string[LayerCount];
  2560.                     LayersPanel.diffuseRemapMaxWStr = new string[LayerCount];
  2561.                     LayersPanel.diffuseRemapMaxXStr = new string[LayerCount];
  2562.                     LayersPanel.diffuseRemapMaxYStr = new string[LayerCount];
  2563.                     LayersPanel.diffuseRemapMaxZStr = new string[LayerCount];
  2564.                     LayersPanel.diffuseRemapMinWStr = new string[LayerCount];
  2565.                     LayersPanel.diffuseRemapMinXStr = new string[LayerCount];
  2566.                     LayersPanel.diffuseRemapMinYStr = new string[LayerCount];
  2567.                     LayersPanel.diffuseRemapMinZStr = new string[LayerCount];
  2568.                     LayersPanel.maskMapRemapMaxWStr = new string[LayerCount];
  2569.                     LayersPanel.maskMapRemapMaxXStr = new string[LayerCount];
  2570.                     LayersPanel.maskMapRemapMaxYStr = new string[LayerCount];
  2571.                     LayersPanel.maskMapRemapMaxZStr = new string[LayerCount];
  2572.                     LayersPanel.maskMapRemapMinWStr = new string[LayerCount];
  2573.                     LayersPanel.maskMapRemapMinXStr = new string[LayerCount];
  2574.                     LayersPanel.maskMapRemapMinYStr = new string[LayerCount];
  2575.                     LayersPanel.maskMapRemapMinZStr = new string[LayerCount];
  2576.                     LayersPanel.normalScaleStr = new string[LayerCount];
  2577.                     LayersPanel.specularRStr = new string[LayerCount];
  2578.                     LayersPanel.specularGStr = new string[LayerCount];
  2579.                     LayersPanel.specularBStr = new string[LayerCount];
  2580.                     LayersPanel.specularAStr = new string[LayerCount];
  2581.                     //########################################################
  2582.                     LayersPanel.NullLayerExists = new bool[LayerCount];
  2583.                     LayersPanel.Different_name = new bool[LayerCount];
  2584.                     LayersPanel.Different_diffuseTexture = new bool[LayerCount];
  2585.                     LayersPanel.Different_maskMapTexture = new bool[LayerCount];
  2586.                     LayersPanel.Different_normalMapTexture = new bool[LayerCount];
  2587.                     LayersPanel.Different_metallic = new bool[LayerCount];
  2588.                     LayersPanel.Different_smoothness = new bool[LayerCount];
  2589.                     LayersPanel.Different_tileOffsetX = new bool[LayerCount];
  2590.                     LayersPanel.Different_tileOffsetY = new bool[LayerCount];
  2591.                     LayersPanel.Different_tileSizeX = new bool[LayerCount];
  2592.                     LayersPanel.Different_tileSizeY = new bool[LayerCount];
  2593.                     LayersPanel.Different_diffuseRemapMaxW = new bool[LayerCount];
  2594.                     LayersPanel.Different_diffuseRemapMaxX = new bool[LayerCount];
  2595.                     LayersPanel.Different_diffuseRemapMaxY = new bool[LayerCount];
  2596.                     LayersPanel.Different_diffuseRemapMaxZ = new bool[LayerCount];
  2597.                     LayersPanel.Different_diffuseRemapMinW = new bool[LayerCount];
  2598.                     LayersPanel.Different_diffuseRemapMinX = new bool[LayerCount];
  2599.                     LayersPanel.Different_diffuseRemapMinY = new bool[LayerCount];
  2600.                     LayersPanel.Different_diffuseRemapMinZ = new bool[LayerCount];
  2601.                     LayersPanel.Different_maskMapRemapMaxW = new bool[LayerCount];
  2602.                     LayersPanel.Different_maskMapRemapMaxX = new bool[LayerCount];
  2603.                     LayersPanel.Different_maskMapRemapMaxY = new bool[LayerCount];
  2604.                     LayersPanel.Different_maskMapRemapMaxZ = new bool[LayerCount];
  2605.                     LayersPanel.Different_maskMapRemapMinW = new bool[LayerCount];
  2606.                     LayersPanel.Different_maskMapRemapMinX = new bool[LayerCount];
  2607.                     LayersPanel.Different_maskMapRemapMinY = new bool[LayerCount];
  2608.                     LayersPanel.Different_maskMapRemapMinZ = new bool[LayerCount];
  2609.                     LayersPanel.Different_normalScale = new bool[LayerCount];
  2610.                     LayersPanel.Different_specularR = new bool[LayerCount];
  2611.                     LayersPanel.Different_specularG = new bool[LayerCount];
  2612.                     LayersPanel.Different_specularB = new bool[LayerCount];
  2613.                     LayersPanel.Different_specularA = new bool[LayerCount];
  2614.                     for (var i = 0; i < LayerCount; i++)
  2615.                     {
  2616.                         c = 0;
  2617.                         TheLayer = null;
  2618.                         LastLayer = null;
  2619.                         LayerGroup = new List<TerrainLayer>();
  2620.                         //########################################################
  2621.                         LayersPanel.NullLayerExists[i] = false;
  2622.                         LayersPanel.Different_name[i] = false;
  2623.                         LayersPanel.Different_diffuseTexture[i] = false;
  2624.                         LayersPanel.Different_maskMapTexture[i] = false;
  2625.                         LayersPanel.Different_normalMapTexture[i] = false;
  2626.                         LayersPanel.Different_metallic[i] = false;
  2627.                         LayersPanel.Different_smoothness[i] = false;
  2628.                         LayersPanel.Different_tileOffsetX[i] = false;
  2629.                         LayersPanel.Different_tileOffsetY[i] = false;
  2630.                         LayersPanel.Different_tileSizeX[i] = false;
  2631.                         LayersPanel.Different_tileSizeY[i] = false;
  2632.                         LayersPanel.Different_diffuseRemapMaxW[i] = false;
  2633.                         LayersPanel.Different_diffuseRemapMaxX[i] = false;
  2634.                         LayersPanel.Different_diffuseRemapMaxY[i] = false;
  2635.                         LayersPanel.Different_diffuseRemapMaxZ[i] = false;
  2636.                         LayersPanel.Different_diffuseRemapMinW[i] = false;
  2637.                         LayersPanel.Different_diffuseRemapMinX[i] = false;
  2638.                         LayersPanel.Different_diffuseRemapMinY[i] = false;
  2639.                         LayersPanel.Different_diffuseRemapMinZ[i] = false;
  2640.                         LayersPanel.Different_maskMapRemapMaxW[i] = false;
  2641.                         LayersPanel.Different_maskMapRemapMaxX[i] = false;
  2642.                         LayersPanel.Different_maskMapRemapMaxY[i] = false;
  2643.                         LayersPanel.Different_maskMapRemapMaxZ[i] = false;
  2644.                         LayersPanel.Different_maskMapRemapMinW[i] = false;
  2645.                         LayersPanel.Different_maskMapRemapMinX[i] = false;
  2646.                         LayersPanel.Different_maskMapRemapMinY[i] = false;
  2647.                         LayersPanel.Different_maskMapRemapMinZ[i] = false;
  2648.                         LayersPanel.Different_normalScale[i] = false;
  2649.                         LayersPanel.Different_specularR[i] = false;
  2650.                         LayersPanel.Different_specularG[i] = false;
  2651.                         LayersPanel.Different_specularB[i] = false;
  2652.                         LayersPanel.Different_specularA[i] = false;
  2653.                         foreach (var TerrainComponent in Terrains)
  2654.                         {
  2655.                             TheLayer = TerrainComponent.terrainData.terrainLayers[i];
  2656.                             if (c == 0)
  2657.                             {
  2658.                                 LastLayer = TheLayer;
  2659.                             }
  2660.                             if (TheLayer == null)
  2661.                             {
  2662.                                 LayersPanel.NullLayerExists[i] = true;
  2663.                             }
  2664.                             else if (!LayersPanel.NullLayerExists[i])
  2665.                             {
  2666.                                 LayersPanel.Different_name[i] = (TheLayer.name != LastLayer.name) ? true : LayersPanel.Different_name[i];
  2667.                                 LayersPanel.Different_diffuseTexture[i] = (TheLayer.diffuseTexture != LastLayer.diffuseTexture) ? true : LayersPanel.Different_diffuseTexture[i];
  2668.                                 LayersPanel.Different_maskMapTexture[i] = (TheLayer.maskMapTexture != LastLayer.maskMapTexture) ? true : LayersPanel.Different_maskMapTexture[i];
  2669.                                 LayersPanel.Different_normalMapTexture[i] = (TheLayer.normalMapTexture != LastLayer.normalMapTexture) ? true : LayersPanel.Different_normalMapTexture[i];
  2670.                                 LayersPanel.Different_metallic[i] = (TheLayer.metallic != LastLayer.metallic) ? true : LayersPanel.Different_metallic[i];
  2671.                                 LayersPanel.Different_smoothness[i] = (TheLayer.smoothness != LastLayer.smoothness) ? true : LayersPanel.Different_smoothness[i];
  2672.                                 LayersPanel.Different_tileOffsetX[i] = (TheLayer.tileOffset.x != LastLayer.tileOffset.x) ? true : LayersPanel.Different_tileOffsetX[i];
  2673.                                 LayersPanel.Different_tileOffsetY[i] = (TheLayer.tileOffset.y != LastLayer.tileOffset.y) ? true : LayersPanel.Different_tileOffsetY[i];
  2674.                                 LayersPanel.Different_tileSizeX[i] = (TheLayer.tileSize.x != LastLayer.tileSize.x) ? true : LayersPanel.Different_tileSizeX[i];
  2675.                                 LayersPanel.Different_tileSizeY[i] = (TheLayer.tileSize.y != LastLayer.tileSize.y) ? true : LayersPanel.Different_tileSizeY[i];
  2676.                                 LayersPanel.Different_diffuseRemapMaxW[i] = (TheLayer.diffuseRemapMax.w != LastLayer.diffuseRemapMax.w) ? true : LayersPanel.Different_diffuseRemapMaxW[i];
  2677.                                 LayersPanel.Different_diffuseRemapMaxX[i] = (TheLayer.diffuseRemapMax.x != LastLayer.diffuseRemapMax.x) ? true : LayersPanel.Different_diffuseRemapMaxX[i];
  2678.                                 LayersPanel.Different_diffuseRemapMaxY[i] = (TheLayer.diffuseRemapMax.y != LastLayer.diffuseRemapMax.y) ? true : LayersPanel.Different_diffuseRemapMaxY[i];
  2679.                                 LayersPanel.Different_diffuseRemapMaxZ[i] = (TheLayer.diffuseRemapMax.z != LastLayer.diffuseRemapMax.z) ? true : LayersPanel.Different_diffuseRemapMaxZ[i];
  2680.                                 LayersPanel.Different_diffuseRemapMinW[i] = (TheLayer.diffuseRemapMin.w != LastLayer.diffuseRemapMin.w) ? true : LayersPanel.Different_diffuseRemapMinW[i];
  2681.                                 LayersPanel.Different_diffuseRemapMinX[i] = (TheLayer.diffuseRemapMin.x != LastLayer.diffuseRemapMin.x) ? true : LayersPanel.Different_diffuseRemapMinX[i];
  2682.                                 LayersPanel.Different_diffuseRemapMinY[i] = (TheLayer.diffuseRemapMin.y != LastLayer.diffuseRemapMin.y) ? true : LayersPanel.Different_diffuseRemapMinY[i];
  2683.                                 LayersPanel.Different_diffuseRemapMinZ[i] = (TheLayer.diffuseRemapMin.z != LastLayer.diffuseRemapMin.z) ? true : LayersPanel.Different_diffuseRemapMinZ[i];
  2684.                                 LayersPanel.Different_maskMapRemapMaxW[i] = (TheLayer.maskMapRemapMax.w != LastLayer.maskMapRemapMax.w) ? true : LayersPanel.Different_maskMapRemapMaxW[i];
  2685.                                 LayersPanel.Different_maskMapRemapMaxX[i] = (TheLayer.maskMapRemapMax.x != LastLayer.maskMapRemapMax.x) ? true : LayersPanel.Different_maskMapRemapMaxX[i];
  2686.                                 LayersPanel.Different_maskMapRemapMaxY[i] = (TheLayer.maskMapRemapMax.y != LastLayer.maskMapRemapMax.y) ? true : LayersPanel.Different_maskMapRemapMaxY[i];
  2687.                                 LayersPanel.Different_maskMapRemapMaxZ[i] = (TheLayer.maskMapRemapMax.z != LastLayer.maskMapRemapMax.z) ? true : LayersPanel.Different_maskMapRemapMaxZ[i];
  2688.                                 LayersPanel.Different_maskMapRemapMinW[i] = (TheLayer.maskMapRemapMin.w != LastLayer.maskMapRemapMin.w) ? true : LayersPanel.Different_maskMapRemapMinW[i];
  2689.                                 LayersPanel.Different_maskMapRemapMinX[i] = (TheLayer.maskMapRemapMin.x != LastLayer.maskMapRemapMin.x) ? true : LayersPanel.Different_maskMapRemapMinX[i];
  2690.                                 LayersPanel.Different_maskMapRemapMinY[i] = (TheLayer.maskMapRemapMin.y != LastLayer.maskMapRemapMin.y) ? true : LayersPanel.Different_maskMapRemapMinY[i];
  2691.                                 LayersPanel.Different_maskMapRemapMinZ[i] = (TheLayer.maskMapRemapMin.z != LastLayer.maskMapRemapMin.z) ? true : LayersPanel.Different_maskMapRemapMinZ[i];
  2692.                                 LayersPanel.Different_normalScale[i] = (TheLayer.normalScale != LastLayer.normalScale) ? true : LayersPanel.Different_normalScale[i];
  2693.                                 LayersPanel.Different_specularR[i] = (TheLayer.specular.r != LastLayer.specular.r) ? true : LayersPanel.Different_specularR[i];
  2694.                                 LayersPanel.Different_specularG[i] = (TheLayer.specular.g != LastLayer.specular.g) ? true : LayersPanel.Different_specularG[i];
  2695.                                 LayersPanel.Different_specularB[i] = (TheLayer.specular.b != LastLayer.specular.b) ? true : LayersPanel.Different_specularB[i];
  2696.                                 LayersPanel.Different_specularA[i] = (TheLayer.specular.a != LastLayer.specular.a) ? true : LayersPanel.Different_specularA[i];
  2697.                             }
  2698.                             LayerGroup.Add(TheLayer);
  2699.                             LastLayer = TheLayer;
  2700.                             c++;
  2701.                         }
  2702.                         LayersPanel.LayerGroups[i] = LayerGroup.ToArray();
  2703.                         //########################################
  2704.                         if (!LayersPanel.NullLayerExists[i])
  2705.                         {
  2706.                             LayersPanel.nameStr[i] = LayersPanel.Different_name[i] ? "" : TheLayer.name;
  2707.                             LayersPanel.diffuseTexture[i] = LayersPanel.Different_diffuseTexture[i] ? null : TheLayer.diffuseTexture;
  2708.                             LayersPanel.maskMapTexture[i] = LayersPanel.Different_maskMapTexture[i] ? null : TheLayer.maskMapTexture;
  2709.                             LayersPanel.normalMapTexture[i] = LayersPanel.Different_normalMapTexture[i] ? null : TheLayer.normalMapTexture;
  2710.                             LayersPanel.metallicStr[i] = LayersPanel.Different_metallic[i] ? "" : TheLayer.metallic + "";
  2711.                             LayersPanel.smoothnessStr[i] = LayersPanel.Different_smoothness[i] ? "" : TheLayer.smoothness + "";
  2712.                             LayersPanel.tileOffsetXStr[i] = LayersPanel.Different_tileOffsetX[i] ? "" : TheLayer.tileOffset.x + "";
  2713.                             LayersPanel.tileOffsetYStr[i] = LayersPanel.Different_tileOffsetY[i] ? "" : TheLayer.tileOffset.y + "";
  2714.                             LayersPanel.tileSizeXStr[i] = LayersPanel.Different_tileSizeX[i] ? "" : TheLayer.tileSize.x + "";
  2715.                             LayersPanel.tileSizeYStr[i] = LayersPanel.Different_tileSizeY[i] ? "" : TheLayer.tileSize.y + "";
  2716.                             LayersPanel.diffuseRemapMaxWStr[i] = LayersPanel.Different_diffuseRemapMaxW[i] ? "" : TheLayer.diffuseRemapMax.w + "";
  2717.                             LayersPanel.diffuseRemapMaxXStr[i] = LayersPanel.Different_diffuseRemapMaxX[i] ? "" : TheLayer.diffuseRemapMax.x + "";
  2718.                             LayersPanel.diffuseRemapMaxYStr[i] = LayersPanel.Different_diffuseRemapMaxY[i] ? "" : TheLayer.diffuseRemapMax.y + "";
  2719.                             LayersPanel.diffuseRemapMaxZStr[i] = LayersPanel.Different_diffuseRemapMaxZ[i] ? "" : TheLayer.diffuseRemapMax.z + "";
  2720.                             LayersPanel.diffuseRemapMinWStr[i] = LayersPanel.Different_diffuseRemapMinW[i] ? "" : TheLayer.diffuseRemapMin.w + "";
  2721.                             LayersPanel.diffuseRemapMinXStr[i] = LayersPanel.Different_diffuseRemapMinX[i] ? "" : TheLayer.diffuseRemapMin.x + "";
  2722.                             LayersPanel.diffuseRemapMinYStr[i] = LayersPanel.Different_diffuseRemapMinY[i] ? "" : TheLayer.diffuseRemapMin.y + "";
  2723.                             LayersPanel.diffuseRemapMinZStr[i] = LayersPanel.Different_diffuseRemapMinZ[i] ? "" : TheLayer.diffuseRemapMin.z + "";
  2724.                             LayersPanel.maskMapRemapMaxWStr[i] = LayersPanel.Different_maskMapRemapMaxW[i] ? "" : TheLayer.maskMapRemapMax.w + "";
  2725.                             LayersPanel.maskMapRemapMaxXStr[i] = LayersPanel.Different_maskMapRemapMaxX[i] ? "" : TheLayer.maskMapRemapMax.x + "";
  2726.                             LayersPanel.maskMapRemapMaxYStr[i] = LayersPanel.Different_maskMapRemapMaxY[i] ? "" : TheLayer.maskMapRemapMax.y + "";
  2727.                             LayersPanel.maskMapRemapMaxZStr[i] = LayersPanel.Different_maskMapRemapMaxZ[i] ? "" : TheLayer.maskMapRemapMax.z + "";
  2728.                             LayersPanel.maskMapRemapMinWStr[i] = LayersPanel.Different_maskMapRemapMinW[i] ? "" : TheLayer.maskMapRemapMin.w + "";
  2729.                             LayersPanel.maskMapRemapMinXStr[i] = LayersPanel.Different_maskMapRemapMinX[i] ? "" : TheLayer.maskMapRemapMin.x + "";
  2730.                             LayersPanel.maskMapRemapMinYStr[i] = LayersPanel.Different_maskMapRemapMinY[i] ? "" : TheLayer.maskMapRemapMin.y + "";
  2731.                             LayersPanel.maskMapRemapMinZStr[i] = LayersPanel.Different_maskMapRemapMinZ[i] ? "" : TheLayer.maskMapRemapMin.z + "";
  2732.                             LayersPanel.normalScaleStr[i] = LayersPanel.Different_normalScale[i] ? "" : TheLayer.normalScale + "";
  2733.                             LayersPanel.specularRStr[i] = LayersPanel.Different_specularR[i] ? "" : TheLayer.specular.r + "";
  2734.                             LayersPanel.specularGStr[i] = LayersPanel.Different_specularG[i] ? "" : TheLayer.specular.g + "";
  2735.                             LayersPanel.specularBStr[i] = LayersPanel.Different_specularB[i] ? "" : TheLayer.specular.b + "";
  2736.                             LayersPanel.specularAStr[i] = LayersPanel.Different_specularA[i] ? "" : TheLayer.specular.a + "";
  2737.                         }
  2738.                     }
  2739.                 }
  2740.             }
  2741.             private void PaintLayersPanel()
  2742.             {
  2743.                 TheLayout.BeginVertical();
  2744.                 if (empty(SelectedTerrains))
  2745.                 {
  2746.                     TheLayout.Label("No terrains selected.");
  2747.                 }
  2748.                 else
  2749.                 {
  2750.                     var Errors = "";
  2751.                     var FirstTerrain = SelectedTerrains[0];
  2752.                     var LayerCount = empty(FirstTerrain.terrainData.terrainLayers) ? 0 : FirstTerrain.terrainData.terrainLayers.Length;
  2753.                     if (SelectedLayerCountsAreDifferent)
  2754.                     {
  2755.                         Errors += "Selected terrains have varying layer counts. Each terrain must have the same number of layers to be edited here.";
  2756.                     }
  2757.                     if (Errors != "")
  2758.                     {
  2759.                         TheLayout.Label(Errors);
  2760.                     }
  2761.                     else
  2762.                     {
  2763.                         TheLayout.BeginVertical("background-color:rgba(0,0,0,0.15);padding:5px;");
  2764.                         if (LayerCount == 0)
  2765.                         {
  2766.                             TheLayout.Label("Selected terrain" + ((SelectedTerrains.Length == 1) ? " has" : "s have") + " no layers.");
  2767.                         }
  2768.                         else
  2769.                         {
  2770.                             TheLayout.Label("Base Texture Resolution must be as large as the Heightmap Resolution for proper painting.", "stretch-width:true;");
  2771.                             TheLayout.BeginHorizontal();
  2772.                             TheLayout.Label("alphamapWidth: " + (LayersPanel.Different_alphamapWidth ? "(different)" : (LayersPanel.alphamapWidth + "")), "width:200px;");
  2773.                             TheLayout.Label("heightmapWidth: " + (LayersPanel.Different_heightmapWidth ? "(different)" : (LayersPanel.heightmapWidth + "")), "width:200px;");
  2774.                             TheLayout.EndHorizontal();
  2775.                             TheLayout.BeginHorizontal();
  2776.                             TheLayout.Label("alphamapHeight: " + (LayersPanel.Different_alphamapHeight ? "(different)" : (LayersPanel.alphamapHeight + "")), "width:200px;");
  2777.                             TheLayout.Label("heightmapHeight: " + (LayersPanel.Different_heightmapHeight ? "(different)" : (LayersPanel.heightmapHeight + "")), "width:200px;");
  2778.                             TheLayout.EndHorizontal();
  2779.                             TheLayout.BeginVertical("stretch-width:true;stretch-height:true;margin-top:5px;");
  2780.                             LayersPanel.ScrollVector = GUILayout.BeginScrollView(LayersPanel.ScrollVector);
  2781.                             var RemoveLayerNum = -1;
  2782.                             var InstantiateLayerNum = -1;
  2783.                             for (var i = 0; i < LayerCount; i++)
  2784.                             {
  2785.                                 TheLayout.BeginHorizontal();
  2786.                                 TheLayout.Label(i + "", "stretch-width:false;font-size:30px;vertical-align:top;");
  2787.                                 TheLayout.BeginVertical("stretch-width:false;background-color:rgba(0,0,0,0.15);width:550px;padding:5px;");
  2788.                                 if (LayersPanel.NullLayerExists[i])
  2789.                                 {
  2790.                                     TheLayout.Label("One or more selected terrains has a null value for this layer.", "min-width:500px;");
  2791.                                     GUILayout.Space(10);
  2792.                                     TheLayout.BeginHorizontal("width:" + TheLayout.LargestWidth + "px;background-color:rgba(0,0,0,0.2);");
  2793.                                     if (TheLayout.Button("Instantiate Null Layer(s)", "width:200px;"))
  2794.                                     {
  2795.                                         InstantiateLayerNum = i;
  2796.                                     }
  2797.                                     GUILayout.FlexibleSpace();
  2798.                                     if (TheLayout.Button("Remove Layer", "width:200px"))
  2799.                                     {
  2800.                                         RemoveLayerNum = i;
  2801.                                     }
  2802.                                     TheLayout.EndHorizontal();
  2803.                                 }
  2804.                                 else
  2805.                                 {
  2806.                                     TheLayout.BeginHorizontal();
  2807.                                     TheLayout.Label("name:", "width:200px");
  2808.                                     LayersPanel.nameStr[i] = TheLayout.TextField(LayersPanel.nameStr[i], "stretch-width:true;");
  2809.                                     if (LayersPanel.Different_name[i])
  2810.                                     {
  2811.                                         TheLayout.Label("(varies)");
  2812.                                     }
  2813.                                     TheLayout.EndHorizontal();
  2814.                                     TheLayout.BeginHorizontal();
  2815.                                     TheLayout.Label("textures:", "width:200px");
  2816.                                     LayersPanel.diffuseTexture[i] = TheLayout.TextureField(LayersPanel.diffuseTexture[i], "diffuse");
  2817.                                     LayersPanel.maskMapTexture[i] = TheLayout.TextureField(LayersPanel.maskMapTexture[i], "maskMap");
  2818.                                     LayersPanel.normalMapTexture[i] = TheLayout.TextureField(LayersPanel.normalMapTexture[i], "normalMap");
  2819.                                     if (LayersPanel.Different_diffuseTexture[i])
  2820.                                     {
  2821.                                         TheLayout.Label("(varies)");
  2822.                                     }
  2823.                                     TheLayout.EndHorizontal();
  2824.                                     TheLayout.BeginHorizontal();
  2825.                                     TheLayout.Label("metallic:", "width:200px");
  2826.                                     LayersPanel.metallicStr[i] = TheLayout.TextField(LayersPanel.metallicStr[i], "width:65px;");
  2827.                                     if (LayersPanel.Different_metallic[i])
  2828.                                     {
  2829.                                         TheLayout.Label("(varies)");
  2830.                                     }
  2831.                                     TheLayout.EndHorizontal();
  2832.                                     TheLayout.BeginHorizontal();
  2833.                                     TheLayout.Label("smoothness:", "width:200px");
  2834.                                     LayersPanel.smoothnessStr[i] = TheLayout.TextField(LayersPanel.smoothnessStr[i], "width:65px;");
  2835.                                     if (LayersPanel.Different_smoothness[i])
  2836.                                     {
  2837.                                         TheLayout.Label("(varies)");
  2838.                                     }
  2839.                                     TheLayout.EndHorizontal();
  2840.                                     TheLayout.BeginHorizontal();
  2841.                                     TheLayout.Label("normalScale:", "width:200px");
  2842.                                     LayersPanel.normalScaleStr[i] = TheLayout.TextField(LayersPanel.normalScaleStr[i], "width:65px;");
  2843.                                     if (LayersPanel.Different_normalScale[i])
  2844.                                     {
  2845.                                         TheLayout.Label("(varies)");
  2846.                                     }
  2847.                                     TheLayout.EndHorizontal();
  2848.                                     TheLayout.BeginHorizontal();
  2849.                                     TheLayout.Label("tileOffset:", "width:200px");
  2850.                                     TheLayout.Label("X");
  2851.                                     LayersPanel.tileOffsetXStr[i] = TheLayout.TextField(LayersPanel.tileOffsetXStr[i], "width:65px;");
  2852.                                     TheLayout.Label("Y");
  2853.                                     LayersPanel.tileOffsetYStr[i] = TheLayout.TextField(LayersPanel.tileOffsetYStr[i], "width:65px;stretch-width:false;");
  2854.                                     if (LayersPanel.Different_tileOffsetX[i] || LayersPanel.Different_tileOffsetY[i])
  2855.                                     {
  2856.                                         TheLayout.Label("(varies)");
  2857.                                     }
  2858.                                     TheLayout.EndHorizontal();
  2859.                                     TheLayout.BeginHorizontal();
  2860.                                     TheLayout.Label("tileSize:", "width:200px");
  2861.                                     TheLayout.Label("X");
  2862.                                     LayersPanel.tileSizeXStr[i] = TheLayout.TextField(LayersPanel.tileSizeXStr[i], "width:65px;");
  2863.                                     TheLayout.Label("Y");
  2864.                                     LayersPanel.tileSizeYStr[i] = TheLayout.TextField(LayersPanel.tileSizeYStr[i], "width:65px;");
  2865.                                     if (LayersPanel.Different_tileSizeX[i] || LayersPanel.Different_tileSizeY[i])
  2866.                                     {
  2867.                                         TheLayout.Label("(varies)");
  2868.                                     }
  2869.                                     TheLayout.EndHorizontal();
  2870.                                     TheLayout.BeginHorizontal();
  2871.                                     TheLayout.Label("diffuseRemapMax:", "width:200px");
  2872.                                     TheLayout.Label("X");
  2873.                                     LayersPanel.diffuseRemapMaxXStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMaxXStr[i], "width:65px;");
  2874.                                     TheLayout.Label("Y");
  2875.                                     LayersPanel.diffuseRemapMaxYStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMaxYStr[i], "width:65px;");
  2876.                                     TheLayout.Label("Z");
  2877.                                     LayersPanel.diffuseRemapMaxZStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMaxZStr[i], "width:65px;");
  2878.                                     TheLayout.Label("W");
  2879.                                     LayersPanel.diffuseRemapMaxWStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMaxWStr[i], "width:65px;");
  2880.                                     if (LayersPanel.Different_diffuseRemapMaxW[i] || LayersPanel.Different_diffuseRemapMaxX[i] || LayersPanel.Different_diffuseRemapMaxY[i] || LayersPanel.Different_diffuseRemapMaxZ[i])
  2881.                                     {
  2882.                                         TheLayout.Label("(varies)");
  2883.                                     }
  2884.                                     TheLayout.EndHorizontal();
  2885.                                     TheLayout.BeginHorizontal();
  2886.                                     TheLayout.Label("diffuseRemapMin:", "width:200px");
  2887.                                     TheLayout.Label("X");
  2888.                                     LayersPanel.diffuseRemapMinXStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMinXStr[i], "width:65px;");
  2889.                                     TheLayout.Label("Y");
  2890.                                     LayersPanel.diffuseRemapMinYStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMinYStr[i], "width:65px;");
  2891.                                     TheLayout.Label("Z");
  2892.                                     LayersPanel.diffuseRemapMinZStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMinZStr[i], "width:65px;");
  2893.                                     TheLayout.Label("W");
  2894.                                     LayersPanel.diffuseRemapMinWStr[i] = TheLayout.TextField(LayersPanel.diffuseRemapMinWStr[i], "width:65px;");
  2895.                                     if (LayersPanel.Different_diffuseRemapMinW[i] || LayersPanel.Different_diffuseRemapMinX[i] || LayersPanel.Different_diffuseRemapMinY[i] || LayersPanel.Different_diffuseRemapMinZ[i])
  2896.                                     {
  2897.                                         TheLayout.Label("(varies)");
  2898.                                     }
  2899.                                     TheLayout.EndHorizontal();
  2900.                                     TheLayout.BeginHorizontal();
  2901.                                     TheLayout.Label("maskMapRemapMax:", "width:200px");
  2902.                                     TheLayout.Label("X");
  2903.                                     LayersPanel.maskMapRemapMaxXStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMaxXStr[i], "width:65px;");
  2904.                                     TheLayout.Label("Y");
  2905.                                     LayersPanel.maskMapRemapMaxYStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMaxYStr[i], "width:65px;");
  2906.                                     TheLayout.Label("Z");
  2907.                                     LayersPanel.maskMapRemapMaxZStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMaxZStr[i], "width:65px;");
  2908.                                     TheLayout.Label("W");
  2909.                                     LayersPanel.maskMapRemapMaxWStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMaxWStr[i], "width:65px;");
  2910.                                     if (LayersPanel.Different_maskMapRemapMaxW[i] || LayersPanel.Different_maskMapRemapMaxX[i] || LayersPanel.Different_maskMapRemapMaxY[i] || LayersPanel.Different_maskMapRemapMaxZ[i])
  2911.                                     {
  2912.                                         TheLayout.Label("(varies)");
  2913.                                     }
  2914.                                     TheLayout.EndHorizontal();
  2915.                                     TheLayout.BeginHorizontal();
  2916.                                     TheLayout.Label("maskMapRemapMin:", "width:200px");
  2917.                                     TheLayout.Label("X");
  2918.                                     LayersPanel.maskMapRemapMinXStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMinXStr[i], "width:65px;");
  2919.                                     TheLayout.Label("Y");
  2920.                                     LayersPanel.maskMapRemapMinYStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMinYStr[i], "width:65px;");
  2921.                                     TheLayout.Label("Z");
  2922.                                     LayersPanel.maskMapRemapMinZStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMinZStr[i], "width:65px;");
  2923.                                     TheLayout.Label("W");
  2924.                                     LayersPanel.maskMapRemapMinWStr[i] = TheLayout.TextField(LayersPanel.maskMapRemapMinWStr[i], "width:65px;");
  2925.                                     if (LayersPanel.Different_maskMapRemapMinW[i] || LayersPanel.Different_maskMapRemapMinX[i] || LayersPanel.Different_maskMapRemapMinY[i] || LayersPanel.Different_maskMapRemapMinZ[i])
  2926.                                     {
  2927.                                         TheLayout.Label("(varies)");
  2928.                                     }
  2929.                                     TheLayout.EndHorizontal();
  2930.                                     TheLayout.BeginHorizontal();
  2931.                                     TheLayout.Label("specular:", "width:200px");
  2932.                                     TheLayout.Label("R");
  2933.                                     LayersPanel.specularRStr[i] = TheLayout.TextField(LayersPanel.specularRStr[i], "width:65px;");
  2934.                                     TheLayout.Label("G");
  2935.                                     LayersPanel.specularGStr[i] = TheLayout.TextField(LayersPanel.specularGStr[i], "width:65px;");
  2936.                                     TheLayout.Label("B");
  2937.                                     LayersPanel.specularBStr[i] = TheLayout.TextField(LayersPanel.specularBStr[i], "width:65px;");
  2938.                                     TheLayout.Label("A");
  2939.                                     LayersPanel.specularAStr[i] = TheLayout.TextField(LayersPanel.specularAStr[i], "width:65px;");
  2940.                                     if (LayersPanel.Different_specularR[i] || LayersPanel.Different_specularG[i] || LayersPanel.Different_specularB[i] || LayersPanel.Different_specularA[i])
  2941.                                     {
  2942.                                         TheLayout.Label("(varies)");
  2943.                                     }
  2944.                                     TheLayout.EndHorizontal();
  2945.                                     TheLayout.BeginHorizontal("");
  2946.                                     TheLayout.Label("Paint Condition:", "");
  2947.                                     LayersPanel.PaintString[i] = TheLayout.TextArea(LayersPanel.PaintString[i], "stretch-width:true;height:60px;margin:0px 10px");
  2948.                                     if (TheLayout.Button("Paint", "width:100px;height:60px;vertical-align:middle;"))
  2949.                                     {
  2950.                                         PaintLayer(SelectedTerrains, i, LayersPanel.PaintString[i], out LayersPanel.LayerPaintErrors[i]);
  2951.                                     }
  2952.                                     TheLayout.EndHorizontal();
  2953.                                     GUILayout.Space(10);
  2954.                                     TheLayout.BeginHorizontal("stretch-width:true;");
  2955.                                     if (TheLayout.Button("Save Layer", "width:200px"))
  2956.                                     {
  2957.                                         EditLayer(LayersPanel.LayerGroups[i], i, out LayersPanel.LayerEditErrors[i]);
  2958.                                     }
  2959.                                     GUILayout.FlexibleSpace();
  2960.                                     if (TheLayout.Button("Remove Layer", "width:200px"))
  2961.                                     {
  2962.                                         RemoveLayerNum = i;
  2963.                                     }
  2964.                                     TheLayout.EndHorizontal();
  2965.                                 }
  2966.                                 if (!empty(LayersPanel.LayerEditErrors[i]))
  2967.                                 {
  2968.                                     TheLayout.BeginHorizontal("background-color:rgba(255,255,0,0.75);");
  2969.                                     TheLayout.Label(LayersPanel.LayerEditErrors[i] ?? "", "");
  2970.                                     TheLayout.EndHorizontal();
  2971.                                 }
  2972.                                 TheLayout.EndVertical();
  2973.                                 TheLayout.EndHorizontal();
  2974.                                 GUILayout.Space(10);
  2975.                             }
  2976.                             GUILayout.EndScrollView();
  2977.                             TheLayout.EndVertical();
  2978.                             if (InstantiateLayerNum > -1)
  2979.                             {
  2980.                                 InstantiateLayer(SelectedTerrains, InstantiateLayerNum);
  2981.                             }
  2982.                             if (RemoveLayerNum > -1)
  2983.                             {
  2984.                                 RemoveLayer(SelectedTerrains, RemoveLayerNum);
  2985.                             }
  2986.                         }
  2987.                         if (TheLayout.Button("Add Layer", "width:200px"))
  2988.                         {
  2989.                             AddLayer(SelectedTerrains);
  2990.                         }
  2991.                         TheLayout.EndVertical();
  2992.                     }
  2993.                 }
  2994.                 TheLayout.EndVertical();
  2995.             }
  2996.             private void PaintLayer(Terrain[] Terrains, int LayerNum, string Criteria, out string Errors)
  2997.             {
  2998.                 int AlphaWidth, AlphaHeight, MeshWidth, MeshHeight, MeshX, MeshZ;
  2999.                 TerrainData TheData;
  3000.                 float[,,] AlphaMaps;
  3001.                 float[,] Heights;
  3002.                 float Height, Steepness, NormalizedX, NormalizedZ;
  3003.                 var Empty = string.IsNullOrEmpty(Criteria);
  3004.                 var TheTruth = Truth.Compile(Empty ? "h==0" : Criteria, new[] { 'h', 's' }, out Errors);
  3005.                 var Values = new Dictionary<string, float> { { "h", 0 }, { "s", 0 } };
  3006.                 foreach (var TheTerrain in Terrains)
  3007.                 {
  3008.                     TheData = TheTerrain.terrainData;
  3009.                     AlphaWidth = TheData.alphamapWidth;
  3010.                     AlphaHeight = TheData.alphamapHeight;
  3011.                     MeshWidth = TheData.heightmapWidth;
  3012.                     MeshHeight = TheData.heightmapHeight;
  3013.                     Heights = TheData.GetHeights(0, 0, MeshWidth, MeshHeight);
  3014.                     AlphaMaps = TheData.GetAlphamaps(0, 0, AlphaWidth, AlphaHeight);
  3015.                     if (LayerNum < TheData.terrainLayers.Length)
  3016.                     {
  3017.                         for (var AlphaX = 0; AlphaX < AlphaWidth; AlphaX++)
  3018.                         {
  3019.                             for (int AlphaZ = 0; AlphaZ < AlphaHeight; AlphaZ++)
  3020.                             {
  3021.                                 NormalizedX = AlphaX / (float)(AlphaWidth - 1);
  3022.                                 NormalizedZ = AlphaZ / (float)(AlphaHeight - 1);
  3023.                                 MeshX = (int)Math.Round(NormalizedX * (MeshWidth - 1));
  3024.                                 MeshZ = (int)Math.Round(NormalizedZ * (MeshHeight - 1));
  3025.                                 Height = Heights[MeshZ, MeshX];
  3026.                                 Steepness = TheData.GetSteepness(NormalizedX, NormalizedZ);
  3027.                                 Values["h"] = Empty ? 0 : Height;
  3028.                                 Values["s"] = Steepness;
  3029.                                 if (TheTruth.Evaluate(Values))
  3030.                                 {
  3031.                                     for (var c = 0; c < TheData.terrainLayers.Length; c++)
  3032.                                     {
  3033.                                         AlphaMaps[AlphaZ, AlphaX, c] = 0;
  3034.                                     }
  3035.                                     AlphaMaps[AlphaZ, AlphaX, LayerNum] = 1;
  3036.                                 }
  3037.                             }
  3038.                         }
  3039.                         TheData.SetAlphamaps(0, 0, AlphaMaps);
  3040.                     }
  3041.                 }
  3042.             }
  3043.             private void AddLayer(Terrain[] Terrains)
  3044.             {
  3045.                 int CurLen;
  3046.                 var SaveAsset = true;
  3047.                 TerrainLayer[] NewArr;
  3048.                 var NewLayer = new TerrainLayer();
  3049.                 NewLayer.name = "Layer_" + RandomInt32;
  3050.                 foreach (var TheTerrain in Terrains)
  3051.                 {
  3052.                     CurLen = (TheTerrain.terrainData.terrainLayers == null) ? 0 : TheTerrain.terrainData.terrainLayers.Length;
  3053.                     NewArr = new TerrainLayer[CurLen + 1];
  3054.                     for (var i = 0; i < CurLen; i++)
  3055.                     {
  3056.                         NewArr[i] = TheTerrain.terrainData.terrainLayers[i];
  3057.                     }
  3058.                     NewArr[CurLen] = NewLayer;
  3059.                     TheTerrain.terrainData.terrainLayers = NewArr;
  3060.                 }
  3061.                 if (SaveAsset)
  3062.                 {
  3063.                     TheAssetBucket.Add(NewLayer, false);
  3064.                 }
  3065.                 RefreshLayersPanel(Terrains);
  3066.             }
  3067.             private void InstantiateLayer(Terrain[] Terrains, int LayerNum)
  3068.             {
  3069.                 var NewLayer = new TerrainLayer();
  3070.                 NewLayer.name = "Layer_" + RandomInt32;
  3071.                 var SaveAsset = true;
  3072.                 TerrainData TheData;
  3073.                 TerrainLayer[] TheLayers;
  3074.                 TerrainLayer[] NewLayers;
  3075.                 foreach (var TheTerrain in Terrains)
  3076.                 {
  3077.                     if (TheTerrain != null)
  3078.                     {
  3079.                         TheData = TheTerrain.terrainData;
  3080.                         if (TheData != null)
  3081.                         {
  3082.                             TheLayers = TheData.terrainLayers;
  3083.                             if (TheLayers != null && TheLayers[LayerNum] == null)
  3084.                             {
  3085.                                 NewLayers = new TerrainLayer[TheLayers.Length];
  3086.                                 for (var i = 0; i < NewLayers.Length; i++)
  3087.                                 {
  3088.                                     if (i == LayerNum)
  3089.                                     {
  3090.                                         NewLayers[i] = NewLayer;
  3091.                                     }
  3092.                                     else
  3093.                                     {
  3094.                                         NewLayers[i] = TheLayers[i];
  3095.                                     }
  3096.                                 }
  3097.                                 TheData.terrainLayers = NewLayers;
  3098.                                 SaveAsset = true;
  3099.                             }
  3100.                         }
  3101.                     }
  3102.                 }
  3103.                 if (SaveAsset)
  3104.                 {
  3105.                     TheAssetBucket.Add(NewLayer, false);
  3106.                 }
  3107.                 RefreshLayersPanel(Terrains);
  3108.             }
  3109.             private void RemoveLayer(Terrain[] Terrains, int LayerNum)
  3110.             {
  3111.                 List<TerrainLayer> LayerList;
  3112.                 foreach (var TheTerrain in Terrains)
  3113.                 {
  3114.                     LayerList = new List<TerrainLayer>(TheTerrain.terrainData.terrainLayers);
  3115.                     if (LayerNum < LayerList.Count)
  3116.                     {
  3117.                         LayerList.RemoveAt(LayerNum);
  3118.                     }
  3119.                     TheTerrain.terrainData.terrainLayers = LayerList.ToArray();
  3120.                 }
  3121.                 RefreshLayersPanel(Terrains);
  3122.             }
  3123.             private void EditLayer(TerrainLayer[] LayerGroup, int LayerNum, out string Errors)
  3124.             {
  3125.                 Errors = "";
  3126.                 var i = LayerNum;
  3127.                 if (LayersPanel.NullLayerExists[i])
  3128.                 {
  3129.                     Errors += "Null layer exists.";
  3130.                 }
  3131.                 else
  3132.                 {
  3133.                     float[] TheSpecularColor;
  3134.                     foreach (var Layer in LayerGroup)
  3135.                     {
  3136.                         TheSpecularColor = new float[] { Layer.specular.r, Layer.specular.g, Layer.specular.b, Layer.specular.a };
  3137.                         if ((LayersPanel.Different_name[i] && !empty(LayersPanel.nameStr[i])) || !LayersPanel.Different_name[i])
  3138.                         {
  3139.                             if (empty(LayersPanel.nameStr[i]))
  3140.                             {
  3141.                                 Errors += "name cannot be empty.\n";
  3142.                             }
  3143.                             else
  3144.                             {
  3145.                                 Layer.name = LayersPanel.nameStr[i];
  3146.                             }
  3147.                         }
  3148.                         if ((LayersPanel.Different_diffuseTexture[i] && !empty(LayersPanel.diffuseTexture[i])) || !LayersPanel.Different_diffuseTexture[i])
  3149.                         {
  3150.                             Layer.diffuseTexture = LayersPanel.diffuseTexture[i];
  3151.                         }
  3152.                         if ((LayersPanel.Different_maskMapTexture[i] && !empty(LayersPanel.maskMapTexture[i])) || !LayersPanel.Different_maskMapTexture[i])
  3153.                         {
  3154.                             Layer.maskMapTexture = LayersPanel.maskMapTexture[i];
  3155.                         }
  3156.                         if ((LayersPanel.Different_normalMapTexture[i] && !empty(LayersPanel.normalMapTexture[i])) || !LayersPanel.Different_normalMapTexture[i])
  3157.                         {
  3158.                             Layer.normalMapTexture = LayersPanel.normalMapTexture[i];
  3159.                         }
  3160.                         if ((LayersPanel.Different_metallic[i] && !empty(LayersPanel.metallicStr[i])) || !LayersPanel.Different_metallic[i])
  3161.                         {
  3162.                             if (!float.TryParse(LayersPanel.metallicStr[i], out float metallic) || metallic < 0)
  3163.                             {
  3164.                                 Errors += "metallic must be a decimal greater than 0.\n";
  3165.                             }
  3166.                             else
  3167.                             {
  3168.                                 Layer.metallic = metallic;
  3169.                             }
  3170.                         }
  3171.                         if ((LayersPanel.Different_smoothness[i] && !empty(LayersPanel.smoothnessStr[i])) || !LayersPanel.Different_smoothness[i])
  3172.                         {
  3173.                             if (!float.TryParse(LayersPanel.smoothnessStr[i], out float smoothness) || smoothness < 0)
  3174.                             {
  3175.                                 Errors += "smoothness must be a decimal greater than 0.\n";
  3176.                             }
  3177.                             else
  3178.                             {
  3179.                                 Layer.smoothness = smoothness;
  3180.                             }
  3181.                         }
  3182.                         if ((LayersPanel.Different_tileOffsetX[i] && !empty(LayersPanel.tileOffsetXStr[i])) || !LayersPanel.Different_tileOffsetX[i])
  3183.                         {
  3184.                             if (!float.TryParse(LayersPanel.tileOffsetXStr[i], out float tileOffsetX) || tileOffsetX < 0)
  3185.                             {
  3186.                                 Errors += "tileOffsetX must be a decimal greater than 0.\n";
  3187.                             }
  3188.                             else
  3189.                             {
  3190.                                 Layer.tileOffset = new Vector2(tileOffsetX, Layer.tileOffset.y);
  3191.                             }
  3192.                         }
  3193.                         if ((LayersPanel.Different_tileOffsetY[i] && !empty(LayersPanel.tileOffsetYStr[i])) || !LayersPanel.Different_tileOffsetY[i])
  3194.                         {
  3195.                             if (!float.TryParse(LayersPanel.tileOffsetYStr[i], out float tileOffsetY) || tileOffsetY < 0)
  3196.                             {
  3197.                                 Errors += "tileOffsetY must be a decimal greater than 0.\n";
  3198.                             }
  3199.                             else
  3200.                             {
  3201.                                 Layer.tileOffset = new Vector2(Layer.tileOffset.y, tileOffsetY);
  3202.                             }
  3203.                         }
  3204.                         if ((LayersPanel.Different_tileSizeX[i] && !empty(LayersPanel.tileSizeXStr[i])) || !LayersPanel.Different_tileSizeX[i])
  3205.                         {
  3206.                             if (!float.TryParse(LayersPanel.tileSizeXStr[i], out float tileSizeX) || tileSizeX < 0)
  3207.                             {
  3208.                                 Errors += "tileSizeX must be a decimal greater than 0.\n";
  3209.                             }
  3210.                             else
  3211.                             {
  3212.                                 Layer.tileSize = new Vector2(tileSizeX, Layer.tileSize.y);
  3213.                             }
  3214.                         }
  3215.                         if ((LayersPanel.Different_tileSizeY[i] && !empty(LayersPanel.tileSizeYStr[i])) || !LayersPanel.Different_tileSizeY[i])
  3216.                         {
  3217.                             if (!float.TryParse(LayersPanel.tileSizeYStr[i], out float tileSizeY) || tileSizeY < 0)
  3218.                             {
  3219.                                 Errors += "tileSizeY must be a decimal greater than 0.\n";
  3220.                             }
  3221.                             else
  3222.                             {
  3223.                                 Layer.tileSize = new Vector2(Layer.tileSize.x, tileSizeY);
  3224.                             }
  3225.                         }
  3226.                         if ((LayersPanel.Different_diffuseRemapMaxW[i] && !empty(LayersPanel.diffuseRemapMaxWStr[i])) || !LayersPanel.Different_diffuseRemapMaxW[i])
  3227.                         {
  3228.                             if (!float.TryParse(LayersPanel.diffuseRemapMaxWStr[i], out float diffuseRemapMaxW) || diffuseRemapMaxW < 0)
  3229.                             {
  3230.                                 Errors += "diffuseRemapMaxW must be a decimal greater than 0.\n";
  3231.                             }
  3232.                             else
  3233.                             {
  3234.                                 Layer.diffuseRemapMax = new Vector4(Layer.diffuseRemapMax.x, Layer.diffuseRemapMax.y, Layer.diffuseRemapMax.z, diffuseRemapMaxW);
  3235.                             }
  3236.                         }
  3237.                         if ((LayersPanel.Different_diffuseRemapMaxX[i] && !empty(LayersPanel.diffuseRemapMaxXStr[i])) || !LayersPanel.Different_diffuseRemapMaxX[i])
  3238.                         {
  3239.                             if (!float.TryParse(LayersPanel.diffuseRemapMaxXStr[i], out float diffuseRemapMaxX) || diffuseRemapMaxX < 0)
  3240.                             {
  3241.                                 Errors += "diffuseRemapMaxX must be a decimal greater than 0.\n";
  3242.                             }
  3243.                             else
  3244.                             {
  3245.                                 Layer.diffuseRemapMax = new Vector4(diffuseRemapMaxX, Layer.diffuseRemapMax.y, Layer.diffuseRemapMax.z, Layer.diffuseRemapMax.w);
  3246.                             }
  3247.                         }
  3248.                         if ((LayersPanel.Different_diffuseRemapMaxY[i] && !empty(LayersPanel.diffuseRemapMaxYStr[i])) || !LayersPanel.Different_diffuseRemapMaxY[i])
  3249.                         {
  3250.                             if (!float.TryParse(LayersPanel.diffuseRemapMaxYStr[i], out float diffuseRemapMaxY) || diffuseRemapMaxY < 0)
  3251.                             {
  3252.                                 Errors += "diffuseRemapMaxY must be a decimal greater than 0.\n";
  3253.                             }
  3254.                             else
  3255.                             {
  3256.                                 Layer.diffuseRemapMax = new Vector4(Layer.diffuseRemapMax.x, diffuseRemapMaxY, Layer.diffuseRemapMax.z, Layer.diffuseRemapMax.w);
  3257.                             }
  3258.                         }
  3259.                         if ((LayersPanel.Different_diffuseRemapMaxZ[i] && !empty(LayersPanel.diffuseRemapMaxZStr[i])) || !LayersPanel.Different_diffuseRemapMaxZ[i])
  3260.                         {
  3261.                             if (!float.TryParse(LayersPanel.diffuseRemapMaxZStr[i], out float diffuseRemapMaxZ) || diffuseRemapMaxZ < 0)
  3262.                             {
  3263.                                 Errors += "diffuseRemapMaxZ must be a decimal greater than 0.\n";
  3264.                             }
  3265.                             else
  3266.                             {
  3267.                                 Layer.diffuseRemapMax = new Vector4(Layer.diffuseRemapMax.x, Layer.diffuseRemapMax.y, diffuseRemapMaxZ, Layer.diffuseRemapMax.w);
  3268.                             }
  3269.                         }
  3270.                         if ((LayersPanel.Different_diffuseRemapMinW[i] && !empty(LayersPanel.diffuseRemapMinWStr[i])) || !LayersPanel.Different_diffuseRemapMinW[i])
  3271.                         {
  3272.                             if (!float.TryParse(LayersPanel.diffuseRemapMinWStr[i], out float diffuseRemapMinW) || diffuseRemapMinW < 0)
  3273.                             {
  3274.                                 Errors += "diffuseRemapMinW must be a decimal greater than 0.\n";
  3275.                             }
  3276.                             else
  3277.                             {
  3278.                                 Layer.diffuseRemapMin = new Vector4(Layer.diffuseRemapMin.x, Layer.diffuseRemapMin.y, Layer.diffuseRemapMin.z, diffuseRemapMinW);
  3279.                             }
  3280.                         }
  3281.                         if ((LayersPanel.Different_diffuseRemapMinX[i] && !empty(LayersPanel.diffuseRemapMinXStr[i])) || !LayersPanel.Different_diffuseRemapMinX[i])
  3282.                         {
  3283.                             if (!float.TryParse(LayersPanel.diffuseRemapMinXStr[i], out float diffuseRemapMinX) || diffuseRemapMinX < 0)
  3284.                             {
  3285.                                 Errors += "diffuseRemapMinX must be a decimal greater than 0.\n";
  3286.                             }
  3287.                             else
  3288.                             {
  3289.                                 Layer.diffuseRemapMin = new Vector4(diffuseRemapMinX, Layer.diffuseRemapMin.y, Layer.diffuseRemapMin.z, Layer.diffuseRemapMin.w);
  3290.                             }
  3291.                         }
  3292.                         if ((LayersPanel.Different_diffuseRemapMinY[i] && !empty(LayersPanel.diffuseRemapMinYStr[i])) || !LayersPanel.Different_diffuseRemapMinY[i])
  3293.                         {
  3294.                             if (!float.TryParse(LayersPanel.diffuseRemapMinYStr[i], out float diffuseRemapMinY) || diffuseRemapMinY < 0)
  3295.                             {
  3296.                                 Errors += "diffuseRemapMinY must be a decimal greater than 0.\n";
  3297.                             }
  3298.                             else
  3299.                             {
  3300.                                 Layer.diffuseRemapMin = new Vector4(Layer.diffuseRemapMin.x, diffuseRemapMinY, Layer.diffuseRemapMin.z, Layer.diffuseRemapMin.w);
  3301.                             }
  3302.                         }
  3303.                         if ((LayersPanel.Different_diffuseRemapMinZ[i] && !empty(LayersPanel.diffuseRemapMinZStr[i])) || !LayersPanel.Different_diffuseRemapMinZ[i])
  3304.                         {
  3305.                             if (!float.TryParse(LayersPanel.diffuseRemapMinZStr[i], out float diffuseRemapMinZ) || diffuseRemapMinZ < 0)
  3306.                             {
  3307.                                 Errors += "diffuseRemapMinZ must be a decimal greater than 0.\n";
  3308.                             }
  3309.                             else
  3310.                             {
  3311.                                 Layer.diffuseRemapMin = new Vector4(Layer.diffuseRemapMin.x, Layer.diffuseRemapMin.y, diffuseRemapMinZ, Layer.diffuseRemapMin.w);
  3312.                             }
  3313.                         }
  3314.                         if ((LayersPanel.Different_maskMapRemapMaxW[i] && !empty(LayersPanel.maskMapRemapMaxWStr[i])) || !LayersPanel.Different_maskMapRemapMaxW[i])
  3315.                         {
  3316.                             if (!float.TryParse(LayersPanel.maskMapRemapMaxWStr[i], out float maskMapRemapMaxW) || maskMapRemapMaxW < 0)
  3317.                             {
  3318.                                 Errors += "maskMapRemapMaxW must be a decimal greater than 0.\n";
  3319.                             }
  3320.                             else
  3321.                             {
  3322.                                 Layer.maskMapRemapMax = new Vector4(Layer.maskMapRemapMax.x, Layer.maskMapRemapMax.y, Layer.maskMapRemapMax.z, maskMapRemapMaxW);
  3323.                             }
  3324.                         }
  3325.                         if ((LayersPanel.Different_maskMapRemapMaxX[i] && !empty(LayersPanel.maskMapRemapMaxXStr[i])) || !LayersPanel.Different_maskMapRemapMaxX[i])
  3326.                         {
  3327.                             if (!float.TryParse(LayersPanel.maskMapRemapMaxXStr[i], out float maskMapRemapMaxX) || maskMapRemapMaxX < 0)
  3328.                             {
  3329.                                 Errors += "maskMapRemapMaxX must be a decimal greater than 0.\n";
  3330.                             }
  3331.                             else
  3332.                             {
  3333.                                 Layer.maskMapRemapMax = new Vector4(maskMapRemapMaxX, Layer.maskMapRemapMax.y, Layer.maskMapRemapMax.z, Layer.maskMapRemapMax.w);
  3334.                             }
  3335.                         }
  3336.                         if ((LayersPanel.Different_maskMapRemapMaxY[i] && !empty(LayersPanel.maskMapRemapMaxYStr[i])) || !LayersPanel.Different_maskMapRemapMaxY[i])
  3337.                         {
  3338.                             if (!float.TryParse(LayersPanel.maskMapRemapMaxYStr[i], out float maskMapRemapMaxY) || maskMapRemapMaxY < 0)
  3339.                             {
  3340.                                 Errors += "maskMapRemapMaxY must be a decimal greater than 0.\n";
  3341.                             }
  3342.                             else
  3343.                             {
  3344.                                 Layer.maskMapRemapMax = new Vector4(Layer.maskMapRemapMax.x, maskMapRemapMaxY, Layer.maskMapRemapMax.z, Layer.maskMapRemapMax.w);
  3345.                             }
  3346.                         }
  3347.                         if ((LayersPanel.Different_maskMapRemapMaxZ[i] && !empty(LayersPanel.maskMapRemapMaxZStr[i])) || !LayersPanel.Different_maskMapRemapMaxZ[i])
  3348.                         {
  3349.                             if (!float.TryParse(LayersPanel.maskMapRemapMaxZStr[i], out float maskMapRemapMaxZ) || maskMapRemapMaxZ < 0)
  3350.                             {
  3351.                                 Errors += "maskMapRemapMaxZ must be a decimal greater than 0.\n";
  3352.                             }
  3353.                             else
  3354.                             {
  3355.                                 Layer.maskMapRemapMax = new Vector4(Layer.maskMapRemapMax.x, Layer.maskMapRemapMax.y, maskMapRemapMaxZ, Layer.maskMapRemapMax.w);
  3356.                             }
  3357.                         }
  3358.                         if ((LayersPanel.Different_maskMapRemapMinW[i] && !empty(LayersPanel.maskMapRemapMinWStr[i])) || !LayersPanel.Different_maskMapRemapMinW[i])
  3359.                         {
  3360.                             if (!float.TryParse(LayersPanel.maskMapRemapMinWStr[i], out float maskMapRemapMinW) || maskMapRemapMinW < 0)
  3361.                             {
  3362.                                 Errors += "maskMapRemapMinW must be a decimal greater than 0.\n";
  3363.                             }
  3364.                             else
  3365.                             {
  3366.                                 Layer.maskMapRemapMin = new Vector4(Layer.maskMapRemapMin.x, Layer.maskMapRemapMin.y, Layer.maskMapRemapMin.z, maskMapRemapMinW);
  3367.                             }
  3368.                         }
  3369.                         if ((LayersPanel.Different_maskMapRemapMinX[i] && !empty(LayersPanel.maskMapRemapMinXStr[i])) || !LayersPanel.Different_maskMapRemapMinX[i])
  3370.                         {
  3371.                             if (!float.TryParse(LayersPanel.maskMapRemapMinXStr[i], out float maskMapRemapMinX) || maskMapRemapMinX < 0)
  3372.                             {
  3373.                                 Errors += "maskMapRemapMinX must be a decimal greater than 0.\n";
  3374.                             }
  3375.                             else
  3376.                             {
  3377.                                 Layer.maskMapRemapMin = new Vector4(maskMapRemapMinX, Layer.maskMapRemapMin.y, Layer.maskMapRemapMin.z, Layer.maskMapRemapMin.w);
  3378.                             }
  3379.                         }
  3380.                         if ((LayersPanel.Different_maskMapRemapMinY[i] && !empty(LayersPanel.maskMapRemapMinYStr[i])) || !LayersPanel.Different_maskMapRemapMinY[i])
  3381.                         {
  3382.                             if (!float.TryParse(LayersPanel.maskMapRemapMinYStr[i], out float maskMapRemapMinY) || maskMapRemapMinY < 0)
  3383.                             {
  3384.                                 Errors += "maskMapRemapMinY must be a decimal greater than 0.\n";
  3385.                             }
  3386.                             else
  3387.                             {
  3388.                                 Layer.maskMapRemapMin = new Vector4(Layer.maskMapRemapMin.x, maskMapRemapMinY, Layer.maskMapRemapMin.z, Layer.maskMapRemapMin.w);
  3389.                             }
  3390.                         }
  3391.                         if ((LayersPanel.Different_maskMapRemapMinZ[i] && !empty(LayersPanel.maskMapRemapMinZStr[i])) || !LayersPanel.Different_maskMapRemapMinZ[i])
  3392.                         {
  3393.                             if (!float.TryParse(LayersPanel.maskMapRemapMinZStr[i], out float maskMapRemapMinZ) || maskMapRemapMinZ < 0)
  3394.                             {
  3395.                                 Errors += "maskMapRemapMinZ must be a decimal greater than 0.\n";
  3396.                             }
  3397.                             else
  3398.                             {
  3399.                                 Layer.maskMapRemapMin = new Vector4(Layer.maskMapRemapMin.x, Layer.maskMapRemapMin.y, maskMapRemapMinZ, Layer.maskMapRemapMin.w);
  3400.                             }
  3401.                         }
  3402.                         if ((LayersPanel.Different_normalScale[i] && !empty(LayersPanel.normalScaleStr[i])) || !LayersPanel.Different_normalScale[i])
  3403.                         {
  3404.                             if (!float.TryParse(LayersPanel.normalScaleStr[i], out float normalScale) || normalScale < 0)
  3405.                             {
  3406.                                 Errors += "normalScale must be a decimal greater than 0.\n";
  3407.                             }
  3408.                             else
  3409.                             {
  3410.                                 Layer.normalScale = normalScale;
  3411.                             }
  3412.                         }
  3413.                         if ((LayersPanel.Different_specularR[i] && !empty(LayersPanel.specularRStr[i])) || !LayersPanel.Different_specularR[i])
  3414.                         {
  3415.                             if (!float.TryParse(LayersPanel.specularRStr[i], out float specularR) || specularR < 0 || specularR > 1)
  3416.                             {
  3417.                                 Errors += "specularR must be a decimal between 0 and 1.\n";
  3418.                             }
  3419.                             else
  3420.                             {
  3421.                                 TheSpecularColor[0] = specularR;
  3422.                             }
  3423.                         }
  3424.                         if ((LayersPanel.Different_specularG[i] && !empty(LayersPanel.specularGStr[i])) || !LayersPanel.Different_specularG[i])
  3425.                         {
  3426.                             if (!float.TryParse(LayersPanel.specularGStr[i], out float specularG) || specularG < 0 || specularG > 1)
  3427.                             {
  3428.                                 Errors += "specularG must be a decimal between 0 and 1.\n";
  3429.                             }
  3430.                             else
  3431.                             {
  3432.                                 TheSpecularColor[1] = specularG;
  3433.                             }
  3434.                         }
  3435.                         if ((LayersPanel.Different_specularB[i] && !empty(LayersPanel.specularBStr[i])) || !LayersPanel.Different_specularB[i])
  3436.                         {
  3437.                             if (!float.TryParse(LayersPanel.specularBStr[i], out float specularB) || specularB < 0 || specularB > 1)
  3438.                             {
  3439.                                 Errors += "specularB must be a decimal between 0 and 1.\n";
  3440.                             }
  3441.                             else
  3442.                             {
  3443.                                 TheSpecularColor[2] = specularB;
  3444.                             }
  3445.                         }
  3446.                         if ((LayersPanel.Different_specularA[i] && !empty(LayersPanel.specularAStr[i])) || !LayersPanel.Different_specularA[i])
  3447.                         {
  3448.                             if (!float.TryParse(LayersPanel.specularAStr[i], out float specularA) || specularA < 0 || specularA > 1)
  3449.                             {
  3450.                                 Errors += "specularA must be a decimal between 0 and 1.\n";
  3451.                             }
  3452.                             else
  3453.                             {
  3454.                                 TheSpecularColor[3] = specularA;
  3455.                             }
  3456.                         }
  3457.                         Layer.specular = new Color(TheSpecularColor[0], TheSpecularColor[1], TheSpecularColor[2], TheSpecularColor[3]);
  3458.                     }
  3459.                 }
  3460.             }
  3461.             //##############################################################################
  3462.             //##############################################################################
  3463.             private static class PropertiesPanel
  3464.             {
  3465.                 public static string DebugMsg = "";
  3466.                 public static int Sort = 0;
  3467.                 public static Vector2 ScrollVector = new Vector2(0, 0);
  3468.             }
  3469.             private void PaintPropertiesPanel()
  3470.             {
  3471.                 if (empty(SelectedTerrains))
  3472.                 {
  3473.                     TheLayout.Label("No terrains selected.");
  3474.                 }
  3475.                 else
  3476.                 {
  3477.                     TheLayout.BeginVertical("width:500px;background-color:rgba(0,0,0,0.15);padding:5px;");
  3478.  
  3479.                     TheLayout.EndVertical();
  3480.                 }
  3481.             }
  3482.             //##############################################################################
  3483.             //##############################################################################
  3484.             private static class DebugPanel
  3485.             {
  3486.                 public static string DebugMsg = "";
  3487.                 public static int Sort = 0;
  3488.                 public static Vector2 ScrollVector = new Vector2(0, 0);
  3489.             }
  3490.             private void PaintDebugPanel()
  3491.             {
  3492.                 /*
  3493.                 */
  3494.                 var SubAssets = TheAssetBucket.GetSubAssets();
  3495.                 TheLayout.BeginVertical("background-color:rgba(0,0,0,0.15);padding:5px;");
  3496.                 TheLayout.BeginHorizontal();
  3497.                 TheLayout.Label("Script Path", "width:128px;");
  3498.                 TheLayout.TextField(ScriptPath, "width:400px;");
  3499.                 TheLayout.EndHorizontal();
  3500.                 TheLayout.BeginHorizontal();
  3501.                 GUI.enabled = !empty(SelectedTerrains);
  3502.                 if (TheLayout.Button("Debug Terrain", "width:200px;"))
  3503.                 {
  3504.                     if (!empty(SelectedTerrains))
  3505.                     {
  3506.                         DebugPanel.DebugMsg = JsonTools.object_to_json(SelectedTerrains[0], 3);
  3507.                     }
  3508.                 }
  3509.                 GUI.enabled = true;
  3510.                 TheLayout.TextField(DebugPanel.DebugMsg, "vertical-align:middle;text-align:left;width:400px;");
  3511.                 TheLayout.EndHorizontal();
  3512.                 TheLayout.BeginHorizontal();
  3513.                 GUI.enabled = SubAssets.Count() > 0;
  3514.                 if (TheLayout.Button("Cleanup sub Assets", "width:200px;"))
  3515.                 {
  3516.                     TheAssetBucket.Clean();
  3517.                 }
  3518.                 GUI.enabled = true;
  3519.                 if (TheLayout.Button("Do thing", "width:200px;"))
  3520.                 {
  3521.                     var AllObjects = Resources.FindObjectsOfTypeAll(typeof(TerrainData));
  3522.                     foreach (var TheObject in SubAssets)
  3523.                     {
  3524.                         Debug.Log(TheObject.name);
  3525.                         //TheObject.hideFlags = HideFlags.None;
  3526.                     }
  3527.                     Debug.Log(AllObjects.Count());
  3528.                 }
  3529.                 TheLayout.EndHorizontal();
  3530.                 TheLayout.BeginHorizontal();
  3531.                 TheLayout.Label(SubAssets.Count() + " sub Assets in " + Regex.Replace(AssetPath, ".*/", "") + "");
  3532.                 TheLayout.EndHorizontal();
  3533.                 TheLayout.Label(TheAssetBucket.GetParamString());
  3534.                 TheLayout.BeginHorizontal("width:300px;");
  3535.                 TheLayout.Label("Sort sub-assets:", "width:128px;");
  3536.                 DebugPanel.Sort = TheLayout.Toolbar(DebugPanel.Sort, new[] { "A-Z", "Type" });
  3537.                 TheLayout.EndHorizontal();
  3538.                 DebugPanel.ScrollVector = GUILayout.BeginScrollView(DebugPanel.ScrollVector);
  3539.                 /*
  3540.                 foreach (var name in Font.GetOSInstalledFontNames())
  3541.                 {
  3542.                     TheLayout.Label(name);
  3543.                 }
  3544.                 var Fonts = Resources.FindObjectsOfTypeAll<Font>();
  3545.                 foreach (var font in Fonts)
  3546.                 {
  3547.                     TheLayout.Label(font.name + ", names: " + JsonTools.object_to_json(font.fontNames));
  3548.                 }
  3549.                 */
  3550.                 TerrainData TheTerrainData;
  3551.                 Texture2D TheTexture;
  3552.                 string LabelText;
  3553.                 Type TheType;
  3554.                 var AssetCollection = SubAssets.OrderBy(x => (DebugPanel.Sort == 0) ? x.name : x.GetType().Name);
  3555.                 foreach (var Obj in AssetCollection)
  3556.                 {
  3557.                     if (Obj == null)
  3558.                     {
  3559.                         LabelText = "(null)";
  3560.                     }
  3561.                     else
  3562.                     {
  3563.                         TheType = Obj.GetType();
  3564.                         LabelText = Obj.name;
  3565.                         if (TheType == typeof(TerrainData))
  3566.                         {
  3567.                             TheTerrainData = (TerrainData)Obj;
  3568.                             LabelText += " (" + TheType.Name + ")";
  3569.                         }
  3570.                         else if (TheType == typeof(Texture2D))
  3571.                         {
  3572.                             TheTexture = (Texture2D)Obj;
  3573.                             LabelText += " (" + TheType.Name + " " + TheTexture.format.ToString() + ")";
  3574.                         }
  3575.                         else
  3576.                         {
  3577.                             LabelText += " (" + TheType.Name + ")";
  3578.                         }
  3579.                     }
  3580.                     LabelText = LabelText + ", hideFlags: " + Obj.hideFlags.ToString();
  3581.                     TheLayout.BeginHorizontal();
  3582.                     TheLayout.Label(LabelText);
  3583.                     TheLayout.EndHorizontal();
  3584.                 }
  3585.                 GUILayout.EndScrollView();
  3586.                 TheLayout.EndVertical();
  3587.             }
  3588.         }
  3589.         //############################################################################################
  3590.         //############################################################################################
  3591.         //############################################################################################
  3592.         //############################################################################################
  3593.         private class AssetBucket
  3594.         {
  3595.             private TerraLab TheAsset;
  3596.             public AssetBucket(TerraLab Asset)
  3597.             {
  3598.                 TheAsset = Asset ?? throw new NullReferenceException();
  3599.             }
  3600.             public IEnumerable<UnityEngine.Object> GetSubAssets()
  3601.             {
  3602.                 return AssetDatabase.LoadAllAssetRepresentationsAtPath(AssetPath).Where(x => x != null);
  3603.             }
  3604.             public string GetParamString()
  3605.             {
  3606.                 return TheAsset.Params;
  3607.             }
  3608.             private static string Encode(string Input)
  3609.             {
  3610.                 return (Input ?? "").Replace("@", "@1").Replace(";", "@2").Replace("=", "@3");
  3611.             }
  3612.             private static string Decode(string Input)
  3613.             {
  3614.                 return (Input ?? "").Replace("@3", "=").Replace("@2", ";").Replace("@1", "@");
  3615.             }
  3616.             public string GetKey(string Key)
  3617.             {
  3618.                 Key = Encode(Key);
  3619.                 var Str = Regex.Replace(TheAsset.Params ?? "", ".*(?:^|;)" + Regex.Escape(Key) + "=", "");
  3620.                 if (Str.Length != TheAsset.Params.Length)
  3621.                 {
  3622.                     //key exists
  3623.                     return Decode(Regex.Replace(Str, ";.*", "", RegexOptions.Singleline));
  3624.                 }
  3625.                 else
  3626.                 {
  3627.                     return "";
  3628.                 }
  3629.             }
  3630.             public string SetKey(string Key, string Val)
  3631.             {
  3632.                 Key = Encode(Key);
  3633.                 var NewVal = Encode(Val);
  3634.                 var Str = Regex.Replace(TheAsset.Params ?? "", "(?<=^|;)" + Regex.Escape(Key) + "[^;]*(?:;|$)", "");
  3635.                 TheAsset.Params = Regex.Replace(Str, "([^;])$", "$1;") + ((Val == "") ? "" : Key + "=" + NewVal + ";");
  3636.                 return Val;
  3637.             }
  3638.             public UnityEngine.Object Get(string AssetName)
  3639.             {
  3640.                 return GetSubAssets().Where(x => x != null && x.name == AssetName).FirstOrDefault();
  3641.             }
  3642.             public void Add(UnityEngine.Object Obj, bool Save = true)
  3643.             {
  3644.                 Add(new[] { Obj }, Save);
  3645.             }
  3646.             public void Add(IEnumerable<UnityEngine.Object> Objs, bool Save = true)
  3647.             {
  3648.                 if (!empty(Objs))
  3649.                 {
  3650.                     var SubAssets = GetSubAssets();
  3651.                     try
  3652.                     {
  3653.                         AssetDatabase.StartAssetEditing();
  3654.                         foreach (var Obj in Objs)
  3655.                         {
  3656.                             if (SubAssets.Contains(Obj))
  3657.                             {
  3658.                                 throw new Exception("Object is already a sub-asset.");
  3659.                             }
  3660.                             AssetDatabase.AddObjectToAsset(Obj, AssetPath);
  3661.                         }
  3662.                     }
  3663.                     finally
  3664.                     {
  3665.                         AssetDatabase.StopAssetEditing();
  3666.                     }
  3667.                     if (Save)
  3668.                     {
  3669.                         AssetDatabase.SaveAssets();
  3670.                     }
  3671.                 }
  3672.             }
  3673.             public void Remove(UnityEngine.Object Obj, bool Save = true)
  3674.             {
  3675.                 Remove(new[] { Obj }, Save);
  3676.             }
  3677.             public void Remove(IEnumerable<UnityEngine.Object> Objs, bool Save = true)
  3678.             {
  3679.                 if (!empty(Objs))
  3680.                 {
  3681.                     try
  3682.                     {
  3683.                         AssetDatabase.StartAssetEditing();
  3684.                         foreach (var Obj in Objs)
  3685.                         {
  3686.                             AssetDatabase.RemoveObjectFromAsset(Obj);
  3687.                         }
  3688.                     }
  3689.                     finally
  3690.                     {
  3691.                         AssetDatabase.StopAssetEditing();
  3692.                     }
  3693.                     if (Save)
  3694.                     {
  3695.                         AssetDatabase.SaveAssets();
  3696.                     }
  3697.                 }
  3698.             }
  3699.             public void Save()
  3700.             {
  3701.                 AssetDatabase.SaveAssets();
  3702.             }
  3703.             public void Clean()
  3704.             {
  3705.                 var SceneGameObjects = SceneManager.GetActiveScene().GetRootGameObjects();
  3706.                 var Dependencies = EditorUtility.CollectDependencies(SceneGameObjects);
  3707.                 var AssetsToRemove = new List<UnityEngine.Object>();
  3708.                 var SubAssets = GetSubAssets();
  3709.                 foreach (var TheObject in SubAssets)
  3710.                 {
  3711.                     if (!Dependencies.Contains(TheObject))
  3712.                     {
  3713.                         AssetsToRemove.Add(TheObject);
  3714.                     }
  3715.                 }
  3716.                 foreach (var TheObject in AssetsToRemove)
  3717.                 {
  3718.                     AssetDatabase.RemoveObjectFromAsset(TheObject);
  3719.                     //if you call DestroyImmediate on an object with the name "ABC" and later try
  3720.                     //to create another object with the same name, you will get the following error:
  3721.                     //"The object of type '...' has been destroyed but you are still trying to access it."
  3722.                     //DestroyImmediate(TheObject, true);
  3723.                 }
  3724.                 //calling SaveAssets() automatically does an import on dirty assets
  3725.                 //so there's no need to call ImportAsset()
  3726.                 AssetDatabase.SaveAssets();
  3727.  
  3728.             }
  3729.         }
  3730.     }
  3731. }
  3732.  
  3733.  
  3734.  
  3735.  
  3736.  
  3737.  
  3738.  
  3739.  
  3740.  
  3741. using System;
  3742. using System.Collections;
  3743. using System.Collections.Generic;
  3744. using System.Linq;
  3745. using System.Linq.Expressions;
  3746. using System.Text.RegularExpressions;
  3747. using System.Reflection;
  3748. using System.Runtime.CompilerServices;
  3749. using UnityEditor;
  3750. using UnityEngine;
  3751. using UnityEngine.SceneManagement;
  3752.  
  3753. namespace TerraLab
  3754. {
  3755.     public class LayoutCSS
  3756.     {
  3757.         public LayoutCSS(EditorWindow Instance)
  3758.         {
  3759.             TheWindow = Instance;
  3760.             DefaultRowSpace = RowSpace = 5;
  3761.             OSFontNames = Font.GetOSInstalledFontNames();
  3762.             foreach (var TheFont in Resources.FindObjectsOfTypeAll<Font>())
  3763.             {
  3764.                 BuiltInFonts[TheFont.name] = TheFont;
  3765.             }
  3766.         }
  3767.         public Font GetFont(string FontName)
  3768.         {
  3769.             FontName = FontName ?? "";
  3770.             if (!FontCache.TryGetValue(FontName, out Font TheFont) && OSFontNames.Contains(FontName))
  3771.             {
  3772.                 TheFont = FontCache[FontName] = Font.CreateDynamicFontFromOSFont(FontName, 16);
  3773.             }
  3774.             return TheFont;
  3775.         }
  3776.         public Font GetBuiltInFont(string FontName)
  3777.         {
  3778.             return BuiltInFonts[FontName ?? ""];
  3779.         }
  3780.         private int LineHeightToFontSize(int LineHeight)
  3781.         {
  3782.             return (int)Math.Ceiling(LineHeight / LineHeightCoefficient);
  3783.         }
  3784.         private int FontSizeToLineHeight(int FontSize)
  3785.         {
  3786.             return (int)Math.Floor(FontSize * LineHeightCoefficient);
  3787.         }
  3788.         private float GetHeight(GUIStyle TheStyle)
  3789.         {
  3790.             return (float)Math.Ceiling(TheStyle.CalcSize(GUIContent.none).y);
  3791.         }
  3792.         private class MinMax
  3793.         {
  3794.             public MinMax(MinMax Existing = null)
  3795.             {
  3796.                 if (Existing != null)
  3797.                 {
  3798.                     MinWidth = Existing.MinWidth;
  3799.                     MaxWidth = Existing.MaxWidth;
  3800.                     MinHeight = Existing.MinHeight;
  3801.                     MaxHeight = Existing.MaxHeight;
  3802.                 }
  3803.             }
  3804.             public float MinWidth = -1;
  3805.             public float MaxWidth = -1;
  3806.             public float MinHeight = -1;
  3807.             public float MaxHeight = -1;
  3808.             public GUILayoutOption[] ToOptionsArray()
  3809.             {
  3810.                 var OptionsList = new List<GUILayoutOption>();
  3811.                 if (MinWidth >= 0)
  3812.                 {
  3813.                     OptionsList.Add(GUILayout.MinWidth(MinWidth));
  3814.                 }
  3815.                 if (MaxWidth >= 0)
  3816.                 {
  3817.                     OptionsList.Add(GUILayout.MaxWidth(MaxWidth));
  3818.                 }
  3819.                 if (MinHeight >= 0)
  3820.                 {
  3821.                     OptionsList.Add(GUILayout.MinHeight(MinHeight));
  3822.                 }
  3823.                 if (MaxHeight >= 0)
  3824.                 {
  3825.                     OptionsList.Add(GUILayout.MaxHeight(MaxHeight));
  3826.                 }
  3827.                 return OptionsList.ToArray();
  3828.             }
  3829.         }
  3830.         public void ResetLargestWidth()
  3831.         {
  3832.             LargestWidth = 0;
  3833.         }
  3834.         public void SetDefaultRowSpace(int pixels)
  3835.         {
  3836.             DefaultRowSpace = pixels;
  3837.         }
  3838.         public void StartRowSpace(int pixels = -1)
  3839.         {
  3840.             RowSpace = (pixels >= 0) ? pixels : DefaultRowSpace;
  3841.             HorizontalJustEnded = false;
  3842.         }
  3843.         public void EndRowSpace()
  3844.         {
  3845.             RowSpace = -1;
  3846.             HorizontalJustEnded = false;
  3847.         }
  3848.         private int RowSpace;
  3849.         private int DefaultRowSpace;
  3850.         private string[] OSFontNames;
  3851.         private EditorWindow TheWindow;
  3852.         private int DefaultFontSize = 14;
  3853.         private bool HorizontalJustEnded = false;
  3854.         //the maximum unity font size is 500, and the default line height at this size is 574
  3855.         private float LineHeightCoefficient = 1.148F;
  3856.         private Tuple<GUIStyle, MinMax> BoxStyle;
  3857.         private Tuple<GUIStyle, MinMax> ButtonStyle;
  3858.         private Tuple<GUIStyle, MinMax> LabelStyle;
  3859.         private Tuple<GUIStyle, MinMax> TextAreaStyle;
  3860.         private Tuple<GUIStyle, MinMax> TextFieldStyle;
  3861.         private Tuple<GUIStyle, MinMax> ToggleStyle;
  3862.         private Tuple<GUIStyle, MinMax> DropdownStyle;
  3863.         private Tuple<GUIStyle, MinMax> HorizontalStyle;
  3864.         private Tuple<GUIStyle, MinMax> VerticalStyle;
  3865.         private Tuple<GUIStyle, MinMax> ToolbarStyle;
  3866.         public float LargestWidth { get; private set; } = 0;
  3867.         private Dictionary<string, Font> FontCache = new Dictionary<string, Font>();
  3868.         private Dictionary<string, Font> BuiltInFonts = new Dictionary<string, Font>();
  3869.         private Dictionary<string, Tuple<GUIStyle, MinMax>> BoxStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3870.         private Dictionary<string, Tuple<GUIStyle, MinMax>> ButtonStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3871.         private Dictionary<string, Tuple<GUIStyle, MinMax>> LabelStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3872.         private Dictionary<string, Tuple<GUIStyle, MinMax>> TextAreaStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3873.         private Dictionary<string, Tuple<GUIStyle, MinMax>> TextFieldStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3874.         private Dictionary<string, Tuple<GUIStyle, MinMax>> ToggleStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3875.         private Dictionary<string, Tuple<GUIStyle, MinMax>> DropdownStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3876.         private Dictionary<string, Tuple<GUIStyle, MinMax>> HorizontalStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3877.         private Dictionary<string, Tuple<GUIStyle, MinMax>> VerticalStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3878.         private Dictionary<string, Tuple<GUIStyle, MinMax>> ToolbarStyleCache = new Dictionary<string, Tuple<GUIStyle, MinMax>>();
  3879.         public GUIStyle SetCommonProperties(GUIStyle TheStyle)
  3880.         {
  3881.             var NewStyle = new GUIStyle(TheStyle);
  3882.             NewStyle.overflow = new RectOffset(0, 0, 0, 0);
  3883.             NewStyle.stretchWidth = false;
  3884.             return NewStyle;
  3885.         }
  3886.         public void SetBoxStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3887.         {
  3888.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, BoxStyleCache, out MinMax OptionsOut, out BoxStyle);
  3889.         }
  3890.         public void SetButtonStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3891.         {
  3892.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, ButtonStyleCache, out MinMax OptionsOut, out ButtonStyle);
  3893.         }
  3894.         public void SetLabelStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3895.         {
  3896.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, LabelStyleCache, out MinMax OptionsOut, out LabelStyle);
  3897.         }
  3898.         public void SetTextAreaStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3899.         {
  3900.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, TextAreaStyleCache, out MinMax OptionsOut, out TextAreaStyle);
  3901.         }
  3902.         public void SetTextFieldStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3903.         {
  3904.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, TextFieldStyleCache, out MinMax OptionsOut, out TextFieldStyle);
  3905.         }
  3906.         public void SetToggleStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3907.         {
  3908.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, ToggleStyleCache, out MinMax OptionsOut, out ToggleStyle);
  3909.         }
  3910.         public void SetDropdownStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3911.         {
  3912.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, DropdownStyleCache, out MinMax OptionsOut, out DropdownStyle);
  3913.         }
  3914.         public void SetHorizontalStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3915.         {
  3916.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, HorizontalStyleCache, out MinMax OptionsOut, out HorizontalStyle);
  3917.         }
  3918.         public void SetVerticalStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3919.         {
  3920.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, VerticalStyleCache, out MinMax OptionsOut, out VerticalStyle);
  3921.         }
  3922.         public void SetToolbarStyle(GUIStyle DefaultStyle, string CSSText = null, Texture2D BackgroundImage = null)
  3923.         {
  3924.             TextToGUIStyle(SetCommonProperties(DefaultStyle), null, CSSText, BackgroundImage, ToolbarStyleCache, out MinMax OptionsOut, out ToolbarStyle);
  3925.         }
  3926.         //############################
  3927.         public void Box(GUIContent content, out Rect ControlRect)
  3928.         {
  3929.             Box(content, null, null, out ControlRect);
  3930.         }
  3931.         public void Box(GUIContent content, string CSSText, out Rect ControlRect)
  3932.         {
  3933.             Box(content, CSSText, null, out ControlRect);
  3934.         }
  3935.         public void Box(GUIContent content, string CSSText = null, Texture2D BackgroundImage = null)
  3936.         {
  3937.             Box(content, CSSText, BackgroundImage, out _);
  3938.         }
  3939.         public void Box(GUIContent content, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  3940.         {
  3941.             var TheStyle = TextToGUIStyle(BoxStyle.Item1, BoxStyle.Item2, CSSText, BackgroundImage, BoxStyleCache, out MinMax Options);
  3942.             GUILayout.Box(content, TheStyle, Options.ToOptionsArray());
  3943.             ControlRect = GetLastRect(ControlTypes.Box);
  3944.             HorizontalJustEnded = false;
  3945.         }
  3946.         public void Box(string text, out Rect ControlRect)
  3947.         {
  3948.             Box(text, null, null, out ControlRect);
  3949.         }
  3950.         public void Box(string text, string CSSText, out Rect ControlRect)
  3951.         {
  3952.             Box(text, CSSText, null, out ControlRect);
  3953.         }
  3954.         public void Box(string text, string CSSText = null, Texture2D BackgroundImage = null)
  3955.         {
  3956.             Box(text, CSSText, BackgroundImage, out _);
  3957.         }
  3958.         public void Box(string text, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  3959.         {
  3960.             text = Regex.Replace(text ?? "", "\\s*$", "");
  3961.             var TheStyle = TextToGUIStyle(BoxStyle.Item1, BoxStyle.Item2, CSSText, BackgroundImage, BoxStyleCache, out MinMax Options);
  3962.             GUILayout.Box(text, TheStyle, Options.ToOptionsArray());
  3963.             ControlRect = GetLastRect(ControlTypes.Box);
  3964.             HorizontalJustEnded = false;
  3965.         }
  3966.         public void Box(Texture image, out Rect ControlRect)
  3967.         {
  3968.             Box(image, null, null, out ControlRect);
  3969.         }
  3970.         public void Box(Texture image, string CSSText, out Rect ControlRect)
  3971.         {
  3972.             Box(image, CSSText, null, out ControlRect);
  3973.         }
  3974.         public void Box(Texture image, string CSSText = null, Texture2D BackgroundImage = null)
  3975.         {
  3976.             Box(image, CSSText, BackgroundImage, out _);
  3977.         }
  3978.         public void Box(Texture image, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  3979.         {
  3980.             var TheStyle = TextToGUIStyle(BoxStyle.Item1, BoxStyle.Item2, CSSText, BackgroundImage, BoxStyleCache, out MinMax Options);
  3981.             GUILayout.Box(image, TheStyle, Options.ToOptionsArray());
  3982.             ControlRect = GetLastRect(ControlTypes.Box);
  3983.             HorizontalJustEnded = false;
  3984.         }
  3985.         //############################
  3986.         public bool Button(GUIContent content, out Rect ControlRect)
  3987.         {
  3988.             return Button(content, null, null, out ControlRect);
  3989.         }
  3990.         public bool Button(GUIContent content, string CSSText, out Rect ControlRect)
  3991.         {
  3992.             return Button(content, CSSText, null, out ControlRect);
  3993.         }
  3994.         public bool Button(GUIContent content, string CSSText = null, Texture2D BackgroundImage = null)
  3995.         {
  3996.             return Button(content, CSSText, BackgroundImage, out _);
  3997.         }
  3998.         public bool Button(GUIContent content, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  3999.         {
  4000.             var TheStyle = TextToGUIStyle(ButtonStyle.Item1, ButtonStyle.Item2, CSSText, BackgroundImage, ButtonStyleCache, out MinMax Options);
  4001.             var result = GUILayout.Button(content, TheStyle, Options.ToOptionsArray());
  4002.             ControlRect = GetLastRect(ControlTypes.Button);
  4003.             HorizontalJustEnded = false;
  4004.             return result;
  4005.         }
  4006.         public bool Button(string text, out Rect ControlRect)
  4007.         {
  4008.             return Button(text, null, null, out ControlRect);
  4009.         }
  4010.         public bool Button(string text, string CSSText, out Rect ControlRect)
  4011.         {
  4012.             return Button(text, CSSText, null, out ControlRect);
  4013.         }
  4014.         public bool Button(string text, string CSSText = null, Texture2D BackgroundImage = null)
  4015.         {
  4016.             return Button(text, CSSText, BackgroundImage, out _);
  4017.         }
  4018.         public bool Button(string text, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4019.         {
  4020.             text = Regex.Replace(text ?? "", "\\s*$", "");
  4021.             var TheStyle = TextToGUIStyle(ButtonStyle.Item1, ButtonStyle.Item2, CSSText, BackgroundImage, ButtonStyleCache, out MinMax Options);
  4022.             if (Options.MinHeight >= 0)
  4023.             {
  4024.                 //there is a bug where if wordWrap=true and a MinHeight is set, the MinHeight value will clip the content
  4025.                 Options = new MinMax(Options);
  4026.                 Options.MinHeight = TheStyle.wordWrap ? -1 : Math.Max(Options.MinHeight, GetHeight(TheStyle));
  4027.             }
  4028.             var result = GUILayout.Button(text, TheStyle, Options.ToOptionsArray());
  4029.             ControlRect = GetLastRect(ControlTypes.Button);
  4030.             HorizontalJustEnded = false;
  4031.             return result;
  4032.         }
  4033.         public bool Button(Texture image, out Rect ControlRect)
  4034.         {
  4035.             return Button(image, null, null, out ControlRect);
  4036.         }
  4037.         public bool Button(Texture image, string CSSText, out Rect ControlRect)
  4038.         {
  4039.             return Button(image, CSSText, null, out ControlRect);
  4040.         }
  4041.         public bool Button(Texture image, string CSSText = null, Texture2D BackgroundImage = null)
  4042.         {
  4043.             return Button(image, CSSText, BackgroundImage, out _);
  4044.         }
  4045.         public bool Button(Texture image, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4046.         {
  4047.             var TheStyle = TextToGUIStyle(ButtonStyle.Item1, ButtonStyle.Item2, CSSText, BackgroundImage, ButtonStyleCache, out MinMax Options);
  4048.             var result = GUILayout.Button(image, TheStyle, Options.ToOptionsArray());
  4049.             ControlRect = GetLastRect(ControlTypes.Button);
  4050.             HorizontalJustEnded = false;
  4051.             return result;
  4052.         }
  4053.         //############################
  4054.         public void Label(GUIContent content, out Rect ControlRect)
  4055.         {
  4056.             Label(content, null, null, out ControlRect);
  4057.         }
  4058.         public void Label(GUIContent content, string CSSText, out Rect ControlRect)
  4059.         {
  4060.             Label(content, CSSText, null, out ControlRect);
  4061.         }
  4062.         public void Label(GUIContent content, string CSSText = null, Texture2D BackgroundImage = null)
  4063.         {
  4064.             Label(content, CSSText, BackgroundImage, out _);
  4065.         }
  4066.         public void Label(GUIContent content, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4067.         {
  4068.             var TheStyle = TextToGUIStyle(LabelStyle.Item1, LabelStyle.Item2, CSSText, BackgroundImage, LabelStyleCache, out MinMax Options);
  4069.             GUILayout.Label(content, TheStyle, Options.ToOptionsArray());
  4070.             ControlRect = GetLastRect(ControlTypes.Label);
  4071.             HorizontalJustEnded = false;
  4072.         }
  4073.         public void Label(string text, out Rect ControlRect)
  4074.         {
  4075.             Label(text, null, null, out ControlRect);
  4076.         }
  4077.         public void Label(string text, string CSSText, out Rect ControlRect)
  4078.         {
  4079.             Label(text, CSSText, null, out ControlRect);
  4080.         }
  4081.         public void Label(string text, string CSSText = null, Texture2D BackgroundImage = null)
  4082.         {
  4083.             Label(text, CSSText, BackgroundImage, out _);
  4084.         }
  4085.         public void Label(string text, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4086.         {
  4087.             text = Regex.Replace(text ?? "", "\\s*$", "");
  4088.             var TheStyle = TextToGUIStyle(LabelStyle.Item1, LabelStyle.Item2, CSSText, BackgroundImage, LabelStyleCache, out MinMax Options);
  4089.             if ((text ?? "").Length == 1 && TheStyle.fixedWidth == 0 && !TheStyle.stretchWidth)
  4090.             {
  4091.                 TheStyle = new GUIStyle(TheStyle);
  4092.                 TheStyle.fixedWidth = TheStyle.CalcSize(new GUIContent("%")).x;
  4093.             }
  4094.             if (Options.MinHeight >= 0)
  4095.             {
  4096.                 //there is a bug where if wordWrap=true and a MinHeight is set, the MinHeight value will clip the content
  4097.                 Options = new MinMax(Options);
  4098.                 Options.MinHeight = TheStyle.wordWrap ? -1 : Math.Max(Options.MinHeight, GetHeight(TheStyle));
  4099.             }
  4100.             GUILayout.Label(text, TheStyle, Options.ToOptionsArray());
  4101.             ControlRect = GetLastRect(ControlTypes.Label);
  4102.             HorizontalJustEnded = false;
  4103.         }
  4104.         public void Label(Texture image, out Rect ControlRect)
  4105.         {
  4106.             Label(image, null, null, out ControlRect);
  4107.         }
  4108.         public void Label(Texture image, string CSSText, out Rect ControlRect)
  4109.         {
  4110.             Label(image, CSSText, null, out ControlRect);
  4111.         }
  4112.         public void Label(Texture image, string CSSText = null, Texture2D BackgroundImage = null)
  4113.         {
  4114.             Label(image, CSSText, BackgroundImage, out _);
  4115.         }
  4116.         public void Label(Texture image, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4117.         {
  4118.             var TheStyle = TextToGUIStyle(LabelStyle.Item1, LabelStyle.Item2, CSSText, BackgroundImage, LabelStyleCache, out MinMax Options);
  4119.             GUILayout.Label(image, TheStyle, Options.ToOptionsArray());
  4120.             ControlRect = GetLastRect(ControlTypes.Label);
  4121.             HorizontalJustEnded = false;
  4122.         }
  4123.         //############################
  4124.         public string TextArea(string text, out Rect ControlRect)
  4125.         {
  4126.             return TextArea(text, null, null, out ControlRect);
  4127.         }
  4128.         public string TextArea(string text, string CSSText, out Rect ControlRect)
  4129.         {
  4130.             return TextArea(text, CSSText, null, out ControlRect);
  4131.         }
  4132.         public string TextArea(string text, string CSSText = null, Texture2D BackgroundImage = null)
  4133.         {
  4134.             return TextArea(text, CSSText, BackgroundImage, out _);
  4135.         }
  4136.         public string TextArea(string text, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4137.         {
  4138.             var TheStyle = TextToGUIStyle(TextAreaStyle.Item1, TextAreaStyle.Item2, CSSText, BackgroundImage, TextAreaStyleCache, out MinMax Options);
  4139.             if (Options.MinHeight >= 0)
  4140.             {
  4141.                 //there is a bug where if wordWrap=true and a MinHeight is set, the MinHeight value will clip the content
  4142.                 Options = new MinMax(Options);
  4143.                 Options.MinHeight = TheStyle.wordWrap ? -1 : Math.Max(Options.MinHeight, GetHeight(TheStyle));
  4144.             }
  4145.             var result = GUILayout.TextArea(text, TheStyle, Options.ToOptionsArray());
  4146.             ControlRect = GetLastRect(ControlTypes.TextArea);
  4147.             HorizontalJustEnded = false;
  4148.             return result;
  4149.         }
  4150.         //############################
  4151.         public string TextField(string text, out Rect ControlRect)
  4152.         {
  4153.             return TextField(text, null, null, out ControlRect);
  4154.         }
  4155.         public string TextField(string text, string CSSText, out Rect ControlRect)
  4156.         {
  4157.             return TextField(text, CSSText, null, out ControlRect);
  4158.         }
  4159.         public string TextField(string text, string CSSText = null, Texture2D BackgroundImage = null)
  4160.         {
  4161.             return TextField(text, CSSText, BackgroundImage, out _);
  4162.         }
  4163.         public string TextField(string text, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4164.         {
  4165.             var TheStyle = TextToGUIStyle(TextFieldStyle.Item1, TextFieldStyle.Item2, CSSText, BackgroundImage, TextFieldStyleCache, out MinMax Options);
  4166.             if (Options.MinHeight >= 0)
  4167.             {
  4168.                 //there is a bug where if wordWrap=true and a MinHeight is set, the MinHeight value will clip the content
  4169.                 Options = new MinMax(Options);
  4170.                 Options.MinHeight = TheStyle.wordWrap ? -1 : Math.Max(Options.MinHeight, GetHeight(TheStyle));
  4171.             }
  4172.             var result = GUILayout.TextField(text, TheStyle, Options.ToOptionsArray());
  4173.             ControlRect = GetLastRect(ControlTypes.TextField);
  4174.             HorizontalJustEnded = false;
  4175.             return result;
  4176.         }
  4177.         //############################
  4178.         public bool Toggle(bool value, out Rect ControlRect)
  4179.         {
  4180.             return Toggle(value, null, null, out ControlRect);
  4181.         }
  4182.         public bool Toggle(bool value, string CSSText, out Rect ControlRect)
  4183.         {
  4184.             return Toggle(value, CSSText, null, out ControlRect);
  4185.         }
  4186.         public bool Toggle(bool value, string CSSText = null, Texture2D BackgroundImage = null)
  4187.         {
  4188.             return Toggle(value, CSSText, BackgroundImage, out _);
  4189.         }
  4190.         public bool Toggle(bool value, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4191.         {
  4192.             var TheStyle = TextToGUIStyle(ToggleStyle.Item1, ToggleStyle.Item2, CSSText, BackgroundImage, ToggleStyleCache, out MinMax Options);
  4193.             var result = GUILayout.Toggle(value, (string)null, TheStyle, Options.ToOptionsArray());
  4194.             ControlRect = GetLastRect(ControlTypes.Toggle);
  4195.             HorizontalJustEnded = false;
  4196.             return result;
  4197.         }
  4198.         //############################
  4199.         public T Dropdown<T>(T options, out Rect ControlRect) where T : Enum
  4200.         {
  4201.             return Dropdown(options, null, null, out ControlRect);
  4202.         }
  4203.         public T Dropdown<T>(T options, string CSSText, out Rect ControlRect) where T : Enum
  4204.         {
  4205.             return Dropdown(options, CSSText, null, out ControlRect);
  4206.         }
  4207.         public T Dropdown<T>(T options, string CSSText = null, Texture2D BackgroundImage = null) where T : Enum
  4208.         {
  4209.             return Dropdown(options, CSSText, BackgroundImage, out _);
  4210.         }
  4211.         public T Dropdown<T>(T options, string CSSText, Texture2D BackgroundImage, out Rect ControlRect) where T : Enum
  4212.         {
  4213.             var TheStyle = TextToGUIStyle(DropdownStyle.Item1, DropdownStyle.Item2, CSSText, BackgroundImage, DropdownStyleCache, out MinMax Options);
  4214.             var result = (T)EditorGUILayout.EnumPopup(options, TheStyle, Options.ToOptionsArray());
  4215.             ControlRect = GetLastRect(ControlTypes.Dropdown);
  4216.             HorizontalJustEnded = false;
  4217.             return result;
  4218.         }
  4219.         //############################
  4220.         public Texture2D TextureField(Texture2D texture, string text = null, float width = -1, float height = -1)
  4221.         {
  4222.             return TextureField(texture, text, width, height, out _);
  4223.         }
  4224.         public Texture2D TextureField(Texture2D texture, string text, out Rect ControlRect)
  4225.         {
  4226.             return TextureField(texture, text, -1, -1, out ControlRect);
  4227.         }
  4228.         public Texture2D TextureField(Texture2D texture, string text, float width, float height, out Rect ControlRect)
  4229.         {
  4230.             var lengthX = (width >= 0) ? width : 80;
  4231.             var lengthY = (height >= 0) ? height : 80;
  4232.             BeginVertical("margin:0;border:0;padding:0;stretch-width:false;");
  4233.             if (text != null)
  4234.             {
  4235.                 Label(text, "margin:0px 4px;width:" + lengthX + "px;height:0px;vertical-align:top;text-align:center;");
  4236.             }
  4237.             var TheTexture = (Texture2D)EditorGUILayout.ObjectField(texture, typeof(Texture2D), false, new GUILayoutOption[] { GUILayout.Width(lengthX), GUILayout.Height(lengthY) });
  4238.             EndVertical();
  4239.             ControlRect = GetLastRect(ControlTypes.ObjectField);
  4240.             HorizontalJustEnded = false;
  4241.             return TheTexture;
  4242.         }
  4243.         //############################
  4244.         public int Toolbar(int selected, GUIContent[] contents, out Rect ControlRect)
  4245.         {
  4246.             return Toolbar(selected, contents, null, null, out ControlRect);
  4247.         }
  4248.         public int Toolbar(int selected, GUIContent[] contents, string CSSText, out Rect ControlRect)
  4249.         {
  4250.             return Toolbar(selected, contents, CSSText, null, out ControlRect);
  4251.         }
  4252.         public int Toolbar(int selected, GUIContent[] contents, string CSSText = null, Texture2D BackgroundImage = null)
  4253.         {
  4254.             return Toolbar(selected, contents, CSSText, BackgroundImage, out _);
  4255.         }
  4256.         public int Toolbar(int selected, GUIContent[] contents, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4257.         {
  4258.             var result = GUILayout.Toolbar(selected, contents, TextToGUIStyle(ToolbarStyle.Item1, ToolbarStyle.Item2, CSSText, BackgroundImage, ToolbarStyleCache, out MinMax Options), Options.ToOptionsArray());
  4259.             ControlRect = GetLastRect(ControlTypes.Toolbar);
  4260.             HorizontalJustEnded = false;
  4261.             return result;
  4262.         }
  4263.         public int Toolbar(int selected, string[] texts, out Rect ControlRect)
  4264.         {
  4265.             return Toolbar(selected, texts, null, null, out ControlRect);
  4266.         }
  4267.         public int Toolbar(int selected, string[] texts, string CSSText, out Rect ControlRect)
  4268.         {
  4269.             return Toolbar(selected, texts, CSSText, null, out ControlRect);
  4270.         }
  4271.         public int Toolbar(int selected, string[] texts, string CSSText = null, Texture2D BackgroundImage = null)
  4272.         {
  4273.             return Toolbar(selected, texts, CSSText, BackgroundImage, out _);
  4274.         }
  4275.         public int Toolbar(int selected, string[] texts, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4276.         {
  4277.             var result = GUILayout.Toolbar(selected, texts, TextToGUIStyle(ToolbarStyle.Item1, ToolbarStyle.Item2, CSSText, BackgroundImage, ToolbarStyleCache, out MinMax Options), Options.ToOptionsArray());
  4278.             ControlRect = GetLastRect(ControlTypes.Toolbar);
  4279.             HorizontalJustEnded = false;
  4280.             return result;
  4281.         }
  4282.         public int Toolbar(int selected, Texture[] images, out Rect ControlRect)
  4283.         {
  4284.             return Toolbar(selected, images, null, null, out ControlRect);
  4285.         }
  4286.         public int Toolbar(int selected, Texture[] images, string CSSText, out Rect ControlRect)
  4287.         {
  4288.             return Toolbar(selected, images, CSSText, null, out ControlRect);
  4289.         }
  4290.         public int Toolbar(int selected, Texture[] images, string CSSText = null, Texture2D BackgroundImage = null)
  4291.         {
  4292.             return Toolbar(selected, images, CSSText, BackgroundImage, out _);
  4293.         }
  4294.         public int Toolbar(int selected, Texture[] images, string CSSText, Texture2D BackgroundImage, out Rect ControlRect)
  4295.         {
  4296.             var result = GUILayout.Toolbar(selected, images, TextToGUIStyle(ToolbarStyle.Item1, ToolbarStyle.Item2, CSSText, BackgroundImage, ToolbarStyleCache, out MinMax Options), Options.ToOptionsArray());
  4297.             ControlRect = GetLastRect(ControlTypes.Toolbar);
  4298.             HorizontalJustEnded = false;
  4299.             return result;
  4300.         }
  4301.         //############################
  4302.         public void BeginHorizontal(string CSSText = null, Texture2D BackgroundImage = null)
  4303.         {
  4304.             if (RowSpace > 0 && HorizontalJustEnded)
  4305.             {
  4306.                 GUILayout.Space(RowSpace);
  4307.             }
  4308.             var TheStyle = TextToGUIStyle(HorizontalStyle.Item1, HorizontalStyle.Item2, CSSText, BackgroundImage, HorizontalStyleCache, out MinMax Options);
  4309.             GUILayout.BeginHorizontal(TheStyle, Options.ToOptionsArray());
  4310.             NestedWidths.Insert(0, TheStyle.fixedWidth);
  4311.             HorizontalJustEnded = false;
  4312.         }
  4313.         public void EndHorizontal()
  4314.         {
  4315.             EndHorizontal(out _);
  4316.         }
  4317.         public void EndHorizontal(out Rect ControlRect)
  4318.         {
  4319.             GUILayout.EndHorizontal();
  4320.             NestedWidths.RemoveAt(0);
  4321.             ControlRect = GetLastRect(ControlTypes.Horizontal);
  4322.             HorizontalJustEnded = true;
  4323.         }
  4324.         //############################
  4325.         public void BeginVertical(string CSSText = null, Texture2D BackgroundImage = null)
  4326.         {
  4327.             var TheStyle = TextToGUIStyle(VerticalStyle.Item1, VerticalStyle.Item2, CSSText, BackgroundImage, VerticalStyleCache, out MinMax Options);
  4328.             GUILayout.BeginVertical(TheStyle, Options.ToOptionsArray());
  4329.             NestedWidths.Insert(0, TheStyle.fixedWidth);
  4330.             HorizontalJustEnded = false;
  4331.         }
  4332.         public void EndVertical()
  4333.         {
  4334.             EndVertical(out _);
  4335.         }
  4336.         public void EndVertical(out Rect ControlRect)
  4337.         {
  4338.             GUILayout.EndVertical();
  4339.             NestedWidths.RemoveAt(0);
  4340.             ControlRect = GetLastRect(ControlTypes.Vertical);
  4341.             HorizontalJustEnded = false;
  4342.         }
  4343.         //############################
  4344.         private int ControlNum = 0;
  4345.         private bool ClearControlCaches = false;
  4346.         private bool ControlTypesConsistent = true;
  4347.         private List<Rect> RectCache = new List<Rect>();
  4348.         private List<ControlTypes> ControlTypeCache = new List<ControlTypes>();
  4349.         private List<float> NestedWidths = new List<float>();
  4350.         private EventType LastEventType = EventType.Layout;
  4351.         private enum ControlTypes
  4352.         {
  4353.             None = 0,
  4354.             Box = 1,
  4355.             Button = 2,
  4356.             Label = 3,
  4357.             TextArea = 4,
  4358.             TextField = 5,
  4359.             Toggle = 6,
  4360.             Dropdown = 7,
  4361.             Horizontal = 8,
  4362.             Vertical = 9,
  4363.             Toolbar = 10,
  4364.             ObjectField = 11
  4365.         }
  4366.         private Rect GetLastRect()
  4367.         {
  4368.             return GetLastRect(ControlTypes.None);
  4369.         }
  4370.         private Rect GetLastRect(ControlTypes ControlType)
  4371.         {
  4372.             if (Event.current.type != LastEventType)
  4373.             {
  4374.                 ControlNum = 0;
  4375.                 ResetLargestWidth();
  4376.                 ControlTypesConsistent = true;
  4377.                 if (LastEventType == EventType.Layout)
  4378.                 {
  4379.                     //repaint so controls aren't slow to refresh their positions
  4380.                     TheWindow.Repaint();
  4381.                 }
  4382.             }
  4383.             Rect TheRect;
  4384.             if (Event.current.type == EventType.Repaint)
  4385.             {
  4386.                 TheRect = GUILayoutUtility.GetLastRect();
  4387.                 if (ClearControlCaches)
  4388.                 {
  4389.                     RectCache.Clear();
  4390.                     ControlTypeCache.Clear();
  4391.                     ClearControlCaches = false;
  4392.                 }
  4393.                 if (RectCache.Count < 1000)
  4394.                 {
  4395.                     RectCache.Add(TheRect);
  4396.                     ControlTypeCache.Add(ControlType);
  4397.                 }
  4398.             }
  4399.             else
  4400.             {
  4401.                 ClearControlCaches = true;
  4402.                 if (ControlNum < RectCache.Count && ControlType == ControlTypeCache[ControlNum] && ControlTypesConsistent)
  4403.                 {
  4404.                     TheRect = RectCache[ControlNum];
  4405.                 }
  4406.                 else
  4407.                 {
  4408.                     //Debug.Log("inconsistent");
  4409.                     ControlTypesConsistent = false;
  4410.                     TheRect = new Rect();
  4411.                 }
  4412.             }
  4413.             ControlNum++;
  4414.             LastEventType = Event.current.type;
  4415.             LargestWidth = Math.Max(TheRect.width, LargestWidth);
  4416.             return TheRect;
  4417.         }
  4418.         //############################
  4419.         private Dictionary<string, float> FloatCache = new Dictionary<string, float>();
  4420.         private float GetFloatVal(string str)
  4421.         {
  4422.             if (FloatCache.TryGetValue(str, out float value))
  4423.             {
  4424.                 return value;
  4425.             }
  4426.             else if (float.TryParse(str, out value))
  4427.             {
  4428.                 return FloatCache[str] = value;
  4429.             }
  4430.             else
  4431.             {
  4432.                 return default;
  4433.             }
  4434.         }
  4435.         private Dictionary<string, int> IntCache = new Dictionary<string, int>();
  4436.         private int GetIntVal(string str)
  4437.         {
  4438.             if (IntCache.TryGetValue(str, out int value))
  4439.             {
  4440.                 return value;
  4441.             }
  4442.             else if (int.TryParse(str, out value))
  4443.             {
  4444.                 return IntCache[str] = value;
  4445.             }
  4446.             else
  4447.             {
  4448.                 return default;
  4449.             }
  4450.         }
  4451.         private bool IsColorChannel(string str, out float value)
  4452.         {
  4453.             value = GetFloatVal(str);
  4454.             return value >= 0 && value <= 255;
  4455.         }
  4456.         private bool IsAlphaChannel(string str, out float value)
  4457.         {
  4458.             value = GetFloatVal(str);
  4459.             return value >= 0 && value <= 1;
  4460.         }
  4461.         private Dictionary<string, string> TextToCSSDictionary(string CSSText)
  4462.         {
  4463.             var TheDictionary = new Dictionary<string, string>();
  4464.             var Matches = Regex.Matches(CSSText, "(?<=\\G|^)\\s*([a-zA-Z0-9-_]+)\\s*:\\s*((?:[^:;'\\s]|\\s(?![\\s;])|'(?:[^\\\\']|\\\\.)*')*)\\s*(?:;|$)");
  4465.             foreach (Match TheMatch in Matches)
  4466.             {
  4467.                 TheDictionary[TheMatch.Groups[1].Value.ToLower()] = TheMatch.Groups[2].Value;
  4468.             }
  4469.             return TheDictionary;
  4470.         }
  4471.         private GUIStyle TextToGUIStyle(GUIStyle DefaultStyle, MinMax OptionsIn, string CSSText, Texture2D BackgroundImage, Dictionary<string, Tuple<GUIStyle, MinMax>> GUIStyleCache, out MinMax OptionsOut)
  4472.         {
  4473.             return TextToGUIStyle(DefaultStyle, OptionsIn, CSSText, BackgroundImage, GUIStyleCache, out OptionsOut, out _);
  4474.         }
  4475.         private GUIStyle TextToGUIStyle(GUIStyle DefaultStyle, MinMax OptionsIn, string CSSText, Texture2D BackgroundImage, Dictionary<string, Tuple<GUIStyle, MinMax>> GUIStyleCache, out MinMax OptionsOut, out Tuple<GUIStyle, MinMax> TheTuple)
  4476.         {
  4477.             CSSText = CSSText ?? "";
  4478.             if (BackgroundImage == null && GUIStyleCache != null)
  4479.             {
  4480.                 if (!GUIStyleCache.TryGetValue(CSSText, out TheTuple))
  4481.                 {
  4482.                     TheTuple = new Tuple<GUIStyle, MinMax>(DictionaryToGUIStyle(DefaultStyle, OptionsIn, TextToCSSDictionary(CSSText), out OptionsOut), OptionsOut);
  4483.                     GUIStyleCache[CSSText] = TheTuple;
  4484.                 }
  4485.             }
  4486.             else
  4487.             {
  4488.                 TheTuple = new Tuple<GUIStyle, MinMax>(DictionaryToGUIStyle(DefaultStyle, OptionsIn, TextToCSSDictionary(CSSText), out OptionsOut), OptionsOut);
  4489.                 if (BackgroundImage != null)
  4490.                 {
  4491.                     ApplyBackgroundImage(TheTuple.Item1, BackgroundImage);
  4492.                 }
  4493.             }
  4494.             OptionsOut = TheTuple.Item2;
  4495.             return TheTuple.Item1;
  4496.         }
  4497.         private void ApplyBackgroundImage(GUIStyle TheStyle, Texture2D BackgroundImage)
  4498.         {
  4499.             TheStyle.active.background = BackgroundImage;
  4500.             TheStyle.focused.background = BackgroundImage;
  4501.             TheStyle.hover.background = BackgroundImage;
  4502.             TheStyle.normal.background = BackgroundImage;
  4503.         }
  4504.         private GUIStyle DictionaryToGUIStyle(GUIStyle DefaultStyle, MinMax OptionsIn, Dictionary<string, string> CSSDictionary, out MinMax OptionsOut)
  4505.         {
  4506.             //active.background---------
  4507.             //active.textColor---------
  4508.             //focused.background---------
  4509.             //focused.textColor---------
  4510.             //hover.background---------
  4511.             //hover.textColor---------
  4512.             //normal.background---------
  4513.             //normal.textColor---------
  4514.             //onActivebackground---------
  4515.             //onActive.textColor---------
  4516.             //onFocusedbackground---------
  4517.             //onFocused.textColor---------
  4518.             //onHoverbackground---------
  4519.             //onHover.textColor---------
  4520.             //onNormalbackground---------
  4521.             //onNormal.textColor---------
  4522.             //border---------
  4523.             //alignment---------
  4524.             //clipping---------
  4525.             //--contentOffset
  4526.             //fixedHeight---------
  4527.             //fixedWidth---------
  4528.             //font---------
  4529.             //fontSize---------
  4530.             //fontStyle
  4531.             //--imagePosition
  4532.             //--lineHeight
  4533.             //margin---------
  4534.             //--name
  4535.             //overflow---------
  4536.             //padding---------
  4537.             //--richText
  4538.             //--stretchHeight
  4539.             //--stretchWidth
  4540.             //wordWrap---------
  4541.             var TheStyle = new GUIStyle(DefaultStyle);
  4542.             OptionsOut = new MinMax(OptionsIn);
  4543.             var HeightSet = false;
  4544.             var MinHeightSet = false;
  4545.             string Key, Val;
  4546.             string[] FontFallbacks = null;
  4547.             var FontSize = -1;
  4548.             var LineHeight = -1;
  4549.             Match TheMatch;
  4550.             MatchCollection TheMatches;
  4551.             Color TheColor;
  4552.             Texture2D TheTexture;
  4553.             int Top, Right, Bottom, Left, i;
  4554.             float FloatVal, R, G, B, A;
  4555.             bool IsValid;
  4556.             bool AlignedTop, AlignedMiddle, AlignedLower, AlignedLeft, AlignedCenter, AlignedRight;
  4557.             GroupCollection Groups;
  4558.             var OutlineKeys = new[] {
  4559.                 "border-width",
  4560.                 "border-top-width",
  4561.                 "border-right-width",
  4562.                 "border-bottom-width",
  4563.                 "border-left-width",
  4564.                 "border",
  4565.                 "border-top",
  4566.                 "border-right",
  4567.                 "border-bottom",
  4568.                 "border-left",
  4569.                 "padding",
  4570.                 "padding-top",
  4571.                 "padding-right",
  4572.                 "padding-bottom",
  4573.                 "padding-left",
  4574.                 "margin",
  4575.                 "margin-top",
  4576.                 "margin-right",
  4577.                 "margin-bottom",
  4578.                 "margin-left"
  4579.             };
  4580.             foreach (var Item in CSSDictionary)
  4581.             {
  4582.                 Key = Item.Key;
  4583.                 Val = Item.Value;
  4584.                 IsValid = false;
  4585.                 TheColor = Color.clear;
  4586.                 Top = Right = Bottom = Left = 0;
  4587.                 if (Key == "background-color" || Key == "color")
  4588.                 {
  4589.                     if ((TheMatch = Regex.Match(Val, "^rgba?\\(\\s*(-?(?:[0-9]+|[0-9]*\\.[0-9]+))\\s*,\\s*(-?(?:[0-9]+|[0-9]*\\.[0-9]+))\\s*,\\s*(-?(?:[0-9]+|[0-9]*\\.[0-9]+))\\s*,\\s*(-?(?:[0-9]+|[0-9]*\\.[0-9]+))\\s*\\)$", RegexOptions.IgnoreCase)).Success)
  4590.                     {
  4591.                         Groups = TheMatch.Groups;
  4592.                         if (IsColorChannel(Groups[1].Value, out R) && IsColorChannel(Groups[2].Value, out G) && IsColorChannel(Groups[3].Value, out B) && IsAlphaChannel(Groups[4].Value, out A))
  4593.                         {
  4594.                             IsValid = true;
  4595.                             TheColor = new Color(R / 255, G / 255, B / 255, A);
  4596.                         }
  4597.                     }
  4598.                     else if ((TheMatch = Regex.Match(Val, "^rgba?\\(\\s*(-?(?:[0-9]+|[0-9]*\\.[0-9]+))\\s*,\\s*(-?(?:[0-9]+|[0-9]*\\.[0-9]+))\\s*,\\s*(-?(?:[0-9]+|[0-9]*\\.[0-9]+))\\s*\\)$", RegexOptions.IgnoreCase)).Success)
  4599.                     {
  4600.                         Groups = TheMatch.Groups;
  4601.                         if (IsColorChannel(Groups[1].Value, out R) && IsColorChannel(Groups[2].Value, out G) && IsColorChannel(Groups[3].Value, out B))
  4602.                         {
  4603.                             IsValid = true;
  4604.                             TheColor = new Color(R / 255, G / 255, B / 255);
  4605.                         }
  4606.                     }
  4607.                     if (IsValid)
  4608.                     {
  4609.                         if (Key == "background-color")
  4610.                         {
  4611.                             TheTexture = TerraLabHelpers.GetSolidTexture(TheColor, 1, 1);
  4612.                             TheStyle.active.background = TheTexture;
  4613.                             TheStyle.focused.background = TheTexture;
  4614.                             TheStyle.hover.background = TheTexture;
  4615.                             TheStyle.normal.background = TheTexture;
  4616.                         }
  4617.                         else
  4618.                         {
  4619.                             TheStyle.active.textColor = TheColor;
  4620.                             TheStyle.focused.textColor = TheColor;
  4621.                             TheStyle.hover.textColor = TheColor;
  4622.                             TheStyle.normal.textColor = TheColor;
  4623.                         }
  4624.                     }
  4625.                 }
  4626.                 else if (OutlineKeys.Contains(Key))
  4627.                 {
  4628.                     if ((TheMatch = Regex.Match(Val, "^(-?(?:[0-9]+|[0-9]*\\.[0-9]+))(?:px)?(?:\\s+(-?(?:[0-9]+|[0-9]*\\.[0-9]+))(?:px)?(?:\\s+(-?(?:[0-9]+|[0-9]*\\.[0-9]+))(?:px)?\\s+(-?(?:[0-9]+|[0-9]*\\.[0-9]+))(?:px)?)?)?$", RegexOptions.IgnoreCase)).Success)
  4629.                     {
  4630.                         IsValid = true;
  4631.                         Groups = TheMatch.Groups;
  4632.                         if (String.IsNullOrEmpty(Groups[2].Value))
  4633.                         {
  4634.                             //is single value                            
  4635.                             Top = GetIntVal(Groups[1].Value);
  4636.                             Right = GetIntVal(Groups[1].Value);
  4637.                             Bottom = GetIntVal(Groups[1].Value);
  4638.                             Left = GetIntVal(Groups[1].Value);
  4639.                         }
  4640.                         else if (String.IsNullOrEmpty(Groups[3].Value) || String.IsNullOrEmpty(Groups[4].Value))
  4641.                         {
  4642.                             //is two-value shorthand
  4643.                             Top = GetIntVal(Groups[1].Value);
  4644.                             Right = GetIntVal(Groups[2].Value);
  4645.                             Bottom = GetIntVal(Groups[1].Value);
  4646.                             Left = GetIntVal(Groups[2].Value);
  4647.                         }
  4648.                         else
  4649.                         {
  4650.                             //is four-value
  4651.                             Top = GetIntVal(Groups[1].Value);
  4652.                             Right = GetIntVal(Groups[2].Value);
  4653.                             Bottom = GetIntVal(Groups[3].Value);
  4654.                             Left = GetIntVal(Groups[4].Value);
  4655.                         }
  4656.                     }
  4657.                     if (IsValid)
  4658.                     {
  4659.                         if (Key.IndexOf("border") > -1)
  4660.                         {
  4661.                             if (Key == "border" || Key == "border-width" || Key.IndexOf("-top") > -1)
  4662.                             {
  4663.                                 TheStyle.border.top = Top;
  4664.                             }
  4665.                             if (Key == "border" || Key == "border-width" || Key.IndexOf("-right") > -1)
  4666.                             {
  4667.                                 TheStyle.border.right = Right;
  4668.                             }
  4669.                             if (Key == "border" || Key == "border-width" || Key.IndexOf("-bottom") > -1)
  4670.                             {
  4671.                                 TheStyle.border.bottom = Bottom;
  4672.                             }
  4673.                             if (Key == "border" || Key == "border-width" || Key.IndexOf("-left") > -1)
  4674.                             {
  4675.                                 TheStyle.border.left = Left;
  4676.                             }
  4677.                         }
  4678.                         else if (Key.IndexOf("padding") > -1)
  4679.                         {
  4680.                             if (Key == "padding" || Key.IndexOf("-top") > -1)
  4681.                             {
  4682.                                 TheStyle.padding.top = Top;
  4683.                             }
  4684.                             if (Key == "padding" || Key.IndexOf("-right") > -1)
  4685.                             {
  4686.                                 TheStyle.padding.right = Right;
  4687.                             }
  4688.                             if (Key == "padding" || Key.IndexOf("-bottom") > -1)
  4689.                             {
  4690.                                 TheStyle.padding.bottom = Bottom;
  4691.                             }
  4692.                             if (Key == "padding" || Key.IndexOf("-left") > -1)
  4693.                             {
  4694.                                 TheStyle.padding.left = Left;
  4695.                             }
  4696.                         }
  4697.                         else if (Key.IndexOf("margin") > -1)
  4698.                         {
  4699.                             if (Key == "margin" || Key.IndexOf("-top") > -1)
  4700.                             {
  4701.                                 TheStyle.margin.top = Top;
  4702.                             }
  4703.                             if (Key == "margin" || Key.IndexOf("-right") > -1)
  4704.                             {
  4705.                                 TheStyle.margin.right = Right;
  4706.                             }
  4707.                             if (Key == "margin" || Key.IndexOf("-bottom") > -1)
  4708.                             {
  4709.                                 TheStyle.margin.bottom = Bottom;
  4710.                             }
  4711.                             if (Key == "margin" || Key.IndexOf("-left") > -1)
  4712.                             {
  4713.                                 TheStyle.margin.left = Left;
  4714.                             }
  4715.                         }
  4716.                     }
  4717.                 }
  4718.                 else if (Key == "text-align")
  4719.                 {
  4720.                     if (Val == "left" || Val == "center" || Val == "right")
  4721.                     {
  4722.                         AlignedTop = TheStyle.alignment == TextAnchor.UpperLeft || TheStyle.alignment == TextAnchor.UpperCenter || TheStyle.alignment == TextAnchor.UpperRight;
  4723.                         AlignedMiddle = TheStyle.alignment == TextAnchor.MiddleLeft || TheStyle.alignment == TextAnchor.MiddleCenter || TheStyle.alignment == TextAnchor.MiddleRight;
  4724.                         AlignedLower = TheStyle.alignment == TextAnchor.LowerLeft || TheStyle.alignment == TextAnchor.LowerCenter || TheStyle.alignment == TextAnchor.LowerRight;
  4725.                         if (Val == "left")
  4726.                         {
  4727.                             TheStyle.alignment = AlignedTop ? TextAnchor.UpperLeft : (AlignedMiddle ? TextAnchor.MiddleLeft : TextAnchor.LowerLeft);
  4728.                         }
  4729.                         else if (Val == "center")
  4730.                         {
  4731.                             TheStyle.alignment = AlignedTop ? TextAnchor.UpperCenter : (AlignedMiddle ? TextAnchor.MiddleCenter : TextAnchor.LowerCenter);
  4732.                         }
  4733.                         else if (Val == "right")
  4734.                         {
  4735.                             TheStyle.alignment = AlignedTop ? TextAnchor.UpperRight : (AlignedMiddle ? TextAnchor.MiddleRight : TextAnchor.LowerRight);
  4736.                         }
  4737.                     }
  4738.                 }
  4739.                 else if (Key == "vertical-align")
  4740.                 {
  4741.                     if (Val == "top" || Val == "middle" || Val == "bottom")
  4742.                     {
  4743.                         AlignedLeft = TheStyle.alignment == TextAnchor.UpperLeft || TheStyle.alignment == TextAnchor.MiddleLeft || TheStyle.alignment == TextAnchor.LowerLeft;
  4744.                         AlignedCenter = TheStyle.alignment == TextAnchor.UpperCenter || TheStyle.alignment == TextAnchor.MiddleCenter || TheStyle.alignment == TextAnchor.LowerCenter;
  4745.                         AlignedRight = TheStyle.alignment == TextAnchor.UpperRight || TheStyle.alignment == TextAnchor.MiddleRight || TheStyle.alignment == TextAnchor.LowerRight;
  4746.                         if (Val == "top")
  4747.                         {
  4748.                             TheStyle.alignment = AlignedLeft ? TextAnchor.UpperLeft : (AlignedCenter ? TextAnchor.UpperCenter : TextAnchor.UpperRight);
  4749.                         }
  4750.                         else if (Val == "middle")
  4751.                         {
  4752.                             TheStyle.alignment = AlignedLeft ? TextAnchor.MiddleLeft : (AlignedCenter ? TextAnchor.MiddleCenter : TextAnchor.MiddleRight);
  4753.                         }
  4754.                         else if (Val == "bottom")
  4755.                         {
  4756.                             TheStyle.alignment = AlignedLeft ? TextAnchor.LowerLeft : (AlignedCenter ? TextAnchor.LowerCenter : TextAnchor.LowerRight);
  4757.                         }
  4758.                     }
  4759.                 }
  4760.                 else if (Key == "overflow")
  4761.                 {
  4762.                     if (Val == "visible")
  4763.                     {
  4764.                         TheStyle.clipping = TextClipping.Overflow;
  4765.                     }
  4766.                     else if (Val == "hidden")
  4767.                     {
  4768.                         TheStyle.clipping = TextClipping.Clip;
  4769.                     }
  4770.                 }
  4771.                 else if (Key == "stretch-width")
  4772.                 {
  4773.                     TheStyle.stretchWidth = (Val == "true");
  4774.                 }
  4775.                 else if (Key == "stretch-height")
  4776.                 {
  4777.                     TheStyle.stretchHeight = (Val == "true");
  4778.                 }
  4779.                 else if (Key == "white-space")
  4780.                 {
  4781.                     TheStyle.wordWrap = (Val != "nowrap");
  4782.                 }
  4783.                 else if (Key == "image-position")
  4784.                 {
  4785.                     if (Val == "image-left")
  4786.                     {
  4787.                         TheStyle.imagePosition = ImagePosition.ImageLeft;
  4788.                     }
  4789.                     else if (Val == "image-above")
  4790.                     {
  4791.                         TheStyle.imagePosition = ImagePosition.ImageAbove;
  4792.                     }
  4793.                     else if (Val == "image-only")
  4794.                     {
  4795.                         TheStyle.imagePosition = ImagePosition.ImageOnly;
  4796.                     }
  4797.                     else if (Val == "text-only")
  4798.                     {
  4799.                         TheStyle.imagePosition = ImagePosition.TextOnly;
  4800.                     }
  4801.                 }
  4802.                 else if (Key == "line-height" || Key == "font-size")
  4803.                 {
  4804.                     if ((TheMatch = Regex.Match(Val, "(-?(?:[0-9]+|[0-9]*\\.[0-9]+))(px|%)?", RegexOptions.IgnoreCase)).Success)
  4805.                     {
  4806.                         Groups = TheMatch.Groups;
  4807.                         if (Groups[2].Value == "%")
  4808.                         {
  4809.                             throw new Exception("percentage widths are not supported: '" + Val + "'");
  4810.                         }
  4811.                         FloatVal = GetFloatVal(Groups[1].Value);
  4812.                         if (Key == "line-height")
  4813.                         {
  4814.                             LineHeight = (int)FloatVal;
  4815.                         }
  4816.                         else if (Key == "font-size")
  4817.                         {
  4818.                             FontSize = (int)FloatVal;
  4819.                         }
  4820.  
  4821.                     }
  4822.                 }
  4823.                 else if (Key == "font-family")
  4824.                 {
  4825.                     TheMatches = Regex.Matches(Val, "(?:^|\\G\\s*,)\\s*'((?:[^\\\\']|\\\\.)*)'");
  4826.                     FontFallbacks = new string[TheMatches.Count];
  4827.                     i = 0;
  4828.                     foreach (Match fontMatch in TheMatches)
  4829.                     {
  4830.                         Groups = fontMatch.Groups;
  4831.                         FontFallbacks[i] = Groups[1].Value;
  4832.                         i++;
  4833.                     }
  4834.                 }
  4835.             }
  4836.             if (FontSize >= 0)
  4837.             {
  4838.                 TheStyle.fontSize = FontSize;
  4839.             }
  4840.             else
  4841.             {
  4842.                 FontSize = DefaultFontSize;
  4843.             }
  4844.             if (LineHeight < 0)
  4845.             {
  4846.                 LineHeight = FontSizeToLineHeight(FontSize);
  4847.             }
  4848.             if (FontFallbacks != null)
  4849.             {
  4850.                 Font TheFont = null;
  4851.                 foreach (var FallbackName in FontFallbacks)
  4852.                 {
  4853.                     if ((TheFont = GetFont(FallbackName)) != null)
  4854.                     {
  4855.                         break;
  4856.                     }
  4857.                 }
  4858.                 TheStyle.font = TheFont;
  4859.             }
  4860.             bool IsPercentage;
  4861.             float NearestSetWidth = 0;
  4862.             foreach (var fixedWidth in NestedWidths)
  4863.             {
  4864.                 if (fixedWidth > 0)
  4865.                 {
  4866.                     NearestSetWidth = fixedWidth;
  4867.                     break;
  4868.                 }
  4869.             }
  4870.             var TextSize = GetHeight(TheStyle);
  4871.             foreach (var Item in CSSDictionary)
  4872.             {
  4873.                 Key = Item.Key;
  4874.                 Val = Item.Value;
  4875.                 if (Key == "width" || Key == "height" || Key == "min-width" || Key == "max-width" || Key == "min-height" || Key == "max-height")
  4876.                 {
  4877.                     if ((TheMatch = Regex.Match(Val, "^(?:(-?(?:[0-9]+|[0-9]*\\.[0-9]+))(px|%)?|text)$", RegexOptions.IgnoreCase)).Success)
  4878.                     {
  4879.                         IsPercentage = false;
  4880.                         Groups = TheMatch.Groups;
  4881.                         if (Groups[2].Value == "%")
  4882.                         {
  4883.                             IsPercentage = true;
  4884.                             //throw new Exception("percentage widths are not supported: '" + Val + "'");
  4885.                         }
  4886.                         if (TheMatch.Value == "text")
  4887.                         {
  4888.                             FloatVal = TextSize;
  4889.                         }
  4890.                         else
  4891.                         {
  4892.                             FloatVal = GetFloatVal(Groups[1].Value);
  4893.                         }
  4894.                         if (Key == "width")
  4895.                         {
  4896.                             FloatVal = IsPercentage ? (FloatVal * 0.01F * NearestSetWidth) : FloatVal;
  4897.                             TheStyle.fixedWidth = FloatVal;
  4898.                         }
  4899.                         else if (Key == "height")
  4900.                         {
  4901.                             HeightSet = true;
  4902.                             TheStyle.fixedHeight = FloatVal;
  4903.                         }
  4904.                         else if (Key == "min-width")
  4905.                         {
  4906.                             FloatVal = IsPercentage ? (FloatVal * 0.01F * NearestSetWidth) : FloatVal;
  4907.                             OptionsOut.MinWidth = FloatVal;
  4908.                         }
  4909.                         else if (Key == "max-width")
  4910.                         {
  4911.                             OptionsOut.MaxWidth = FloatVal;
  4912.                         }
  4913.                         else if (Key == "min-height")
  4914.                         {
  4915.                             MinHeightSet = true;
  4916.                             OptionsOut.MinHeight = FloatVal;
  4917.                         }
  4918.                         else if (Key == "max-height")
  4919.                         {
  4920.                             OptionsOut.MaxHeight = FloatVal;
  4921.                         }
  4922.                     }
  4923.                 }
  4924.             }
  4925.             return TheStyle;
  4926.         }
  4927.     }
  4928. }
  4929.  
  4930.  
  4931.  
  4932.  
  4933.  
  4934.  
  4935.  
  4936.  
  4937.  
  4938.  
  4939. using System;
  4940. using System.Collections;
  4941. using System.Collections.Generic;
  4942. using System.Linq;
  4943. using System.Linq.Expressions;
  4944. using System.Text.RegularExpressions;
  4945. using System.Reflection;
  4946. using UnityEditor;
  4947. using UnityEngine;
  4948. using UnityEngine.SceneManagement;
  4949.  
  4950.  
  4951. namespace TerraLab
  4952. {
  4953.     public static class TerraLabHelpers
  4954.     {
  4955.         private static Dictionary<string, Texture2D> SolidTextureCache = new Dictionary<string, Texture2D>();
  4956.         private static Dictionary<string, Texture2D> GridTextureCache = new Dictionary<string, Texture2D>();
  4957.         private static bool DelayApply = false;
  4958.         public static GUIStyle SetBackgroundColor(this GUIStyle TheStyle, Color TheColor, double alpha = -1, double light = -1)
  4959.         {
  4960.             return TheStyle.SetBackgroundColor(TheColor.r, TheColor.g, TheColor.b, alpha, light);
  4961.         }
  4962.         public static GUIStyle SetBackgroundColor(this GUIStyle TheStyle, double r, double g, double b, double alpha = -1, double light = -1)
  4963.         {
  4964.             var NewStyle = new GUIStyle(TheStyle);
  4965.             var TheTexture = GetSolidTexture(r, g, b, alpha, light);
  4966.             NewStyle.normal.background = TheTexture;
  4967.             NewStyle.focused.background = TheTexture;
  4968.             NewStyle.active.background = TheTexture;
  4969.             NewStyle.hover.background = TheTexture;
  4970.             return NewStyle;
  4971.         }
  4972.         public static Texture2D GetSolidTexture(Color TheColor, int width = -1, int height = -1)
  4973.         {
  4974.             return GetSolidTexture(TheColor.r, TheColor.g, TheColor.b, TheColor.a, 0.5, width = -1, height = -1);
  4975.         }
  4976.         public static Texture2D GetSolidTexture(Color TheColor, double alpha = -1, double light = -1, int width = -1, int height = -1)
  4977.         {
  4978.             return GetSolidTexture(TheColor.r, TheColor.g, TheColor.b, alpha, light, width, height);
  4979.         }
  4980.         public static Texture2D GetSolidTexture(double r, double g, double b, double alpha = -1, double light = -1, int width = -1, int height = -1)
  4981.         {
  4982.             alpha = (alpha < 0) ? 1 : Math.Min(alpha, 1);
  4983.             width = (width < 0) ? 32 : width;
  4984.             height = (height < 0) ? 32 : height;
  4985.             if (light >= 0 && light < 0.5)
  4986.             {
  4987.                 r = r * (2 * light);
  4988.                 g = g * (2 * light);
  4989.                 b = b * (2 * light);
  4990.             }
  4991.             else if (light <= 1 && light > 0.5)
  4992.             {
  4993.                 r = r + ((1 - r) * ((2 * light) - 1));
  4994.                 g = g + ((1 - g) * ((2 * light) - 1));
  4995.                 b = b + ((1 - b) * ((2 * light) - 1));
  4996.             }
  4997.             var Key = r + "," + g + "," + b + "," + alpha + "," + light + "," + width + "," + height;
  4998.             if (SolidTextureCache.TryGetValue(Key, out Texture2D TheTexture))
  4999.             {
  5000.                 return TheTexture;
  5001.             }
  5002.             else
  5003.             {
  5004.                 TheTexture = new Texture2D(width, height);
  5005.                 for (var x = 0; x < width; x++)
  5006.                 {
  5007.                     for (var y = 0; y < height; y++)
  5008.                     {
  5009.                         TheTexture.SetPixel(x, y, new Color((float)r, (float)g, (float)b, (float)alpha));
  5010.                     }
  5011.                 }
  5012.                 if (!DelayApply)
  5013.                 {
  5014.                     TheTexture.Apply();
  5015.                 }
  5016.                 SolidTextureCache.Add(Key, TheTexture);
  5017.                 return TheTexture;
  5018.             }
  5019.         }
  5020.         public static Texture2D GetWhiteGridTexture(Color TheColor, int width = -1, int height = -1)
  5021.         {
  5022.             return GetWhiteGridTexture(TheColor.r, TheColor.g, TheColor.b, TheColor.a, 0.5, width, height);
  5023.         }
  5024.         public static Texture2D GetWhiteGridTexture(Color TheColor, double alpha = -1, double light = -1, int width = -1, int height = -1)
  5025.         {
  5026.             return GetWhiteGridTexture(TheColor.r, TheColor.g, TheColor.b, alpha, light, width, height);
  5027.         }
  5028.         public static Texture2D GetWhiteGridTexture(double r, double g, double b, double alpha = -1, double light = -1, int width = -1, int height = -1)
  5029.         {
  5030.             var Key = r + "," + g + "," + b + "," + alpha + "," + light + "," + width + "," + height;
  5031.             if (GridTextureCache.TryGetValue(Key, out Texture2D TheTexture))
  5032.             {
  5033.                 return TheTexture;
  5034.             }
  5035.             else
  5036.             {
  5037.                 DelayApply = true;
  5038.                 TheTexture = GetSolidTexture(r, g, b, alpha, light, width, height);
  5039.                 DelayApply = false;
  5040.                 for (var y = 0; y < TheTexture.height; y++)
  5041.                 {
  5042.                     TheTexture.SetPixel(0, y, Color.white);
  5043.                 }
  5044.                 for (var x = 0; x < TheTexture.width; x++)
  5045.                 {
  5046.                     TheTexture.SetPixel(x, TheTexture.height - 1, Color.white);
  5047.                 }
  5048.                 TheTexture.Apply();
  5049.                 GridTextureCache.Add(Key, TheTexture);
  5050.                 return TheTexture;
  5051.             }
  5052.         }
  5053.     }
  5054. }
  5055.  
  5056.  
  5057.  
  5058.  
  5059.  
  5060.  
  5061.  
  5062.  
  5063.  
  5064.  
  5065. using System;
  5066. using System.IO;
  5067. using System.Collections;
  5068. using System.Collections.Generic;
  5069. using System.Linq;
  5070. using System.Text;
  5071. using System.Text.RegularExpressions;
  5072. using System.Runtime.Serialization.Formatters.Binary;
  5073. using System.Reflection;
  5074.  
  5075. namespace TerraLab
  5076. {
  5077.     public static class GenericHelpers
  5078.     {
  5079.         //EXTENSIONS
  5080.         public static long ToUtcUnixTimeSeconds(this DateTime obj)
  5081.         {
  5082.             return ((DateTimeOffset)DateTime.SpecifyKind(obj, DateTimeKind.Utc)).ToUnixTimeSeconds();
  5083.         }
  5084.         //METHODS
  5085.         public static bool empty<T>(T val, bool TrueIfEmptyArray = true)
  5086.         {
  5087.             //this method returns true if val is null, an empty string, or an array with no elements
  5088.             //the optional parameter TrueIfEmptyArray lets you control whether to return true if val is an empty array
  5089.             if (is_null(val))
  5090.             {
  5091.                 return true;
  5092.             }
  5093.             else if (val.GetType() == typeof(string))
  5094.             {
  5095.                 return (val as string) == "";
  5096.             }
  5097.             else if (TrueIfEmptyArray && is_enumerable(val, out IEnumerable the_enumerable))
  5098.             {
  5099.                 foreach (var the_element in the_enumerable)
  5100.                 {
  5101.                     return false;
  5102.                 }
  5103.                 return true;
  5104.             }
  5105.             return false;
  5106.         }
  5107.         public static bool is_null<T>(T val)
  5108.         {
  5109.             //this method returns null if val is null
  5110.             return is_null(val, out bool is_nullable);
  5111.         }
  5112.         public static bool is_null<T>(T val, out bool is_nullable)
  5113.         {
  5114.             //this method returns null if val is null
  5115.             //the out parameter is_nullable returns whether val was even nullable to begin with
  5116.             return ((is_nullable = (default(T) == null)) && EqualityComparer<T>.Default.Equals(val, default(T)));
  5117.         }
  5118.         public static bool is_enumerable<T>(T val)
  5119.         {
  5120.             //this method returns true if val implements IEnumerable
  5121.             return is_enumerable(val, out IEnumerable the_enumerable);
  5122.         }
  5123.         public static bool is_enumerable<T>(T val, out IEnumerable the_enumerable)
  5124.         {
  5125.             //this method returns true if val implements IEnumerable
  5126.             //the out parameter returns val cast as an IEnumerable
  5127.             return (the_enumerable = val as IEnumerable) != null;
  5128.         }
  5129.         public static bool value_or_string<T>(T val)
  5130.         {
  5131.             //this method returns true if val is a primitive, a value type, or is a string
  5132.             return is_null(val) ? true : value_or_string(val.GetType());
  5133.         }
  5134.         public static bool value_or_string(Type the_type)
  5135.         {
  5136.             //this method returns true if the_type is a primitive type, a value type, or is a string type
  5137.             return (the_type.IsPrimitive || the_type.IsValueType || the_type == typeof(string)) && the_type.GetGenericArguments().Length == 0;
  5138.         }
  5139.         public static Type[] GetTypesInNamespace(string Namespace)
  5140.         {
  5141.             //this method takes a namespace and returns an array of all the types/classes defined within it
  5142.             var SelectedTypes = new List<Type>();
  5143.             foreach (var TheType in Assembly.GetExecutingAssembly().GetTypes())
  5144.             {
  5145.                 if (TheType.Namespace == Namespace)
  5146.                 {
  5147.                     SelectedTypes.Add(TheType);
  5148.                 }
  5149.             }
  5150.             return SelectedTypes.ToArray();
  5151.         }
  5152.         public static Type[] GetAssignableTypes(Type ParentType, bool CurrentAssemblyOnly = false)
  5153.         {
  5154.             //this method takes a parent type and lists all the classes that can be cast to it
  5155.             var SelectedTypes = new List<Type>();
  5156.             if (CurrentAssemblyOnly)
  5157.             {
  5158.                 SelectedTypes.AddRange(Assembly.GetExecutingAssembly().GetTypes().Where(x => ParentType.IsAssignableFrom(x) && x != ParentType));
  5159.             }
  5160.             else
  5161.             {
  5162.                 foreach (var TheAssembly in AppDomain.CurrentDomain.GetAssemblies())
  5163.                 {
  5164.                     SelectedTypes.AddRange(TheAssembly.GetTypes().Where(x => ParentType.IsAssignableFrom(x) && x != ParentType));
  5165.                 }
  5166.             }
  5167.             return SelectedTypes.ToArray();
  5168.         }
  5169.         public static string regex_mirror_replace(string SearchPattern, string Replacement, string SearchString, string ChangeString)
  5170.         {
  5171.             //this method replaces characters in "ChangeString" based on the location of matches found in "SearchString"
  5172.             //the length of "ChangeString" must match the length of "SearchString" for it to work
  5173.             //SearchPattern - the pattern to look for in the "mirror" string
  5174.             //SearchString - the "mirror" string to be searched
  5175.             //Replacement - the text to replace whatever was found by SearchPattern
  5176.             //ChangeString - the actual string that will be changed based on matches found in SearchString (the "mirror" string)
  5177.             string Str;
  5178.             int StrPos;
  5179.             int StrLen;
  5180.             string NewStr;
  5181.             ChangeString = ChangeString ?? "";
  5182.             SearchString = SearchString ?? "";
  5183.             if (SearchString.Length != ChangeString.Length)
  5184.             {
  5185.                 throw new Exception("regex_mirror_replace error: SearchString and ChangeString are different lengths (" + SearchString.Length + " versus " + ChangeString.Length + ").");
  5186.             }
  5187.             var Matches = Regex.Matches(SearchString, SearchPattern);
  5188.             var Offset = 0;
  5189.             foreach (Match TheMatch in Matches)
  5190.             {
  5191.                 Str = TheMatch.Value;
  5192.                 StrPos = TheMatch.Index;
  5193.                 StrLen = Str.Length;
  5194.                 NewStr = Regex.Replace(Str, "^(.*)$", Replacement, RegexOptions.Singleline);
  5195.                 ChangeString = ChangeString.Substring(0, StrPos + Offset) + NewStr + ChangeString.Substring(StrPos + StrLen + Offset);
  5196.                 Offset = Offset + (NewStr.Length - StrLen);
  5197.             }
  5198.             return ChangeString;
  5199.         }
  5200.         public static string mirror_no_strings(string input, string RepeatChar = " ")
  5201.         {
  5202.             //this takes a string with quoted statements in it and replaces the statements with spaces
  5203.             //for example, the following string:
  5204.             //SELECT * FROM MYTABLE WHERE DESC = 'fresh'" AND ID > 5
  5205.             //becomes:
  5206.             //SELECT * FROM MYTABLE WHERE DESC = '     '" AND ID > 5
  5207.             return regex_repeat_string("\"(?:[^\\\\\"]|\\\\.)*\"|'(?:[^\\\\']|\\\\.)*'", RepeatChar, input, false, RegexOptions.Singleline);
  5208.         }
  5209.         public static string regex_repeat_string(string Pattern, string RepeatChar, string input, bool KeepMatchEndChars = false, RegexOptions Options = RegexOptions.None)
  5210.         {
  5211.             //this method takes a string (input) and searches for a regular expression (pattern)
  5212.             //for every match that is found, it replaces it with a string (RepeatChar) that is repeated as many times as the match is long
  5213.             //e.g. regex_repeat_string("a[bc]+", "4", "azbdacloabbl") returns "azbd44lo444l"
  5214.             //KeepMatchEndChars tells the method to not replace the end chars of the matches it finds (the previous example would return "azbdacloa4bl")
  5215.             //KeepMatchEndChars is helpful when you're using the method on, for example, an SQL string with string literals in it, and you want to see where the quotes were
  5216.             //it's useful when you want to parse SQL or other code where string literals might interfere with your parsing algorithm
  5217.             //regex_repeat_string("\"(?:[^\\\\\"]|\\\\.)*\"|'(?:[^\\\\']|\\\\.)*'", " ", "SELECT * FROM MYTABLE WHERE DESC = 'fresh and delicious'", true)
  5218.             //returns "SELECT * FROM MYTABLE WHERE DESC = '                   '" (notice how the 'fresh and delicious' string is the same length as before, but just replaced with spaces)
  5219.             var ReplacePattern = KeepMatchEndChars ? "(?<=.).(?=.)" : ".";
  5220.             input = Regex.Replace(input, Pattern, delegate (Match TheMatch)
  5221.             {
  5222.                 return Regex.Replace(TheMatch.Value, ReplacePattern, RepeatChar, RegexOptions.Singleline);
  5223.             }, Options);
  5224.             return input;
  5225.         }
  5226.         public static bool IsPowerOfTwo(int x)
  5227.         {
  5228.             return (x != 0) && ((x & (x - 1)) == 0);
  5229.         }
  5230.         public static bool IsInteger(decimal input)
  5231.         {
  5232.             //this method returns true if the decimal is a whole number
  5233.             return (input % 1) == 0;
  5234.         }
  5235.         public static string PadLeft<T>(T x, char repeatChar, int length)
  5236.         {
  5237.             var str = (x == null) ? "" : x.ToString();
  5238.             return new String(repeatChar, length - str.Length) + str;
  5239.         }
  5240.         public static string PadRight<T>(T x, char repeatChar, int length)
  5241.         {
  5242.             var str = (x == null) ? "" : x.ToString();
  5243.             return str + new String(repeatChar, length - str.Length);
  5244.         }
  5245.         public static string AddCommas(string input)
  5246.         {
  5247.             //this adds the thousands comma to a number (e.g. 1000 becomes 1,000)
  5248.             if (!decimal.TryParse(input, out decimal value))
  5249.             {
  5250.                 throw new Exception("AddCommas error: input must be numeric");
  5251.             }
  5252.             return AddCommas(value);
  5253.         }
  5254.         public static string AddCommas(decimal input)
  5255.         {
  5256.             //this adds the thousands comma to a number (e.g. 1000 becomes 1,000)
  5257.             var decimals = Regex.Replace(input.ToString(), "^[^.]*\\.?", "").Length;
  5258.             return String.Format("{0:n" + decimals + "}", input);
  5259.         }
  5260.         public static byte[] ObjectToByteArray(object obj)
  5261.         {
  5262.             byte[] Result;
  5263.             var TheFormatter = new BinaryFormatter();
  5264.             using (var TheStream = new MemoryStream())
  5265.             {
  5266.                 TheFormatter.Serialize(TheStream, obj);
  5267.                 Result = TheStream.ToArray();
  5268.             }
  5269.             return Result;
  5270.         }
  5271.         public static object ByteArrayToObject(byte[] bytes)
  5272.         {
  5273.             object Result;
  5274.             var TheFormatter = new BinaryFormatter();
  5275.             using (var TheStream = new MemoryStream(bytes))
  5276.             {
  5277.                 Result = TheFormatter.Deserialize(TheStream);
  5278.             }
  5279.             return Result;
  5280.         }
  5281.         public static string MemoryToBase64(object obj)
  5282.         {
  5283.             //this method takes an object from memory and encodes it into a Base64 string
  5284.             return Base64Encode(ObjectToByteArray(obj));
  5285.         }
  5286.         public static object Base64ToMemory(string base64EncodedData)
  5287.         {
  5288.             //this method takes a Base64 string and decodes it to an object in memory
  5289.             return ByteArrayToObject(Base64DecodeToBytes(base64EncodedData));
  5290.         }
  5291.         public static string Base64Encode(string plainText)
  5292.         {
  5293.             //this method takes a string and encodes it into a Base64 string
  5294.             return is_null(plainText) ? null : Convert.ToBase64String(Encoding.UTF8.GetBytes(plainText));
  5295.         }
  5296.         public static string Base64Encode(byte[] bytes)
  5297.         {
  5298.             //this method takes a byte array and encodes it into a Base64 string
  5299.             return is_null(bytes) ? null : Convert.ToBase64String(bytes);
  5300.         }
  5301.         public static string Base64DecodeToString(string base64EncodedData)
  5302.         {
  5303.             //this method takes a Base64 string and decodes it to a string
  5304.             return is_null(base64EncodedData) ? null : Encoding.UTF8.GetString(Convert.FromBase64String(base64EncodedData));
  5305.         }
  5306.         public static byte[] Base64DecodeToBytes(string base64EncodedData)
  5307.         {
  5308.             //this method takes a Base64 string and decodes it to a byte array
  5309.             return is_null(base64EncodedData) ? null : Convert.FromBase64String(base64EncodedData);
  5310.         }
  5311.     }
  5312. }
Add Comment
Please, Sign In to add comment