VoxelFrameAnimationObjectEditor.cs 56 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113
  1. using UnityEngine;
  2. using UnityEngine.Assertions;
  3. using UnityEditor;
  4. using UnityEditorInternal;
  5. using System;
  6. using System.IO;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. namespace VoxelImporter
  10. {
  11. [CustomEditor(typeof(VoxelFrameAnimationObject))]
  12. public class VoxelFrameAnimationObjectEditor : VoxelBaseEditor
  13. {
  14. public VoxelFrameAnimationObject objectTarget { get; protected set; }
  15. public VoxelFrameAnimationObjectCore objectCore { get; protected set; }
  16. protected ReorderableList frameList;
  17. protected override void OnEnable()
  18. {
  19. base.OnEnable();
  20. objectTarget = target as VoxelFrameAnimationObject;
  21. if (objectTarget == null) return;
  22. baseCore = objectCore = new VoxelFrameAnimationObjectCore(objectTarget);
  23. OnEnableInitializeSet();
  24. editorCommon.InitializeIcon();
  25. UpdateFrameList();
  26. AnimationUtility.onCurveWasModified -= EditorOnCurveWasModified;
  27. AnimationUtility.onCurveWasModified += EditorOnCurveWasModified;
  28. }
  29. protected override void OnDisable()
  30. {
  31. base.OnDisable();
  32. AnimationUtility.onCurveWasModified -= EditorOnCurveWasModified;
  33. }
  34. protected override void InspectorGUI()
  35. {
  36. base.InspectorGUI();
  37. Event e = Event.current;
  38. #if UNITY_2018_3_OR_NEWER
  39. {
  40. if (prefabType == PrefabAssetType.Regular && !baseCore.isPrefabEditMode)
  41. {
  42. EditorGUI.BeginDisabledGroup(true);
  43. }
  44. }
  45. #endif
  46. Action<UnityEngine.Object, string> TypeTitle = (o, title) =>
  47. {
  48. if (o == null)
  49. EditorGUILayout.LabelField(title, guiStyleMagentaBold);
  50. else if (prefabEnable && !AssetDatabase.Contains(o))
  51. EditorGUILayout.LabelField(title, guiStyleRedBold);
  52. else
  53. EditorGUILayout.LabelField(title, EditorStyles.boldLabel);
  54. };
  55. InspectorGUI_Import();
  56. #region Object
  57. if (!string.IsNullOrEmpty(baseTarget.voxelFilePath))
  58. {
  59. //Object
  60. baseTarget.edit_objectFoldout = EditorGUILayout.Foldout(baseTarget.edit_objectFoldout, "Object", guiStyleFoldoutBold);
  61. if (baseTarget.edit_objectFoldout)
  62. {
  63. EditorGUILayout.BeginVertical(GUI.skin.box);
  64. #region Mesh
  65. if (baseTarget.advancedMode)
  66. {
  67. EditorGUILayout.LabelField("Mesh", EditorStyles.boldLabel);
  68. EditorGUI.indentLevel++;
  69. InspectorGUI_Object_Mesh_Settings();
  70. EditorGUI.indentLevel--;
  71. }
  72. #endregion
  73. #region Material
  74. {
  75. {
  76. if (objectTarget.materials == null || objectTarget.materials.Count == 0)
  77. EditorGUILayout.LabelField("Material", guiStyleMagentaBold);
  78. else if (prefabEnable)
  79. {
  80. bool contains = true;
  81. for (int i = 0; i < objectTarget.materials.Count; i++)
  82. {
  83. if (objectTarget.materials[i] == null || !AssetDatabase.Contains(objectTarget.materials[i]))
  84. {
  85. contains = false;
  86. break;
  87. }
  88. }
  89. EditorGUILayout.LabelField("Material", contains ? EditorStyles.boldLabel : guiStyleRedBold);
  90. }
  91. else
  92. EditorGUILayout.LabelField("Material", EditorStyles.boldLabel);
  93. }
  94. EditorGUI.indentLevel++;
  95. #region updateMeshRendererMaterials
  96. if (baseTarget.advancedMode)
  97. {
  98. EditorGUI.BeginChangeCheck();
  99. var updateMeshRendererMaterials = EditorGUILayout.ToggleLeft("Update the Mesh Renderer Materials", baseTarget.updateMeshRendererMaterials);
  100. if (EditorGUI.EndChangeCheck())
  101. {
  102. if (EditorUtility.DisplayDialog("Update the Mesh Renderer Materials", "It will be changed.\nAre you sure?", "ok", "cancel"))
  103. {
  104. UndoRecordObject("Inspector");
  105. baseTarget.updateMeshRendererMaterials = updateMeshRendererMaterials;
  106. baseCore.SetRendererCompornent();
  107. }
  108. }
  109. }
  110. #endregion
  111. if (materialList != null)
  112. {
  113. materialList.DoLayoutList();
  114. }
  115. InspectorGUI_ConfigureMaterial();
  116. EditorGUI.indentLevel--;
  117. }
  118. #endregion
  119. #region Texture
  120. if (baseTarget.advancedMode)
  121. {
  122. TypeTitle(objectTarget.atlasTexture, "Texture");
  123. EditorGUI.indentLevel++;
  124. #region updateMaterialTexture
  125. {
  126. EditorGUI.BeginChangeCheck();
  127. var updateMaterialTexture = EditorGUILayout.ToggleLeft("Update the Material Texture", baseTarget.updateMaterialTexture);
  128. if (EditorGUI.EndChangeCheck())
  129. {
  130. if (EditorUtility.DisplayDialog("Update the Material Texture", "It will be changed.\nAre you sure?", "ok", "cancel"))
  131. {
  132. UndoRecordObject("Inspector");
  133. baseTarget.updateMaterialTexture = updateMaterialTexture;
  134. baseCore.SetRendererCompornent();
  135. }
  136. }
  137. }
  138. #endregion
  139. #region Texture
  140. {
  141. EditorGUILayout.BeginHorizontal();
  142. {
  143. EditorGUI.BeginDisabledGroup(true);
  144. EditorGUILayout.ObjectField(objectTarget.atlasTexture, typeof(Texture2D), false);
  145. EditorGUI.EndDisabledGroup();
  146. }
  147. if (objectTarget.atlasTexture != null)
  148. {
  149. if (!IsMainAsset(objectTarget.atlasTexture))
  150. {
  151. if (GUILayout.Button("Save", GUILayout.Width(48), GUILayout.Height(16)))
  152. {
  153. #region Create Texture
  154. string path = EditorUtility.SaveFilePanel("Save atlas texture", baseCore.GetDefaultPath(), string.Format("{0}_tex.png", baseTarget.gameObject.name), "png");
  155. if (!string.IsNullOrEmpty(path))
  156. {
  157. if (path.IndexOf(Application.dataPath) < 0)
  158. {
  159. SaveInsideAssetsFolderDisplayDialog();
  160. }
  161. else
  162. {
  163. UndoRecordObject("Save Atlas Texture");
  164. File.WriteAllBytes(path, objectTarget.atlasTexture.EncodeToPNG());
  165. path = path.Replace(Application.dataPath, "Assets");
  166. AssetDatabase.ImportAsset(path);
  167. objectCore.SetTextureImporterSetting(path, objectTarget.atlasTexture);
  168. objectTarget.atlasTexture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
  169. Refresh();
  170. }
  171. }
  172. #endregion
  173. }
  174. }
  175. {
  176. if (GUILayout.Button("Reset", GUILayout.Width(48), GUILayout.Height(16)))
  177. {
  178. #region Reset Texture
  179. UndoRecordObject("Reset Atlas Texture");
  180. objectTarget.atlasTexture = null;
  181. Refresh();
  182. #endregion
  183. }
  184. }
  185. }
  186. EditorGUILayout.EndHorizontal();
  187. }
  188. #endregion
  189. #region Generate Mip Maps
  190. {
  191. EditorGUI.BeginChangeCheck();
  192. var generateMipMaps = EditorGUILayout.Toggle("Generate Mip Maps", baseTarget.generateMipMaps);
  193. if (EditorGUI.EndChangeCheck())
  194. {
  195. UndoRecordObject("Inspector");
  196. baseTarget.generateMipMaps = generateMipMaps;
  197. Refresh();
  198. }
  199. }
  200. #endregion
  201. #region Texture Size
  202. {
  203. EditorGUILayout.LabelField("Texture Size", objectTarget.atlasTexture != null ? string.Format("{0} x {1}", objectTarget.atlasTexture.width, objectTarget.atlasTexture.height) : "");
  204. }
  205. #endregion
  206. EditorGUI.indentLevel--;
  207. }
  208. #endregion
  209. EditorGUILayout.EndVertical();
  210. }
  211. }
  212. #endregion
  213. #region Animation
  214. if (!string.IsNullOrEmpty(baseTarget.voxelFilePath))
  215. {
  216. objectTarget.edit_animationFoldout = EditorGUILayout.Foldout(objectTarget.edit_animationFoldout, "Animation", guiStyleFoldoutBold);
  217. if (objectTarget.edit_animationFoldout)
  218. {
  219. EditorGUILayout.BeginVertical(GUI.skin.box);
  220. {
  221. EditorGUILayout.BeginHorizontal();
  222. {
  223. {
  224. if (objectTarget.frames == null || objectTarget.frames.Count == 0)
  225. EditorGUILayout.LabelField("Frame", guiStyleMagentaBold);
  226. else
  227. {
  228. bool contains = true;
  229. for (int i = 0; i < objectTarget.frames.Count; i++)
  230. {
  231. if (objectTarget.frames[i] == null || objectTarget.frames[i].mesh == null || !AssetDatabase.Contains(objectTarget.frames[i].mesh))
  232. {
  233. contains = false;
  234. break;
  235. }
  236. }
  237. EditorGUILayout.LabelField("Frame", contains ? EditorStyles.boldLabel : guiStyleRedBold);
  238. }
  239. }
  240. Action<string> OpenFile = (path) =>
  241. {
  242. if (!baseCore.IsEnableFile(path))
  243. return;
  244. UndoRecordObject("Open Voxel File", true);
  245. UnityEngine.Object obj = null;
  246. if (path.Contains(Application.dataPath))
  247. {
  248. var assetPath = path.Replace(Application.dataPath, "Assets");
  249. var sprites = AssetDatabase.LoadAllAssetsAtPath(assetPath);
  250. obj = UnityEditor.AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(assetPath);
  251. if (obj != null)
  252. {
  253. bool done = false;
  254. if (obj is Texture2D)
  255. {
  256. TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
  257. if (importer != null && importer.spriteImportMode == SpriteImportMode.Multiple)
  258. {
  259. for (int j = 0; j < sprites.Length; j++)
  260. {
  261. if (sprites[j] is Sprite)
  262. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileObject = sprites[j], name = objectTarget.Edit_GetUniqueFrameName(sprites[j].name) });
  263. }
  264. done = true;
  265. }
  266. }
  267. else if (objectCore.GetFileType(path) == VoxelBase.FileType.vox)
  268. {
  269. var subCount = objectCore.GetVoxelFileSubCount(path);
  270. if (subCount > 1)
  271. {
  272. for (int i = 0; i < subCount; i++)
  273. {
  274. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileObject = obj, voxelFileSubIndex = i, name = objectTarget.Edit_GetUniqueFrameName(string.Format("{0}_{1}", Path.GetFileNameWithoutExtension(path), i)) });
  275. }
  276. done = true;
  277. }
  278. }
  279. if (!done)
  280. {
  281. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileObject = obj, name = objectTarget.Edit_GetUniqueFrameName(obj.name) });
  282. }
  283. }
  284. }
  285. else
  286. {
  287. bool done = false;
  288. if (objectCore.GetFileType(path) == VoxelBase.FileType.vox)
  289. {
  290. var subCount = objectCore.GetVoxelFileSubCount(path);
  291. if (subCount > 1)
  292. {
  293. for (int i = 0; i < subCount; i++)
  294. {
  295. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileSubIndex = i, name = objectTarget.Edit_GetUniqueFrameName(string.Format("{0}_{1}", Path.GetFileNameWithoutExtension(path), i)) });
  296. }
  297. done = true;
  298. }
  299. }
  300. if (!done)
  301. {
  302. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, name = objectTarget.Edit_GetUniqueFrameName(Path.GetFileNameWithoutExtension(path)) });
  303. }
  304. }
  305. objectCore.ReCreate();
  306. };
  307. var rect = GUILayoutUtility.GetRect(new GUIContent("Open"), guiStyleDropDown, GUILayout.Width(64));
  308. if (GUI.Button(rect, "Open", guiStyleDropDown))
  309. {
  310. GenericMenu menu = new GenericMenu();
  311. #region vox
  312. menu.AddItem(new GUIContent("MagicaVoxel (*.vox)"), false, () =>
  313. {
  314. var path = EditorUtility.OpenFilePanel("Open MagicaVoxel File", !string.IsNullOrEmpty(baseTarget.voxelFilePath) ? Path.GetDirectoryName(baseTarget.voxelFilePath) : "", "vox");
  315. if (!string.IsNullOrEmpty(path))
  316. {
  317. OpenFile(path);
  318. }
  319. });
  320. #endregion
  321. #region qb
  322. menu.AddItem(new GUIContent("Qubicle Binary (*.qb)"), false, () =>
  323. {
  324. var path = EditorUtility.OpenFilePanel("Open Qubicle Binary File", !string.IsNullOrEmpty(baseTarget.voxelFilePath) ? Path.GetDirectoryName(baseTarget.voxelFilePath) : "", "qb");
  325. if (!string.IsNullOrEmpty(path))
  326. {
  327. OpenFile(path);
  328. }
  329. });
  330. #endregion
  331. #region png
  332. menu.AddItem(new GUIContent("Pixel Art (*.png)"), false, () =>
  333. {
  334. var path = EditorUtility.OpenFilePanel("Open Pixel Art File", !string.IsNullOrEmpty(baseTarget.voxelFilePath) ? Path.GetDirectoryName(baseTarget.voxelFilePath) : "", "png");
  335. if (!string.IsNullOrEmpty(path))
  336. {
  337. OpenFile(path);
  338. }
  339. });
  340. #endregion
  341. menu.ShowAsContext();
  342. }
  343. #region Drag&Drop
  344. {
  345. switch (e.type)
  346. {
  347. case EventType.DragUpdated:
  348. case EventType.DragPerform:
  349. if (!rect.Contains(e.mousePosition)) break;
  350. if (DragAndDrop.paths.Length == 0) break;
  351. DragAndDrop.AcceptDrag();
  352. DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
  353. if (e.type == EventType.DragPerform)
  354. {
  355. UndoRecordObject("Open Voxel File", true);
  356. if (DragAndDrop.objectReferences.Length > 0)
  357. {
  358. for (int i = 0; i < DragAndDrop.objectReferences.Length; i++)
  359. {
  360. var obj = DragAndDrop.objectReferences[i];
  361. var assetPath = AssetDatabase.GetAssetPath(obj);
  362. var sprites = AssetDatabase.LoadAllAssetsAtPath(assetPath);
  363. string path = assetPath;
  364. if (!baseCore.IsEnableFile(path))
  365. continue;
  366. if (Path.GetPathRoot(path) == "")
  367. path = Application.dataPath + assetPath.Remove(0, "Assets".Length);
  368. bool done = false;
  369. if (obj is Texture2D)
  370. {
  371. TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
  372. if (importer != null && importer.spriteImportMode == SpriteImportMode.Multiple)
  373. {
  374. for (int j = 0; j < sprites.Length; j++)
  375. {
  376. if (sprites[j] is Sprite)
  377. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileObject = sprites[j], name = objectTarget.Edit_GetUniqueFrameName(sprites[j].name) });
  378. }
  379. done = true;
  380. }
  381. }
  382. else if (objectCore.GetFileType(path) == VoxelBase.FileType.vox)
  383. {
  384. var subCount = objectCore.GetVoxelFileSubCount(path);
  385. if (subCount > 1)
  386. {
  387. for (int j = 0; j < subCount; j++)
  388. {
  389. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileObject = obj, voxelFileSubIndex = j, name = objectTarget.Edit_GetUniqueFrameName(string.Format("{0}_{1}", Path.GetFileNameWithoutExtension(path), j)) });
  390. }
  391. done = true;
  392. }
  393. }
  394. if (!done)
  395. {
  396. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileObject = obj, name = objectTarget.Edit_GetUniqueFrameName(obj.name) });
  397. }
  398. }
  399. }
  400. else
  401. {
  402. for (int i = 0; i < DragAndDrop.paths.Length; i++)
  403. {
  404. string path = DragAndDrop.paths[i];
  405. if (Path.GetPathRoot(path) == "")
  406. path = Application.dataPath + DragAndDrop.paths[i].Remove(0, "Assets".Length);
  407. if (!baseCore.IsEnableFile(path))
  408. continue;
  409. bool done = false;
  410. if (objectCore.GetFileType(path) == VoxelBase.FileType.vox)
  411. {
  412. var subCount = objectCore.GetVoxelFileSubCount(path);
  413. if (subCount > 1)
  414. {
  415. for (int j = 0; j < subCount; j++)
  416. {
  417. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, voxelFileSubIndex = j, name = objectTarget.Edit_GetUniqueFrameName(string.Format("{0}_{1}", Path.GetFileNameWithoutExtension(path), j)) });
  418. }
  419. done = true;
  420. }
  421. }
  422. if (!done)
  423. {
  424. objectTarget.frames.Add(new VoxelFrameAnimationObject.FrameData() { voxelFilePath = path, name = objectTarget.Edit_GetUniqueFrameName(Path.GetFileNameWithoutExtension(path)) });
  425. }
  426. }
  427. }
  428. objectCore.ReCreate();
  429. e.Use();
  430. }
  431. break;
  432. }
  433. }
  434. #endregion
  435. }
  436. EditorGUILayout.EndHorizontal();
  437. }
  438. {
  439. EditorGUI.indentLevel++;
  440. {
  441. IconRender();
  442. if (frameList != null)
  443. {
  444. frameList.DoLayoutList();
  445. }
  446. #if UNITY_2018_3_OR_NEWER
  447. {
  448. if (prefabType == PrefabAssetType.Regular && !baseCore.isPrefabEditMode)
  449. {
  450. EditorGUI.EndDisabledGroup();
  451. }
  452. }
  453. #endif
  454. FrameListWindowGUI();
  455. #if UNITY_2018_3_OR_NEWER
  456. {
  457. if (prefabType == PrefabAssetType.Regular && !baseCore.isPrefabEditMode)
  458. {
  459. EditorGUI.BeginDisabledGroup(true);
  460. }
  461. }
  462. #endif
  463. }
  464. EditorGUI.indentLevel--;
  465. }
  466. EditorGUILayout.Space();
  467. #region HelpBox
  468. {
  469. {
  470. HashSet<string> helpList = new HashSet<string>();
  471. {
  472. if (objectTarget.frames != null)
  473. {
  474. for (int i = 0; i < objectTarget.frames.Count; i++)
  475. {
  476. if (objectTarget.frames[i] == null || objectTarget.frames[i].mesh == null || !AssetDatabase.Contains(objectTarget.frames[i].mesh))
  477. {
  478. helpList.Add("Mesh");
  479. break;
  480. }
  481. }
  482. }
  483. else
  484. {
  485. helpList.Add("Mesh");
  486. }
  487. }
  488. if (helpList.Count > 0)
  489. {
  490. EditorGUILayout.HelpBox(GetHelpStrings(new List<string>(helpList)), MessageType.Error);
  491. EditorGUILayout.BeginHorizontal();
  492. EditorGUILayout.Space();
  493. if (GUILayout.Button("Save All Unsaved Assets"))
  494. {
  495. ContextSaveAllUnsavedAssets(new MenuCommand(baseTarget));
  496. }
  497. EditorGUILayout.Space();
  498. EditorGUILayout.EndHorizontal();
  499. EditorGUILayout.Space();
  500. }
  501. }
  502. }
  503. #endregion
  504. EditorGUILayout.EndVertical();
  505. }
  506. }
  507. #endregion
  508. InspectorGUI_Refresh();
  509. #if UNITY_2018_3_OR_NEWER
  510. {
  511. if (prefabType == PrefabAssetType.Regular && !baseCore.isPrefabEditMode)
  512. {
  513. EditorGUI.EndDisabledGroup();
  514. }
  515. }
  516. #endif
  517. }
  518. protected void FrameListWindowGUI()
  519. {
  520. try
  521. {
  522. EditorGUILayout.BeginHorizontal();
  523. EditorGUILayout.Space();
  524. if (GUILayout.Button("Frame List Window", VoxelFrameAnimationListWindow.instance == null ? GUI.skin.button : guiStyleBoldActiveButton)) //exception...
  525. {
  526. if (VoxelFrameAnimationListWindow.instance == null)
  527. {
  528. VoxelFrameAnimationListWindow.Create(objectTarget);
  529. VoxelFrameAnimationListWindow.instance.frameIndexChanged += () =>
  530. {
  531. if (objectTarget.edit_frameEnable)
  532. frameList.index = objectTarget.edit_frameIndex;
  533. else
  534. objectTarget.edit_frameIndex = -1;
  535. if(frameList != null)
  536. {
  537. frameList.index = objectTarget.edit_frameIndex;
  538. }
  539. UpdateConfigureEnableMesh();
  540. objectCore.SetCurrentMesh();
  541. };
  542. VoxelFrameAnimationListWindow.instance.previewCameraModeChanged += () =>
  543. {
  544. objectCore.ClearFramesIcon();
  545. };
  546. }
  547. else
  548. {
  549. VoxelFrameAnimationListWindow.instance.Close();
  550. }
  551. }
  552. EditorGUILayout.Space();
  553. }
  554. catch
  555. {
  556. }
  557. finally
  558. {
  559. EditorGUILayout.EndHorizontal();
  560. }
  561. }
  562. protected override List<Material> GetMaterialListMaterials()
  563. {
  564. return objectTarget.materials;
  565. }
  566. protected override void AddMaterialData(string name)
  567. {
  568. for (int i = 0; i < objectTarget.frames.Count; i++)
  569. {
  570. objectTarget.frames[i].materialData.Add(new MaterialData() { name = name });
  571. }
  572. }
  573. protected override void RemoveMaterialData(int index)
  574. {
  575. for (int i = 0; i < objectTarget.frames.Count; i++)
  576. {
  577. objectTarget.frames[i].materialData.RemoveAt(index);
  578. }
  579. }
  580. protected void SetPreviewCameraTransform(Bounds bounds)
  581. {
  582. var transform = editorCommon.iconCamera.transform;
  583. var sizeMax = Mathf.Max(bounds.size.x, Mathf.Max(bounds.size.y, bounds.size.z));
  584. switch (objectTarget.edit_previewCameraMode)
  585. {
  586. case VoxelFrameAnimationObject.Edit_CameraMode.forward:
  587. {
  588. var rot = Quaternion.AngleAxis(180f, Vector3.up);
  589. transform.localRotation = rot;
  590. sizeMax = Mathf.Max(bounds.size.x, bounds.size.y);
  591. transform.localPosition = new Vector3(bounds.center.x, bounds.center.y, bounds.max.z) - transform.forward;
  592. }
  593. break;
  594. case VoxelFrameAnimationObject.Edit_CameraMode.back:
  595. {
  596. transform.localRotation = Quaternion.identity;
  597. sizeMax = Mathf.Max(bounds.size.x, bounds.size.y);
  598. transform.localPosition = new Vector3(bounds.center.x, bounds.center.y, bounds.min.z) - transform.forward;
  599. }
  600. break;
  601. case VoxelFrameAnimationObject.Edit_CameraMode.up:
  602. {
  603. var rot = Quaternion.AngleAxis(90f, Vector3.right);
  604. transform.localRotation = rot;
  605. sizeMax = Mathf.Max(bounds.size.x, bounds.size.z);
  606. transform.localPosition = new Vector3(bounds.center.x, bounds.max.y, bounds.center.z) - transform.forward;
  607. }
  608. break;
  609. case VoxelFrameAnimationObject.Edit_CameraMode.down:
  610. {
  611. var rot = Quaternion.AngleAxis(-90f, Vector3.right);
  612. transform.localRotation = rot;
  613. sizeMax = Mathf.Max(bounds.size.x, bounds.size.z);
  614. transform.localPosition = new Vector3(bounds.center.x, bounds.min.y, bounds.center.z) - transform.forward;
  615. }
  616. break;
  617. case VoxelFrameAnimationObject.Edit_CameraMode.right:
  618. {
  619. var rot = Quaternion.AngleAxis(-90f, Vector3.up);
  620. transform.localRotation = rot;
  621. sizeMax = Mathf.Max(bounds.size.y, bounds.size.z);
  622. transform.localPosition = new Vector3(bounds.max.x, bounds.center.y, bounds.center.z) - transform.forward;
  623. }
  624. break;
  625. case VoxelFrameAnimationObject.Edit_CameraMode.left:
  626. {
  627. var rot = Quaternion.AngleAxis(90f, Vector3.up);
  628. transform.localRotation = rot;
  629. sizeMax = Mathf.Max(bounds.size.y, bounds.size.z);
  630. transform.localPosition = new Vector3(bounds.min.x, bounds.center.y, bounds.center.z) - transform.forward;
  631. }
  632. break;
  633. }
  634. var camera = editorCommon.iconCamera.GetComponent<Camera>();
  635. camera.orthographic = true;
  636. camera.orthographicSize = sizeMax * 0.6f;
  637. camera.farClipPlane = 1f + sizeMax * 5f;
  638. }
  639. protected void UpdateFrameList()
  640. {
  641. frameList = null;
  642. if (objectTarget.frames == null) return;
  643. frameList = new ReorderableList(
  644. serializedObject,
  645. serializedObject.FindProperty("frames"),
  646. true, true, false, true
  647. );
  648. frameList.elementHeight = 40;
  649. frameList.drawHeaderCallback = (rect) =>
  650. {
  651. {
  652. Rect r = rect;
  653. {
  654. r.x -= 16;
  655. r.width = 80;
  656. EditorGUI.BeginChangeCheck();
  657. var edit_previewCameraMode = (VoxelFrameAnimationObject.Edit_CameraMode)EditorGUI.EnumPopup(r, objectTarget.edit_previewCameraMode);
  658. if (EditorGUI.EndChangeCheck())
  659. {
  660. Undo.RecordObject(objectTarget, "Camera Mode");
  661. objectTarget.edit_previewCameraMode = edit_previewCameraMode;
  662. objectCore.ClearFramesIcon();
  663. if (VoxelFrameAnimationListWindow.instance != null)
  664. VoxelFrameAnimationListWindow.instance.Repaint();
  665. }
  666. }
  667. r.x += 16 + frameList.elementHeight + 12;
  668. r.width = rect.width - r.width;
  669. EditorGUI.LabelField(r, "Object & Mesh", EditorStyles.boldLabel);
  670. }
  671. {
  672. Rect r = rect;
  673. r.x += r.width - 100;
  674. r.width = 100;
  675. if (GUI.Button(r, "Select None"))
  676. {
  677. frameList.index = objectTarget.edit_frameIndex = -1;
  678. UpdateConfigureEnableMesh();
  679. objectCore.SetCurrentMesh();
  680. }
  681. }
  682. };
  683. frameList.drawElementCallback = (rect, index, isActive, isFocused) =>
  684. {
  685. rect.yMin += 2;
  686. rect.yMax -= 2;
  687. if (index < objectTarget.frames.Count && objectTarget.frames[index] != null)
  688. {
  689. Rect r = rect;
  690. #region Icon
  691. r.width = frameList.elementHeight - 2;
  692. r.height = frameList.elementHeight - 2;
  693. if (objectTarget.frames[index].icon != null)
  694. GUI.DrawTexture(r, objectTarget.frames[index].icon);
  695. r.x += r.width + 2;
  696. #endregion
  697. r.width = rect.width - (r.x - rect.x);
  698. r.height = 16;
  699. #region Name
  700. {
  701. EditorGUI.BeginChangeCheck();
  702. var name = EditorGUI.TextField(r, objectTarget.frames[index].name);
  703. if (EditorGUI.EndChangeCheck())
  704. {
  705. UndoRecordObject("Change Frame Name");
  706. objectTarget.frames[index].name = objectTarget.Edit_GetUniqueFrameName(name);
  707. }
  708. }
  709. #endregion
  710. #region Object
  711. {
  712. const int FrameIndexWidth = 32;
  713. Rect rs = r;
  714. rs.width /= 2;
  715. rs.y += 18 + 2;
  716. rs.width -= FrameIndexWidth;
  717. if (objectTarget.frames[index].voxelFileObject != null)
  718. {
  719. EditorGUI.BeginChangeCheck();
  720. var obj = EditorGUI.ObjectField(rs, objectTarget.frames[index].voxelFileObject, typeof(UnityEngine.Object), false);
  721. if (EditorGUI.EndChangeCheck())
  722. {
  723. var path = Application.dataPath + AssetDatabase.GetAssetPath(obj).Remove(0, "Assets".Length);
  724. if (baseCore.IsEnableFile(path))
  725. {
  726. UndoRecordObject("Change Frame Voxel File");
  727. objectTarget.frames[index].voxelFileObject = obj;
  728. objectTarget.frames[index].voxelFileSubIndex = 0;
  729. objectTarget.frames[index].voxelData = null;
  730. objectTarget.frames[index].voxelDataCreatedVoxelFileTimeTicks = 0;
  731. Refresh();
  732. }
  733. }
  734. }
  735. else
  736. {
  737. EditorGUI.LabelField(rs, Path.GetFileName(objectTarget.frames[index].voxelFilePath));
  738. }
  739. rs.x += rs.width;
  740. rs.width = FrameIndexWidth;
  741. EditorGUI.LabelField(rs, new GUIContent(objectTarget.frames[index].voxelFileSubIndex.ToString(), "Frame Index"));
  742. }
  743. #endregion
  744. #region Mesh
  745. {
  746. Rect rs = r;
  747. rs.width /= 2;
  748. rs.x += rs.width;
  749. rs.y += 18 + 2;
  750. if (baseTarget.advancedMode)
  751. rs.width -= 104;
  752. if (baseTarget.advancedMode && IsMainAsset(objectTarget.frames[index].mesh))
  753. rs.width += 48;
  754. EditorGUI.BeginDisabledGroup(true);
  755. EditorGUI.ObjectField(rs, objectTarget.frames[index].mesh, typeof(Mesh), false);
  756. EditorGUI.EndDisabledGroup();
  757. rs.x += rs.width + 4;
  758. if (baseTarget.advancedMode && IsMainAsset(objectTarget.frames[index].mesh))
  759. rs.x -= 48;
  760. if (baseTarget.advancedMode && objectTarget.frames[index].mesh != null)
  761. {
  762. rs.width = 48;
  763. rs.height = 16;
  764. if (!IsMainAsset(objectTarget.frames[index].mesh))
  765. {
  766. if (GUI.Button(rs, "Save"))
  767. {
  768. #region Create Mesh
  769. var name = objectTarget.frames[index].voxelFileObject != null ? objectTarget.frames[index].voxelFileObject.name : Path.GetFileNameWithoutExtension(objectTarget.frames[index].voxelFilePath);
  770. var path = EditorUtility.SaveFilePanel("Save mesh", objectCore.GetDefaultPath(), string.Format("{0}_mesh_{1}.asset", baseTarget.gameObject.name, name), "asset");
  771. if (!string.IsNullOrEmpty(path))
  772. {
  773. if (path.IndexOf(Application.dataPath) < 0)
  774. {
  775. SaveInsideAssetsFolderDisplayDialog();
  776. }
  777. else
  778. {
  779. UndoRecordObject("Save Mesh");
  780. path = path.Replace(Application.dataPath, "Assets");
  781. var oldObj = objectTarget.frames[index].mesh;
  782. AssetDatabase.CreateAsset(Mesh.Instantiate(objectTarget.frames[index].mesh), path);
  783. objectTarget.frames[index].mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
  784. if (objectTarget.mesh == oldObj)
  785. objectTarget.mesh = objectTarget.frames[index].mesh;
  786. Refresh();
  787. objectCore.SwapAnimationObjectReference(oldObj, objectTarget.frames[index].mesh);
  788. InternalEditorUtility.RepaintAllViews();
  789. }
  790. }
  791. #endregion
  792. }
  793. }
  794. rs.x += rs.width + 4;
  795. if (GUI.Button(rs, "Reset"))
  796. {
  797. #region Reset Mesh
  798. UndoRecordObject("Reset Mesh");
  799. var oldObj = objectTarget.frames[index].mesh;
  800. objectTarget.frames[index].mesh = null;
  801. if (objectTarget.mesh == oldObj)
  802. objectTarget.mesh = null;
  803. Refresh();
  804. objectCore.SwapAnimationObjectReference(oldObj, objectTarget.frames[index].mesh);
  805. InternalEditorUtility.RepaintAllViews();
  806. #endregion
  807. }
  808. }
  809. }
  810. #endregion
  811. }
  812. };
  813. frameList.onSelectCallback = (list) =>
  814. {
  815. objectTarget.edit_frameIndex = list.index;
  816. UpdateConfigureEnableMesh();
  817. objectCore.SetCurrentMesh();
  818. if (VoxelFrameAnimationListWindow.instance != null)
  819. VoxelFrameAnimationListWindow.instance.FrameIndexChanged();
  820. };
  821. frameList.onChangedCallback = (list) =>
  822. {
  823. objectCore.ReadyVoxelData(true);
  824. objectCore.ClearFramesIcon();
  825. if (VoxelFrameAnimationListWindow.instance != null)
  826. VoxelFrameAnimationListWindow.instance.Repaint();
  827. };
  828. frameList.onRemoveCallback = (list) =>
  829. {
  830. if (list.index >= 0)
  831. {
  832. UndoRecordObject("Remove Frame");
  833. objectTarget.frames.RemoveAt(list.index);
  834. if (list.index < objectTarget.edit_frameIndex)
  835. objectTarget.edit_frameIndex--;
  836. objectCore.SetCurrentMesh();
  837. Refresh();
  838. if (VoxelFrameAnimationListWindow.instance != null)
  839. VoxelFrameAnimationListWindow.instance.Repaint();
  840. }
  841. };
  842. if (objectTarget.edit_frameEnable)
  843. frameList.index = objectTarget.edit_frameIndex;
  844. else
  845. objectTarget.edit_frameIndex = -1;
  846. }
  847. public void IconRender()
  848. {
  849. if (objectTarget.frames == null) return;
  850. foreach (var frame in objectTarget.frames)
  851. {
  852. if (frame.icon == null && frame.materialIndexes != null)
  853. {
  854. Material[] materials = new Material[frame.materialIndexes.Count];
  855. for (int j = 0; j < frame.materialIndexes.Count; j++)
  856. {
  857. var mindex = frame.materialIndexes[j];
  858. if (objectTarget.materials == null || mindex >= objectTarget.materials.Count) continue;
  859. materials[j] = objectTarget.materials[mindex];
  860. }
  861. var mesh = frame.mesh;
  862. if (mesh != null && mesh.subMeshCount > 0)
  863. {
  864. var bounds = mesh.bounds;
  865. {
  866. var size = bounds.size;
  867. for (int i = 0; i < 3; i++)
  868. {
  869. if (size[i] <= 0f)
  870. size[i] = 1f;
  871. }
  872. bounds.size = size;
  873. }
  874. editorCommon.CreateIconObject(objectTarget.transform, mesh, materials);
  875. SetPreviewCameraTransform(bounds);
  876. frame.icon = editorCommon.IconObjectRender();
  877. }
  878. }
  879. }
  880. }
  881. protected override void UpdateConfigureEnableMesh()
  882. {
  883. if (baseTarget.edit_configureMode != VoxelBase.Edit_ConfigureMode.None)
  884. {
  885. if (objectTarget.voxelData == null)
  886. {
  887. objectCore.ReadyVoxelData();
  888. }
  889. objectTarget.Edit_SetFrameCurrentVoxelOtherData();
  890. }
  891. base.UpdateConfigureEnableMesh();
  892. }
  893. private int editorOnCurveWasModifiedCount;
  894. private void EditorOnCurveWasModified(AnimationClip clip, EditorCurveBinding binding, AnimationUtility.CurveModifiedType deleted)
  895. {
  896. if (editorOnCurveWasModifiedCount++ == 0)
  897. {
  898. if (deleted == AnimationUtility.CurveModifiedType.CurveModified)
  899. {
  900. if (binding.type == typeof(MeshRenderer))
  901. {
  902. //AnimationUtility.SetObjectReferenceCurve(clip, binding, null); So it will be back in this useless.
  903. AnimationUtility.SetObjectReferenceCurve(clip, binding, new ObjectReferenceKeyframe[0]);
  904. }
  905. }
  906. }
  907. editorOnCurveWasModifiedCount--;
  908. }
  909. protected override void Refresh()
  910. {
  911. base.Refresh();
  912. UpdateFrameList();
  913. }
  914. [MenuItem("CONTEXT/VoxelFrameAnimationObject/Save All Unsaved Assets")]
  915. private static void ContextSaveAllUnsavedAssets(MenuCommand menuCommand)
  916. {
  917. var objectTarget = menuCommand.context as VoxelFrameAnimationObject;
  918. if (objectTarget == null) return;
  919. var objectCore = new VoxelFrameAnimationObjectCore(objectTarget);
  920. var folder = EditorUtility.OpenFolderPanel("Save all", objectCore.GetDefaultPath(), null);
  921. if (string.IsNullOrEmpty(folder)) return;
  922. if (folder.IndexOf(Application.dataPath) < 0)
  923. {
  924. SaveInsideAssetsFolderDisplayDialog();
  925. return;
  926. }
  927. Undo.RecordObject(objectTarget, "Save All Unsaved Assets");
  928. #region Material
  929. if (objectTarget.materials != null)
  930. {
  931. for (int index = 0; index < objectTarget.materials.Count; index++)
  932. {
  933. if (objectTarget.materials[index] == null || IsMainAsset(objectTarget.materials[index])) continue;
  934. var path = folder + "/" + string.Format("{0}_mat{1}.mat", objectTarget.gameObject.name, index);
  935. path = path.Replace(Application.dataPath, "Assets");
  936. path = AssetDatabase.GenerateUniqueAssetPath(path);
  937. AssetDatabase.CreateAsset(Material.Instantiate(objectTarget.materials[index]), path);
  938. objectTarget.materials[index] = AssetDatabase.LoadAssetAtPath<Material>(path);
  939. }
  940. }
  941. #endregion
  942. #region Texture
  943. if (objectTarget.atlasTexture != null && !IsMainAsset(objectTarget.atlasTexture))
  944. {
  945. var path = folder + "/" + string.Format("{0}_tex.png", objectTarget.gameObject.name);
  946. {
  947. path = AssetDatabase.GenerateUniqueAssetPath(path.Replace(Application.dataPath, "Assets"));
  948. path = (Application.dataPath + path).Replace("AssetsAssets", "Assets");
  949. }
  950. File.WriteAllBytes(path, objectTarget.atlasTexture.EncodeToPNG());
  951. path = path.Replace(Application.dataPath, "Assets");
  952. AssetDatabase.ImportAsset(path);
  953. objectCore.SetTextureImporterSetting(path, objectTarget.atlasTexture);
  954. objectTarget.atlasTexture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);
  955. }
  956. #endregion
  957. #region Mesh
  958. if (objectTarget.frames != null)
  959. {
  960. for (int i = 0; i < objectTarget.frames.Count; i++)
  961. {
  962. if (objectTarget.frames[i].mesh != null && !IsMainAsset(objectTarget.frames[i].mesh))
  963. {
  964. var name = objectTarget.frames[i].voxelFileObject != null ? objectTarget.frames[i].voxelFileObject.name : Path.GetFileNameWithoutExtension(objectTarget.frames[i].voxelFilePath);
  965. var path = folder + "/" + string.Format("{0}_mesh_{1}.asset", objectTarget.gameObject.name, name);
  966. path = path.Replace(Application.dataPath, "Assets");
  967. path = AssetDatabase.GenerateUniqueAssetPath(path);
  968. var oldObj = objectTarget.frames[i].mesh;
  969. AssetDatabase.CreateAsset(Mesh.Instantiate(objectTarget.frames[i].mesh), path);
  970. objectTarget.frames[i].mesh = AssetDatabase.LoadAssetAtPath<Mesh>(path);
  971. if (objectTarget.mesh == oldObj)
  972. objectTarget.mesh = objectTarget.frames[i].mesh;
  973. objectCore.SwapAnimationObjectReference(oldObj, objectTarget.frames[i].mesh);
  974. }
  975. }
  976. }
  977. #endregion
  978. objectCore.ReCreate();
  979. InternalEditorUtility.RepaintAllViews();
  980. }
  981. [MenuItem("CONTEXT/VoxelFrameAnimationObject/Reset All Assets")]
  982. private static void ResetAllSavedAssets(MenuCommand menuCommand)
  983. {
  984. var objectTarget = menuCommand.context as VoxelFrameAnimationObject;
  985. if (objectTarget == null) return;
  986. var objectCore = new VoxelFrameAnimationObjectCore(objectTarget);
  987. Undo.RecordObject(objectTarget, "Reset All Assets");
  988. #region Material
  989. if (objectTarget.materials != null)
  990. {
  991. for (int i = 0; i < objectTarget.materials.Count; i++)
  992. {
  993. if (!IsMainAsset(objectTarget.materials[i]))
  994. objectTarget.materials[i] = null;
  995. else
  996. objectTarget.materials[i] = Instantiate<Material>(objectTarget.materials[i]);
  997. }
  998. }
  999. #endregion
  1000. #region Texture
  1001. objectTarget.atlasTexture = null;
  1002. #endregion
  1003. #region Mesh
  1004. objectTarget.mesh = null;
  1005. List<UnityEngine.Object> oldFramesMesh = null;
  1006. if (objectTarget.frames != null)
  1007. {
  1008. oldFramesMesh = new List<UnityEngine.Object>(objectTarget.frames.Count);
  1009. for (int i = 0; i < objectTarget.frames.Count; i++)
  1010. {
  1011. oldFramesMesh.Add(objectTarget.frames[i].mesh);
  1012. objectTarget.frames[i].mesh = null;
  1013. }
  1014. }
  1015. #endregion
  1016. objectCore.ReCreate();
  1017. #region Mesh
  1018. if (oldFramesMesh != null)
  1019. {
  1020. for (int i = 0; i < oldFramesMesh.Count; i++)
  1021. {
  1022. objectCore.SwapAnimationObjectReference(oldFramesMesh[i], objectTarget.frames[i].mesh);
  1023. }
  1024. }
  1025. #endregion
  1026. InternalEditorUtility.RepaintAllViews();
  1027. }
  1028. [MenuItem("CONTEXT/VoxelFrameAnimationObject/Export COLLADA(dae) File", false, 10000)]
  1029. private static void ExportDaeFile(MenuCommand menuCommand)
  1030. {
  1031. var objectTarget = menuCommand.context as VoxelFrameAnimationObject;
  1032. if (objectTarget == null) return;
  1033. var objectCore = new VoxelFrameAnimationObjectCore(objectTarget);
  1034. string path = EditorUtility.SaveFilePanel("Export COLLADA(dae) File", objectCore.GetDefaultPath(), string.Format("{0}.dae", Path.GetFileNameWithoutExtension(objectTarget.voxelFilePath)), "dae");
  1035. if (string.IsNullOrEmpty(path)) return;
  1036. if (!objectCore.ExportDaeFile(path))
  1037. {
  1038. Debug.LogErrorFormat("<color=green>[Voxel Importer]</color> Export COLLADA(dae) File error. file:{0}", path);
  1039. }
  1040. }
  1041. [MenuItem("CONTEXT/VoxelFrameAnimationObject/Export COLLADA(dae) File", true)]
  1042. private static bool IsValidateExportDaeFile(MenuCommand menuCommand)
  1043. {
  1044. var objectTarget = menuCommand.context as VoxelFrameAnimationObject;
  1045. if (objectTarget == null) return false;
  1046. #if UNITY_2018_3_OR_NEWER
  1047. return true;
  1048. #else
  1049. return PrefabUtility.GetPrefabType(objectTarget) != PrefabType.Prefab;
  1050. #endif
  1051. }
  1052. [MenuItem("CONTEXT/VoxelFrameAnimationObject/Remove All Voxel Importer Compornent", false, 10100)]
  1053. private static void RemoveAllVoxelImporterCompornent(MenuCommand menuCommand)
  1054. {
  1055. var objectTarget = menuCommand.context as VoxelFrameAnimationObject;
  1056. if (objectTarget == null) return;
  1057. Undo.DestroyObjectImmediate(objectTarget);
  1058. }
  1059. }
  1060. }