ExportModelEditorWindow.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. #if UNITY_2018_1_OR_NEWER
  4. using UnityEditor.Presets;
  5. #endif
  6. using System.Linq;
  7. using System.Security.Permissions;
  8. namespace UnityEditor.Formats.Fbx.Exporter
  9. {
  10. internal abstract class ExportOptionsEditorWindow : EditorWindow
  11. {
  12. protected const string DefaultWindowTitle = "Export Options";
  13. protected const float SelectableLabelMinWidth = 90;
  14. protected const float BrowseButtonWidth = 25;
  15. protected const float LabelWidth = 175;
  16. protected const float FieldOffset = 18;
  17. protected const float TextFieldAlignOffset = 3;
  18. protected const float ExportButtonWidth = 100;
  19. protected const float FbxExtOffset = -7;
  20. protected virtual float MinWindowHeight { get { return 300; } }
  21. protected virtual string ExportButtonName { get { return "Export"; } }
  22. protected virtual GUIContent WindowTitle { get { return new GUIContent (DefaultWindowTitle); } }
  23. private string m_exportFileName = "";
  24. protected string ExportFileName
  25. {
  26. get { return m_exportFileName; }
  27. set { m_exportFileName = value; }
  28. }
  29. private UnityEditor.Editor m_innerEditor;
  30. protected UnityEditor.Editor InnerEditor
  31. {
  32. get { return m_innerEditor; }
  33. set { m_innerEditor = value; }
  34. }
  35. #if UNITY_2018_1_OR_NEWER
  36. private FbxExportPresetSelectorReceiver m_receiver;
  37. protected FbxExportPresetSelectorReceiver Receiver
  38. {
  39. get { return m_receiver; }
  40. set { m_receiver = value; }
  41. }
  42. #endif
  43. private static GUIContent presetIcon { get { return EditorGUIUtility.IconContent ("Preset.Context"); }}
  44. private static GUIStyle presetIconButton { get { return new GUIStyle("IconButton"); }}
  45. private bool m_showOptions;
  46. private GUIStyle m_nameTextFieldStyle;
  47. protected GUIStyle NameTextFieldStyle
  48. {
  49. get {
  50. if (m_nameTextFieldStyle == null)
  51. {
  52. m_nameTextFieldStyle = new GUIStyle(GUIStyle.none);
  53. m_nameTextFieldStyle.alignment = TextAnchor.LowerCenter;
  54. m_nameTextFieldStyle.clipping = TextClipping.Clip;
  55. m_nameTextFieldStyle.normal.textColor = EditorStyles.textField.normal.textColor;
  56. }
  57. return m_nameTextFieldStyle;
  58. }
  59. set { m_nameTextFieldStyle = value; }
  60. }
  61. private GUIStyle m_fbxExtLabelStyle;
  62. protected GUIStyle FbxExtLabelStyle
  63. {
  64. get {
  65. if (m_fbxExtLabelStyle == null)
  66. {
  67. m_fbxExtLabelStyle = new GUIStyle(GUIStyle.none);
  68. m_fbxExtLabelStyle.alignment = TextAnchor.MiddleLeft;
  69. m_fbxExtLabelStyle.richText = true;
  70. m_fbxExtLabelStyle.contentOffset = new Vector2(FbxExtOffset, 0);
  71. }
  72. return m_fbxExtLabelStyle;
  73. }
  74. set { m_fbxExtLabelStyle = value; }
  75. }
  76. private float m_fbxExtLabelWidth = -1;
  77. protected float FbxExtLabelWidth
  78. {
  79. get
  80. {
  81. if(m_fbxExtLabelWidth < 0)
  82. {
  83. m_fbxExtLabelWidth = FbxExtLabelStyle.CalcSize(new GUIContent(".fbx")).x;
  84. }
  85. return m_fbxExtLabelWidth;
  86. }
  87. set { m_fbxExtLabelWidth = value; }
  88. }
  89. protected abstract bool DisableTransferAnim { get; }
  90. protected abstract bool DisableNameSelection { get; }
  91. protected abstract ExportOptionsSettingsSerializeBase SettingsObject { get; }
  92. private UnityEngine.Object[] m_toExport;
  93. protected Object[] GetToExport(){ return m_toExport; }
  94. protected void SetToExport(Object[] value){ m_toExport = value; }
  95. protected virtual void OnEnable(){
  96. #if UNITY_2018_1_OR_NEWER
  97. InitializeReceiver ();
  98. #endif
  99. m_showOptions = true;
  100. this.minSize = new Vector2 (SelectableLabelMinWidth + LabelWidth + BrowseButtonWidth, MinWindowHeight);
  101. }
  102. protected static T CreateWindow<T>() where T : EditorWindow {
  103. return (T)EditorWindow.GetWindow <T>(DefaultWindowTitle, focus:true);
  104. }
  105. protected virtual void InitializeWindow(string filename = ""){
  106. this.titleContent = WindowTitle;
  107. this.SetFilename (filename);
  108. }
  109. #if UNITY_2018_1_OR_NEWER
  110. protected void InitializeReceiver(){
  111. if (!Receiver) {
  112. Receiver = ScriptableObject.CreateInstance<FbxExportPresetSelectorReceiver> () as FbxExportPresetSelectorReceiver;
  113. Receiver.SelectionChanged -= OnPresetSelectionChanged;
  114. Receiver.SelectionChanged += OnPresetSelectionChanged;
  115. Receiver.DialogClosed -= SaveExportSettings;
  116. Receiver.DialogClosed += SaveExportSettings;
  117. }
  118. }
  119. #endif
  120. internal void SetFilename(string filename){
  121. // remove .fbx from end of filename
  122. int extIndex = filename.LastIndexOf(".fbx");
  123. if (extIndex < 0) {
  124. ExportFileName = filename;
  125. return;
  126. }
  127. ExportFileName = filename.Remove(extIndex);
  128. }
  129. public void SaveExportSettings()
  130. {
  131. // save once preset selection is finished
  132. EditorUtility.SetDirty (ExportSettings.instance);
  133. ExportSettings.instance.Save ();
  134. }
  135. public void OnPresetSelectionChanged()
  136. {
  137. this.Repaint ();
  138. }
  139. protected bool SelectionContainsPrefabInstanceWithAddedObjects()
  140. {
  141. var exportSet = GetToExport();
  142. Stack<Object> stack = new Stack<Object>(exportSet);
  143. while (stack.Count > 0)
  144. {
  145. var go = ModelExporter.GetGameObject(stack.Pop());
  146. if (!go)
  147. {
  148. continue;
  149. }
  150. if(PrefabUtility.IsAnyPrefabInstanceRoot(go) && PrefabUtility.GetAddedGameObjects(go).Count > 0)
  151. {
  152. return true;
  153. }
  154. foreach (Transform child in go.transform)
  155. {
  156. stack.Push(child.gameObject);
  157. }
  158. }
  159. return false;
  160. }
  161. protected abstract bool Export ();
  162. /// <summary>
  163. /// Function to be used by derived classes to add custom UI between the file path selector and export options.
  164. /// </summary>
  165. protected virtual void CreateCustomUI(){}
  166. #if UNITY_2018_1_OR_NEWER
  167. protected abstract void ShowPresetReceiver ();
  168. protected void ShowPresetReceiver(UnityEngine.Object target){
  169. InitializeReceiver ();
  170. Receiver.SetTarget(target);
  171. Receiver.SetInitialValue (new Preset (target));
  172. UnityEditor.Presets.PresetSelector.ShowSelector(target, null, true, Receiver);
  173. }
  174. #endif
  175. protected Transform TransferAnimationSource {
  176. get {
  177. return SettingsObject.AnimationSource;
  178. }
  179. set {
  180. if (!TransferAnimationSourceIsValid (value)) {
  181. return;
  182. }
  183. SettingsObject.SetAnimationSource (value);
  184. }
  185. }
  186. protected Transform TransferAnimationDest {
  187. get {
  188. return SettingsObject.AnimationDest;
  189. }
  190. set {
  191. if (!TransferAnimationDestIsValid (value)) {
  192. return;
  193. }
  194. SettingsObject.SetAnimationDest (value);
  195. }
  196. }
  197. //-------Helper functions for determining if Animation source and dest are valid---------
  198. /// <summary>
  199. /// Determines whether p is an ancestor to t.
  200. /// </summary>
  201. /// <returns><c>true</c> if p is ancestor to t; otherwise, <c>false</c>.</returns>
  202. /// <param name="p">P.</param>
  203. /// <param name="t">T.</param>
  204. protected bool IsAncestor(Transform p, Transform t){
  205. var curr = t;
  206. while (curr != null) {
  207. if (curr == p) {
  208. return true;
  209. }
  210. curr = curr.parent;
  211. }
  212. return false;
  213. }
  214. /// <summary>
  215. /// Determines whether t1 and t2 are in the same hierarchy.
  216. /// </summary>
  217. /// <returns><c>true</c> if t1 is in same hierarchy as t2; otherwise, <c>false</c>.</returns>
  218. /// <param name="t1">T1.</param>
  219. /// <param name="t2">T2.</param>
  220. protected bool IsInSameHierarchy(Transform t1, Transform t2){
  221. return (IsAncestor (t1, t2) || IsAncestor (t2, t1));
  222. }
  223. protected virtual GameObject FirstGameObjectToExport
  224. {
  225. get {
  226. return ModelExporter.GetGameObject(GetToExport()[0]);
  227. }
  228. }
  229. protected bool TransferAnimationSourceIsValid(Transform newValue){
  230. if (!newValue) {
  231. return true;
  232. }
  233. if (GetToExport() == null || GetToExport().Length <= 0) {
  234. Debug.LogWarning ("FbxExportSettings: no Objects selected for export, can't transfer animation");
  235. return false;
  236. }
  237. var selectedGO = FirstGameObjectToExport;
  238. // source must be ancestor to dest
  239. if (TransferAnimationDest && !IsAncestor(newValue, TransferAnimationDest)) {
  240. Debug.LogWarningFormat("FbxExportSettings: Source {0} must be an ancestor of {1}", newValue.name, TransferAnimationDest.name);
  241. return false;
  242. }
  243. // must be in same hierarchy as selected GO
  244. if (!selectedGO || !IsInSameHierarchy(newValue, selectedGO.transform)) {
  245. Debug.LogWarningFormat("FbxExportSettings: Source {0} must be in the same hierarchy as {1}", newValue.name, selectedGO? selectedGO.name : "the selected object");
  246. return false;
  247. }
  248. return true;
  249. }
  250. protected bool TransferAnimationDestIsValid(Transform newValue){
  251. if (!newValue) {
  252. return true;
  253. }
  254. if (GetToExport() == null || GetToExport().Length <= 0) {
  255. Debug.LogWarning ("FbxExportSettings: no Objects selected for export, can't transfer animation");
  256. return false;
  257. }
  258. var selectedGO = FirstGameObjectToExport;
  259. // source must be ancestor to dest
  260. if (TransferAnimationSource && !IsAncestor(TransferAnimationSource, newValue)) {
  261. Debug.LogWarningFormat("FbxExportSettings: Destination {0} must be a descendant of {1}", newValue.name, TransferAnimationSource.name);
  262. return false;
  263. }
  264. // must be in same hierarchy as selected GO
  265. if (!selectedGO || !IsInSameHierarchy(newValue, selectedGO.transform)) {
  266. Debug.LogWarningFormat("FbxExportSettings: Destination {0} must be in the same hierarchy as {1}", newValue.name, selectedGO? selectedGO.name : "the selected object");
  267. return false;
  268. }
  269. return true;
  270. }
  271. /// <summary>
  272. /// Add UI to turn the dialog off next time the user exports
  273. /// </summary>
  274. protected virtual void DoNotShowDialogUI() { }
  275. // -------------------------------------------------------------------------------------
  276. protected void OnGUI ()
  277. {
  278. // Increasing the label width so that none of the text gets cut off
  279. EditorGUIUtility.labelWidth = LabelWidth;
  280. GUILayout.BeginHorizontal ();
  281. GUILayout.FlexibleSpace ();
  282. #if UNITY_2018_1_OR_NEWER
  283. if(EditorGUILayout.DropdownButton(presetIcon, FocusType.Keyboard, presetIconButton)){
  284. ShowPresetReceiver ();
  285. }
  286. #endif
  287. GUILayout.EndHorizontal();
  288. EditorGUILayout.LabelField("Naming");
  289. EditorGUI.indentLevel++;
  290. GUILayout.BeginHorizontal ();
  291. EditorGUILayout.LabelField(new GUIContent(
  292. "Export Name",
  293. "Filename to save model to."),GUILayout.Width(LabelWidth-TextFieldAlignOffset));
  294. EditorGUI.BeginDisabledGroup (DisableNameSelection);
  295. // Show the export name with an uneditable ".fbx" at the end
  296. //-------------------------------------
  297. EditorGUILayout.BeginVertical ();
  298. EditorGUILayout.BeginHorizontal(EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
  299. EditorGUI.indentLevel--;
  300. // continually resize to contents
  301. var textFieldSize = NameTextFieldStyle.CalcSize (new GUIContent(ExportFileName));
  302. ExportFileName = EditorGUILayout.TextField (ExportFileName, NameTextFieldStyle, GUILayout.Width(textFieldSize.x + 5), GUILayout.MinWidth(5));
  303. ExportFileName = ModelExporter.ConvertToValidFilename (ExportFileName);
  304. EditorGUILayout.LabelField ("<color=#808080ff>.fbx</color>", FbxExtLabelStyle, GUILayout.Width(FbxExtLabelWidth));
  305. EditorGUI.indentLevel++;
  306. EditorGUILayout.EndHorizontal();
  307. EditorGUILayout.EndVertical ();
  308. //-----------------------------------
  309. EditorGUI.EndDisabledGroup ();
  310. GUILayout.EndHorizontal ();
  311. GUILayout.BeginHorizontal();
  312. EditorGUILayout.LabelField(new GUIContent(
  313. "Export Path",
  314. "Location where the FBX will be saved."),GUILayout.Width(LabelWidth - FieldOffset));
  315. var pathLabels = ExportSettings.GetMixedFbxSavePaths();
  316. if (this is ConvertToPrefabEditorWindow)
  317. {
  318. pathLabels = ExportSettings.GetRelativeFbxSavePaths();
  319. }
  320. ExportSettings.instance.SelectedFbxPath = EditorGUILayout.Popup (ExportSettings.instance.SelectedFbxPath, pathLabels, GUILayout.MinWidth(SelectableLabelMinWidth));
  321. // Set export setting for exporting outside the project on choosing a path
  322. if (!pathLabels[ExportSettings.instance.SelectedFbxPath].Substring(0, 6).Equals("Assets"))
  323. {
  324. ExportSettings.instance.ExportOutsideProject = true;
  325. }
  326. else
  327. {
  328. ExportSettings.instance.ExportOutsideProject = false;
  329. }
  330. if (GUILayout.Button(new GUIContent("...", "Browse to a new location to export to"), EditorStyles.miniButton, GUILayout.Width(BrowseButtonWidth)))
  331. {
  332. string initialPath = Application.dataPath;
  333. string fullPath = EditorUtility.OpenFolderPanel(
  334. "Select Export Model Path", initialPath, null
  335. );
  336. // Unless the user canceled, save path.
  337. if (!string.IsNullOrEmpty(fullPath))
  338. {
  339. var relativePath = ExportSettings.ConvertToAssetRelativePath(fullPath);
  340. // If exporting an fbx for a prefab, not allowed to export outside the Assets folder
  341. if (this is ConvertToPrefabEditorWindow && string.IsNullOrEmpty(relativePath))
  342. {
  343. Debug.LogWarning("Please select a location in the Assets folder");
  344. }
  345. // We're exporting outside Assets folder, so store the absolute path
  346. else if (string.IsNullOrEmpty(relativePath))
  347. {
  348. ExportSettings.instance.ExportOutsideProject = true;
  349. ExportSettings.AddFbxSavePath(fullPath);
  350. }
  351. // Store the relative path to the Assets folder
  352. else
  353. {
  354. ExportSettings.AddFbxSavePath(relativePath);
  355. }
  356. // Make sure focus is removed from the selectable label
  357. // otherwise it won't update
  358. GUIUtility.hotControl = 0;
  359. GUIUtility.keyboardControl = 0;
  360. }
  361. }
  362. GUILayout.EndHorizontal();
  363. CreateCustomUI();
  364. EditorGUILayout.Space ();
  365. EditorGUI.BeginDisabledGroup (DisableTransferAnim);
  366. EditorGUI.indentLevel--;
  367. GUILayout.BeginHorizontal();
  368. EditorGUILayout.LabelField(new GUIContent(
  369. "Transfer Animation",
  370. "Transfer transform animation from source to destination. Animation on objects between source and destination will also be transferred to destination."
  371. ), GUILayout.Width(LabelWidth - FieldOffset));
  372. GUILayout.EndHorizontal();
  373. EditorGUI.indentLevel++;
  374. TransferAnimationSource = EditorGUILayout.ObjectField ("Source", TransferAnimationSource, typeof(Transform), allowSceneObjects: true) as Transform;
  375. TransferAnimationDest = EditorGUILayout.ObjectField ("Destination", TransferAnimationDest, typeof(Transform), allowSceneObjects: true) as Transform;
  376. EditorGUILayout.Space ();
  377. EditorGUI.EndDisabledGroup ();
  378. EditorGUI.indentLevel--;
  379. m_showOptions = EditorGUILayout.Foldout (m_showOptions, "Options");
  380. EditorGUI.indentLevel++;
  381. if (m_showOptions) {
  382. InnerEditor.OnInspectorGUI ();
  383. }
  384. // if we are exporting or converting a prefab with overrides, then show a warning
  385. if (SelectionContainsPrefabInstanceWithAddedObjects())
  386. {
  387. EditorGUILayout.Space();
  388. EditorGUILayout.HelpBox("Prefab instance overrides will be exported", MessageType.Warning, true);
  389. }
  390. GUILayout.FlexibleSpace ();
  391. GUILayout.BeginHorizontal ();
  392. DoNotShowDialogUI();
  393. GUILayout.FlexibleSpace ();
  394. if (GUILayout.Button ("Cancel", GUILayout.Width(ExportButtonWidth))) {
  395. this.Close ();
  396. }
  397. if (GUILayout.Button (ExportButtonName, GUILayout.Width(ExportButtonWidth))) {
  398. if (Export ()) {
  399. this.Close ();
  400. }
  401. }
  402. GUILayout.EndHorizontal ();
  403. EditorGUILayout.Space(); // adding a space at bottom of dialog so buttons aren't right at the edge
  404. if (GUI.changed) {
  405. SaveExportSettings ();
  406. }
  407. }
  408. /// <summary>
  409. /// Checks whether the file exists and if it does then asks if it should be overwritten.
  410. /// </summary>
  411. /// <returns><c>true</c>, if file should be overwritten, <c>false</c> otherwise.</returns>
  412. /// <param name="filePath">File path.</param>
  413. protected bool OverwriteExistingFile(string filePath){
  414. // check if file already exists, give a warning if it does
  415. if (System.IO.File.Exists (filePath)) {
  416. bool overwrite = UnityEditor.EditorUtility.DisplayDialog (
  417. string.Format("{0} Warning", ModelExporter.PACKAGE_UI_NAME),
  418. string.Format("File {0} already exists.\nOverwrite cannot be undone.", filePath),
  419. "Overwrite", "Cancel");
  420. if (!overwrite) {
  421. if (GUI.changed) {
  422. SaveExportSettings ();
  423. }
  424. return false;
  425. }
  426. }
  427. return true;
  428. }
  429. }
  430. internal class ExportModelEditorWindow : ExportOptionsEditorWindow
  431. {
  432. protected override float MinWindowHeight { get { return 310; } } // determined by trial and error
  433. protected override bool DisableNameSelection {
  434. get {
  435. return false;
  436. }
  437. }
  438. protected override GameObject FirstGameObjectToExport
  439. {
  440. get
  441. {
  442. return (IsTimelineAnim)
  443. ? AnimationOnlyExportData.GetGameObjectAndAnimationClip(GetToExport()[0]).Key
  444. : ModelExporter.GetGameObject(GetToExport()[0]);
  445. }
  446. }
  447. protected override bool DisableTransferAnim {
  448. get {
  449. // don't transfer animation if we are exporting more than one hierarchy, the timeline clips from
  450. // a playable director, or if only the model is being exported
  451. // if we are on the timeline then export length can be more than 1
  452. return GetToExport() == null || GetToExport().Length == 0 || (!IsTimelineAnim && GetToExport().Length > 1) || SettingsObject.ModelAnimIncludeOption == ExportSettings.Include.Model;
  453. }
  454. }
  455. private bool m_isTimelineAnim = false;
  456. protected bool IsTimelineAnim {
  457. get { return m_isTimelineAnim; }
  458. set{
  459. m_isTimelineAnim = value;
  460. if (m_isTimelineAnim) {
  461. m_previousInclude = ExportSettings.instance.ExportModelSettings.info.ModelAnimIncludeOption;
  462. ExportSettings.instance.ExportModelSettings.info.SetModelAnimIncludeOption(ExportSettings.Include.Anim);
  463. }
  464. if (InnerEditor) {
  465. var exportModelSettingsEditor = InnerEditor as ExportModelSettingsEditor;
  466. if (exportModelSettingsEditor) {
  467. exportModelSettingsEditor.DisableIncludeDropdown(m_isTimelineAnim);
  468. }
  469. }
  470. }
  471. }
  472. private bool m_singleHierarchyExport = true;
  473. protected bool SingleHierarchyExport {
  474. get { return m_singleHierarchyExport; }
  475. set {
  476. m_singleHierarchyExport = value;
  477. if (InnerEditor) {
  478. var exportModelSettingsEditor = InnerEditor as ExportModelSettingsEditor;
  479. if (exportModelSettingsEditor) {
  480. exportModelSettingsEditor.SetIsSingleHierarchy (m_singleHierarchyExport);
  481. }
  482. }
  483. }
  484. }
  485. protected override ExportOptionsSettingsSerializeBase SettingsObject
  486. {
  487. get { return ExportSettings.instance.ExportModelSettings.info; }
  488. }
  489. private ExportSettings.Include m_previousInclude = ExportSettings.Include.ModelAndAnim;
  490. public static void Init (IEnumerable<UnityEngine.Object> toExport, string filename = "", bool isTimelineAnim = false)
  491. {
  492. ExportModelEditorWindow window = CreateWindow<ExportModelEditorWindow> ();
  493. window.IsTimelineAnim = isTimelineAnim;
  494. int numObjects = window.SetGameObjectsToExport (toExport);
  495. if (string.IsNullOrEmpty (filename)) {
  496. filename = window.DefaultFilename;
  497. }
  498. window.InitializeWindow (filename);
  499. window.SingleHierarchyExport = (numObjects == 1);
  500. window.Show ();
  501. }
  502. protected int SetGameObjectsToExport(IEnumerable<UnityEngine.Object> toExport){
  503. SetToExport(toExport.ToArray ());
  504. if (GetToExport().Length==0) return 0;
  505. TransferAnimationSource = null;
  506. TransferAnimationDest = null;
  507. // if only one object selected, set transfer source/dest to this object
  508. if (GetToExport().Length == 1 || (IsTimelineAnim && GetToExport().Length > 0))
  509. {
  510. GameObject go = FirstGameObjectToExport;
  511. if (go)
  512. {
  513. TransferAnimationSource = go.transform;
  514. TransferAnimationDest = go.transform;
  515. }
  516. }
  517. return GetToExport().Length;
  518. }
  519. /// <summary>
  520. /// Gets the filename from objects to export.
  521. /// </summary>
  522. /// <returns>The object's name if one object selected, "Untitled" if multiple
  523. /// objects selected for export.</returns>
  524. protected string DefaultFilename {
  525. get
  526. {
  527. var filename = "";
  528. if (GetToExport().Length == 1)
  529. {
  530. filename = GetToExport()[0].name;
  531. }
  532. else
  533. {
  534. filename = "Untitled";
  535. }
  536. return filename;
  537. }
  538. }
  539. protected override void OnEnable ()
  540. {
  541. base.OnEnable ();
  542. if (!InnerEditor) {
  543. InnerEditor = UnityEditor.Editor.CreateEditor (ExportSettings.instance.ExportModelSettings);
  544. this.SingleHierarchyExport = m_singleHierarchyExport;
  545. this.IsTimelineAnim = m_isTimelineAnim;
  546. }
  547. }
  548. protected void OnDisable()
  549. {
  550. RestoreSettings ();
  551. }
  552. /// <summary>
  553. /// Restore changed export settings after export
  554. /// </summary>
  555. protected virtual void RestoreSettings()
  556. {
  557. if (IsTimelineAnim) {
  558. ExportSettings.instance.ExportModelSettings.info.SetModelAnimIncludeOption(m_previousInclude);
  559. SaveExportSettings ();
  560. }
  561. }
  562. [SecurityPermission(SecurityAction.LinkDemand)]
  563. protected override bool Export(){
  564. if (string.IsNullOrEmpty (ExportFileName)) {
  565. Debug.LogError ("FbxExporter: Please specify an fbx filename");
  566. return false;
  567. }
  568. var folderPath = ExportSettings.FbxAbsoluteSavePath;
  569. var filePath = System.IO.Path.Combine (folderPath, ExportFileName + ".fbx");
  570. if (!OverwriteExistingFile (filePath)) {
  571. return false;
  572. }
  573. if (ModelExporter.ExportObjects (filePath, GetToExport(), SettingsObject) != null) {
  574. // refresh the asset database so that the file appears in the
  575. // asset folder view.
  576. AssetDatabase.Refresh ();
  577. }
  578. return true;
  579. }
  580. #if UNITY_2018_1_OR_NEWER
  581. protected override void ShowPresetReceiver ()
  582. {
  583. ShowPresetReceiver (ExportSettings.instance.ExportModelSettings);
  584. }
  585. #endif
  586. }
  587. }