holopy3/Assets/MeshCombiner/Editor/MeshCombinerEditor.cs
2020-12-10 15:25:12 +01:00

141 lines
5.5 KiB
C#

using System.Linq;
using System.Text.RegularExpressions;
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof(MeshCombiner))]
public class MeshCombinerEditor : Editor
{
public override void OnInspectorGUI()
{
MeshCombiner meshCombiner = (MeshCombiner)target;
Mesh mesh = meshCombiner.GetComponent<MeshFilter>().sharedMesh;
#region Script:
GUI.enabled = false;
EditorGUILayout.ObjectField("Script", MonoScript.FromMonoBehaviour((MeshCombiner)target), typeof(MeshCombiner), false);
GUI.enabled = true;
#endregion Script.
#region MeshFiltersToSkip array:
SerializedProperty meshFiltersToSkip = serializedObject.FindProperty("meshFiltersToSkip");
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(meshFiltersToSkip, true);
if(EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
#endregion MeshFiltersToSkip array.
#region Button which combine Meshes into one Mesh & Toggles with combine options:
// Button:
if(GUILayout.Button("Combine Meshes"))
{
meshCombiner.CombineMeshes(true);
}
// Toggles:
meshCombiner.CreateMultiMaterialMesh = GUILayout.Toggle(meshCombiner.CreateMultiMaterialMesh, "Create Multi-Material Mesh");
meshCombiner.CombineInactiveChildren = GUILayout.Toggle(meshCombiner.CombineInactiveChildren, "Combine Inactive Children");
meshCombiner.DeactivateCombinedChildren = GUILayout.Toggle(meshCombiner.DeactivateCombinedChildren, "Deactivate Combined Children");
meshCombiner.DeactivateCombinedChildrenMeshRenderers = GUILayout.Toggle(meshCombiner.DeactivateCombinedChildrenMeshRenderers,
"Deactivate Combined Children's MeshRenderers");
// The last (5) "Destroy Combined Children" Toggle:
GUIStyle style = new GUIStyle(EditorStyles.toggle);
if(meshCombiner.DestroyCombinedChildren)
{
style.onNormal.textColor = new Color(1, 0.15f, 0);
}
meshCombiner.DestroyCombinedChildren = GUILayout.Toggle(meshCombiner.DestroyCombinedChildren,
new GUIContent("Destroy Combined Children", "In the editor this operation can NOT be undone!\n\n"+
"If you want to bring back destroyed GameObjects, you have to load again the scene without saving."), style);
#endregion Button which combine Meshes into one Mesh & Toggles with combine options.
#region Path to the folder where combined Meshes will be saved:
// Create Labels:
GUILayout.Label("");
GUILayout.Label(new GUIContent("Folder path:", "Folder path to save combined Mesh."));
// Create style wherein text color will be red if folder path is not valid:
style = new GUIStyle(EditorStyles.textField);
bool isValidPath = IsValidPath(meshCombiner.FolderPath);
if(!isValidPath)
{
style.normal.textColor = Color.red;
style.focused.textColor = Color.red;
}
// Create TextField with custom style:
meshCombiner.FolderPath = EditorGUILayout.TextField(meshCombiner.FolderPath, style);
#endregion Path to the folder where combined Meshes will be saved.
#region Button which save/show combined Mesh:
bool meshIsSaved = (mesh != null && AssetDatabase.Contains(mesh));
GUI.enabled = (mesh != null && (isValidPath || meshIsSaved)); // Valid path is required for not saved Mesh.
string saveMeshButtonText = (meshIsSaved) ? "Show Saved Combined Mesh" : "Save Combined Mesh";
if(GUILayout.Button(saveMeshButtonText))
{
meshCombiner.FolderPath = SaveCombinedMesh(mesh, meshCombiner.FolderPath);
}
GUI.enabled = true;
#endregion Button which save/show combined Mesh.
}
private bool IsValidPath(string folderPath)
{
string pattern = "[:*?\"<>|]"; // Prohibited characters.
Regex regex = new Regex(pattern);
return (!regex.IsMatch(folderPath));
}
private string SaveCombinedMesh(Mesh mesh, string folderPath)
{
bool meshIsSaved = AssetDatabase.Contains(mesh); // If is saved then only show it in the project view.
#region Create directories if Mesh and path doesn't exists:
folderPath = folderPath.Replace('\\', '/');
if(!meshIsSaved && !AssetDatabase.IsValidFolder("Assets/"+folderPath))
{
string[] folderNames = folderPath.Split('/');
folderNames = folderNames.Where((folderName) => !folderName.Equals("")).ToArray();
folderNames = folderNames.Where((folderName) => !folderName.Equals(" ")).ToArray();
folderPath = "/"; // Reset folder path.
for(int i = 0; i < folderNames.Length; i++)
{
folderNames[i] = folderNames[i].Trim();
if(!AssetDatabase.IsValidFolder("Assets"+folderPath+folderNames[i]))
{
string folderPathWithoutSlash = folderPath.Substring(0, folderPath.Length-1); // Delete last "/" character.
AssetDatabase.CreateFolder("Assets"+folderPathWithoutSlash, folderNames[i]);
}
folderPath += folderNames[i]+"/";
}
folderPath = folderPath.Substring(1, folderPath.Length-2); // Delete first and last "/" character.
}
#endregion Create directories if Mesh and path doesn't exists.
#region Save Mesh:
if(!meshIsSaved)
{
string meshPath = "Assets/"+folderPath+"/"+mesh.name+".asset";
int assetNumber = 1;
while(AssetDatabase.LoadAssetAtPath(meshPath, typeof(Mesh)) != null) // If Mesh with same name exists, change name.
{
meshPath = "Assets/"+folderPath+"/"+mesh.name+" ("+assetNumber+").asset";
assetNumber++;
}
AssetDatabase.CreateAsset(mesh, meshPath);
AssetDatabase.SaveAssets();
Debug.Log("<color=#ff9900><b>Mesh \""+mesh.name+"\" was saved in the \""+folderPath+"\" folder.</b></color>"); // Show info about saved mesh.
}
#endregion Save Mesh.
EditorGUIUtility.PingObject(mesh); // Show Mesh in the project view.
return folderPath;
}
}