VoxelChunksObjectChunkEditor.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. using UnityEngine;
  2. using UnityEngine.Assertions;
  3. using UnityEditor;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.IO;
  7. #if UNITY_2018_3_OR_NEWER
  8. using UnityEditor.Experimental.SceneManagement;
  9. #endif
  10. namespace VoxelImporter
  11. {
  12. [CustomEditor(typeof(VoxelChunksObjectChunk))]
  13. public class VoxelChunksObjectChunkEditor : EditorCommon
  14. {
  15. public VoxelChunksObjectChunk chunkTarget { get; private set; }
  16. public VoxelChunksObject objectTarget { get; private set; }
  17. public VoxelChunksObjectChunkCore chunkCore { get; protected set; }
  18. public VoxelChunksObjectCore objectCore { get; protected set; }
  19. #region GuiStyle
  20. private GUIStyle guiStyleMagentaBold;
  21. private GUIStyle guiStyleRedBold;
  22. private GUIStyle guiStyleFoldoutBold;
  23. #endregion
  24. #region Prefab
  25. #if UNITY_2018_3_OR_NEWER
  26. protected PrefabAssetType prefabType { get { return PrefabUtility.GetPrefabAssetType(objectTarget.gameObject); } }
  27. protected bool prefabEnable { get { return prefabType == PrefabAssetType.Regular || isPrefabEditMode; } }
  28. protected bool isPrefab { get { return false; } }
  29. protected bool isPrefabEditMode { get { return PrefabStageUtility.GetCurrentPrefabStage() != null && PrefabStageUtility.GetCurrentPrefabStage().prefabContentsRoot != null; } }
  30. #else
  31. protected PrefabType prefabType { get { return PrefabUtility.GetPrefabType(objectTarget.gameObject); } }
  32. protected bool prefabEnable { get { var type = prefabType; return type == PrefabType.Prefab || type == PrefabType.PrefabInstance || type == PrefabType.DisconnectedPrefabInstance; } }
  33. protected bool isPrefab { get { return prefabType == PrefabType.Prefab; } }
  34. #endif
  35. #endregion
  36. void OnEnable()
  37. {
  38. chunkTarget = target as VoxelChunksObjectChunk;
  39. if (chunkTarget == null) return;
  40. chunkCore = new VoxelChunksObjectChunkCore(chunkTarget);
  41. if (chunkTarget.transform.parent == null) return;
  42. objectTarget = chunkTarget.transform.parent.GetComponent<VoxelChunksObject>();
  43. if (objectTarget == null) return;
  44. objectCore = new VoxelChunksObjectCore(objectTarget);
  45. chunkCore.Initialize();
  46. }
  47. public override void OnInspectorGUI()
  48. {
  49. if (chunkTarget == null || objectTarget == null)
  50. {
  51. DrawDefaultInspector();
  52. return;
  53. }
  54. #if UNITY_2018_3_OR_NEWER
  55. {
  56. if (prefabType == PrefabAssetType.Regular && !isPrefabEditMode)
  57. {
  58. EditorGUILayout.HelpBox("Prefab can only be edited in Prefab mode.", MessageType.Info);
  59. EditorGUI.BeginDisabledGroup(true);
  60. }
  61. }
  62. #endif
  63. #region GuiStyle
  64. if (guiStyleMagentaBold == null)
  65. guiStyleMagentaBold = new GUIStyle(EditorStyles.boldLabel);
  66. guiStyleMagentaBold.normal.textColor = Color.magenta;
  67. if (guiStyleRedBold == null)
  68. guiStyleRedBold = new GUIStyle(EditorStyles.boldLabel);
  69. guiStyleRedBold.normal.textColor = Color.red;
  70. if (guiStyleFoldoutBold == null)
  71. guiStyleFoldoutBold = new GUIStyle(EditorStyles.foldout);
  72. guiStyleFoldoutBold.fontStyle = FontStyle.Bold;
  73. #endregion
  74. serializedObject.Update();
  75. EditorGUI.BeginDisabledGroup(isPrefab);
  76. InspectorGUI();
  77. EditorGUI.EndDisabledGroup();
  78. serializedObject.ApplyModifiedProperties();
  79. #if UNITY_2018_3_OR_NEWER
  80. {
  81. if (prefabType == PrefabAssetType.Regular && !isPrefabEditMode)
  82. {
  83. EditorGUI.EndDisabledGroup();
  84. }
  85. }
  86. #endif
  87. }
  88. protected void InspectorGUI()
  89. {
  90. #region Simple
  91. {
  92. EditorGUI.BeginChangeCheck();
  93. var mode = GUILayout.Toolbar(objectTarget.advancedMode ? 1 : 0, VoxelBaseEditor.Edit_AdvancedModeStrings);
  94. if (EditorGUI.EndChangeCheck())
  95. {
  96. objectTarget.advancedMode = mode != 0 ? true : false;
  97. }
  98. }
  99. #endregion
  100. EditorGUILayout.Space();
  101. Action<UnityEngine.Object, string> TypeTitle = (o, title) =>
  102. {
  103. if (o == null)
  104. EditorGUILayout.LabelField(title, guiStyleMagentaBold);
  105. else if (prefabEnable && !AssetDatabase.Contains(o))
  106. EditorGUILayout.LabelField(title, guiStyleRedBold);
  107. else
  108. EditorGUILayout.LabelField(title, EditorStyles.boldLabel);
  109. };
  110. {
  111. EditorGUILayout.BeginHorizontal();
  112. EditorGUILayout.Space();
  113. if (GUILayout.Button("Reset Transform"))
  114. {
  115. Undo.RecordObject(chunkTarget.transform, "Reset Transform");
  116. chunkTarget.transform.localPosition = chunkTarget.basicOffset;
  117. chunkTarget.transform.localRotation = Quaternion.identity;
  118. chunkTarget.transform.localScale = Vector3.one;
  119. }
  120. EditorGUILayout.Space();
  121. EditorGUILayout.EndHorizontal();
  122. }
  123. #region Object
  124. if (objectTarget.advancedMode)
  125. {
  126. chunkTarget.edit_objectFoldout = EditorGUILayout.Foldout(chunkTarget.edit_objectFoldout, "Object", guiStyleFoldoutBold);
  127. if (chunkTarget.edit_objectFoldout)
  128. {
  129. EditorGUILayout.BeginVertical(GUI.skin.box);
  130. #region Mesh
  131. {
  132. TypeTitle(chunkTarget.mesh, "Mesh");
  133. EditorGUI.indentLevel++;
  134. #region Mesh
  135. {
  136. EditorGUILayout.BeginHorizontal();
  137. {
  138. EditorGUI.BeginDisabledGroup(true);
  139. EditorGUILayout.ObjectField(chunkTarget.mesh, typeof(Mesh), false);
  140. EditorGUI.EndDisabledGroup();
  141. }
  142. if (chunkTarget.mesh != null)
  143. {
  144. if (!IsMainAsset(chunkTarget.mesh))
  145. {
  146. if (GUILayout.Button("Save", GUILayout.Width(48), GUILayout.Height(16)))
  147. {
  148. #region Create Mesh
  149. string path = EditorUtility.SaveFilePanel("Save mesh", chunkCore.GetDefaultPath(), string.Format("{0}_{1}_mesh.asset", objectTarget.gameObject.name, chunkTarget.chunkName), "asset");
  150. if (!string.IsNullOrEmpty(path))
  151. {
  152. if (path.IndexOf(Application.dataPath) < 0)
  153. {
  154. SaveInsideAssetsFolderDisplayDialog();
  155. }
  156. else
  157. {
  158. Undo.RecordObject(objectTarget, "Save Mesh");
  159. Undo.RecordObject(chunkTarget, "Save Mesh");
  160. path = path.Replace(Application.dataPath, "Assets");
  161. AssetDatabase.CreateAsset(Mesh.Instantiate(chunkTarget.mesh), path);
  162. chunkTarget.mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
  163. Refresh();
  164. }
  165. }
  166. #endregion
  167. }
  168. }
  169. {
  170. if (GUILayout.Button("Reset", GUILayout.Width(48), GUILayout.Height(16)))
  171. {
  172. #region Reset Mesh
  173. Undo.RecordObject(objectTarget, "Reset Mesh");
  174. Undo.RecordObject(chunkTarget, "Reset Mesh");
  175. chunkTarget.mesh = null;
  176. Refresh();
  177. #endregion
  178. }
  179. }
  180. }
  181. EditorGUILayout.EndHorizontal();
  182. }
  183. #endregion
  184. #region Vertex Count
  185. {
  186. EditorGUILayout.LabelField("Vertex Count", chunkTarget.mesh != null ? chunkTarget.mesh.vertexCount.ToString() : "");
  187. }
  188. #endregion
  189. EditorGUI.indentLevel--;
  190. }
  191. #endregion
  192. #region Material
  193. if (objectTarget.materialMode == VoxelChunksObject.MaterialMode.Individual)
  194. {
  195. {
  196. if (chunkTarget.materials == null || chunkTarget.materials.Count == 0)
  197. EditorGUILayout.LabelField("Material", guiStyleMagentaBold);
  198. else if (prefabEnable)
  199. {
  200. bool contains = true;
  201. for (int i = 0; i < chunkTarget.materials.Count; i++)
  202. {
  203. if (!AssetDatabase.Contains(chunkTarget.materials[i]))
  204. {
  205. contains = false;
  206. break;
  207. }
  208. }
  209. EditorGUILayout.LabelField("Material", contains ? EditorStyles.boldLabel : guiStyleRedBold);
  210. }
  211. else
  212. EditorGUILayout.LabelField("Material", EditorStyles.boldLabel);
  213. }
  214. EditorGUI.indentLevel++;
  215. #region Material
  216. for (int i = 0; i < chunkTarget.materials.Count; i++)
  217. {
  218. EditorGUILayout.BeginHorizontal();
  219. {
  220. EditorGUI.BeginDisabledGroup(true);
  221. EditorGUILayout.ObjectField(chunkTarget.materials[i], typeof(Material), false);
  222. EditorGUI.EndDisabledGroup();
  223. }
  224. if (chunkTarget.materials[i] != null)
  225. {
  226. if (!IsMainAsset(chunkTarget.materials[i]))
  227. {
  228. if (GUILayout.Button("Save", GUILayout.Width(48), GUILayout.Height(16)))
  229. {
  230. #region Create Material
  231. string defaultName = string.Format("{0}_{1}_mat{2}.mat", objectTarget.gameObject.name, chunkTarget.chunkName, i);
  232. string path = EditorUtility.SaveFilePanel("Save material", chunkCore.GetDefaultPath(), defaultName, "mat");
  233. if (!string.IsNullOrEmpty(path))
  234. {
  235. if (path.IndexOf(Application.dataPath) < 0)
  236. {
  237. SaveInsideAssetsFolderDisplayDialog();
  238. }
  239. else
  240. {
  241. Undo.RecordObject(objectTarget, "Save Material");
  242. Undo.RecordObject(chunkTarget, "Save Material");
  243. path = path.Replace(Application.dataPath, "Assets");
  244. AssetDatabase.CreateAsset(Material.Instantiate(chunkTarget.materials[i]), path);
  245. chunkTarget.materials[i] = AssetDatabase.LoadAssetAtPath<Material>(path);
  246. Refresh();
  247. }
  248. }
  249. #endregion
  250. }
  251. }
  252. {
  253. if (GUILayout.Button("Reset", GUILayout.Width(48), GUILayout.Height(16)))
  254. {
  255. #region Reset Material
  256. Undo.RecordObject(objectTarget, "Reset Material");
  257. Undo.RecordObject(chunkTarget, "Reset Material");
  258. if (!IsMainAsset(chunkTarget.materials[i]))
  259. chunkTarget.materials[i] = null;
  260. else
  261. chunkTarget.materials[i] = Instantiate<Material>(chunkTarget.materials[i]);
  262. Refresh();
  263. #endregion
  264. }
  265. }
  266. }
  267. EditorGUILayout.EndHorizontal();
  268. }
  269. #endregion
  270. EditorGUI.indentLevel--;
  271. }
  272. #endregion
  273. #region Texture
  274. if (objectTarget.materialMode == VoxelChunksObject.MaterialMode.Individual)
  275. {
  276. TypeTitle(chunkTarget.atlasTexture, "Texture");
  277. EditorGUI.indentLevel++;
  278. #region Texture
  279. {
  280. EditorGUILayout.BeginHorizontal();
  281. {
  282. EditorGUI.BeginDisabledGroup(true);
  283. EditorGUILayout.ObjectField(chunkTarget.atlasTexture, typeof(Texture2D), false);
  284. EditorGUI.EndDisabledGroup();
  285. }
  286. if (chunkTarget.atlasTexture != null)
  287. {
  288. if (!IsMainAsset(chunkTarget.atlasTexture))
  289. {
  290. if (GUILayout.Button("Save", GUILayout.Width(48), GUILayout.Height(16)))
  291. {
  292. #region Create Texture
  293. string defaultName = string.Format("{0}_{1}_tex.png", objectTarget.gameObject.name, chunkTarget.chunkName);
  294. string path = EditorUtility.SaveFilePanel("Save atlas texture", chunkCore.GetDefaultPath(), defaultName, "png");
  295. if (!string.IsNullOrEmpty(path))
  296. {
  297. if (path.IndexOf(Application.dataPath) < 0)
  298. {
  299. SaveInsideAssetsFolderDisplayDialog();
  300. }
  301. else
  302. {
  303. Undo.RecordObject(objectTarget, "Save Atlas Texture");
  304. Undo.RecordObject(chunkTarget, "Save Atlas Texture");
  305. File.WriteAllBytes(path, chunkTarget.atlasTexture.EncodeToPNG());
  306. path = path.Replace(Application.dataPath, "Assets");
  307. AssetDatabase.ImportAsset(path);
  308. objectCore.SetTextureImporterSetting(path, chunkTarget.atlasTexture);
  309. chunkTarget.atlasTexture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
  310. Refresh();
  311. }
  312. }
  313. #endregion
  314. }
  315. }
  316. {
  317. if (GUILayout.Button("Reset", GUILayout.Width(48), GUILayout.Height(16)))
  318. {
  319. #region Reset Texture
  320. Undo.RecordObject(objectTarget, "Reset Atlas Texture");
  321. Undo.RecordObject(chunkTarget, "Reset Atlas Texture");
  322. chunkTarget.atlasTexture = null;
  323. Refresh();
  324. #endregion
  325. }
  326. }
  327. }
  328. EditorGUILayout.EndHorizontal();
  329. }
  330. #endregion
  331. #region Texture Size
  332. {
  333. EditorGUILayout.LabelField("Texture Size", chunkTarget.atlasTexture != null ? string.Format("{0} x {1}", chunkTarget.atlasTexture.width, chunkTarget.atlasTexture.height) : "");
  334. }
  335. #endregion
  336. EditorGUI.indentLevel--;
  337. }
  338. #endregion
  339. EditorGUILayout.EndVertical();
  340. }
  341. }
  342. else
  343. {
  344. EditorGUILayout.Space();
  345. }
  346. #endregion
  347. #region Refresh
  348. if (GUILayout.Button("Refresh"))
  349. {
  350. Undo.RecordObject(objectTarget, "Inspector");
  351. Undo.RecordObject(chunkTarget, "Inspector");
  352. Refresh();
  353. }
  354. #endregion
  355. }
  356. protected void Refresh()
  357. {
  358. objectCore.ReCreate();
  359. }
  360. }
  361. }