using UnityEngine;
using System.Linq;
using System.Reflection;
using System.IO;
using System.Collections.Generic;
using UnityEngine.Polybrush;
using Polybrush;
namespace UnityEditor.Polybrush
{
///
/// Helper functions for editor
///
static class PolyEditorUtility
{
const string k_PackageDirectory = "Packages/com.unity.polybrush";
const string k_UserAssetDirectory = "Assets/Polybrush Data/";
///
/// True if this gameObject is in the Selection.gameObjects
///
///
///
internal static bool InSelection(GameObject gameObject)
{
//null check
if(gameObject == null)
{
return false;
}
Transform[] selectedTransform = Selection.GetTransforms(SelectionMode.Unfiltered);
return selectedTransform.Contains(gameObject.transform);
}
///
/// GetMeshGUID version without the ref parameter
///
/// mesh source
/// ModelSource category
internal static ModelSource GetMeshGUID(Mesh mesh)
{
string temp = string.Empty;
return GetMeshGUID(mesh, ref temp);
}
///
/// Return the mesh source, and the guid if applicable (scene instances don't get GUIDs).
///
/// mesh source
/// guid returned
/// ModelSource category
internal static ModelSource GetMeshGUID(Mesh mesh, ref string guid)
{
if(mesh == null)
{
return ModelSource.Error;
}
string path = AssetDatabase.GetAssetPath(mesh);
if(path != "")
{
AssetImporter assetImporter = AssetImporter.GetAtPath(path);
if( assetImporter != null )
{
// Only imported model (e.g. FBX) assets use the ModelImporter,
// where a saved asset will have an AssetImporter but *not* ModelImporter.
// A procedural mesh (one only existing in a scene) will not have any.
if (assetImporter is ModelImporter)
{
guid = AssetDatabase.AssetPathToGUID(path);
return ModelSource.Imported;
}
else
{
guid = AssetDatabase.AssetPathToGUID(path);
return ModelSource.Asset;
}
}
else
{
return ModelSource.Scene;
}
}
return ModelSource.Scene;
}
internal const int DIALOG_OK = 0;
internal const int DIALOG_CANCEL = 1;
internal const int DIALOG_ALT = 2;
internal const string DO_NOT_SAVE = "DO_NOT_SAVE";
///
/// Save any modifications to the EditableObject. If the mesh is a scene mesh or imported mesh, it
/// will be saved to a new asset. If the mesh was originally an asset mesh, the asset is overwritten.
///
/// mesh to save
/// will update the mesh filter with the new mesh if not null
/// will update the skinned mesh renderer with the new mesh if not null
/// return true if save was successful, false if user-canceled or otherwise failed.
internal static bool SaveMeshAsset(Mesh mesh, MeshFilter meshFilter = null, SkinnedMeshRenderer skinnedMeshRenderer = null, int overridenDialogResult = -1, string overridenPath = "")
{
if (mesh == null) return false;
string save_path = !string.IsNullOrEmpty(overridenPath) ? overridenPath : DO_NOT_SAVE;
ModelSource source = GetMeshGUID(mesh);
switch (source)
{
case ModelSource.Asset:
int saveChanges = overridenDialogResult != -1
? overridenDialogResult
: EditorUtility.DisplayDialogComplex(
"Save Changes",
"Save changes to edited mesh?",
"Save", // DIALOG_OK
"Cancel", // DIALOG_CANCEL
"Save As"); // DIALOG_ALT
if(saveChanges == DIALOG_OK)
save_path = AssetDatabase.GetAssetPath(mesh);
else if(saveChanges == DIALOG_ALT)
save_path = EditorUtility.SaveFilePanelInProject("Save Mesh As", mesh.name + ".asset", "asset", "Save edited mesh to");
else
return false;
break;
case ModelSource.Imported:
case ModelSource.Scene:
default:
save_path = EditorUtility.SaveFilePanelInProject("Save Mesh As", mesh.name + ".asset", "asset", "Save edited mesh to");
break;
}
if(!save_path.Equals(DO_NOT_SAVE) && !string.IsNullOrEmpty(save_path))
{
Mesh existing = AssetDatabase.LoadAssetAtPath(save_path);
bool overwrite = existing != null;
Mesh dst = overwrite ? existing : new Mesh();
PolyMeshUtility.Copy(mesh, dst);
if(!overwrite)
AssetDatabase.CreateAsset(dst, save_path);
AssetDatabase.Refresh();
return true;
}
// Save was canceled
return false;
}
///
/// Load an icon
///
/// location of the icon
/// The loaded icon
internal static Texture2D LoadIcon(string icon)
{
MethodInfo loadIconMethod = typeof(EditorGUIUtility).GetMethod("LoadIcon", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);
Texture2D img = (Texture2D) loadIconMethod.Invoke(null, new object[] { icon } );
return img;
}
internal static string RootFolder
{
get
{
return k_PackageDirectory;
}
}
internal static string UserAssetDirectory
{
get
{
return k_UserAssetDirectory;
}
}
internal static T LoadDefaultAsset(string path) where T : UnityEngine.Object
{
return AssetDatabase.LoadAssetAtPath(k_PackageDirectory + "/Content/" + path);
}
///
/// Fetch a default asset from path relative to the product folder. If not found, a new one is created.
///
/// >the type to retrieve, must inherit from ScriptableObject and implement IHasDefault and ICustomSettings
/// The first asset of the type T found inside the project (order set by AssetDataBase.FindAssets function. If none returns a new object T with default values set by IHasDefault.
internal static T GetFirstOrNew() where T : ScriptableObject, IHasDefault, ICustomSettings
{
string[] all = AssetDatabase.FindAssets("t:" + typeof(T));
T asset = all.Length > 0 ? AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(all.First())) : null;
if(asset == null)
{
return CreateNew();
}
return asset;
}
///
/// Create a new asset at path relative to the product folder.
///
/// >the type to create, must inherit from ScriptableObject and implement IHasDefault and ICustomSettings
/// A new object T with default values set by IHasDefault.
internal static T CreateNew() where T : ScriptableObject, IHasDefault, ICustomSettings
{
T asset = ScriptableObject.CreateInstance();
asset.SetDefaultValues();
EditorUtility.SetDirty(asset);
string folder = UserAssetDirectory;
if (!Directory.Exists(folder))
Directory.CreateDirectory(folder);
string subfolder = folder + asset.assetsFolder;
if (!Directory.Exists(subfolder))
Directory.CreateDirectory(subfolder);
string assetPath = AssetDatabase.GenerateUniqueAssetPath(subfolder + typeof(T).Name + "-Default.asset");
if (string.IsNullOrEmpty(assetPath))
{
return null;
}
AssetDatabase.CreateAsset(asset, assetPath);
AssetDatabase.Refresh();
return asset;
}
///
/// Fetch all assets of type `T`
///
/// the type to retrieve, must inherit from ScriptableObject and implement IHasDefault and ICustomSettings
/// All the assets of that type on the project
internal static List GetAll() where T: ScriptableObject, IHasDefault, ICustomSettings
{
var tGuids = AssetDatabase.FindAssets("t:" + typeof(T));
var Ts = new List();
foreach (var guid in tGuids)
Ts.Add(AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(guid)));
return Ts;
}
///
/// Set the selected render state for an object. In Unity 5.4 and lower, this just toggles wireframe on or off.
///
/// Renderer to change selection state
/// State to be set
internal static void SetSelectionRenderState(Renderer renderer, SelectionRenderState state)
{
#if UNITY_5_3 || UNITY_5_4
EditorUtility.SetSelectedWireframeHidden(renderer, state == 0);
#else
EditorUtility.SetSelectedRenderState(renderer, (EditorSelectedRenderState) state );
#endif
}
internal static SelectionRenderState GetSelectionRenderState()
{
#if UNITY_5_3 || UNITY_5_4
return SelectionRenderState.Wireframe;
#else
bool wireframe = false, outline = false;
try {
wireframe = (bool) ReflectionUtility.GetValue(null, "UnityEditor.AnnotationUtility", "showSelectionWire");
outline = (bool) ReflectionUtility.GetValue(null, "UnityEditor.AnnotationUtility", "showSelectionOutline");
} catch {
Debug.LogWarning("Looks like Unity changed the AnnotationUtility \"showSelectionOutline\"\nPlease email contact@procore3d.com and let Karl know!");
}
SelectionRenderState state = SelectionRenderState.None;
if(wireframe) state |= SelectionRenderState.Wireframe;
if(outline) state |= SelectionRenderState.Outline;
return state;
#endif
}
/**
* Returns true if this object is a prefab in the Project view.
*/
internal static bool IsPrefabAsset(Object go)
{
#if UNITY_2018_3_OR_NEWER
return PrefabUtility.IsPartOfPrefabAsset(go);
#else
return PrefabUtility.GetPrefabType(go) == PrefabType.Prefab;
#endif
}
/**
* Returns true if the given array contains at least one prefab.
*/
internal static bool ContainsPrefabAssets(UnityEngine.Object[] objects)
{
for (int i = 0; i < objects.Length; ++i)
{
UnityEngine.Object obj = objects[i];
if (PolyEditorUtility.IsPrefabAsset(obj))
return true;
}
return false;
}
///
/// Returns true if GameObject has a PolybrushMesh component.
///
///
///
internal static bool IsPolybrushObject(GameObject gameObject)
{
return gameObject.GetComponent() != null;
}
#pragma warning disable 612
///
/// Utility to help convert objects modified with the Beta version of Polybrush (Asset Store)
/// to Polybrus 1.x.
///
///
internal static PolybrushMesh ConvertGameObjectToNewFormat(z_AdditionalVertexStreams component)
{
GameObject go = component.gameObject;
PolybrushMesh newComponent = go.GetComponent();
MeshFilter mf = go.GetComponent();
Mesh mesh = component.m_AdditionalVertexStreamMesh;
Undo.DestroyObjectImmediate(component);
// Cancel conversion if no mesh if found on Z_AdditionalVertexStreams
if (mesh == null)
return null;
if (newComponent == null)
{
newComponent = Undo.AddComponent(go);
newComponent.Initialize();
}
newComponent.mode = PolybrushMesh.Mode.AdditionalVertexStream;
newComponent.SetMesh(PolyMeshUtility.DeepCopy(mf.sharedMesh));
newComponent.SetAdditionalVertexStreams(mesh);
return newComponent;
}
#pragma warning restore 612
}
}