diff --git a/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs b/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs index 96b10e3b..f86678b5 100644 --- a/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs +++ b/3ds Max/Max2Babylon/Forms/ExporterForm.Designer.cs @@ -31,7 +31,7 @@ private void InitializeComponent() this.components = new System.ComponentModel.Container(); this.butExport = new System.Windows.Forms.Button(); this.label1 = new System.Windows.Forms.Label(); - this.txtModelName = new System.Windows.Forms.RichTextBox(); + this.txtModelPath = new System.Windows.Forms.RichTextBox(); this.butModelBrowse = new System.Windows.Forms.Button(); this.saveFileDialog = new System.Windows.Forms.SaveFileDialog(); this.progressBar = new System.Windows.Forms.ProgressBar(); @@ -56,7 +56,7 @@ private void InitializeComponent() this.btnEnvBrowse = new System.Windows.Forms.Button(); this.chkNoAutoLight = new System.Windows.Forms.CheckBox(); this.textureLabel = new System.Windows.Forms.Label(); - this.txtTextureName = new System.Windows.Forms.RichTextBox(); + this.txtTexturesPath = new System.Windows.Forms.RichTextBox(); this.btnTxtBrowse = new System.Windows.Forms.Button(); this.chkExportMaterials = new System.Windows.Forms.CheckBox(); this.chkKHRMaterialsUnlit = new System.Windows.Forms.CheckBox(); @@ -108,32 +108,32 @@ private void InitializeComponent() // label1 // this.label1.AutoSize = true; - this.label1.Location = new System.Drawing.Point(6, 17); + this.label1.Location = new System.Drawing.Point(11, 51); this.label1.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label1.Name = "label1"; - this.label1.Size = new System.Drawing.Size(68, 13); + this.label1.Size = new System.Drawing.Size(63, 13); this.label1.TabIndex = 1; - this.label1.Text = "Model name:"; + this.label1.Text = "Model path:"; // - // txtModelName + // txtModelPath // - this.txtModelName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.txtModelPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.txtModelName.Location = new System.Drawing.Point(86, 14); - this.txtModelName.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.txtModelName.Multiline = false; - this.txtModelName.Name = "txtModelName"; - this.txtModelName.Size = new System.Drawing.Size(708, 20); - this.txtModelName.TabIndex = 2; - this.txtModelName.Text = ""; - this.txtModelName.TextChanged += new System.EventHandler(this.txtFilename_TextChanged); - this.txtModelName.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ExporterForm_KeyDown); + this.txtModelPath.Location = new System.Drawing.Point(91, 48); + this.txtModelPath.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtModelPath.Multiline = false; + this.txtModelPath.Name = "txtModelPath"; + this.txtModelPath.Size = new System.Drawing.Size(708, 20); + this.txtModelPath.TabIndex = 2; + this.txtModelPath.Text = ""; + this.txtModelPath.TextChanged += new System.EventHandler(this.txtFilename_TextChanged); + this.txtModelPath.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ExporterForm_KeyDown); // // butModelBrowse // this.butModelBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.butModelBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.butModelBrowse.Location = new System.Drawing.Point(800, 12); + this.butModelBrowse.Location = new System.Drawing.Point(805, 46); this.butModelBrowse.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.butModelBrowse.Name = "butModelBrowse"; this.butModelBrowse.Size = new System.Drawing.Size(28, 23); @@ -243,7 +243,7 @@ private void InitializeComponent() this.groupBox1.Controls.Add(this.btnEnvBrowse); this.groupBox1.Controls.Add(this.chkNoAutoLight); this.groupBox1.Controls.Add(this.textureLabel); - this.groupBox1.Controls.Add(this.txtTextureName); + this.groupBox1.Controls.Add(this.txtTexturesPath); this.groupBox1.Controls.Add(this.btnTxtBrowse); this.groupBox1.Controls.Add(this.chkExportMaterials); this.groupBox1.Controls.Add(this.chkKHRMaterialsUnlit); @@ -268,7 +268,7 @@ private void InitializeComponent() this.groupBox1.Controls.Add(this.chkHidden); this.groupBox1.Controls.Add(this.label1); this.groupBox1.Controls.Add(this.chkWriteTextures); - this.groupBox1.Controls.Add(this.txtModelName); + this.groupBox1.Controls.Add(this.txtModelPath); this.groupBox1.Controls.Add(this.chkManifest); this.groupBox1.Controls.Add(this.butModelBrowse); this.groupBox1.Controls.Add(this.label2); @@ -445,30 +445,30 @@ private void InitializeComponent() // textureLabel // this.textureLabel.AutoSize = true; - this.textureLabel.Location = new System.Drawing.Point(6, 43); + this.textureLabel.Location = new System.Drawing.Point(11, 83); this.textureLabel.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.textureLabel.Name = "textureLabel"; - this.textureLabel.Size = new System.Drawing.Size(75, 13); + this.textureLabel.Size = new System.Drawing.Size(76, 13); this.textureLabel.TabIndex = 24; - this.textureLabel.Text = "Texture folder:"; + this.textureLabel.Text = "Textures Path:"; // - // txtTextureName + // txtTexturesPath // - this.txtTextureName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + this.txtTexturesPath.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.txtTextureName.Location = new System.Drawing.Point(86, 40); - this.txtTextureName.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); - this.txtTextureName.Multiline = false; - this.txtTextureName.Name = "txtTextureName"; - this.txtTextureName.Size = new System.Drawing.Size(708, 20); - this.txtTextureName.TabIndex = 25; - this.txtTextureName.Text = ""; + this.txtTexturesPath.Location = new System.Drawing.Point(91, 80); + this.txtTexturesPath.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); + this.txtTexturesPath.Multiline = false; + this.txtTexturesPath.Name = "txtTexturesPath"; + this.txtTexturesPath.Size = new System.Drawing.Size(708, 20); + this.txtTexturesPath.TabIndex = 25; + this.txtTexturesPath.Text = ""; // // btnTxtBrowse // this.btnTxtBrowse.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnTxtBrowse.FlatStyle = System.Windows.Forms.FlatStyle.Flat; - this.btnTxtBrowse.Location = new System.Drawing.Point(800, 38); + this.btnTxtBrowse.Location = new System.Drawing.Point(805, 78); this.btnTxtBrowse.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.btnTxtBrowse.Name = "btnTxtBrowse"; this.btnTxtBrowse.Size = new System.Drawing.Size(28, 23); @@ -595,7 +595,7 @@ private void InitializeComponent() // // txtQuality // - this.txtQuality.Location = new System.Drawing.Point(403, 92); + this.txtQuality.Location = new System.Drawing.Point(786, 151); this.txtQuality.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.txtQuality.Name = "txtQuality"; this.txtQuality.Size = new System.Drawing.Size(43, 20); @@ -607,7 +607,7 @@ private void InitializeComponent() // labelQuality // this.labelQuality.AutoSize = true; - this.labelQuality.Location = new System.Drawing.Point(319, 94); + this.labelQuality.Location = new System.Drawing.Point(702, 153); this.labelQuality.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.labelQuality.Name = "labelQuality"; this.labelQuality.Size = new System.Drawing.Size(79, 13); @@ -658,7 +658,7 @@ private void InitializeComponent() // label4 // this.label4.AutoSize = true; - this.label4.Location = new System.Drawing.Point(331, 70); + this.label4.Location = new System.Drawing.Point(714, 129); this.label4.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label4.Name = "label4"; this.label4.Size = new System.Drawing.Size(67, 13); @@ -667,7 +667,7 @@ private void InitializeComponent() // // txtScaleFactor // - this.txtScaleFactor.Location = new System.Drawing.Point(403, 68); + this.txtScaleFactor.Location = new System.Drawing.Point(786, 127); this.txtScaleFactor.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.txtScaleFactor.Name = "txtScaleFactor"; this.txtScaleFactor.Size = new System.Drawing.Size(42, 20); @@ -679,7 +679,7 @@ private void InitializeComponent() // label3 // this.label3.AutoSize = true; - this.label3.Location = new System.Drawing.Point(6, 66); + this.label3.Location = new System.Drawing.Point(11, 18); this.label3.Margin = new System.Windows.Forms.Padding(4, 0, 4, 0); this.label3.Name = "label3"; this.label3.Size = new System.Drawing.Size(74, 13); @@ -694,7 +694,7 @@ private void InitializeComponent() "binary babylon", "gltf", "glb"}); - this.comboOutputFormat.Location = new System.Drawing.Point(86, 64); + this.comboOutputFormat.Location = new System.Drawing.Point(91, 16); this.comboOutputFormat.Margin = new System.Windows.Forms.Padding(4, 5, 4, 5); this.comboOutputFormat.Name = "comboOutputFormat"; this.comboOutputFormat.Size = new System.Drawing.Size(121, 21); @@ -854,7 +854,7 @@ private void InitializeComponent() private System.Windows.Forms.Button butExport; private System.Windows.Forms.Label label1; - private System.Windows.Forms.RichTextBox txtModelName; + private System.Windows.Forms.RichTextBox txtModelPath; private System.Windows.Forms.Button butModelBrowse; private System.Windows.Forms.SaveFileDialog saveFileDialog; private System.Windows.Forms.ProgressBar progressBar; @@ -887,7 +887,7 @@ private void InitializeComponent() private System.Windows.Forms.CheckBox chkExportMaterials; private System.Windows.Forms.Button saveOptionBtn; private System.Windows.Forms.Label textureLabel; - private System.Windows.Forms.RichTextBox txtTextureName; + private System.Windows.Forms.RichTextBox txtTexturesPath; private System.Windows.Forms.Button btnTxtBrowse; private System.Windows.Forms.Label label5; private System.Windows.Forms.Label label7; diff --git a/3ds Max/Max2Babylon/Forms/ExporterForm.cs b/3ds Max/Max2Babylon/Forms/ExporterForm.cs index 1ab85390..c5e29975 100644 --- a/3ds Max/Max2Babylon/Forms/ExporterForm.cs +++ b/3ds Max/Max2Babylon/Forms/ExporterForm.cs @@ -1,145 +1,145 @@ -using Autodesk.Max; -using BabylonExport.Entities; -using System; -using System.Diagnostics; -using System.IO; -using System.Threading.Tasks; -using System.Windows.Forms; -using Utilities; -using Color = System.Drawing.Color; -using Microsoft.WindowsAPICodePack.Dialogs; -using System.Collections.Generic; -using System.Linq; - -namespace Max2Babylon -{ - public partial class ExporterForm : Form - { - private const string ModelFilePathProperty = "modelFilePathProperty"; - private const string TextureFolderPathProperty = "textureFolderPathProperty"; - - private readonly BabylonExportActionItem babylonExportAction; - private BabylonExporter exporter; - private bool gltfPipelineInstalled = true; // true if the gltf-pipeline is installed and runnable. - - TreeNode currentNode; - int currentRank; - - private ExportItem singleExportItem; - - - private bool filePostOpenCallback = false; - private GlobalDelegates.Delegate5 m_FilePostOpenDelegate; - - private void RegisterFilePreOpen() - { - if (!filePostOpenCallback) - { - m_FilePostOpenDelegate = new GlobalDelegates.Delegate5(OnFilePostOpen); - GlobalInterface.Instance.RegisterNotification(this.m_FilePostOpenDelegate, null, SystemNotificationCode.FilePostOpen ); - - filePostOpenCallback = true; - } - } - - private void OnFilePostOpen(IntPtr param0, IntPtr param1) - { - LoadOptions(); - } - - private void OnFilePostOpen(IntPtr param0, INotifyInfo param1) - { - LoadOptions(); - } - - public ExporterForm(BabylonExportActionItem babylonExportAction) - { - InitializeComponent(); - RegisterFilePreOpen(); - - - this.Text = $"Babylon.js - Export scene to babylon or glTF format v{BabylonExporter.exporterVersion}"; - - this.babylonExportAction = babylonExportAction; - - // Check if the gltf-pipeline module is installed - try - { - Process gltfPipeline = new Process(); - gltfPipeline.StartInfo.FileName = "gltf-pipeline.cmd"; - - // Hide the cmd window that show the gltf-pipeline result - gltfPipeline.StartInfo.UseShellExecute = false; - gltfPipeline.StartInfo.CreateNoWindow = true; - - gltfPipeline.Start(); - gltfPipeline.WaitForExit(); - } - catch - { - gltfPipelineInstalled = false; - } - - groupBox1.MouseMove += groupBox1_MouseMove; - } - - private void LoadOptions() - { - string storedModelPath = Loader.Core.RootNode.GetStringProperty(ExportParameters.ModelFilePathProperty, string.Empty); - string absoluteModelPath = Tools.ResolveRelativePath(storedModelPath); - txtModelName.MaxPath(absoluteModelPath); - - string storedFolderPath = Loader.Core.RootNode.GetStringProperty(ExportParameters.TextureFolderPathProperty, string.Empty); - string absoluteTexturesFolderPath = Tools.ResolveRelativePath(storedFolderPath); - txtTextureName.MaxPath(absoluteTexturesFolderPath); - - singleExportItem = new ExportItem(absoluteModelPath); - - Tools.PrepareCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest"); - Tools.PrepareCheckBox(chkWriteTextures, Loader.Core.RootNode, "babylonjs_writetextures", 1); - Tools.PrepareCheckBox(chkOverwriteTextures, Loader.Core.RootNode, "babylonjs_overwritetextures", 1); - Tools.PrepareCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden"); - Tools.PrepareCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave", 1); - Tools.PrepareCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected"); - Tools.PrepareCheckBox(chkExportTangents, Loader.Core.RootNode, "babylonjs_exporttangents"); - Tools.PrepareComboBox(comboOutputFormat, Loader.Core.RootNode, "babylonjs_outputFormat", "babylon"); - Tools.PrepareTextBox(txtScaleFactor, Loader.Core.RootNode, "babylonjs_txtScaleFactor", "1"); - Tools.PrepareTextBox(txtQuality, Loader.Core.RootNode, "babylonjs_txtCompression", "100"); - Tools.PrepareCheckBox(chkMergeAOwithMR, Loader.Core.RootNode, "babylonjs_mergeAOwithMR", 1); - Tools.PrepareCheckBox(chkDracoCompression, Loader.Core.RootNode, "babylonjs_dracoCompression", 0); - Tools.PrepareCheckBox(chkKHRLightsPunctual, Loader.Core.RootNode, "babylonjs_khrLightsPunctual"); - Tools.PrepareCheckBox(chkKHRTextureTransform, Loader.Core.RootNode, "babylonjs_khrTextureTransform"); - Tools.PrepareCheckBox(chkAnimgroupExportNonAnimated, Loader.Core.RootNode, "babylonjs_animgroupexportnonanimated"); - Tools.PrepareCheckBox(chkDoNotOptimizeAnimations, Loader.Core.RootNode, "babylonjs_donotoptimizeanimations"); - Tools.PrepareCheckBox(chkKHRMaterialsUnlit, Loader.Core.RootNode, "babylonjs_khr_materials_unlit"); - Tools.PrepareCheckBox(chkExportMaterials, Loader.Core.RootNode, "babylonjs_export_materials", 1); - Tools.PrepareCheckBox(chkExportMorphTangents, Loader.Core.RootNode, "babylonjs_export_Morph_Tangents", 0); - Tools.PrepareCheckBox(chkExportMorphNormals, Loader.Core.RootNode, "babylonjs_export_Morph_Normals", 1); - Tools.PrepareComboBox(cmbBakeAnimationOptions, Loader.Core.RootNode, "babylonjs_bakeAnimationsType", (int)BakeAnimationType.DoNotBakeAnimation); - Tools.PrepareCheckBox(chkApplyPreprocessToScene, Loader.Core.RootNode, "babylonjs_applyPreprocess", 0); - - if (comboOutputFormat.SelectedText == "babylon" || comboOutputFormat.SelectedText == "binary babylon" || !gltfPipelineInstalled) - { - chkDracoCompression.Checked = false; - chkDracoCompression.Enabled = false; - } - - Tools.PrepareCheckBox(chkFullPBR, Loader.Core.RootNode, ExportParameters.PBRFullPropertyName); - Tools.PrepareCheckBox(chkNoAutoLight, Loader.Core.RootNode, ExportParameters.PBRNoLightPropertyName); - string storedEnvironmentPath = Loader.Core.RootNode.GetStringProperty(ExportParameters.PBREnvironmentPathPropertyName, string.Empty); - string absoluteEnvironmentPath = Tools.ResolveRelativePath(storedEnvironmentPath); - txtEnvironmentName.MaxPath(absoluteEnvironmentPath); - - Tools.PrepareCheckBox(chkUsePreExportProces, Loader.Core.RootNode, "babylonjs_preproces", 0); - Tools.PrepareCheckBox(chkFlatten, Loader.Core.RootNode, "babylonjs_flattenScene", 0); - Tools.PrepareCheckBox(chkMrgContainersAndXref, Loader.Core.RootNode, "babylonjs_mergecontainersandxref", 0); - } - - private void ExporterForm_Load(object sender, EventArgs e) - { - LoadOptions(); - - var maxVersion = Tools.GetMaxVersion(); +using Autodesk.Max; +using BabylonExport.Entities; +using System; +using System.Diagnostics; +using System.IO; +using System.Threading.Tasks; +using System.Windows.Forms; +using Utilities; +using Color = System.Drawing.Color; +using Microsoft.WindowsAPICodePack.Dialogs; +using System.Collections.Generic; +using System.Linq; + +namespace Max2Babylon +{ + public partial class ExporterForm : Form + { + private const string ModelFilePathProperty = "modelFilePathProperty"; + private const string TextureFolderPathProperty = "textureFolderPathProperty"; + + private readonly BabylonExportActionItem babylonExportAction; + private BabylonExporter exporter; + private bool gltfPipelineInstalled = true; // true if the gltf-pipeline is installed and runnable. + + TreeNode currentNode; + int currentRank; + + private ExportItem singleExportItem; + + + private bool filePostOpenCallback = false; + private GlobalDelegates.Delegate5 m_FilePostOpenDelegate; + + private void RegisterFilePreOpen() + { + if (!filePostOpenCallback) + { + m_FilePostOpenDelegate = new GlobalDelegates.Delegate5(OnFilePostOpen); + GlobalInterface.Instance.RegisterNotification(this.m_FilePostOpenDelegate, null, SystemNotificationCode.FilePostOpen ); + + filePostOpenCallback = true; + } + } + + private void OnFilePostOpen(IntPtr param0, IntPtr param1) + { + LoadOptions(); + } + + private void OnFilePostOpen(IntPtr param0, INotifyInfo param1) + { + LoadOptions(); + } + + public ExporterForm(BabylonExportActionItem babylonExportAction) + { + InitializeComponent(); + RegisterFilePreOpen(); + + + this.Text = $"Babylon.js - Export scene to babylon or glTF format v{BabylonExporter.exporterVersion}"; + + this.babylonExportAction = babylonExportAction; + + // Check if the gltf-pipeline module is installed + try + { + Process gltfPipeline = new Process(); + gltfPipeline.StartInfo.FileName = "gltf-pipeline.cmd"; + + // Hide the cmd window that show the gltf-pipeline result + gltfPipeline.StartInfo.UseShellExecute = false; + gltfPipeline.StartInfo.CreateNoWindow = true; + + gltfPipeline.Start(); + gltfPipeline.WaitForExit(); + } + catch + { + gltfPipelineInstalled = false; + } + + groupBox1.MouseMove += groupBox1_MouseMove; + } + + private void LoadOptions() + { + string storedModelPath = Loader.Core.RootNode.GetStringProperty(ExportParameters.ModelFilePathProperty, string.Empty); + string absoluteModelPath = Tools.ResolveRelativePath(storedModelPath); + txtModelPath.MaxPath(absoluteModelPath); + + string storedFolderPath = Loader.Core.RootNode.GetStringProperty(ExportParameters.TextureFolderPathProperty, string.Empty); + string absoluteTexturesFolderPath = Tools.ResolveRelativePath(storedFolderPath); + txtTexturesPath.MaxPath(absoluteTexturesFolderPath); + + singleExportItem = new ExportItem(absoluteModelPath); + + Tools.PrepareCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest"); + Tools.PrepareCheckBox(chkWriteTextures, Loader.Core.RootNode, "babylonjs_writetextures", 1); + Tools.PrepareCheckBox(chkOverwriteTextures, Loader.Core.RootNode, "babylonjs_overwritetextures", 1); + Tools.PrepareCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden"); + Tools.PrepareCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave", 1); + Tools.PrepareCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected"); + Tools.PrepareCheckBox(chkExportTangents, Loader.Core.RootNode, "babylonjs_exporttangents"); + Tools.PrepareComboBox(comboOutputFormat, Loader.Core.RootNode, "babylonjs_outputFormat", "babylon"); + Tools.PrepareTextBox(txtScaleFactor, Loader.Core.RootNode, "babylonjs_txtScaleFactor", "1"); + Tools.PrepareTextBox(txtQuality, Loader.Core.RootNode, "babylonjs_txtCompression", "100"); + Tools.PrepareCheckBox(chkMergeAOwithMR, Loader.Core.RootNode, "babylonjs_mergeAOwithMR", 1); + Tools.PrepareCheckBox(chkDracoCompression, Loader.Core.RootNode, "babylonjs_dracoCompression", 0); + Tools.PrepareCheckBox(chkKHRLightsPunctual, Loader.Core.RootNode, "babylonjs_khrLightsPunctual"); + Tools.PrepareCheckBox(chkKHRTextureTransform, Loader.Core.RootNode, "babylonjs_khrTextureTransform"); + Tools.PrepareCheckBox(chkAnimgroupExportNonAnimated, Loader.Core.RootNode, "babylonjs_animgroupexportnonanimated"); + Tools.PrepareCheckBox(chkDoNotOptimizeAnimations, Loader.Core.RootNode, "babylonjs_donotoptimizeanimations"); + Tools.PrepareCheckBox(chkKHRMaterialsUnlit, Loader.Core.RootNode, "babylonjs_khr_materials_unlit"); + Tools.PrepareCheckBox(chkExportMaterials, Loader.Core.RootNode, "babylonjs_export_materials", 1); + Tools.PrepareCheckBox(chkExportMorphTangents, Loader.Core.RootNode, "babylonjs_export_Morph_Tangents", 0); + Tools.PrepareCheckBox(chkExportMorphNormals, Loader.Core.RootNode, "babylonjs_export_Morph_Normals", 1); + Tools.PrepareComboBox(cmbBakeAnimationOptions, Loader.Core.RootNode, "babylonjs_bakeAnimationsType", (int)BakeAnimationType.DoNotBakeAnimation); + Tools.PrepareCheckBox(chkApplyPreprocessToScene, Loader.Core.RootNode, "babylonjs_applyPreprocess", 0); + + if (comboOutputFormat.SelectedText == "babylon" || comboOutputFormat.SelectedText == "binary babylon" || !gltfPipelineInstalled) + { + chkDracoCompression.Checked = false; + chkDracoCompression.Enabled = false; + } + + Tools.PrepareCheckBox(chkFullPBR, Loader.Core.RootNode, ExportParameters.PBRFullPropertyName); + Tools.PrepareCheckBox(chkNoAutoLight, Loader.Core.RootNode, ExportParameters.PBRNoLightPropertyName); + string storedEnvironmentPath = Loader.Core.RootNode.GetStringProperty(ExportParameters.PBREnvironmentPathPropertyName, string.Empty); + string absoluteEnvironmentPath = Tools.ResolveRelativePath(storedEnvironmentPath); + txtEnvironmentName.MaxPath(absoluteEnvironmentPath); + + Tools.PrepareCheckBox(chkUsePreExportProces, Loader.Core.RootNode, "babylonjs_preproces", 0); + Tools.PrepareCheckBox(chkFlatten, Loader.Core.RootNode, "babylonjs_flattenScene", 0); + Tools.PrepareCheckBox(chkMrgContainersAndXref, Loader.Core.RootNode, "babylonjs_mergecontainersandxref", 0); + } + + private void ExporterForm_Load(object sender, EventArgs e) + { + LoadOptions(); + + var maxVersion = Tools.GetMaxVersion(); if (maxVersion.Major == 22 && maxVersion.Minor < 2) { CreateErrorMessage("You must update 3dsMax 2020 to version 2020.2 to use Max2Babylon. Unpatched versions of 3dsMax will crash during export.", 0); @@ -147,347 +147,358 @@ private void ExporterForm_Load(object sender, EventArgs e) else { CreateMessage(String.Format("Using Max2Babylon for 3dsMax version v{0}.{1}.{2}.{3}", maxVersion.Major, maxVersion.Minor, maxVersion.Revision, maxVersion.BuildNumber), Color.Black, 0, true); - } - } - - private void butModelBrowse_Click(object sender, EventArgs e) - { - if (!string.IsNullOrEmpty(txtModelName.Text)) - { - string intialDirectory = Path.GetDirectoryName(txtModelName.Text); - - if (!Directory.Exists(intialDirectory)) - { - intialDirectory = Loader.Core.GetDir((int)MaxDirectory.ProjectFolder); - } - - if (!Directory.Exists(intialDirectory)) - { - intialDirectory = null; - } - - saveFileDialog.InitialDirectory = intialDirectory; - } - - if (saveFileDialog.ShowDialog(this) == DialogResult.OK) - { - txtModelName.MaxPath(saveFileDialog.FileName); - } - } - - private void btnTextureBrowse_Click(object sender, EventArgs e) - { - if (string.IsNullOrWhiteSpace(txtModelName.Text)) - { - MessageBox.Show("Select model file path first"); - return; - } - - CommonOpenFileDialog dialog = new CommonOpenFileDialog(); - - string intialDirectory = txtTextureName.Text; - - if (!Directory.Exists(intialDirectory)) - { - intialDirectory = Path.GetDirectoryName(txtModelName.Text); - } - - if (!Directory.Exists(intialDirectory)) - { - intialDirectory = Loader.Core.GetDir((int)MaxDirectory.ProjectFolder); - } - - if (!Directory.Exists(intialDirectory)) - { - intialDirectory = null; - } - - dialog.InitialDirectory = intialDirectory; - dialog.IsFolderPicker = true; - - if (dialog.ShowDialog() == CommonFileDialogResult.Ok) - { - string selectedFolderPath = dialog.FileName; - string absoluteModelPath = txtModelName.Text; - - if (!PathUtilities.IsBelowPath(selectedFolderPath, absoluteModelPath)) - { - MessageBox.Show("WARNING: folderPath should be below model file path"); - } - - txtTextureName.MaxPath(selectedFolderPath); - } - } - - private void btnEnvBrowse_Click(object sender, EventArgs e) - { - if (!string.IsNullOrEmpty(txtEnvironmentName.Text)) - { - string intialDirectory = Path.GetDirectoryName(txtEnvironmentName.Text); - - if (!Directory.Exists(intialDirectory)) - { - intialDirectory = Loader.Core.GetDir((int)MaxDirectory.ProjectFolder); - } - - if (!Directory.Exists(intialDirectory)) - { - intialDirectory = null; - } - - envFileDialog.InitialDirectory = intialDirectory; - } - - if (envFileDialog.ShowDialog() == DialogResult.OK) - { - txtEnvironmentName.MaxPath(envFileDialog.FileName); - } - } - - private async void butExport_Click(object sender, EventArgs e) - { - try - { - if (chkUsePreExportProces.Checked) - { - Loader.Core.FileHold(); - } - - await DoExport(singleExportItem); - } - catch{} - finally - { - if (chkUsePreExportProces.Checked && !chkApplyPreprocessToScene.Checked) - { - Loader.Core.SetQuietMode(true); - Loader.Core.FileFetch(); - Loader.Core.SetQuietMode(false); - } - } - } - - private async Task DoExport(ExportItemList exportItemList) - { - treeView.Nodes.Clear(); - - bool allSucceeded = true; - foreach (ExportItem item in exportItemList) - { - if (!item.Selected) continue; - - allSucceeded = allSucceeded && await DoExport(item, true, false); - - if (exporter.IsCancelled) - break; - } - - return allSucceeded; - } - - private void saveOptionBtn_Click(object sender, EventArgs e) - { - SaveOptions(); - } - - private void SaveOptions() - { - Tools.UpdateCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest"); - Tools.UpdateCheckBox(chkWriteTextures, Loader.Core.RootNode, "babylonjs_writetextures"); - Tools.UpdateCheckBox(chkOverwriteTextures, Loader.Core.RootNode, "babylonjs_overwritetextures"); - Tools.UpdateCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden"); - Tools.UpdateCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave"); - Tools.UpdateCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected"); - Tools.UpdateCheckBox(chkExportTangents, Loader.Core.RootNode, "babylonjs_exporttangents"); - Tools.UpdateComboBox(comboOutputFormat, Loader.Core.RootNode, "babylonjs_outputFormat"); - Tools.UpdateTextBox(txtScaleFactor, Loader.Core.RootNode, "babylonjs_txtScaleFactor"); - Tools.UpdateTextBox(txtQuality, Loader.Core.RootNode, "babylonjs_txtCompression"); - Tools.UpdateCheckBox(chkMergeAOwithMR, Loader.Core.RootNode, "babylonjs_mergeAOwithMR"); - Tools.UpdateCheckBox(chkDracoCompression, Loader.Core.RootNode, "babylonjs_dracoCompression"); - Tools.UpdateCheckBox(chkKHRTextureTransform, Loader.Core.RootNode, "babylonjs_khrTextureTransform"); - Tools.UpdateCheckBox(chkKHRLightsPunctual, Loader.Core.RootNode, "babylonjs_khrLightsPunctual"); - Tools.UpdateCheckBox(chkKHRMaterialsUnlit, Loader.Core.RootNode, "babylonjs_khr_materials_unlit"); - Tools.UpdateCheckBox(chkExportMaterials, Loader.Core.RootNode, "babylonjs_export_materials"); - Tools.UpdateCheckBox(chkAnimgroupExportNonAnimated, Loader.Core.RootNode, "babylonjs_animgroupexportnonanimated"); - Tools.UpdateCheckBox(chkDoNotOptimizeAnimations, Loader.Core.RootNode, "babylonjs_donotoptimizeanimations"); - Tools.UpdateCheckBox(chkExportMorphTangents, Loader.Core.RootNode, "babylonjs_export_Morph_Tangents"); - Tools.UpdateCheckBox(chkExportMorphNormals, Loader.Core.RootNode, "babylonjs_export_Morph_Normals"); - Tools.UpdateComboBoxByIndex(cmbBakeAnimationOptions, Loader.Core.RootNode, "babylonjs_bakeAnimationsType"); - Tools.UpdateCheckBox(chkApplyPreprocessToScene,Loader.Core.RootNode, "babylonjs_applyPreprocess"); - - Loader.Core.RootNode.SetStringProperty(ExportParameters.ModelFilePathProperty, Tools.RelativePathStore(txtModelName.Text)); - Loader.Core.RootNode.SetStringProperty(ExportParameters.TextureFolderPathProperty, Tools.RelativePathStore(txtTextureName.Text)); - - Tools.UpdateCheckBox(chkFullPBR, Loader.Core.RootNode, ExportParameters.PBRFullPropertyName); - Tools.UpdateCheckBox(chkNoAutoLight, Loader.Core.RootNode, ExportParameters.PBRNoLightPropertyName); - Loader.Core.RootNode.SetStringProperty(ExportParameters.PBREnvironmentPathPropertyName, Tools.RelativePathStore(txtEnvironmentName.Text)); - - Tools.UpdateCheckBox(chkUsePreExportProces, Loader.Core.RootNode, "babylonjs_preproces"); - Tools.UpdateCheckBox(chkFlatten, Loader.Core.RootNode, "babylonjs_flattenScene"); - Tools.UpdateCheckBox(chkMrgContainersAndXref, Loader.Core.RootNode, "babylonjs_mergecontainersandxref"); - } - - private async Task DoExport(ExportItem exportItem, bool multiExport = false, bool clearLogs = true) - { - new BabylonAnimationActionItem().Close(); - SaveOptions(); - - //store layer visibility status and force visibility on - - Dictionary layerState = new Dictionary(); - if (exportItem.Layers != null) - { - foreach (IILayer layer in exportItem.Layers) - { - List treeLayers = layer.LayerTree().ToList(); - treeLayers.Add(layer); - - foreach (IILayer l in treeLayers) - { -#if MAX2015 - layerState.Add( l, l.IsHidden); -#else - layerState.Add( l, l.IsHidden(false)); -#endif - l.Hide(false,false); - } - - } - } - - exporter = new BabylonExporter(); - - if (clearLogs) - treeView.Nodes.Clear(); - - exporter.OnImportProgressChanged += progress => - { - progressBar.Value = progress; - Application.DoEvents(); - }; - - exporter.OnWarning += (warning, rank) => CreateWarningMessage(warning, rank); - - exporter.OnError += (error, rank) => CreateErrorMessage(error, rank); - - exporter.OnMessage += (message, color, rank, emphasis) => CreateMessage(message, color, rank, emphasis); - - butExport.Enabled = false; - butExportAndRun.Enabled = false; - butMultiExport.Enabled = false; - butCancel.Enabled = true; - - bool success = true; - try - { - string modelAbsolutePath = multiExport ? exportItem.ExportFilePathAbsolute : txtModelName.Text; - string textureExportPath = multiExport ? exportItem.ExportTexturesesFolderPath : txtTextureName.Text; - - var scaleFactorParsed = 1.0f; - var textureQualityParsed = 100L; + } + } + + private void butModelBrowse_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(txtModelPath.Text)) + { + string intialDirectory = Path.GetDirectoryName(txtModelPath.Text); + + if (!Directory.Exists(intialDirectory)) + { + intialDirectory = Loader.Core.GetDir((int)MaxDirectory.ProjectFolder); + } + + if (!Directory.Exists(intialDirectory)) + { + intialDirectory = null; + } + + saveFileDialog.InitialDirectory = intialDirectory; + } + + if (saveFileDialog.ShowDialog(this) == DialogResult.OK) + { + txtModelPath.MaxPath(saveFileDialog.FileName); + if (string.IsNullOrWhiteSpace(txtTexturesPath.Text)) + { + string defaultTexturesDir = Path.GetDirectoryName(txtModelPath.Text); + txtTexturesPath.MaxPath(defaultTexturesDir); + } + + if (!PathUtilities.IsBelowPath(txtTexturesPath.Text, txtModelPath.Text)) + { + CreateWarningMessage("WARNING: textures path should be below model file path, not all client renderers support this feature", 0); + } + } + } + + private void btnTextureBrowse_Click(object sender, EventArgs e) + { + if (string.IsNullOrWhiteSpace(txtModelPath.Text)) + { + MessageBox.Show("Select model file path first"); + return; + } + + CommonOpenFileDialog dialog = new CommonOpenFileDialog(); + + string intialDirectory = txtTexturesPath.Text; + + if (!Directory.Exists(intialDirectory)) + { + intialDirectory = Path.GetDirectoryName(txtModelPath.Text); + } + + if (!Directory.Exists(intialDirectory)) + { + intialDirectory = Loader.Core.GetDir((int)MaxDirectory.ProjectFolder); + } + + if (!Directory.Exists(intialDirectory)) + { + intialDirectory = null; + } + + dialog.InitialDirectory = intialDirectory; + dialog.IsFolderPicker = true; + + if (dialog.ShowDialog() == CommonFileDialogResult.Ok) + { + string selectedFolderPath = dialog.FileName; + string absoluteModelPath = txtModelPath.Text; + + if (!PathUtilities.IsBelowPath(selectedFolderPath, absoluteModelPath)) + { + CreateWarningMessage("WARNING: textures path should be below model file path, not all client renderers support this feature",0); + } + + txtTexturesPath.MaxPath(selectedFolderPath); + } + } + + private void btnEnvBrowse_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(txtEnvironmentName.Text)) + { + string intialDirectory = Path.GetDirectoryName(txtEnvironmentName.Text); + + if (!Directory.Exists(intialDirectory)) + { + intialDirectory = Loader.Core.GetDir((int)MaxDirectory.ProjectFolder); + } + + if (!Directory.Exists(intialDirectory)) + { + intialDirectory = null; + } + + envFileDialog.InitialDirectory = intialDirectory; + } + + if (envFileDialog.ShowDialog() == DialogResult.OK) + { + txtEnvironmentName.MaxPath(envFileDialog.FileName); + } + } + + private async void butExport_Click(object sender, EventArgs e) + { + try + { + if (chkUsePreExportProces.Checked) + { + Loader.Core.FileHold(); + } + + await DoExport(singleExportItem); + } + catch{} + finally + { + if (chkUsePreExportProces.Checked && !chkApplyPreprocessToScene.Checked) + { + Loader.Core.SetQuietMode(true); + Loader.Core.FileFetch(); + Loader.Core.SetQuietMode(false); + } + } + } + + private async Task DoExport(ExportItemList exportItemList) + { + treeView.Nodes.Clear(); + + bool allSucceeded = true; + foreach (ExportItem item in exportItemList) + { + if (!item.Selected) continue; + + allSucceeded = allSucceeded && await DoExport(item, true, false); + + if (exporter.IsCancelled) + break; + } + + return allSucceeded; + } + + private void saveOptionBtn_Click(object sender, EventArgs e) + { + SaveOptions(); + } + + private void SaveOptions() + { + Tools.UpdateCheckBox(chkManifest, Loader.Core.RootNode, "babylonjs_generatemanifest"); + Tools.UpdateCheckBox(chkWriteTextures, Loader.Core.RootNode, "babylonjs_writetextures"); + Tools.UpdateCheckBox(chkOverwriteTextures, Loader.Core.RootNode, "babylonjs_overwritetextures"); + Tools.UpdateCheckBox(chkHidden, Loader.Core.RootNode, "babylonjs_exporthidden"); + Tools.UpdateCheckBox(chkAutoSave, Loader.Core.RootNode, "babylonjs_autosave"); + Tools.UpdateCheckBox(chkOnlySelected, Loader.Core.RootNode, "babylonjs_onlySelected"); + Tools.UpdateCheckBox(chkExportTangents, Loader.Core.RootNode, "babylonjs_exporttangents"); + Tools.UpdateComboBox(comboOutputFormat, Loader.Core.RootNode, "babylonjs_outputFormat"); + Tools.UpdateTextBox(txtScaleFactor, Loader.Core.RootNode, "babylonjs_txtScaleFactor"); + Tools.UpdateTextBox(txtQuality, Loader.Core.RootNode, "babylonjs_txtCompression"); + Tools.UpdateCheckBox(chkMergeAOwithMR, Loader.Core.RootNode, "babylonjs_mergeAOwithMR"); + Tools.UpdateCheckBox(chkDracoCompression, Loader.Core.RootNode, "babylonjs_dracoCompression"); + Tools.UpdateCheckBox(chkKHRTextureTransform, Loader.Core.RootNode, "babylonjs_khrTextureTransform"); + Tools.UpdateCheckBox(chkKHRLightsPunctual, Loader.Core.RootNode, "babylonjs_khrLightsPunctual"); + Tools.UpdateCheckBox(chkKHRMaterialsUnlit, Loader.Core.RootNode, "babylonjs_khr_materials_unlit"); + Tools.UpdateCheckBox(chkExportMaterials, Loader.Core.RootNode, "babylonjs_export_materials"); + Tools.UpdateCheckBox(chkAnimgroupExportNonAnimated, Loader.Core.RootNode, "babylonjs_animgroupexportnonanimated"); + Tools.UpdateCheckBox(chkDoNotOptimizeAnimations, Loader.Core.RootNode, "babylonjs_donotoptimizeanimations"); + Tools.UpdateCheckBox(chkExportMorphTangents, Loader.Core.RootNode, "babylonjs_export_Morph_Tangents"); + Tools.UpdateCheckBox(chkExportMorphNormals, Loader.Core.RootNode, "babylonjs_export_Morph_Normals"); + Tools.UpdateComboBoxByIndex(cmbBakeAnimationOptions, Loader.Core.RootNode, "babylonjs_bakeAnimationsType"); + Tools.UpdateCheckBox(chkApplyPreprocessToScene,Loader.Core.RootNode, "babylonjs_applyPreprocess"); + + Loader.Core.RootNode.SetStringProperty(ExportParameters.ModelFilePathProperty, Tools.RelativePathStore(txtModelPath.Text)); + Loader.Core.RootNode.SetStringProperty(ExportParameters.TextureFolderPathProperty, Tools.RelativePathStore(txtTexturesPath.Text)); + + Tools.UpdateCheckBox(chkFullPBR, Loader.Core.RootNode, ExportParameters.PBRFullPropertyName); + Tools.UpdateCheckBox(chkNoAutoLight, Loader.Core.RootNode, ExportParameters.PBRNoLightPropertyName); + Loader.Core.RootNode.SetStringProperty(ExportParameters.PBREnvironmentPathPropertyName, Tools.RelativePathStore(txtEnvironmentName.Text)); + + Tools.UpdateCheckBox(chkUsePreExportProces, Loader.Core.RootNode, "babylonjs_preproces"); + Tools.UpdateCheckBox(chkFlatten, Loader.Core.RootNode, "babylonjs_flattenScene"); + Tools.UpdateCheckBox(chkMrgContainersAndXref, Loader.Core.RootNode, "babylonjs_mergecontainersandxref"); + } + + private async Task DoExport(ExportItem exportItem, bool multiExport = false, bool clearLogs = true) + { + new BabylonAnimationActionItem().Close(); + SaveOptions(); + + //store layer visibility status and force visibility on + + Dictionary layerState = new Dictionary(); + if (exportItem.Layers != null) + { + foreach (IILayer layer in exportItem.Layers) + { + List treeLayers = layer.LayerTree().ToList(); + treeLayers.Add(layer); + + foreach (IILayer l in treeLayers) + { +#if MAX2015 + layerState.Add( l, l.IsHidden); +#else + layerState.Add( l, l.IsHidden(false)); +#endif + l.Hide(false,false); + } + + } + } + + exporter = new BabylonExporter(); + + if (clearLogs) + treeView.Nodes.Clear(); + + exporter.OnImportProgressChanged += progress => + { + progressBar.Value = progress; + Application.DoEvents(); + }; + + exporter.OnWarning += (warning, rank) => CreateWarningMessage(warning, rank); + + exporter.OnError += (error, rank) => CreateErrorMessage(error, rank); + + exporter.OnMessage += (message, color, rank, emphasis) => CreateMessage(message, color, rank, emphasis); + + butExport.Enabled = false; + butExportAndRun.Enabled = false; + butMultiExport.Enabled = false; + butCancel.Enabled = true; + + bool success = true; + try + { + string modelAbsolutePath = multiExport ? exportItem.ExportFilePathAbsolute : txtModelPath.Text; + string textureExportPath = multiExport ? exportItem.ExportTexturesesFolderPath : txtTexturesPath.Text; + + var scaleFactorParsed = 1.0f; + var textureQualityParsed = 100L; try { scaleFactorParsed = float.Parse(txtScaleFactor.Text); - } - catch (Exception e) + } + catch (Exception e) { throw new InvalidDataException(String.Format("Invalid Scale Factor value: {0}", txtScaleFactor.Text)); - } + } try { textureQualityParsed = long.Parse(txtQuality.Text); - } - catch (Exception e) + } + catch (Exception e) { throw new InvalidDataException(String.Format("Invalid Texture Quality value: {0}", txtScaleFactor.Text)); - } - MaxExportParameters exportParameters = new MaxExportParameters - { - outputPath = modelAbsolutePath, - textureFolder = textureExportPath, - outputFormat = comboOutputFormat.SelectedItem.ToString(), - scaleFactor = scaleFactorParsed, - writeTextures = chkWriteTextures.Checked, - overwriteTextures = chkOverwriteTextures.Checked, - exportHiddenObjects = chkHidden.Checked, - exportOnlySelected = chkOnlySelected.Checked, - generateManifest = chkManifest.Checked, - autoSaveSceneFile = chkAutoSave.Checked, - exportTangents = chkExportTangents.Checked, - exportMorphTangents = chkExportMorphTangents.Checked, - exportMorphNormals = chkExportMorphNormals.Checked, - txtQuality = textureQualityParsed, - mergeAOwithMR = chkMergeAOwithMR.Checked, - bakeAnimationType = (BakeAnimationType)cmbBakeAnimationOptions.SelectedIndex, - dracoCompression = chkDracoCompression.Checked, - enableKHRLightsPunctual = chkKHRLightsPunctual.Checked, - enableKHRTextureTransform = chkKHRTextureTransform.Checked, - enableKHRMaterialsUnlit = chkKHRMaterialsUnlit.Checked, - exportMaterials = chkExportMaterials.Checked, - optimizeAnimations = !chkDoNotOptimizeAnimations.Checked, - animgroupExportNonAnimated = chkAnimgroupExportNonAnimated.Checked, - exportNode = exportItem?.Node, - exportLayers = exportItem?.Layers, - pbrNoLight = chkNoAutoLight.Checked, - pbrFull = chkFullPBR.Checked, - pbrEnvironment = txtEnvironmentName.Text, - usePreExportProcess = chkUsePreExportProces.Checked, - flattenScene = chkFlatten.Checked, - mergeContainersAndXRef = chkMrgContainersAndXref.Checked, - useMultiExporter = multiExport - }; - - exporter.callerForm = this; - - exporter.Export(exportParameters); - } - catch (OperationCanceledException) - { - progressBar.Value = 0; - success = false; - } - catch (Exception ex) - { - IUTF8Str operationStatus = GlobalInterface.Instance.UTF8Str.Create("BabylonExportAborted"); - Loader.Global.BroadcastNotification(SystemNotificationCode.PreExport, operationStatus); - - currentNode = CreateTreeNode(0, "Export cancelled: " + ex.Message, Color.Red); - currentNode = CreateTreeNode(1, ex.ToString(), Color.Red); - currentNode.EnsureVisible(); - - progressBar.Value = 0; - success = false; - } - - butCancel.Enabled = false; - butExport.Enabled = true; - butMultiExport.Enabled = true; - butExportAndRun.Enabled = WebServer.IsSupported; - - BringToFront(); - - //re-store layer visibility status - if (exportItem.Layers != null) - { - foreach (IILayer layer in exportItem.Layers) - { - List treeLayers = layer.LayerTree().ToList(); - treeLayers.Add(layer); - foreach (IILayer l in treeLayers) - { - bool exist; - layerState.TryGetValue(l, out exist); - if (exist) - { - l.Hide(layerState[l], false); - } - } - } - } - - return success; - } - + } + + MaxExportParameters exportParameters = new MaxExportParameters + { + outputPath = modelAbsolutePath, + textureFolder = textureExportPath, + outputFormat = comboOutputFormat.SelectedItem.ToString(), + scaleFactor = scaleFactorParsed, + writeTextures = chkWriteTextures.Checked, + overwriteTextures = chkOverwriteTextures.Checked, + exportHiddenObjects = chkHidden.Checked, + exportOnlySelected = chkOnlySelected.Checked, + generateManifest = chkManifest.Checked, + autoSaveSceneFile = chkAutoSave.Checked, + exportTangents = chkExportTangents.Checked, + exportMorphTangents = chkExportMorphTangents.Checked, + exportMorphNormals = chkExportMorphNormals.Checked, + txtQuality = textureQualityParsed, + mergeAOwithMR = chkMergeAOwithMR.Checked, + bakeAnimationType = (BakeAnimationType)cmbBakeAnimationOptions.SelectedIndex, + dracoCompression = chkDracoCompression.Checked, + enableKHRLightsPunctual = chkKHRLightsPunctual.Checked, + enableKHRTextureTransform = chkKHRTextureTransform.Checked, + enableKHRMaterialsUnlit = chkKHRMaterialsUnlit.Checked, + exportMaterials = chkExportMaterials.Checked, + optimizeAnimations = !chkDoNotOptimizeAnimations.Checked, + animgroupExportNonAnimated = chkAnimgroupExportNonAnimated.Checked, + exportNode = exportItem?.Node, + exportLayers = exportItem?.Layers, + pbrNoLight = chkNoAutoLight.Checked, + pbrFull = chkFullPBR.Checked, + pbrEnvironment = txtEnvironmentName.Text, + usePreExportProcess = chkUsePreExportProces.Checked, + flattenScene = chkFlatten.Checked, + mergeContainersAndXRef = chkMrgContainersAndXref.Checked, + useMultiExporter = multiExport + }; + + exporter.callerForm = this; + + exporter.Export(exportParameters); + } + catch (OperationCanceledException) + { + progressBar.Value = 0; + success = false; + } + catch (Exception ex) + { + IUTF8Str operationStatus = GlobalInterface.Instance.UTF8Str.Create("BabylonExportAborted"); + Loader.Global.BroadcastNotification(SystemNotificationCode.PreExport, operationStatus); + + currentNode = CreateTreeNode(0, "Export cancelled: " + ex.Message, Color.Red); + currentNode = CreateTreeNode(1, ex.ToString(), Color.Red); + currentNode.EnsureVisible(); + + progressBar.Value = 0; + success = false; + } + + butCancel.Enabled = false; + butExport.Enabled = true; + butMultiExport.Enabled = true; + butExportAndRun.Enabled = WebServer.IsSupported; + + BringToFront(); + + //re-store layer visibility status + if (exportItem.Layers != null) + { + foreach (IILayer layer in exportItem.Layers) + { + List treeLayers = layer.LayerTree().ToList(); + treeLayers.Add(layer); + foreach (IILayer l in treeLayers) + { + bool exist; + layerState.TryGetValue(l, out exist); + if (exist) + { + l.Hide(layerState[l], false); + } + } + } + } + + return success; + } + void CreateWarningMessage(string warning, int rank) { try @@ -500,22 +511,22 @@ void CreateWarningMessage(string warning, int rank) //do nothing } Application.DoEvents(); - } - + } + void CreateErrorMessage(string error, int rank) - { - try - { - currentNode = CreateTreeNode(rank, error, Color.Red); - currentNode.EnsureVisible(); - } - catch - { - //do nothing - } + { + try + { + currentNode = CreateTreeNode(rank, error, Color.Red); + currentNode.EnsureVisible(); + } + catch + { + //do nothing + } Application.DoEvents(); - } - + } + void CreateMessage(string message, Color color, int rank, bool emphasis) { try @@ -532,284 +543,284 @@ void CreateMessage(string message, Color color, int rank, bool emphasis) //do nothing } Application.DoEvents(); - } - - private TreeNode CreateTreeNode(int rank, string text, Color color) - { - TreeNode newNode = null; - - Invoke(new Action(() => - { - newNode = new TreeNode(text) { ForeColor = color }; - if (rank < 0 || rank > currentRank + 1) - { - rank = 0; - treeView.Nodes.Add(new TreeNode("Invalid rank passed to CreateTreeNode (through RaiseMessage, RaiseWarning or RaiseError)!") { ForeColor = Color.DarkOrange }); - } - if (rank == 0) - { - treeView.Nodes.Add(newNode); - } - else if (rank == currentRank + 1) - { - currentNode.Nodes.Add(newNode); - } - else - { - var parentNode = currentNode; - while (currentRank != rank - 1) - { - parentNode = parentNode.Parent; - currentRank--; - } - parentNode.Nodes.Add(newNode); - } - - currentRank = rank; - })); - - return newNode; - } - - private void ExporterForm_FormClosed(object sender, FormClosedEventArgs e) - { - if (exporter != null) - { - exporter.IsCancelled = true; - } - babylonExportAction.Close(); - } - - private void txtFilename_TextChanged(object sender, EventArgs e) - { - butExport.Enabled = !string.IsNullOrEmpty(txtModelName.Text.Trim()); - butExportAndRun.Enabled = butExport.Enabled && WebServer.IsSupported; - } - - private void butCancel_Click(object sender, EventArgs e) - { - exporter.IsCancelled = true; - } - - private void ExporterForm_Activated(object sender, EventArgs e) - { - Loader.Global.DisableAccelerators(); - } - - private void ExporterForm_Deactivate(object sender, EventArgs e) - { - Loader.Global.EnableAccelerators(); - } - - private async void butExportAndRun_Click(object sender, EventArgs e) - { - try - { - if (chkUsePreExportProces.Checked) - { - Loader.Core.FileHold(); - } - - if (await DoExport(singleExportItem)) - { - WebServer.SceneFilename = Path.GetFileName(txtModelName.Text); - WebServer.SceneFolder = Path.GetDirectoryName(txtModelName.Text); - - Process.Start(WebServer.url + WebServer.SceneFilename); - - WindowState = FormWindowState.Minimized; - } - } - catch{} - finally - { - if (chkUsePreExportProces.Checked && !chkApplyPreprocessToScene.Checked) - { - Loader.Core.SetQuietMode(true); - Loader.Core.FileFetch(); - Loader.Core.SetQuietMode(false); - } - } - } - - private void butClose_Click(object sender, EventArgs e) - { - Close(); - } - - private void comboOutputFormat_SelectedIndexChanged(object sender, EventArgs e) - { - var outputFormat = comboOutputFormat.SelectedItem.ToString(); - switch (outputFormat) - { - case "babylon": - case "binary babylon": - this.saveFileDialog.DefaultExt = "babylon"; - this.saveFileDialog.Filter = "Babylon files|*.babylon"; - chkDracoCompression.Checked = false; - chkDracoCompression.Enabled = false; - chkWriteTextures.Enabled = true; - chkOverwriteTextures.Enabled = true; - txtTextureName.Text = string.Empty; - txtTextureName.Enabled = false; - textureLabel.Enabled = false; - btnTxtBrowse.Enabled = false; - chkNoAutoLight.Enabled = true; - chkFullPBR.Enabled = true; - btnEnvBrowse.Enabled = true; - txtEnvironmentName.Enabled = true; - chkKHRMaterialsUnlit.Enabled = false; - chkKHRLightsPunctual.Enabled = false; - chkKHRTextureTransform.Enabled = false; - break; - case "gltf": - this.saveFileDialog.DefaultExt = "gltf"; - this.saveFileDialog.Filter = "glTF files|*.gltf"; - chkDracoCompression.Enabled = gltfPipelineInstalled; - chkWriteTextures.Enabled = true; - chkOverwriteTextures.Enabled = true; - txtTextureName.Enabled = true; - textureLabel.Enabled = true; - btnTxtBrowse.Enabled = true; - chkNoAutoLight.Enabled = false; - chkNoAutoLight.Checked = false; - chkFullPBR.Enabled = false; - chkFullPBR.Checked = false; - btnEnvBrowse.Enabled = false; - txtEnvironmentName.Enabled = false; - txtEnvironmentName.Text = string.Empty; - chkKHRMaterialsUnlit.Enabled = true; - chkKHRLightsPunctual.Enabled = true; - chkKHRTextureTransform.Enabled = true; - break; - case "glb": - this.saveFileDialog.DefaultExt = "glb"; - this.saveFileDialog.Filter = "glb files|*.glb"; - chkDracoCompression.Enabled = gltfPipelineInstalled; - chkWriteTextures.Checked = true; - chkWriteTextures.Enabled = false; - chkOverwriteTextures.Checked = true; - chkOverwriteTextures.Enabled = false; - txtTextureName.Text = string.Empty; - txtTextureName.Enabled = false; - textureLabel.Enabled = false; - btnTxtBrowse.Enabled = false; - chkNoAutoLight.Enabled = false; - chkNoAutoLight.Checked = false; - chkFullPBR.Enabled = false; - chkFullPBR.Checked = false; - btnEnvBrowse.Enabled = false; - txtEnvironmentName.Enabled = false; - txtEnvironmentName.Text = string.Empty; - chkKHRMaterialsUnlit.Enabled = true; - chkKHRLightsPunctual.Enabled = true; - chkKHRTextureTransform.Enabled = true; - break; - } - - string newModelPath = Path.ChangeExtension(txtModelName.Text, this.saveFileDialog.DefaultExt); - this.txtModelName.MaxPath(newModelPath); - } - - /// - /// Show a toolTip when the mouse is over the chkDracoCompression checkBox - /// - /// - /// - bool IsShown = false; - private void groupBox1_MouseMove(object sender, MouseEventArgs e) - { - Control ctrl = groupBox1.GetChildAtPoint(e.Location); - - if (ctrl != null) - { - if (ctrl == chkDracoCompression && !ctrl.Enabled && !IsShown) - { - string tip = "For glTF and glb export only.\nNode.js and gltf-pipeline modules are required."; - toolTipDracoCompression.Show(tip, chkDracoCompression, chkDracoCompression.Width / 2, chkDracoCompression.Height / 2); - IsShown = true; - } - } - else - { - toolTipDracoCompression.Hide(chkDracoCompression); - IsShown = false; - } - } - - /// - /// Handle the tab navigation - /// - /// - /// - private void ExporterForm_KeyDown(object sender, KeyEventArgs e) - { - if (e.KeyCode == Keys.Tab) - { - if (e.Modifiers == Keys.Shift) - ProcessTabKey(false); - else - ProcessTabKey(true); - } - } - - private async void butMultiExport_Click(object sender, EventArgs e) - { - string outputFileExt; - outputFileExt = comboOutputFormat.SelectedItem.ToString(); - if (outputFileExt.Contains("binary babylon")) - outputFileExt = "babylon"; - - ExportItemList exportItemList = new ExportItemList(outputFileExt); - - exportItemList.LoadFromData(); - - int numLoadedItems = exportItemList.Count; - - if (ModifierKeys == Keys.Shift) - { - MultiExportForm form = new MultiExportForm(exportItemList); - form.ShowDialog(this); - } - else if (numLoadedItems > 0) - { - try - { - if (chkUsePreExportProces.Checked) - { - Loader.Core.FileHold(); - } - await DoExport(exportItemList); - } - catch{} - finally - { - if (chkUsePreExportProces.Checked && !chkApplyPreprocessToScene.Checked) - { - Loader.Core.SetQuietMode(true); - Loader.Core.FileFetch(); - Loader.Core.SetQuietMode(false); - } - } - } - } - - private void chkUsePreExportProces_CheckedChanged(object sender, EventArgs e) - { - if (!chkUsePreExportProces.Checked) - { - chkMrgContainersAndXref.Enabled = false; - cmbBakeAnimationOptions.Enabled = false; - lblBakeAnimation.Enabled = false; - chkApplyPreprocessToScene.Enabled = false; - } - else - { - chkMrgContainersAndXref.Enabled = true; - cmbBakeAnimationOptions.Enabled = true; - lblBakeAnimation.Enabled = true; - chkApplyPreprocessToScene.Enabled = true; - } - } - } -} + } + + private TreeNode CreateTreeNode(int rank, string text, Color color) + { + TreeNode newNode = null; + + Invoke(new Action(() => + { + newNode = new TreeNode(text) { ForeColor = color }; + if (rank < 0 || rank > currentRank + 1) + { + rank = 0; + treeView.Nodes.Add(new TreeNode("Invalid rank passed to CreateTreeNode (through RaiseMessage, RaiseWarning or RaiseError)!") { ForeColor = Color.DarkOrange }); + } + if (rank == 0) + { + treeView.Nodes.Add(newNode); + } + else if (rank == currentRank + 1) + { + currentNode.Nodes.Add(newNode); + } + else + { + var parentNode = currentNode; + while (currentRank != rank - 1) + { + parentNode = parentNode.Parent; + currentRank--; + } + parentNode.Nodes.Add(newNode); + } + + currentRank = rank; + })); + + return newNode; + } + + private void ExporterForm_FormClosed(object sender, FormClosedEventArgs e) + { + if (exporter != null) + { + exporter.IsCancelled = true; + } + babylonExportAction.Close(); + } + + private void txtFilename_TextChanged(object sender, EventArgs e) + { + butExport.Enabled = !string.IsNullOrEmpty(txtModelPath.Text.Trim()); + butExportAndRun.Enabled = butExport.Enabled && WebServer.IsSupported; + } + + private void butCancel_Click(object sender, EventArgs e) + { + exporter.IsCancelled = true; + } + + private void ExporterForm_Activated(object sender, EventArgs e) + { + Loader.Global.DisableAccelerators(); + } + + private void ExporterForm_Deactivate(object sender, EventArgs e) + { + Loader.Global.EnableAccelerators(); + } + + private async void butExportAndRun_Click(object sender, EventArgs e) + { + try + { + if (chkUsePreExportProces.Checked) + { + Loader.Core.FileHold(); + } + + if (await DoExport(singleExportItem)) + { + WebServer.SceneFilename = Path.GetFileName(txtModelPath.Text); + WebServer.SceneFolder = Path.GetDirectoryName(txtModelPath.Text); + + Process.Start(WebServer.url + WebServer.SceneFilename); + + WindowState = FormWindowState.Minimized; + } + } + catch{} + finally + { + if (chkUsePreExportProces.Checked && !chkApplyPreprocessToScene.Checked) + { + Loader.Core.SetQuietMode(true); + Loader.Core.FileFetch(); + Loader.Core.SetQuietMode(false); + } + } + } + + private void butClose_Click(object sender, EventArgs e) + { + Close(); + } + + private void comboOutputFormat_SelectedIndexChanged(object sender, EventArgs e) + { + var outputFormat = comboOutputFormat.SelectedItem.ToString(); + switch (outputFormat) + { + case "babylon": + case "binary babylon": + this.saveFileDialog.DefaultExt = "babylon"; + this.saveFileDialog.Filter = "Babylon files|*.babylon"; + chkDracoCompression.Checked = false; + chkDracoCompression.Enabled = false; + chkWriteTextures.Enabled = true; + chkOverwriteTextures.Enabled = true; + txtTexturesPath.Text = string.Empty; + txtTexturesPath.Enabled = false; + textureLabel.Enabled = false; + btnTxtBrowse.Enabled = false; + chkNoAutoLight.Enabled = true; + chkFullPBR.Enabled = true; + btnEnvBrowse.Enabled = true; + txtEnvironmentName.Enabled = true; + chkKHRMaterialsUnlit.Enabled = false; + chkKHRLightsPunctual.Enabled = false; + chkKHRTextureTransform.Enabled = false; + break; + case "gltf": + this.saveFileDialog.DefaultExt = "gltf"; + this.saveFileDialog.Filter = "glTF files|*.gltf"; + chkDracoCompression.Enabled = gltfPipelineInstalled; + chkWriteTextures.Enabled = true; + chkOverwriteTextures.Enabled = true; + txtTexturesPath.Enabled = true; + textureLabel.Enabled = true; + btnTxtBrowse.Enabled = true; + chkNoAutoLight.Enabled = false; + chkNoAutoLight.Checked = false; + chkFullPBR.Enabled = false; + chkFullPBR.Checked = false; + btnEnvBrowse.Enabled = false; + txtEnvironmentName.Enabled = false; + txtEnvironmentName.Text = string.Empty; + chkKHRMaterialsUnlit.Enabled = true; + chkKHRLightsPunctual.Enabled = true; + chkKHRTextureTransform.Enabled = true; + break; + case "glb": + this.saveFileDialog.DefaultExt = "glb"; + this.saveFileDialog.Filter = "glb files|*.glb"; + chkDracoCompression.Enabled = gltfPipelineInstalled; + chkWriteTextures.Checked = true; + chkWriteTextures.Enabled = false; + chkOverwriteTextures.Checked = true; + chkOverwriteTextures.Enabled = false; + txtTexturesPath.Text = string.Empty; + txtTexturesPath.Enabled = false; + textureLabel.Enabled = false; + btnTxtBrowse.Enabled = false; + chkNoAutoLight.Enabled = false; + chkNoAutoLight.Checked = false; + chkFullPBR.Enabled = false; + chkFullPBR.Checked = false; + btnEnvBrowse.Enabled = false; + txtEnvironmentName.Enabled = false; + txtEnvironmentName.Text = string.Empty; + chkKHRMaterialsUnlit.Enabled = true; + chkKHRLightsPunctual.Enabled = true; + chkKHRTextureTransform.Enabled = true; + break; + } + + string newModelPath = Path.ChangeExtension(txtModelPath.Text, this.saveFileDialog.DefaultExt); + this.txtModelPath.MaxPath(newModelPath); + } + + /// + /// Show a toolTip when the mouse is over the chkDracoCompression checkBox + /// + /// + /// + bool IsShown = false; + private void groupBox1_MouseMove(object sender, MouseEventArgs e) + { + Control ctrl = groupBox1.GetChildAtPoint(e.Location); + + if (ctrl != null) + { + if (ctrl == chkDracoCompression && !ctrl.Enabled && !IsShown) + { + string tip = "For glTF and glb export only.\nNode.js and gltf-pipeline modules are required."; + toolTipDracoCompression.Show(tip, chkDracoCompression, chkDracoCompression.Width / 2, chkDracoCompression.Height / 2); + IsShown = true; + } + } + else + { + toolTipDracoCompression.Hide(chkDracoCompression); + IsShown = false; + } + } + + /// + /// Handle the tab navigation + /// + /// + /// + private void ExporterForm_KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Tab) + { + if (e.Modifiers == Keys.Shift) + ProcessTabKey(false); + else + ProcessTabKey(true); + } + } + + private async void butMultiExport_Click(object sender, EventArgs e) + { + string outputFileExt; + outputFileExt = comboOutputFormat.SelectedItem.ToString(); + if (outputFileExt.Contains("binary babylon")) + outputFileExt = "babylon"; + + ExportItemList exportItemList = new ExportItemList(outputFileExt); + + exportItemList.LoadFromData(); + + int numLoadedItems = exportItemList.Count; + + if (ModifierKeys == Keys.Shift) + { + MultiExportForm form = new MultiExportForm(exportItemList); + form.ShowDialog(this); + } + else if (numLoadedItems > 0) + { + try + { + if (chkUsePreExportProces.Checked) + { + Loader.Core.FileHold(); + } + await DoExport(exportItemList); + } + catch{} + finally + { + if (chkUsePreExportProces.Checked && !chkApplyPreprocessToScene.Checked) + { + Loader.Core.SetQuietMode(true); + Loader.Core.FileFetch(); + Loader.Core.SetQuietMode(false); + } + } + } + } + + private void chkUsePreExportProces_CheckedChanged(object sender, EventArgs e) + { + if (!chkUsePreExportProces.Checked) + { + chkMrgContainersAndXref.Enabled = false; + cmbBakeAnimationOptions.Enabled = false; + lblBakeAnimation.Enabled = false; + chkApplyPreprocessToScene.Enabled = false; + } + else + { + chkMrgContainersAndXref.Enabled = true; + cmbBakeAnimationOptions.Enabled = true; + lblBakeAnimation.Enabled = true; + chkApplyPreprocessToScene.Enabled = true; + } + } + } +} diff --git a/SharedProjects/Babylon2GLTF/GLTFExporter.Texture.cs b/SharedProjects/Babylon2GLTF/GLTFExporter.Texture.cs index 9d63a790..6509f1ed 100644 --- a/SharedProjects/Babylon2GLTF/GLTFExporter.Texture.cs +++ b/SharedProjects/Babylon2GLTF/GLTFExporter.Texture.cs @@ -160,7 +160,8 @@ private GLTFTextureInfo ExportTexture(BabylonTexture babylonTexture, GLTF gltf, string textureUri = name; if (!string.IsNullOrWhiteSpace(exportParameters.textureFolder)) { - textureUri = PathUtilities.GetRelativePath( exportParameters.outputPath,exportParameters.textureFolder) + "/"+ name; + textureUri = PathUtilities.GetRelativePath( exportParameters.outputPath,exportParameters.textureFolder); + textureUri = Path.Combine(textureUri, name); } gltfImage = new GLTFImage { diff --git a/SharedProjects/Babylon2GLTF/GLTFExporter.cs b/SharedProjects/Babylon2GLTF/GLTFExporter.cs index 4c587d4b..f5ebac39 100644 --- a/SharedProjects/Babylon2GLTF/GLTFExporter.cs +++ b/SharedProjects/Babylon2GLTF/GLTFExporter.cs @@ -470,7 +470,11 @@ private string gltfToJson(GLTF gltf) // Use the bounded writer in case some values are infinity () using (var jsonWriter = new JsonTextWriterBounded(sw)) { +#if DEBUG + jsonWriter.Formatting = Formatting.Indented; +#else jsonWriter.Formatting = Formatting.None; +#endif jsonSerializer.Serialize(jsonWriter, gltf); } return sb.ToString(); @@ -482,7 +486,7 @@ private List SwitchImagesFromUriToBinary(GLTF gltf) foreach (GLTFImage gltfImage in gltf.ImagesList) { - var path = Path.Combine(gltf.OutputFolder, Uri.UnescapeDataString(gltfImage.uri)); + var path = Path.Combine(gltf.OutputFolder, gltfImage.uri); byte[] imageBytes = File.ReadAllBytes(path); // Chunk must be padded with trailing zeros (0x00) to satisfy alignment requirements diff --git a/SharedProjects/GltfExport.Entities/GLTFImage.cs b/SharedProjects/GltfExport.Entities/GLTFImage.cs index 1daede76..a2b16dcf 100644 --- a/SharedProjects/GltfExport.Entities/GLTFImage.cs +++ b/SharedProjects/GltfExport.Entities/GLTFImage.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Runtime.Serialization; namespace GLTFExport.Entities @@ -12,14 +13,7 @@ public string uri get { return _uri; } set { - if (value == null) - { - _uri = null; - } - else - { - _uri = Uri.EscapeDataString(value); - } + _uri = value; } } diff --git a/SharedProjects/Utilities/PathUtilities.cs b/SharedProjects/Utilities/PathUtilities.cs index a248b667..48f74c2f 100644 --- a/SharedProjects/Utilities/PathUtilities.cs +++ b/SharedProjects/Utilities/PathUtilities.cs @@ -23,18 +23,15 @@ public static string GetRelativePath(string fromPath, string toPath) if (string.IsNullOrEmpty(toPath)) throw new ArgumentNullException("toPath"); - Uri fromUri = new Uri(fromPath); - Uri toUri = new Uri(toPath); + Uri fromUri = new Uri(AppendDirectorySeparatorChar(fromPath)); + Uri toUri = new Uri(AppendDirectorySeparatorChar(toPath)); if (fromUri.Scheme != toUri.Scheme) return toPath; Uri relativeUri = fromUri.MakeRelativeUri(toUri); string relativePath = Uri.UnescapeDataString(relativeUri.ToString()); - - if (string.Equals(toUri.Scheme, Uri.UriSchemeFile, StringComparison.OrdinalIgnoreCase)) - relativePath = relativePath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - + return relativePath; } @@ -47,6 +44,18 @@ public static bool IsBelowPath(string childPath, string parentPath) } return false; + } + + private static string AppendDirectorySeparatorChar(string path) + { + // Append a slash only if the path is a directory and does not have a slash. + if (!Path.HasExtension(path) && + !path.EndsWith(Path.DirectorySeparatorChar.ToString())) + { + return path + Path.DirectorySeparatorChar; + } + + return path; } } }