2025-03-11 15:30:07 +08:00

877 lines
35 KiB
C#

using System.Collections.Generic;
using UnityEngine;
#if UNITY_2018_1_OR_NEWER
using UnityEditor.Presets;
#endif
using System.Linq;
using System.Security.Permissions;
namespace UnityEditor.Formats.Fbx.Exporter
{
internal abstract class ExportOptionsEditorWindow : EditorWindow
{
internal const string DefaultWindowTitle = "Export Options";
protected const float SelectableLabelMinWidth = 120;
protected const float BrowseButtonWidth = 25;
protected const float LabelWidth = 175;
protected const float FieldOffset = 18;
protected const float TextFieldAlignOffset = 3;
protected const float ExportButtonWidth = 100;
protected const float FbxExtOffset = -7;
protected virtual float MinWindowHeight { get { return 300; } }
protected virtual string ExportButtonName { get { return "Export"; } }
protected virtual GUIContent WindowTitle { get { return new GUIContent (DefaultWindowTitle); } }
private string m_exportFileName = "";
protected string ExportFileName
{
get { return m_exportFileName; }
set { m_exportFileName = value; }
}
private UnityEditor.Editor m_innerEditor;
protected UnityEditor.Editor InnerEditor
{
get { return m_innerEditor; }
set { m_innerEditor = value; }
}
#if UNITY_2018_1_OR_NEWER
private FbxExportPresetSelectorReceiver m_receiver;
protected FbxExportPresetSelectorReceiver Receiver
{
get { return m_receiver; }
set { m_receiver = value; }
}
#endif
private static GUIContent presetIcon { get { return EditorGUIUtility.IconContent ("Preset.Context"); }}
private static GUIStyle presetIconButton { get { return new GUIStyle("IconButton"); }}
private bool m_showOptions;
private GUIStyle m_nameTextFieldStyle;
protected GUIStyle NameTextFieldStyle
{
get {
if (m_nameTextFieldStyle == null)
{
m_nameTextFieldStyle = new GUIStyle(GUIStyle.none);
m_nameTextFieldStyle.alignment = TextAnchor.MiddleCenter;
m_nameTextFieldStyle.clipping = TextClipping.Clip;
m_nameTextFieldStyle.normal.textColor = EditorStyles.textField.normal.textColor;
}
return m_nameTextFieldStyle;
}
set { m_nameTextFieldStyle = value; }
}
private GUIStyle m_fbxExtLabelStyle;
protected GUIStyle FbxExtLabelStyle
{
get {
if (m_fbxExtLabelStyle == null)
{
m_fbxExtLabelStyle = new GUIStyle(GUIStyle.none);
m_fbxExtLabelStyle.alignment = TextAnchor.MiddleLeft;
m_fbxExtLabelStyle.richText = true;
m_fbxExtLabelStyle.contentOffset = new Vector2(FbxExtOffset, 0);
}
return m_fbxExtLabelStyle;
}
set { m_fbxExtLabelStyle = value; }
}
private float m_fbxExtLabelWidth = -1;
protected float FbxExtLabelWidth
{
get
{
if(m_fbxExtLabelWidth < 0)
{
m_fbxExtLabelWidth = FbxExtLabelStyle.CalcSize(new GUIContent(".fbx")).x;
}
return m_fbxExtLabelWidth;
}
set { m_fbxExtLabelWidth = value; }
}
protected abstract bool DisableTransferAnim { get; }
protected abstract bool DisableNameSelection { get; }
protected abstract ExportOptionsSettingsSerializeBase SettingsObject { get; }
// Helper functions for persisting the Export Settings for the session
protected abstract string SessionStoragePrefix { get; }
protected const string k_SessionSettingsName = "Settings";
protected const string k_SessionFbxPathsName = "FbxSavePath";
protected const string k_SessionSelectedFbxPathName = "SelectedFbxPath";
protected const string k_SessionPrefabPathsName = "PrefabSavePath";
protected const string k_SessionSelectedPrefabPathName = "SelectedPrefabPath";
protected void StorePathsInSession(string varName, List<string> paths)
{
if(paths == null)
{
return;
}
var n = paths.Count;
SessionState.SetInt(string.Format(SessionStoragePrefix, varName), n);
for (int i = 0; i < n; i++)
{
SessionState.SetString(string.Format(SessionStoragePrefix + "_{1}", varName, i), paths[i]);
}
}
protected void RestorePathsFromSession(string varName, List<string> defaultsPaths, out List<string> paths)
{
var n = SessionState.GetInt(string.Format(SessionStoragePrefix, varName), 0);
if (n <= 0)
{
paths = defaultsPaths;
return;
}
paths = new List<string>();
for (int i = 0; i < n; i++)
{
var path = SessionState.GetString(string.Format(SessionStoragePrefix + "_{1}", varName, i), null);
if (!string.IsNullOrEmpty(path))
{
paths.Add(path);
}
}
}
protected static void ClearPathsFromSession(string varName, string prefix)
{
var n = SessionState.GetInt(string.Format(prefix, varName), 0);
SessionState.EraseInt(string.Format(prefix, varName));
for(int i = 0; i < n; i++)
{
SessionState.EraseString(string.Format(prefix + "_{1}", varName, i));
}
}
protected virtual void StoreSettingsInSession()
{
var settings = SettingsObject;
var json = EditorJsonUtility.ToJson(settings);
SessionState.SetString(string.Format(SessionStoragePrefix, k_SessionSettingsName), json);
StorePathsInSession(k_SessionFbxPathsName, m_fbxSavePaths);
SessionState.SetInt(string.Format(SessionStoragePrefix, k_SessionSelectedFbxPathName), SelectedFbxPath);
}
protected virtual void RestoreSettingsFromSession(ExportOptionsSettingsSerializeBase defaults)
{
var settings = SettingsObject;
var json = SessionState.GetString(string.Format(SessionStoragePrefix, k_SessionSettingsName), EditorJsonUtility.ToJson(defaults));
if (!string.IsNullOrEmpty(json))
{
EditorJsonUtility.FromJsonOverwrite(json, settings);
}
}
public static void ResetAllSessionSettings(string prefix, string settingsDefaults = null)
{
SessionState.EraseString(string.Format(prefix, k_SessionSettingsName));
// Set the defaults of the settings.
// If there exists a Default Preset for the Convert/Export settings, then if the project settings are modified,
// the Default Preset will be reloaded instead of the project settings. Therefore, set them explicitely if projects settings desired.
if (!string.IsNullOrEmpty(settingsDefaults))
{
SessionState.SetString(string.Format(prefix, k_SessionSettingsName), settingsDefaults);
}
ClearPathsFromSession(k_SessionFbxPathsName, prefix);
SessionState.EraseInt(string.Format(prefix, k_SessionSelectedFbxPathName));
ClearPathsFromSession(k_SessionPrefabPathsName, prefix);
SessionState.EraseInt(string.Format(prefix, k_SessionSelectedPrefabPathName));
}
public virtual void ResetSessionSettings(string settingsDefaults = null)
{
ResetAllSessionSettings(SessionStoragePrefix, settingsDefaults);
m_fbxSavePaths = null;
SelectedFbxPath = 0;
}
private List<string> m_fbxSavePaths;
internal List<string> FbxSavePaths
{
get
{
if (m_fbxSavePaths == null)
{
// Try to restore from session, fall back to Fbx Export Settings
RestorePathsFromSession(k_SessionFbxPathsName, ExportSettings.instance.GetCopyOfFbxSavePaths(), out m_fbxSavePaths);
SelectedFbxPath = SessionState.GetInt(string.Format(SessionStoragePrefix, k_SessionSelectedFbxPathName), ExportSettings.instance.SelectedFbxPath);
}
return m_fbxSavePaths;
}
}
[SerializeField]
private int m_selectedFbxPath = 0;
internal int SelectedFbxPath
{
get { return m_selectedFbxPath; }
set { m_selectedFbxPath = value; }
}
private UnityEngine.Object[] m_toExport;
protected Object[] GetToExport(){ return m_toExport; }
protected void SetToExport(Object[] value){ m_toExport = value; }
protected virtual void OnEnable(){
#if UNITY_2018_1_OR_NEWER
InitializeReceiver ();
#endif
m_showOptions = true;
this.minSize = new Vector2 (SelectableLabelMinWidth + LabelWidth + BrowseButtonWidth + ExportButtonWidth, MinWindowHeight);
}
protected static T CreateWindow<T>() where T : EditorWindow {
return (T)EditorWindow.GetWindow <T>(DefaultWindowTitle, focus:true);
}
protected virtual void InitializeWindow(string filename = ""){
this.titleContent = WindowTitle;
this.SetFilename (filename);
}
#if UNITY_2018_1_OR_NEWER
protected void InitializeReceiver(){
if (!Receiver) {
Receiver = ScriptableObject.CreateInstance<FbxExportPresetSelectorReceiver> () as FbxExportPresetSelectorReceiver;
Receiver.SelectionChanged -= OnPresetSelectionChanged;
Receiver.SelectionChanged += OnPresetSelectionChanged;
Receiver.DialogClosed -= SaveExportSettings;
Receiver.DialogClosed += SaveExportSettings;
}
}
#endif
internal void SetFilename(string filename){
// remove .fbx from end of filename
int extIndex = filename.LastIndexOf(".fbx");
if (extIndex < 0) {
ExportFileName = filename;
return;
}
ExportFileName = filename.Remove(extIndex);
}
public abstract void SaveExportSettings();
public void OnPresetSelectionChanged()
{
this.Repaint ();
}
protected bool SelectionContainsPrefabInstanceWithAddedObjects()
{
var exportSet = GetToExport();
// FBX-60 (fogbug 1307749):
// On Linux OnGUI() sometimes gets called a few times before
// the export set is set and window.show() is called.
// This leads to this function being called from OnGUI() with a
// null or empty export set, and an ArgumentNullException when
// creating the stack.
// Check that the set exists and has values before creating the stack.
if (exportSet == null || exportSet.Length <= 0)
{
return false;
}
Stack<Object> stack = new Stack<Object>(exportSet);
while (stack.Count > 0)
{
var go = ModelExporter.GetGameObject(stack.Pop());
if (!go)
{
continue;
}
if(PrefabUtility.IsAnyPrefabInstanceRoot(go) && PrefabUtility.GetAddedGameObjects(go).Count > 0)
{
return true;
}
foreach (Transform child in go.transform)
{
stack.Push(child.gameObject);
}
}
return false;
}
protected abstract bool Export ();
/// <summary>
/// Function to be used by derived classes to add custom UI between the file path selector and export options.
/// </summary>
protected virtual void CreateCustomUI(){}
#if UNITY_2018_1_OR_NEWER
protected abstract void ShowPresetReceiver ();
protected void ShowPresetReceiver(UnityEngine.Object target){
InitializeReceiver ();
Receiver.SetTarget(target);
Receiver.SetInitialValue (new Preset (target));
UnityEditor.Presets.PresetSelector.ShowSelector(target, null, true, Receiver);
}
#endif
protected Transform TransferAnimationSource {
get {
return SettingsObject.AnimationSource;
}
set {
if (!TransferAnimationSourceIsValid (value)) {
return;
}
SettingsObject.SetAnimationSource (value);
}
}
protected Transform TransferAnimationDest {
get {
return SettingsObject.AnimationDest;
}
set {
if (!TransferAnimationDestIsValid (value)) {
return;
}
SettingsObject.SetAnimationDest (value);
}
}
//-------Helper functions for determining if Animation source and dest are valid---------
/// <summary>
/// Determines whether p is an ancestor to t.
/// </summary>
/// <returns><c>true</c> if p is ancestor to t; otherwise, <c>false</c>.</returns>
/// <param name="p">P.</param>
/// <param name="t">T.</param>
protected bool IsAncestor(Transform p, Transform t){
var curr = t;
while (curr != null) {
if (curr == p) {
return true;
}
curr = curr.parent;
}
return false;
}
/// <summary>
/// Determines whether t1 and t2 are in the same hierarchy.
/// </summary>
/// <returns><c>true</c> if t1 is in same hierarchy as t2; otherwise, <c>false</c>.</returns>
/// <param name="t1">T1.</param>
/// <param name="t2">T2.</param>
protected bool IsInSameHierarchy(Transform t1, Transform t2){
return (IsAncestor (t1, t2) || IsAncestor (t2, t1));
}
protected virtual GameObject FirstGameObjectToExport
{
get {
return ModelExporter.GetGameObject(GetToExport()[0]);
}
}
protected bool TransferAnimationSourceIsValid(Transform newValue){
if (!newValue) {
return true;
}
if (GetToExport() == null || GetToExport().Length <= 0) {
Debug.LogWarning ("FbxExportSettings: no Objects selected for export, can't transfer animation");
return false;
}
var selectedGO = FirstGameObjectToExport;
// source must be ancestor to dest
if (TransferAnimationDest && !IsAncestor(newValue, TransferAnimationDest)) {
Debug.LogWarningFormat("FbxExportSettings: Source {0} must be an ancestor of {1}", newValue.name, TransferAnimationDest.name);
return false;
}
// must be in same hierarchy as selected GO
if (!selectedGO || !IsInSameHierarchy(newValue, selectedGO.transform)) {
Debug.LogWarningFormat("FbxExportSettings: Source {0} must be in the same hierarchy as {1}", newValue.name, selectedGO? selectedGO.name : "the selected object");
return false;
}
return true;
}
protected bool TransferAnimationDestIsValid(Transform newValue){
if (!newValue) {
return true;
}
if (GetToExport() == null || GetToExport().Length <= 0) {
Debug.LogWarning ("FbxExportSettings: no Objects selected for export, can't transfer animation");
return false;
}
var selectedGO = FirstGameObjectToExport;
// source must be ancestor to dest
if (TransferAnimationSource && !IsAncestor(TransferAnimationSource, newValue)) {
Debug.LogWarningFormat("FbxExportSettings: Destination {0} must be a descendant of {1}", newValue.name, TransferAnimationSource.name);
return false;
}
// must be in same hierarchy as selected GO
if (!selectedGO || !IsInSameHierarchy(newValue, selectedGO.transform)) {
Debug.LogWarningFormat("FbxExportSettings: Destination {0} must be in the same hierarchy as {1}", newValue.name, selectedGO? selectedGO.name : "the selected object");
return false;
}
return true;
}
/// <summary>
/// Add UI to turn the dialog off next time the user exports
/// </summary>
protected virtual void DoNotShowDialogUI()
{
EditorGUI.indentLevel--;
ExportSettings.instance.DisplayOptionsWindow = !EditorGUILayout.Toggle(
new GUIContent("Don't ask me again", "Don't ask me again, use the last used paths and options instead"),
!ExportSettings.instance.DisplayOptionsWindow
);
}
// -------------------------------------------------------------------------------------
protected void OnGUI ()
{
// Increasing the label width so that none of the text gets cut off
EditorGUIUtility.labelWidth = LabelWidth;
GUILayout.BeginHorizontal ();
GUILayout.FlexibleSpace ();
#if UNITY_2018_1_OR_NEWER
if(EditorGUILayout.DropdownButton(presetIcon, FocusType.Keyboard, presetIconButton)){
ShowPresetReceiver ();
}
#endif
GUILayout.EndHorizontal();
EditorGUILayout.LabelField("Naming");
EditorGUI.indentLevel++;
GUILayout.BeginHorizontal ();
EditorGUILayout.LabelField(new GUIContent(
"Export Name",
"Filename to save model to."),GUILayout.Width(LabelWidth-TextFieldAlignOffset));
EditorGUI.BeginDisabledGroup (DisableNameSelection);
// Show the export name with an uneditable ".fbx" at the end
//-------------------------------------
EditorGUILayout.BeginVertical ();
EditorGUILayout.BeginHorizontal(EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
EditorGUI.indentLevel--;
// continually resize to contents
var textFieldSize = NameTextFieldStyle.CalcSize (new GUIContent(ExportFileName));
ExportFileName = EditorGUILayout.TextField (ExportFileName, NameTextFieldStyle, GUILayout.Width(textFieldSize.x + 5), GUILayout.MinWidth(5));
ExportFileName = ModelExporter.ConvertToValidFilename (ExportFileName);
EditorGUILayout.LabelField ("<color=#808080ff>.fbx</color>", FbxExtLabelStyle, GUILayout.Width(FbxExtLabelWidth));
EditorGUI.indentLevel++;
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical ();
//-----------------------------------
EditorGUI.EndDisabledGroup ();
GUILayout.EndHorizontal ();
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent(
"Export Path",
"Location where the FBX will be saved."),GUILayout.Width(LabelWidth - FieldOffset));
var pathLabels = ExportSettings.GetMixedSavePaths(FbxSavePaths);
if (this is ConvertToPrefabEditorWindow)
{
pathLabels = ExportSettings.GetRelativeFbxSavePaths(FbxSavePaths, ref m_selectedFbxPath);
}
SelectedFbxPath = EditorGUILayout.Popup (SelectedFbxPath, pathLabels, GUILayout.MinWidth(SelectableLabelMinWidth));
if (!(this is ConvertToPrefabEditorWindow))
{
var exportSettingsEditor = InnerEditor as ExportModelSettingsEditor;
// Set export setting for exporting outside the project on choosing a path
var exportOutsideProject = !pathLabels[SelectedFbxPath].Substring(0, 6).Equals("Assets");
exportSettingsEditor.SetExportingOutsideProject(exportOutsideProject);
}
if (GUILayout.Button(new GUIContent("...", "Browse to a new location to export to"), EditorStyles.miniButton, GUILayout.Width(BrowseButtonWidth)))
{
string initialPath = Application.dataPath;
string fullPath = EditorUtility.SaveFolderPanel(
"Select Export Model Path", initialPath, null
);
// Unless the user canceled, save path.
if (!string.IsNullOrEmpty(fullPath))
{
var relativePath = ExportSettings.ConvertToAssetRelativePath(fullPath);
// If exporting an fbx for a prefab, not allowed to export outside the Assets folder
if (this is ConvertToPrefabEditorWindow && string.IsNullOrEmpty(relativePath))
{
Debug.LogWarning("Please select a location in the Assets folder");
}
// We're exporting outside Assets folder, so store the absolute path
else if (string.IsNullOrEmpty(relativePath))
{
ExportSettings.AddSavePath(fullPath, FbxSavePaths, exportOutsideProject: true);
SelectedFbxPath = 0;
}
// Store the relative path to the Assets folder
else
{
ExportSettings.AddSavePath(relativePath, FbxSavePaths, exportOutsideProject: false);
SelectedFbxPath = 0;
}
// Make sure focus is removed from the selectable label
// otherwise it won't update
GUIUtility.hotControl = 0;
GUIUtility.keyboardControl = 0;
}
}
GUILayout.EndHorizontal();
CreateCustomUI();
EditorGUILayout.Space ();
EditorGUI.BeginDisabledGroup (DisableTransferAnim);
EditorGUI.indentLevel--;
GUILayout.BeginHorizontal();
EditorGUILayout.LabelField(new GUIContent(
"Transfer Animation",
"Transfer transform animation from source to destination. Animation on objects between source and destination will also be transferred to destination."
), GUILayout.Width(LabelWidth - FieldOffset));
GUILayout.EndHorizontal();
EditorGUI.indentLevel++;
TransferAnimationSource = EditorGUILayout.ObjectField ("Source", TransferAnimationSource, typeof(Transform), allowSceneObjects: true) as Transform;
TransferAnimationDest = EditorGUILayout.ObjectField ("Destination", TransferAnimationDest, typeof(Transform), allowSceneObjects: true) as Transform;
EditorGUILayout.Space ();
EditorGUI.EndDisabledGroup ();
EditorGUI.indentLevel--;
m_showOptions = EditorGUILayout.Foldout (m_showOptions, "Options");
EditorGUI.indentLevel++;
if (m_showOptions) {
InnerEditor.OnInspectorGUI ();
}
// if we are exporting or converting a prefab with overrides, then show a warning
if (SelectionContainsPrefabInstanceWithAddedObjects())
{
EditorGUILayout.Space();
EditorGUILayout.HelpBox("Prefab instance overrides will be exported", MessageType.Warning, true);
}
GUILayout.FlexibleSpace ();
GUILayout.BeginHorizontal ();
DoNotShowDialogUI();
GUILayout.FlexibleSpace ();
if (GUILayout.Button ("Cancel", GUILayout.Width(ExportButtonWidth))) {
this.Close ();
}
if (GUILayout.Button (ExportButtonName, GUILayout.Width(ExportButtonWidth))) {
if (Export ()) {
this.Close ();
}
}
GUILayout.EndHorizontal ();
EditorGUILayout.Space(); // adding a space at bottom of dialog so buttons aren't right at the edge
if (GUI.changed)
{
SaveExportSettings();
}
}
/// <summary>
/// Checks whether the file exists and if it does then asks if it should be overwritten.
/// </summary>
/// <returns><c>true</c>, if file should be overwritten, <c>false</c> otherwise.</returns>
/// <param name="filePath">File path.</param>
protected bool OverwriteExistingFile(string filePath){
// check if file already exists, give a warning if it does
if (System.IO.File.Exists (filePath)) {
bool overwrite = UnityEditor.EditorUtility.DisplayDialog (
string.Format("{0} Warning", ModelExporter.PACKAGE_UI_NAME),
string.Format("File {0} already exists.\nOverwrite cannot be undone.", filePath),
"Overwrite", "Cancel");
if (!overwrite) {
if (GUI.changed)
{
SaveExportSettings();
}
return false;
}
}
return true;
}
}
internal class ExportModelEditorWindow : ExportOptionsEditorWindow
{
public const string k_SessionStoragePrefix = "FbxExporterOptions_{0}";
protected override string SessionStoragePrefix { get { return k_SessionStoragePrefix; } }
protected override float MinWindowHeight { get { return 310; } } // determined by trial and error
protected override bool DisableNameSelection {
get {
return false;
}
}
protected override GameObject FirstGameObjectToExport
{
get
{
return (IsTimelineAnim)
? AnimationOnlyExportData.GetGameObjectAndAnimationClip(GetToExport()[0]).Key
: ModelExporter.GetGameObject(GetToExport()[0]);
}
}
protected override bool DisableTransferAnim {
get {
// don't transfer animation if we are exporting more than one hierarchy, the timeline clips from
// a playable director, or if only the model is being exported
// if we are on the timeline then export length can be more than 1
return GetToExport() == null || GetToExport().Length == 0 || (!IsTimelineAnim && GetToExport().Length > 1) || SettingsObject.ModelAnimIncludeOption == ExportSettings.Include.Model;
}
}
private bool m_isTimelineAnim = false;
protected bool IsTimelineAnim {
get { return m_isTimelineAnim; }
set{
m_isTimelineAnim = value;
if (m_isTimelineAnim) {
m_previousInclude = ExportModelSettingsInstance.info.ModelAnimIncludeOption;
ExportModelSettingsInstance.info.SetModelAnimIncludeOption(ExportSettings.Include.Anim);
}
if (InnerEditor) {
var exportModelSettingsEditor = InnerEditor as ExportModelSettingsEditor;
if (exportModelSettingsEditor) {
exportModelSettingsEditor.DisableIncludeDropdown(m_isTimelineAnim);
}
}
}
}
private bool m_singleHierarchyExport = true;
protected bool SingleHierarchyExport {
get { return m_singleHierarchyExport; }
set {
m_singleHierarchyExport = value;
if (InnerEditor) {
var exportModelSettingsEditor = InnerEditor as ExportModelSettingsEditor;
if (exportModelSettingsEditor) {
exportModelSettingsEditor.SetIsSingleHierarchy (m_singleHierarchyExport);
}
}
}
}
public override void ResetSessionSettings(string defaultSettings = null)
{
base.ResetSessionSettings(defaultSettings);
// save the source and dest as these are not serialized
var source = m_exportModelSettingsInstance.info.AnimationSource;
var dest = m_exportModelSettingsInstance.info.AnimationDest;
m_exportModelSettingsInstance = null;
ExportModelSettingsInstance.info.SetAnimationSource(source);
ExportModelSettingsInstance.info.SetAnimationDest(dest);
InnerEditor = Editor.CreateEditor(ExportModelSettingsInstance);
}
private ExportModelSettings m_exportModelSettingsInstance;
public ExportModelSettings ExportModelSettingsInstance
{
get
{
if(m_exportModelSettingsInstance == null)
{
// make a copy of the settings
m_exportModelSettingsInstance = ScriptableObject.CreateInstance(typeof(ExportModelSettings)) as ExportModelSettings;
// load settings stored in Unity session, default to DefaultPreset, if none then Export Settings
var defaultPresets = Preset.GetDefaultPresetsForObject(m_exportModelSettingsInstance);
if (defaultPresets.Length <= 0)
{
RestoreSettingsFromSession(ExportSettings.instance.ExportModelSettings.info);
}
else
{
// apply the first default preset
// TODO: figure out what it means to have multiple default presets, when would they be applied?
defaultPresets[0].ApplyTo(m_exportModelSettingsInstance);
RestoreSettingsFromSession(m_exportModelSettingsInstance.info);
}
}
return m_exportModelSettingsInstance;
}
}
public override void SaveExportSettings()
{
// check if the settings are different from what is in the Project Settings and only store
// if they are. Otherwise we want to keep them updated with changes to the Project Settings.
bool settingsChanged = !(ExportModelSettingsInstance.Equals(ExportSettings.instance.ExportModelSettings));
var projectSettingsPaths = ExportSettings.instance.GetCopyOfFbxSavePaths();
settingsChanged |= !projectSettingsPaths.SequenceEqual(FbxSavePaths);
settingsChanged |= SelectedFbxPath != ExportSettings.instance.SelectedFbxPath;
if (settingsChanged)
{
StoreSettingsInSession();
}
}
protected override ExportOptionsSettingsSerializeBase SettingsObject
{
get { return ExportModelSettingsInstance.info; }
}
private ExportSettings.Include m_previousInclude = ExportSettings.Include.ModelAndAnim;
public static ExportModelEditorWindow Init (IEnumerable<UnityEngine.Object> toExport, string filename = "", bool isTimelineAnim = false)
{
ExportModelEditorWindow window = CreateWindow<ExportModelEditorWindow> ();
window.IsTimelineAnim = isTimelineAnim;
int numObjects = window.SetGameObjectsToExport (toExport);
if (string.IsNullOrEmpty (filename)) {
filename = window.DefaultFilename;
}
window.InitializeWindow (filename);
window.SingleHierarchyExport = (numObjects == 1);
window.Show ();
return window;
}
protected int SetGameObjectsToExport(IEnumerable<UnityEngine.Object> toExport){
SetToExport(toExport.ToArray ());
if (GetToExport().Length==0) return 0;
TransferAnimationSource = null;
TransferAnimationDest = null;
// if only one object selected, set transfer source/dest to this object
if (GetToExport().Length == 1 || (IsTimelineAnim && GetToExport().Length > 0))
{
GameObject go = FirstGameObjectToExport;
if (go)
{
TransferAnimationSource = go.transform;
TransferAnimationDest = go.transform;
}
}
return GetToExport().Length;
}
/// <summary>
/// Gets the filename from objects to export.
/// </summary>
/// <returns>The object's name if one object selected, "Untitled" if multiple
/// objects selected for export.</returns>
protected string DefaultFilename {
get
{
var filename = "";
if (GetToExport().Length == 1)
{
filename = GetToExport()[0].name;
}
else
{
filename = "Untitled";
}
return filename;
}
}
protected override void OnEnable ()
{
base.OnEnable ();
if (!InnerEditor) {
InnerEditor = UnityEditor.Editor.CreateEditor (ExportModelSettingsInstance);
this.SingleHierarchyExport = m_singleHierarchyExport;
this.IsTimelineAnim = m_isTimelineAnim;
}
}
protected void OnDisable()
{
RestoreSettings ();
}
/// <summary>
/// Restore changed export settings after export
/// </summary>
protected virtual void RestoreSettings()
{
if (IsTimelineAnim) {
ExportModelSettingsInstance.info.SetModelAnimIncludeOption(m_previousInclude);
}
}
[SecurityPermission(SecurityAction.LinkDemand)]
protected override bool Export(){
if (string.IsNullOrEmpty (ExportFileName)) {
Debug.LogError ("FbxExporter: Please specify an fbx filename");
return false;
}
var folderPath = ExportSettings.GetAbsoluteSavePath(FbxSavePaths[SelectedFbxPath]);
var filePath = System.IO.Path.Combine (folderPath, ExportFileName + ".fbx");
if (!OverwriteExistingFile (filePath)) {
return false;
}
if (ModelExporter.ExportObjects (filePath, GetToExport(), SettingsObject) != null) {
// refresh the asset database so that the file appears in the
// asset folder view.
AssetDatabase.Refresh ();
}
return true;
}
#if UNITY_2018_1_OR_NEWER
protected override void ShowPresetReceiver ()
{
ShowPresetReceiver (ExportModelSettingsInstance);
}
#endif
}
}