// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Reflection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
using Simplygon;
using UnityEditor;
using UnityEngine;
using UnityEditor.IMGUI.Controls;
using SimplygonUnityEditorPlugin.Logger;

namespace SimplygonUI
{
    public class SimplygonVersion
    {
        public static readonly string Version = "9.2";
        public static readonly string Build = "9.2.1400.0";
        public static readonly string Commit = "c47d3175d00ec884bd836442df285bc06f7754eb";
    }

    public enum SimplygonIntegrationType
    {
        Max,
        Max2021,
        Maya,
        Unity,
        Blender,
    }

    public class SimplygonIntegration
    {
        public static SimplygonIntegrationType Type { get; set; }
    }

    public class SimplygonMaterialChannelMapping
    {
        public static string GetMappedMaterialChannelName(string materialChannelName)
        {
            string mappedMaterialChannelName = materialChannelName;
            if (mappedMaterialChannelName == "diffuseColor")
            {
                mappedMaterialChannelName = "Albedo";
            }
            if (mappedMaterialChannelName == "specularColor")
            {
                mappedMaterialChannelName = "Specular";
            }
            if (mappedMaterialChannelName == "emissiveColor")
            {
                mappedMaterialChannelName = "Emission";
            }
            if (mappedMaterialChannelName == "metallic")
            {
                mappedMaterialChannelName = "Metallic";
            }
            if (mappedMaterialChannelName == "roughness")
            {
                mappedMaterialChannelName = "Smoothness";
            }
            if (mappedMaterialChannelName == "normal")
            {
                mappedMaterialChannelName = "Normal";
            }
            if (mappedMaterialChannelName == "geometry")
            {
                mappedMaterialChannelName = "Geometry";
            }
            if (mappedMaterialChannelName == "displacement")
            {
                mappedMaterialChannelName = "Displacement";
            }
            if (mappedMaterialChannelName == "occlusion")
            {
                mappedMaterialChannelName = "Occlusion";
            }
            return mappedMaterialChannelName;
        }

    }

    public class SimplygonPipelineDatabase
    {
        public static string PipelineDirectory { get; protected set; }
        public static List<SimplygonPipeline> PipelineTemplates = new List<SimplygonPipeline>();
        public static List<SimplygonMaterialCaster> MaterialCasterTemplates = new List<SimplygonMaterialCaster>();

        public static void Refresh()
        {
            string simplygon9SharedDirectory = Environment.GetEnvironmentVariable("SIMPLYGON_9_SHARED");
            if (string.IsNullOrWhiteSpace(simplygon9SharedDirectory))
            {
                simplygon9SharedDirectory = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), "Simplygon", "9");
            }

            simplygon9SharedDirectory = Environment.ExpandEnvironmentVariables(simplygon9SharedDirectory);
            PipelineDirectory = System.IO.Path.Combine(simplygon9SharedDirectory, "Pipelines");
            if (!System.IO.Directory.Exists(PipelineDirectory))
            {
                System.IO.Directory.CreateDirectory(PipelineDirectory);
            }

            PipelineTemplates.Clear();
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.ReductionPipeline, "Template/Advanced/Reduction", false));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.RemeshingPipeline, "Template/Advanced/Remeshing", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.AggregationPipeline, "Template/Advanced/Aggregation", false));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.BillboardCloudPipeline, "Template/Advanced/Billboard cloud", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.BillboardCloudVegetationPipeline, "Template/Advanced/Billboard cloud for vegetation", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.ImpostorFromSingleViewPipeline, "Template/Advanced/Impostor from single view", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.OcclusionMeshPipeline, "Template/Advanced/Occlusion mesh", false));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.ReductionPipeline, "Template/Basic/Reduction", false));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.ReductionPipeline, "Template/Basic/Reduction with material baking", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.RemeshingPipeline, "Template/Basic/Remeshing with material baking", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.AggregationPipeline, "Template/Basic/Aggregation", false));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.AggregationPipeline, "Template/Basic/Aggregation with material baking", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.BillboardCloudPipeline, "Template/Basic/Billboard cloud", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.BillboardCloudVegetationPipeline, "Template/Basic/Billboard cloud for vegetation", true));
            PipelineTemplates.Add(new SimplygonPipeline(ESimplygonPipeline.ImpostorFromSingleViewPipeline, "Template/Basic/Impostor from single view", true));

            MaterialCasterTemplates.Clear();
            MaterialCasterTemplates.Add(new SimplygonMaterialCaster(ESimplygonPipeline.Passthrough, ESimplygonMaterialCaster.ColorCaster, "Color", "Template/Advanced/ColorCaster"));
            MaterialCasterTemplates.Add(new SimplygonMaterialCaster(ESimplygonPipeline.Passthrough, ESimplygonMaterialCaster.NormalCaster, "Normal", "Template/Advanced/NormalCaster"));
            MaterialCasterTemplates.Add(new SimplygonMaterialCaster(ESimplygonPipeline.Passthrough, ESimplygonMaterialCaster.DisplacementCaster, "Displacement", "Template/Advanced/DisplacementCaster"));
            MaterialCasterTemplates.Add(new SimplygonMaterialCaster(ESimplygonPipeline.Passthrough, ESimplygonMaterialCaster.AmbientOcclusionCaster, "AmbientOcclusion", "Template/Advanced/AmbientOcclusionCaster"));
            MaterialCasterTemplates.Add(new SimplygonMaterialCaster(ESimplygonPipeline.Passthrough, ESimplygonMaterialCaster.GeometryDataCaster, "GeometryData", "Template/Advanced/GeometryDataCaster"));
            MaterialCasterTemplates.Add(new SimplygonMaterialCaster(ESimplygonPipeline.Passthrough, ESimplygonMaterialCaster.VertexColorCaster, "VertexColor", "Template/Advanced/VertexColorCaster"));
            LoadPipelines(string.Empty);
        }

        protected static void LoadPipelines(string relativeDirectory)
        {
            string directory = System.IO.Path.Combine(PipelineDirectory, relativeDirectory);
            if (System.IO.Directory.Exists(directory))
            {
                var files = System.IO.Directory.EnumerateFiles(directory, "*.json");
                foreach (var file in files)
                {
                    try
                    {
                        var pipeline = new SimplygonPipeline(file, JObject.Parse(System.IO.File.ReadAllText(file)));
                        if (pipeline != null)
                        {
                            pipeline.FilePath = file;
                            pipeline.MenuPath = string.IsNullOrEmpty(relativeDirectory) ? $"{System.IO.Path.GetFileNameWithoutExtension(file)}" : $"{relativeDirectory}/{System.IO.Path.GetFileNameWithoutExtension(file)}";
                            PipelineTemplates.Add(pipeline);
                        }

                    }

                    catch(Exception ex)
                    {
                        SimplygonLogger.Instance.Log(Category.Error, $"Could not load pipeline '{file}' due to an error. Details: {ex.Message}");
                    }

                }

                var subDirectories = System.IO.Directory.EnumerateDirectories(directory);
                foreach (var subDirectory in subDirectories)
                {
                    string subDirectoryName = System.IO.Path.GetFileNameWithoutExtension(subDirectory);
                    LoadPipelines(string.IsNullOrEmpty(relativeDirectory) ? subDirectoryName : $"{relativeDirectory}/{subDirectoryName}");
                }

            }

        }

    }

    public class SimplygonTreeViewItem : TreeViewItem, INotifyPropertyChanged
    {
        private static int currentTreeViewId = 0;
        public virtual bool Visible { get { return visible; } set { visible = value; OnPropertyChanged(); } }
        protected bool visible;
        public virtual bool VisibleOverride { get { return visibleOverride; } set { visibleOverride = value; visible = value; OnPropertyChanged(); } }
        protected bool visibleOverride;
        public event PropertyChangedEventHandler PropertyChanged;
        public virtual bool IsEditEnabled { get { return isEditEnabled; } set { isEditEnabled = value; OnPropertyChanged(); } }
        public string Name { get { return name; } set { name = value; OnPropertyChanged(); } }
        private string name;
        public ObservableCollection<SimplygonTreeViewItem> Items { get; set; }
        protected bool isEditEnabled;
        public SimplygonTreeViewItem(string name) : base(currentTreeViewId++, -1, name)
        {
            Name = name;
            VisibleOverride = true;
            Items = new ObservableCollection<SimplygonTreeViewItem>();
        }

        protected void OnPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }

        public void SetVisible(bool visible, bool recursively)
        {
            Visible = visible;
            if (recursively)
            {
                foreach(var item in Items)
                {
                    item.SetVisible(visible, recursively);
                }

            }

        }

    }

    public class SimplygonSettings : SimplygonTreeViewItem
    {
        public SimplygonPipeline Pipeline { get; set; }
        public virtual void Reset() { }

        public SimplygonSettings(string name) : base(name)
        {
        }

        public virtual SimplygonSettings DeepCopy()
        {
            return (SimplygonSettings)this.MemberwiseClone();
        }

        public virtual void SetEditMode(bool isEditEnabled) { }
        public virtual JObject SaveJson(bool serializeUIComponents) { return new JObject(); }
    }

    public class SimplygonSettingsProperty : SimplygonTreeViewItem
    {
        public string Type { get; set; }
        public string HelpText { get; set; }
        public string TypeOverride { get; set; }
        public bool HasDependencyObject { get; set; }
        public virtual void Reset() { }

        public SimplygonSettingsProperty(string name) : base(name)
        {
        }

        public virtual void ShowUI(Rect rect)
        {
        }

    }

    public interface SimplygonSettingsPropertyFolderBrowser
    {
        void SetPath(string path);
        string GetPath();
    }

    public class SimplygonReductionSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(ReductionTargetTriangleRatioEnabledUI.Visible) return true;
                if(ReductionTargetTriangleRatioUI.Visible) return true;
                if(ReductionTargetTriangleCountEnabledUI.Visible) return true;
                if(ReductionTargetTriangleCountUI.Visible) return true;
                if(ReductionTargetMaxDeviationEnabledUI.Visible) return true;
                if(ReductionTargetMaxDeviationUI.Visible) return true;
                if(ReductionTargetOnScreenSizeEnabledUI.Visible) return true;
                if(ReductionTargetOnScreenSizeUI.Visible) return true;
                if(ReductionTargetStopConditionUI.Visible) return true;
                if(ReductionHeuristicsUI.Visible) return true;
                if(GeometryImportanceUI.Visible) return true;
                if(MaterialImportanceUI.Visible) return true;
                if(TextureImportanceUI.Visible) return true;
                if(ShadingImportanceUI.Visible) return true;
                if(GroupImportanceUI.Visible) return true;
                if(VertexColorImportanceUI.Visible) return true;
                if(EdgeSetImportanceUI.Visible) return true;
                if(SkinningImportanceUI.Visible) return true;
                if(CurvatureImportanceUI.Visible) return true;
                if(CreateGeomorphGeometryUI.Visible) return true;
                if(AllowDegenerateTexCoordsUI.Visible) return true;
                if(KeepSymmetryUI.Visible) return true;
                if(UseAutomaticSymmetryDetectionUI.Visible) return true;
                if(UseSymmetryQuadRetriangulatorUI.Visible) return true;
                if(SymmetryAxisUI.Visible) return true;
                if(SymmetryOffsetUI.Visible) return true;
                if(SymmetryDetectionToleranceUI.Visible) return true;
                if(DataCreationPreferencesUI.Visible) return true;
                if(OutwardMoveMultiplierUI.Visible) return true;
                if(InwardMoveMultiplierUI.Visible) return true;
                if(UseHighQualityNormalCalculationUI.Visible) return true;
                if(MergeGeometriesUI.Visible) return true;
                if(KeepUnprocessedSceneMeshesUI.Visible) return true;
                if(LockGeometricBorderUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool ReductionTargetTriangleRatioEnabled { get { return _ReductionTargetTriangleRatioEnabled; } set { _ReductionTargetTriangleRatioEnabled = value; OnPropertyChanged(); } }
        private bool _ReductionTargetTriangleRatioEnabled;
        public SimplygonReductionTargetTriangleRatioEnabledEx ReductionTargetTriangleRatioEnabledUI { get; set; }
        public class SimplygonReductionTargetTriangleRatioEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ReductionTargetTriangleRatioEnabled;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetTriangleRatioEnabled != value;
                    Parent.ReductionTargetTriangleRatioEnabled = value;
                    Parent.ReductionTargetTriangleRatioUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonReductionTargetTriangleRatioEnabledEx() : base("ReductionTargetTriangleRatioEnabled")
            {
                Type = "bool";
                HelpText = "Enable triangle ratio as a reduction target. The reducer will stop when the set triangle-ratio has been reached.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonReductionTargetTriangleRatioEnabledEx(dynamic jsonData) : base("ReductionTargetTriangleRatioEnabled")
            {
                Type = "bool";
                HelpText = "Enable triangle ratio as a reduction target. The reducer will stop when the set triangle-ratio has been reached.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetTriangleRatioEnabledEx DeepCopy()
            {
                return (SimplygonReductionTargetTriangleRatioEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ReductionTargetTriangleRatioEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float ReductionTargetTriangleRatio { get { return _ReductionTargetTriangleRatio; } set { _ReductionTargetTriangleRatio = value; OnPropertyChanged(); } }
        private float _ReductionTargetTriangleRatio;
        public SimplygonReductionTargetTriangleRatioEx ReductionTargetTriangleRatioUI { get; set; }
        public class SimplygonReductionTargetTriangleRatioEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ReductionTargetTriangleRatio;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetTriangleRatio != value;
                    Parent.ReductionTargetTriangleRatio = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.ReductionTargetTriangleRatioEnabled; } set { Parent.ReductionTargetTriangleRatioEnabled = value; OnPropertyChanged(); } }

            public SimplygonReductionTargetTriangleRatioEx() : base("ReductionTargetTriangleRatio")
            {
                Type = "real";
                HelpText = "The wanted reduction ratio. The range is 0->1.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonReductionTargetTriangleRatioEx(dynamic jsonData) : base("ReductionTargetTriangleRatio")
            {
                Type = "real";
                HelpText = "The wanted reduction ratio. The range is 0->1.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetTriangleRatio: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetTriangleRatio: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetTriangleRatioEx DeepCopy()
            {
                return (SimplygonReductionTargetTriangleRatioEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.ReductionTargetTriangleRatioEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    float value = Parent.ReductionTargetTriangleRatio;
                    value = EditorGUI.Slider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public bool ReductionTargetTriangleCountEnabled { get { return _ReductionTargetTriangleCountEnabled; } set { _ReductionTargetTriangleCountEnabled = value; OnPropertyChanged(); } }
        private bool _ReductionTargetTriangleCountEnabled;
        public SimplygonReductionTargetTriangleCountEnabledEx ReductionTargetTriangleCountEnabledUI { get; set; }
        public class SimplygonReductionTargetTriangleCountEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ReductionTargetTriangleCountEnabled;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetTriangleCountEnabled != value;
                    Parent.ReductionTargetTriangleCountEnabled = value;
                    Parent.ReductionTargetTriangleCountUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonReductionTargetTriangleCountEnabledEx() : base("ReductionTargetTriangleCountEnabled")
            {
                Type = "bool";
                HelpText = "Enable triangle count as a reduction target. The reducer will stop when the set triangle count has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonReductionTargetTriangleCountEnabledEx(dynamic jsonData) : base("ReductionTargetTriangleCountEnabled")
            {
                Type = "bool";
                HelpText = "Enable triangle count as a reduction target. The reducer will stop when the set triangle count has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetTriangleCountEnabledEx DeepCopy()
            {
                return (SimplygonReductionTargetTriangleCountEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ReductionTargetTriangleCountEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int ReductionTargetTriangleCount { get { return _ReductionTargetTriangleCount; } set { _ReductionTargetTriangleCount = value; OnPropertyChanged(); } }
        private int _ReductionTargetTriangleCount;
        public SimplygonReductionTargetTriangleCountEx ReductionTargetTriangleCountUI { get; set; }
        public class SimplygonReductionTargetTriangleCountEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.ReductionTargetTriangleCount;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetTriangleCount != value;
                    Parent.ReductionTargetTriangleCount = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.ReductionTargetTriangleCountEnabled; } set { Parent.ReductionTargetTriangleCountEnabled = value; OnPropertyChanged(); } }

            public SimplygonReductionTargetTriangleCountEx() : base("ReductionTargetTriangleCount")
            {
                Type = "uint";
                HelpText = "The wanted triangle count. The range is 0->inf.";
                TypeOverride = "";
                DefaultValue = 10000;
                MinValue = 0;
                MaxValue = 10000000;
                DefaultMinValue = 0;
                DefaultMaxValue = 10000000;
                TicksFrequencyValue = 10000;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonReductionTargetTriangleCountEx(dynamic jsonData) : base("ReductionTargetTriangleCount")
            {
                Type = "uint";
                HelpText = "The wanted triangle count. The range is 0->inf.";
                TypeOverride = "";
                DefaultValue = 10000;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetTriangleCount: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10000000;
                DefaultMaxValue = 10000000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetTriangleCount: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10000;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetTriangleCountEx DeepCopy()
            {
                return (SimplygonReductionTargetTriangleCountEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.ReductionTargetTriangleCountEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    int value = Parent.ReductionTargetTriangleCount;
                    value = EditorGUI.IntSlider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public bool ReductionTargetMaxDeviationEnabled { get { return _ReductionTargetMaxDeviationEnabled; } set { _ReductionTargetMaxDeviationEnabled = value; OnPropertyChanged(); } }
        private bool _ReductionTargetMaxDeviationEnabled;
        public SimplygonReductionTargetMaxDeviationEnabledEx ReductionTargetMaxDeviationEnabledUI { get; set; }
        public class SimplygonReductionTargetMaxDeviationEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ReductionTargetMaxDeviationEnabled;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetMaxDeviationEnabled != value;
                    Parent.ReductionTargetMaxDeviationEnabled = value;
                    Parent.ReductionTargetMaxDeviationUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonReductionTargetMaxDeviationEnabledEx() : base("ReductionTargetMaxDeviationEnabled")
            {
                Type = "bool";
                HelpText = "Enable max deviation as a reduction target. The reducer will stop when the set max deviation has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonReductionTargetMaxDeviationEnabledEx(dynamic jsonData) : base("ReductionTargetMaxDeviationEnabled")
            {
                Type = "bool";
                HelpText = "Enable max deviation as a reduction target. The reducer will stop when the set max deviation has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetMaxDeviationEnabledEx DeepCopy()
            {
                return (SimplygonReductionTargetMaxDeviationEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ReductionTargetMaxDeviationEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float ReductionTargetMaxDeviation { get { return _ReductionTargetMaxDeviation; } set { _ReductionTargetMaxDeviation = value; OnPropertyChanged(); } }
        private float _ReductionTargetMaxDeviation;
        public SimplygonReductionTargetMaxDeviationEx ReductionTargetMaxDeviationUI { get; set; }
        public class SimplygonReductionTargetMaxDeviationEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ReductionTargetMaxDeviation;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetMaxDeviation != value;
                    Parent.ReductionTargetMaxDeviation = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.ReductionTargetMaxDeviationEnabled; } set { Parent.ReductionTargetMaxDeviationEnabled = value; OnPropertyChanged(); } }

            public SimplygonReductionTargetMaxDeviationEx() : base("ReductionTargetMaxDeviation")
            {
                Type = "real";
                HelpText = "The MaxDeviation value, the maximum surface-deviation between the reduced geometry and the original.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonReductionTargetMaxDeviationEx(dynamic jsonData) : base("ReductionTargetMaxDeviation")
            {
                Type = "real";
                HelpText = "The MaxDeviation value, the maximum surface-deviation between the reduced geometry and the original.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetMaxDeviation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetMaxDeviation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetMaxDeviationEx DeepCopy()
            {
                return (SimplygonReductionTargetMaxDeviationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.ReductionTargetMaxDeviationEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    float value = Parent.ReductionTargetMaxDeviation;
                    value = EditorGUI.Slider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public bool ReductionTargetOnScreenSizeEnabled { get { return _ReductionTargetOnScreenSizeEnabled; } set { _ReductionTargetOnScreenSizeEnabled = value; OnPropertyChanged(); } }
        private bool _ReductionTargetOnScreenSizeEnabled;
        public SimplygonReductionTargetOnScreenSizeEnabledEx ReductionTargetOnScreenSizeEnabledUI { get; set; }
        public class SimplygonReductionTargetOnScreenSizeEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ReductionTargetOnScreenSizeEnabled;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetOnScreenSizeEnabled != value;
                    Parent.ReductionTargetOnScreenSizeEnabled = value;
                    Parent.ReductionTargetOnScreenSizeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonReductionTargetOnScreenSizeEnabledEx() : base("ReductionTargetOnScreenSizeEnabled")
            {
                Type = "bool";
                HelpText = "Enable on screen size as a reduction target. The reducer will stop when the set on screen size has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonReductionTargetOnScreenSizeEnabledEx(dynamic jsonData) : base("ReductionTargetOnScreenSizeEnabled")
            {
                Type = "bool";
                HelpText = "Enable on screen size as a reduction target. The reducer will stop when the set on screen size has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetOnScreenSizeEnabledEx DeepCopy()
            {
                return (SimplygonReductionTargetOnScreenSizeEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ReductionTargetOnScreenSizeEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int ReductionTargetOnScreenSize { get { return _ReductionTargetOnScreenSize; } set { _ReductionTargetOnScreenSize = value; OnPropertyChanged(); } }
        private int _ReductionTargetOnScreenSize;
        public SimplygonReductionTargetOnScreenSizeEx ReductionTargetOnScreenSizeUI { get; set; }
        public class SimplygonReductionTargetOnScreenSizeEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.ReductionTargetOnScreenSize;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetOnScreenSize != value;
                    Parent.ReductionTargetOnScreenSize = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.ReductionTargetOnScreenSizeEnabled; } set { Parent.ReductionTargetOnScreenSizeEnabled = value; OnPropertyChanged(); } }

            public SimplygonReductionTargetOnScreenSizeEx() : base("ReductionTargetOnScreenSize")
            {
                Type = "uint";
                HelpText = "The OnScreenSize value, used to calculate the maximum surface-deviation allowed, by assuming errors less than 1 pixel onscreen will not be noticeable.";
                TypeOverride = "";
                DefaultValue = 300;
                MinValue = 20;
                MaxValue = 100000;
                DefaultMinValue = 20;
                DefaultMaxValue = 100000;
                TicksFrequencyValue = 10;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonReductionTargetOnScreenSizeEx(dynamic jsonData) : base("ReductionTargetOnScreenSize")
            {
                Type = "uint";
                HelpText = "The OnScreenSize value, used to calculate the maximum surface-deviation allowed, by assuming errors less than 1 pixel onscreen will not be noticeable.";
                TypeOverride = "";
                DefaultValue = 300;
                MinValue = 20;
                DefaultMinValue = 20;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetOnScreenSize: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 100000;
                DefaultMaxValue = 100000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetOnScreenSize: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetOnScreenSizeEx DeepCopy()
            {
                return (SimplygonReductionTargetOnScreenSizeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.ReductionTargetOnScreenSizeEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    int value = Parent.ReductionTargetOnScreenSize;
                    value = EditorGUI.IntSlider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public EStopCondition ReductionTargetStopCondition { get { return _ReductionTargetStopCondition; } set { _ReductionTargetStopCondition = value; OnPropertyChanged(); } }
        private EStopCondition _ReductionTargetStopCondition;
        public SimplygonReductionTargetStopConditionEx ReductionTargetStopConditionUI { get; set; }
        public class SimplygonReductionTargetStopConditionEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public EStopCondition Value
            {
                get
                {
                    return Parent.ReductionTargetStopCondition;
                }

                set
                {
                    bool needReload = Parent.ReductionTargetStopCondition != value;
                    Parent.ReductionTargetStopCondition = value;
                    OnPropertyChanged();
                }

            }

            public EStopCondition DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EStopCondition)); } }

            public SimplygonReductionTargetStopConditionEx() : base("ReductionTargetStopCondition")
            {
                Type = "enum";
                HelpText = "The stop condition for the reducer.  Any -> the reducer will stop when any single one of the set reduction targets have been reached.  All -> the reducer will stop when all enabled reduction targets have been set.";
                TypeOverride = "";
                DefaultValue = EStopCondition.All;
                Visible = true;
            }

            public SimplygonReductionTargetStopConditionEx(dynamic jsonData) : base("ReductionTargetStopCondition")
            {
                Type = "enum";
                HelpText = "The stop condition for the reducer.  Any -> the reducer will stop when any single one of the set reduction targets have been reached.  All -> the reducer will stop when all enabled reduction targets have been set.";
                TypeOverride = "";
                DefaultValue = EStopCondition.All;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionTargetStopConditionEx DeepCopy()
            {
                return (SimplygonReductionTargetStopConditionEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.ReductionTargetStopCondition;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EStopCondition)value;
            }

        }

        public EReductionHeuristics ReductionHeuristics { get { return _ReductionHeuristics; } set { _ReductionHeuristics = value; OnPropertyChanged(); } }
        private EReductionHeuristics _ReductionHeuristics;
        public SimplygonReductionHeuristicsEx ReductionHeuristicsUI { get; set; }
        public class SimplygonReductionHeuristicsEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public EReductionHeuristics Value
            {
                get
                {
                    return Parent.ReductionHeuristics;
                }

                set
                {
                    bool needReload = Parent.ReductionHeuristics != value;
                    Parent.ReductionHeuristics = value;
                    OnPropertyChanged();
                }

            }

            public EReductionHeuristics DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EReductionHeuristics)); } }

            public SimplygonReductionHeuristicsEx() : base("ReductionHeuristics")
            {
                Type = "enum";
                HelpText = "The flag that decides how precise the reducer will be during the mesh reduction. Fast -> Reducer will be faster, but onscreensize and trianglecount will not match perfectly.  Consistent -> Reducer will be slower, but onscreensize and trianglecount will consistently give matching results.";
                TypeOverride = "";
                DefaultValue = EReductionHeuristics.Fast;
                Visible = true;
            }

            public SimplygonReductionHeuristicsEx(dynamic jsonData) : base("ReductionHeuristics")
            {
                Type = "enum";
                HelpText = "The flag that decides how precise the reducer will be during the mesh reduction. Fast -> Reducer will be faster, but onscreensize and trianglecount will not match perfectly.  Consistent -> Reducer will be slower, but onscreensize and trianglecount will consistently give matching results.";
                TypeOverride = "";
                DefaultValue = EReductionHeuristics.Fast;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReductionHeuristicsEx DeepCopy()
            {
                return (SimplygonReductionHeuristicsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.ReductionHeuristics;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EReductionHeuristics)value;
            }

        }

        public float GeometryImportance { get { return _GeometryImportance; } set { _GeometryImportance = value; OnPropertyChanged(); } }
        private float _GeometryImportance;
        public SimplygonGeometryImportanceEx GeometryImportanceUI { get; set; }
        public class SimplygonGeometryImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.GeometryImportance;
                }

                set
                {
                    bool needReload = Parent.GeometryImportance != value;
                    Parent.GeometryImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonGeometryImportanceEx() : base("GeometryImportance")
            {
                Type = "real";
                HelpText = "The importance value of the position of the vertices and triangles of the Geometry, or the silhouette of the Geometry. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonGeometryImportanceEx(dynamic jsonData) : base("GeometryImportance")
            {
                Type = "real";
                HelpText = "The importance value of the position of the vertices and triangles of the Geometry, or the silhouette of the Geometry. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometryImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometryImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGeometryImportanceEx DeepCopy()
            {
                return (SimplygonGeometryImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.GeometryImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MaterialImportance { get { return _MaterialImportance; } set { _MaterialImportance = value; OnPropertyChanged(); } }
        private float _MaterialImportance;
        public SimplygonMaterialImportanceEx MaterialImportanceUI { get; set; }
        public class SimplygonMaterialImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MaterialImportance;
                }

                set
                {
                    bool needReload = Parent.MaterialImportance != value;
                    Parent.MaterialImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMaterialImportanceEx() : base("MaterialImportance")
            {
                Type = "real";
                HelpText = "The importance value of the boundary between triangles with different materials. For example, if triangles with a metallic material are connected to triangles with a wood material, this setting will determine how important it is to keep the border between them intact. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonMaterialImportanceEx(dynamic jsonData) : base("MaterialImportance")
            {
                Type = "real";
                HelpText = "The importance value of the boundary between triangles with different materials. For example, if triangles with a metallic material are connected to triangles with a wood material, this setting will determine how important it is to keep the border between them intact. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaterialImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaterialImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialImportanceEx DeepCopy()
            {
                return (SimplygonMaterialImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MaterialImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float TextureImportance { get { return _TextureImportance; } set { _TextureImportance = value; OnPropertyChanged(); } }
        private float _TextureImportance;
        public SimplygonTextureImportanceEx TextureImportanceUI { get; set; }
        public class SimplygonTextureImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.TextureImportance;
                }

                set
                {
                    bool needReload = Parent.TextureImportance != value;
                    Parent.TextureImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonTextureImportanceEx() : base("TextureImportance")
            {
                Type = "real";
                HelpText = "The importance value of the UV coordinates of the Geometry, both the boundary of the UV charts, as well as the UV stretch across the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonTextureImportanceEx(dynamic jsonData) : base("TextureImportance")
            {
                Type = "real";
                HelpText = "The importance value of the UV coordinates of the Geometry, both the boundary of the UV charts, as well as the UV stretch across the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTextureImportanceEx DeepCopy()
            {
                return (SimplygonTextureImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.TextureImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float ShadingImportance { get { return _ShadingImportance; } set { _ShadingImportance = value; OnPropertyChanged(); } }
        private float _ShadingImportance;
        public SimplygonShadingImportanceEx ShadingImportanceUI { get; set; }
        public class SimplygonShadingImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ShadingImportance;
                }

                set
                {
                    bool needReload = Parent.ShadingImportance != value;
                    Parent.ShadingImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonShadingImportanceEx() : base("ShadingImportance")
            {
                Type = "real";
                HelpText = "The importance value of the vertex-normals of the Geometry, both the sharp edges, as well as how the normals interpolate over the surface of the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonShadingImportanceEx(dynamic jsonData) : base("ShadingImportance")
            {
                Type = "real";
                HelpText = "The importance value of the vertex-normals of the Geometry, both the sharp edges, as well as how the normals interpolate over the surface of the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ShadingImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ShadingImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonShadingImportanceEx DeepCopy()
            {
                return (SimplygonShadingImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ShadingImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float GroupImportance { get { return _GroupImportance; } set { _GroupImportance = value; OnPropertyChanged(); } }
        private float _GroupImportance;
        public SimplygonGroupImportanceEx GroupImportanceUI { get; set; }
        public class SimplygonGroupImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.GroupImportance;
                }

                set
                {
                    bool needReload = Parent.GroupImportance != value;
                    Parent.GroupImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonGroupImportanceEx() : base("GroupImportance")
            {
                Type = "real";
                HelpText = "The importance value of the boundary between triangles from different sub-geometries. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonGroupImportanceEx(dynamic jsonData) : base("GroupImportance")
            {
                Type = "real";
                HelpText = "The importance value of the boundary between triangles from different sub-geometries. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GroupImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GroupImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGroupImportanceEx DeepCopy()
            {
                return (SimplygonGroupImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.GroupImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float VertexColorImportance { get { return _VertexColorImportance; } set { _VertexColorImportance = value; OnPropertyChanged(); } }
        private float _VertexColorImportance;
        public SimplygonVertexColorImportanceEx VertexColorImportanceUI { get; set; }
        public class SimplygonVertexColorImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.VertexColorImportance;
                }

                set
                {
                    bool needReload = Parent.VertexColorImportance != value;
                    Parent.VertexColorImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonVertexColorImportanceEx() : base("VertexColorImportance")
            {
                Type = "real";
                HelpText = "The importance value of the vertex-colors of the Geometry, both the boundary between triangles with different colors, as well as how the colors interpolate over the surface of the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonVertexColorImportanceEx(dynamic jsonData) : base("VertexColorImportance")
            {
                Type = "real";
                HelpText = "The importance value of the vertex-colors of the Geometry, both the boundary between triangles with different colors, as well as how the colors interpolate over the surface of the triangles. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"VertexColorImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"VertexColorImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonVertexColorImportanceEx DeepCopy()
            {
                return (SimplygonVertexColorImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.VertexColorImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float EdgeSetImportance { get { return _EdgeSetImportance; } set { _EdgeSetImportance = value; OnPropertyChanged(); } }
        private float _EdgeSetImportance;
        public SimplygonEdgeSetImportanceEx EdgeSetImportanceUI { get; set; }
        public class SimplygonEdgeSetImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.EdgeSetImportance;
                }

                set
                {
                    bool needReload = Parent.EdgeSetImportance != value;
                    Parent.EdgeSetImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonEdgeSetImportanceEx() : base("EdgeSetImportance")
            {
                Type = "real";
                HelpText = "The importance value of user selected edges. Can be used when a Boolean UserCornerField with the name SgEdgeSelectionSet is added to the Geometry. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonEdgeSetImportanceEx(dynamic jsonData) : base("EdgeSetImportance")
            {
                Type = "real";
                HelpText = "The importance value of user selected edges. Can be used when a Boolean UserCornerField with the name SgEdgeSelectionSet is added to the Geometry. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"EdgeSetImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"EdgeSetImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonEdgeSetImportanceEx DeepCopy()
            {
                return (SimplygonEdgeSetImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.EdgeSetImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float SkinningImportance { get { return _SkinningImportance; } set { _SkinningImportance = value; OnPropertyChanged(); } }
        private float _SkinningImportance;
        public SimplygonSkinningImportanceEx SkinningImportanceUI { get; set; }
        public class SimplygonSkinningImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.SkinningImportance;
                }

                set
                {
                    bool needReload = Parent.SkinningImportance != value;
                    Parent.SkinningImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonSkinningImportanceEx() : base("SkinningImportance")
            {
                Type = "real";
                HelpText = "The importance value of the bone-weights of the vertices. The more impact a vertex has on the skinning of the Geometry (for example, vertices close to joints), the more likely it is to be kept. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonSkinningImportanceEx(dynamic jsonData) : base("SkinningImportance")
            {
                Type = "real";
                HelpText = "The importance value of the bone-weights of the vertices. The more impact a vertex has on the skinning of the Geometry (for example, vertices close to joints), the more likely it is to be kept. The importance is relative to the values of the other mesh features (or disabling an importance entirely by setting it to 0). A higher number means higher importance. Default is 1.0";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SkinningImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SkinningImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSkinningImportanceEx DeepCopy()
            {
                return (SimplygonSkinningImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.SkinningImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float CurvatureImportance { get { return _CurvatureImportance; } set { _CurvatureImportance = value; OnPropertyChanged(); } }
        private float _CurvatureImportance;
        public SimplygonCurvatureImportanceEx CurvatureImportanceUI { get; set; }
        public class SimplygonCurvatureImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.CurvatureImportance;
                }

                set
                {
                    bool needReload = Parent.CurvatureImportance != value;
                    Parent.CurvatureImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonCurvatureImportanceEx() : base("CurvatureImportance")
            {
                Type = "real";
                HelpText = "This importance is deprecated and disabled.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonCurvatureImportanceEx(dynamic jsonData) : base("CurvatureImportance")
            {
                Type = "real";
                HelpText = "This importance is deprecated and disabled.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"CurvatureImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"CurvatureImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonCurvatureImportanceEx DeepCopy()
            {
                return (SimplygonCurvatureImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.CurvatureImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool CreateGeomorphGeometry { get { return _CreateGeomorphGeometry; } set { _CreateGeomorphGeometry = value; OnPropertyChanged(); } }
        private bool _CreateGeomorphGeometry;
        public SimplygonCreateGeomorphGeometryEx CreateGeomorphGeometryUI { get; set; }
        public class SimplygonCreateGeomorphGeometryEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.CreateGeomorphGeometry;
                }

                set
                {
                    bool needReload = Parent.CreateGeomorphGeometry != value;
                    Parent.CreateGeomorphGeometry = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonCreateGeomorphGeometryEx() : base("CreateGeomorphGeometry")
            {
                Type = "bool";
                HelpText = "The CreateGeomorphGeometry value. If set, the reducer will create a GeometryData object that is a morphed version of the original GeometryData, that can be used to morph between the original geometry and the reduced geometry. Should not be used together with TJunctionRemover, NormalRecalculation or Material LOD.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonCreateGeomorphGeometryEx(dynamic jsonData) : base("CreateGeomorphGeometry")
            {
                Type = "bool";
                HelpText = "The CreateGeomorphGeometry value. If set, the reducer will create a GeometryData object that is a morphed version of the original GeometryData, that can be used to morph between the original geometry and the reduced geometry. Should not be used together with TJunctionRemover, NormalRecalculation or Material LOD.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonCreateGeomorphGeometryEx DeepCopy()
            {
                return (SimplygonCreateGeomorphGeometryEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.CreateGeomorphGeometry;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool AllowDegenerateTexCoords { get { return _AllowDegenerateTexCoords; } set { _AllowDegenerateTexCoords = value; OnPropertyChanged(); } }
        private bool _AllowDegenerateTexCoords;
        public SimplygonAllowDegenerateTexCoordsEx AllowDegenerateTexCoordsUI { get; set; }
        public class SimplygonAllowDegenerateTexCoordsEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.AllowDegenerateTexCoords;
                }

                set
                {
                    bool needReload = Parent.AllowDegenerateTexCoords != value;
                    Parent.AllowDegenerateTexCoords = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonAllowDegenerateTexCoordsEx() : base("AllowDegenerateTexCoords")
            {
                Type = "bool";
                HelpText = "The AllowDegenerateTexCoords flag. If true, texture coordinates are allowed to become degenerate (triangles can have 0 area in texture space). This may sometimes look better, but if tangent space normals are used, tangent spaces may become degenerate.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonAllowDegenerateTexCoordsEx(dynamic jsonData) : base("AllowDegenerateTexCoords")
            {
                Type = "bool";
                HelpText = "The AllowDegenerateTexCoords flag. If true, texture coordinates are allowed to become degenerate (triangles can have 0 area in texture space). This may sometimes look better, but if tangent space normals are used, tangent spaces may become degenerate.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonAllowDegenerateTexCoordsEx DeepCopy()
            {
                return (SimplygonAllowDegenerateTexCoordsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.AllowDegenerateTexCoords;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool KeepSymmetry { get { return _KeepSymmetry; } set { _KeepSymmetry = value; OnPropertyChanged(); } }
        private bool _KeepSymmetry;
        public SimplygonKeepSymmetryEx KeepSymmetryUI { get; set; }
        public class SimplygonKeepSymmetryEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.KeepSymmetry;
                }

                set
                {
                    bool needReload = Parent.KeepSymmetry != value;
                    Parent.KeepSymmetry = value;
                    Parent.UseAutomaticSymmetryDetectionUI.Visible = Visible;
                    Parent.UseSymmetryQuadRetriangulatorUI.Visible = Visible;
                    Parent.SymmetryAxisUI.Visible = Visible;
                    Parent.SymmetryOffsetUI.Visible = Visible;
                    Parent.SymmetryDetectionToleranceUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonKeepSymmetryEx() : base("KeepSymmetry")
            {
                Type = "bool";
                HelpText = "The KeepSymmetry flag. If set, the reducer will detect symmetric features, and retain symmetry during processing. Please note that for a geometry to be considered symmetrical, also the texture coordinates must be mirrored.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonKeepSymmetryEx(dynamic jsonData) : base("KeepSymmetry")
            {
                Type = "bool";
                HelpText = "The KeepSymmetry flag. If set, the reducer will detect symmetric features, and retain symmetry during processing. Please note that for a geometry to be considered symmetrical, also the texture coordinates must be mirrored.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonKeepSymmetryEx DeepCopy()
            {
                return (SimplygonKeepSymmetryEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.KeepSymmetry;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseAutomaticSymmetryDetection { get { return _UseAutomaticSymmetryDetection; } set { _UseAutomaticSymmetryDetection = value; OnPropertyChanged(); } }
        private bool _UseAutomaticSymmetryDetection;
        public SimplygonUseAutomaticSymmetryDetectionEx UseAutomaticSymmetryDetectionUI { get; set; }
        public class SimplygonUseAutomaticSymmetryDetectionEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseAutomaticSymmetryDetection;
                }

                set
                {
                    bool needReload = Parent.UseAutomaticSymmetryDetection != value;
                    Parent.UseAutomaticSymmetryDetection = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.KeepSymmetryUI != null ) { return Parent.KeepSymmetry && Parent.KeepSymmetryUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonUseAutomaticSymmetryDetectionEx() : base("UseAutomaticSymmetryDetection")
            {
                Type = "bool";
                HelpText = "The AutomaticSymmetryDetection flag. If set, and KeepSymmetry is on, the reducer will detect any X,Y,Z symmetry plane and will override any user set symmetry plane with the detected one. If no symmetry is found, KeepSymmetry will be turned off before reduction.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseAutomaticSymmetryDetectionEx(dynamic jsonData) : base("UseAutomaticSymmetryDetection")
            {
                Type = "bool";
                HelpText = "The AutomaticSymmetryDetection flag. If set, and KeepSymmetry is on, the reducer will detect any X,Y,Z symmetry plane and will override any user set symmetry plane with the detected one. If no symmetry is found, KeepSymmetry will be turned off before reduction.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseAutomaticSymmetryDetectionEx DeepCopy()
            {
                return (SimplygonUseAutomaticSymmetryDetectionEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.KeepSymmetryUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseAutomaticSymmetryDetection;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseSymmetryQuadRetriangulator { get { return _UseSymmetryQuadRetriangulator; } set { _UseSymmetryQuadRetriangulator = value; OnPropertyChanged(); } }
        private bool _UseSymmetryQuadRetriangulator;
        public SimplygonUseSymmetryQuadRetriangulatorEx UseSymmetryQuadRetriangulatorUI { get; set; }
        public class SimplygonUseSymmetryQuadRetriangulatorEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseSymmetryQuadRetriangulator;
                }

                set
                {
                    bool needReload = Parent.UseSymmetryQuadRetriangulator != value;
                    Parent.UseSymmetryQuadRetriangulator = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.KeepSymmetryUI != null ) { return Parent.KeepSymmetry && Parent.KeepSymmetryUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonUseSymmetryQuadRetriangulatorEx() : base("UseSymmetryQuadRetriangulator")
            {
                Type = "bool";
                HelpText = "The UseSymmetryQuadRetriangulator flag. If true, and KeepSymmetry is on, any triangles that have been triangulated from symmetrical quads into unsymmetrical triangles are detected and fixed. The edges of said triangles are flipped across the old quad so that the mesh becomes symmetrical again.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseSymmetryQuadRetriangulatorEx(dynamic jsonData) : base("UseSymmetryQuadRetriangulator")
            {
                Type = "bool";
                HelpText = "The UseSymmetryQuadRetriangulator flag. If true, and KeepSymmetry is on, any triangles that have been triangulated from symmetrical quads into unsymmetrical triangles are detected and fixed. The edges of said triangles are flipped across the old quad so that the mesh becomes symmetrical again.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseSymmetryQuadRetriangulatorEx DeepCopy()
            {
                return (SimplygonUseSymmetryQuadRetriangulatorEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.KeepSymmetryUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseSymmetryQuadRetriangulator;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public ESymmetryAxis SymmetryAxis { get { return _SymmetryAxis; } set { _SymmetryAxis = value; OnPropertyChanged(); } }
        private ESymmetryAxis _SymmetryAxis;
        public SimplygonSymmetryAxisEx SymmetryAxisUI { get; set; }
        public class SimplygonSymmetryAxisEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public ESymmetryAxis Value
            {
                get
                {
                    return Parent.SymmetryAxis;
                }

                set
                {
                    bool needReload = Parent.SymmetryAxis != value;
                    Parent.SymmetryAxis = value;
                    OnPropertyChanged();
                }

            }

            public ESymmetryAxis DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.KeepSymmetryUI != null ) { return Parent.KeepSymmetry && Parent.KeepSymmetryUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(ESymmetryAxis)); } }

            public SimplygonSymmetryAxisEx() : base("SymmetryAxis")
            {
                Type = "enum";
                HelpText = "Set what axis to be used for symmetry calculations.";
                TypeOverride = "";
                DefaultValue = ESymmetryAxis.X;
                Visible = true;
            }

            public SimplygonSymmetryAxisEx(dynamic jsonData) : base("SymmetryAxis")
            {
                Type = "enum";
                HelpText = "Set what axis to be used for symmetry calculations.";
                TypeOverride = "";
                DefaultValue = ESymmetryAxis.X;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSymmetryAxisEx DeepCopy()
            {
                return (SimplygonSymmetryAxisEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.KeepSymmetryUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.SymmetryAxis;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (ESymmetryAxis)value;
            }

        }

        public float SymmetryOffset { get { return _SymmetryOffset; } set { _SymmetryOffset = value; OnPropertyChanged(); } }
        private float _SymmetryOffset;
        public SimplygonSymmetryOffsetEx SymmetryOffsetUI { get; set; }
        public class SimplygonSymmetryOffsetEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.SymmetryOffset;
                }

                set
                {
                    bool needReload = Parent.SymmetryOffset != value;
                    Parent.SymmetryOffset = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public override bool Visible { get { if( Parent.KeepSymmetryUI != null ) { return Parent.KeepSymmetry && Parent.KeepSymmetryUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonSymmetryOffsetEx() : base("SymmetryOffset")
            {
                Type = "real";
                HelpText = "Set SymmetryOffset, the position on the symmetry axis where the symmetry plane is placed.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonSymmetryOffsetEx(dynamic jsonData) : base("SymmetryOffset")
            {
                Type = "real";
                HelpText = "Set SymmetryOffset, the position on the symmetry axis where the symmetry plane is placed.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SymmetryOffset: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SymmetryOffset: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSymmetryOffsetEx DeepCopy()
            {
                return (SimplygonSymmetryOffsetEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.KeepSymmetryUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.SymmetryOffset;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float SymmetryDetectionTolerance { get { return _SymmetryDetectionTolerance; } set { _SymmetryDetectionTolerance = value; OnPropertyChanged(); } }
        private float _SymmetryDetectionTolerance;
        public SimplygonSymmetryDetectionToleranceEx SymmetryDetectionToleranceUI { get; set; }
        public class SimplygonSymmetryDetectionToleranceEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.SymmetryDetectionTolerance;
                }

                set
                {
                    bool needReload = Parent.SymmetryDetectionTolerance != value;
                    Parent.SymmetryDetectionTolerance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public override bool Visible { get { if( Parent.KeepSymmetryUI != null ) { return Parent.KeepSymmetry && Parent.KeepSymmetryUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonSymmetryDetectionToleranceEx() : base("SymmetryDetectionTolerance")
            {
                Type = "real";
                HelpText = "The tolerance used when detecting symmetry. Values in the ranges 1e-5 to 1e-3 will usually produce good results. This specific tolerance corresponds to the off-plane tolerance, ie. the tolerance of the coordinate components that are not the symmetry axis. The in-plane tolerance is always 10 times the off-plane tolerance. This value is relative to the size of the Geometry, so 0.01 would mean 1% of the bounding box size of the Geometry.";
                TypeOverride = "";
                DefaultValue = 0.0001f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.0001f;
                Visible = true;
            }

            public SimplygonSymmetryDetectionToleranceEx(dynamic jsonData) : base("SymmetryDetectionTolerance")
            {
                Type = "real";
                HelpText = "The tolerance used when detecting symmetry. Values in the ranges 1e-5 to 1e-3 will usually produce good results. This specific tolerance corresponds to the off-plane tolerance, ie. the tolerance of the coordinate components that are not the symmetry axis. The in-plane tolerance is always 10 times the off-plane tolerance. This value is relative to the size of the Geometry, so 0.01 would mean 1% of the bounding box size of the Geometry.";
                TypeOverride = "";
                DefaultValue = 0.0001f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SymmetryDetectionTolerance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SymmetryDetectionTolerance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.0001f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSymmetryDetectionToleranceEx DeepCopy()
            {
                return (SimplygonSymmetryDetectionToleranceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.KeepSymmetryUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.SymmetryDetectionTolerance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EDataCreationPreferences DataCreationPreferences { get { return _DataCreationPreferences; } set { _DataCreationPreferences = value; OnPropertyChanged(); } }
        private EDataCreationPreferences _DataCreationPreferences;
        public SimplygonDataCreationPreferencesEx DataCreationPreferencesUI { get; set; }
        public class SimplygonDataCreationPreferencesEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public EDataCreationPreferences Value
            {
                get
                {
                    return Parent.DataCreationPreferences;
                }

                set
                {
                    bool needReload = Parent.DataCreationPreferences != value;
                    Parent.DataCreationPreferences = value;
                    OnPropertyChanged();
                }

            }

            public EDataCreationPreferences DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDataCreationPreferences)); } }

            public SimplygonDataCreationPreferencesEx() : base("DataCreationPreferences")
            {
                Type = "enum";
                HelpText = "The flag that specifies how big 'freedom' Simplygon has when it comes to altering vertex/triangle data. Allowing more altered data means it will be easier to create good looking LODs, but without altered data it will be easier to keep the memory-usage in the LOD-chain more optimized. Note: When using OnlyUseOriginalData, the geometry being reduced can not have a node transformation matrix other than the identity matrix.";
                TypeOverride = "";
                DefaultValue = EDataCreationPreferences.PreferOptimizedResult;
                Visible = true;
            }

            public SimplygonDataCreationPreferencesEx(dynamic jsonData) : base("DataCreationPreferences")
            {
                Type = "enum";
                HelpText = "The flag that specifies how big 'freedom' Simplygon has when it comes to altering vertex/triangle data. Allowing more altered data means it will be easier to create good looking LODs, but without altered data it will be easier to keep the memory-usage in the LOD-chain more optimized. Note: When using OnlyUseOriginalData, the geometry being reduced can not have a node transformation matrix other than the identity matrix.";
                TypeOverride = "";
                DefaultValue = EDataCreationPreferences.PreferOptimizedResult;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDataCreationPreferencesEx DeepCopy()
            {
                return (SimplygonDataCreationPreferencesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DataCreationPreferences;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDataCreationPreferences)value;
            }

        }

        public float OutwardMoveMultiplier { get { return _OutwardMoveMultiplier; } set { _OutwardMoveMultiplier = value; OnPropertyChanged(); } }
        private float _OutwardMoveMultiplier;
        public SimplygonOutwardMoveMultiplierEx OutwardMoveMultiplierUI { get; set; }
        public class SimplygonOutwardMoveMultiplierEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.OutwardMoveMultiplier;
                }

                set
                {
                    bool needReload = Parent.OutwardMoveMultiplier != value;
                    Parent.OutwardMoveMultiplier = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonOutwardMoveMultiplierEx() : base("OutwardMoveMultiplier")
            {
                Type = "real";
                HelpText = "The outward move multiplier, how much the mesh is allowed to grow its silhouette perimeter.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonOutwardMoveMultiplierEx(dynamic jsonData) : base("OutwardMoveMultiplier")
            {
                Type = "real";
                HelpText = "The outward move multiplier, how much the mesh is allowed to grow its silhouette perimeter.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OutwardMoveMultiplier: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OutwardMoveMultiplier: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutwardMoveMultiplierEx DeepCopy()
            {
                return (SimplygonOutwardMoveMultiplierEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.OutwardMoveMultiplier;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float InwardMoveMultiplier { get { return _InwardMoveMultiplier; } set { _InwardMoveMultiplier = value; OnPropertyChanged(); } }
        private float _InwardMoveMultiplier;
        public SimplygonInwardMoveMultiplierEx InwardMoveMultiplierUI { get; set; }
        public class SimplygonInwardMoveMultiplierEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.InwardMoveMultiplier;
                }

                set
                {
                    bool needReload = Parent.InwardMoveMultiplier != value;
                    Parent.InwardMoveMultiplier = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonInwardMoveMultiplierEx() : base("InwardMoveMultiplier")
            {
                Type = "real";
                HelpText = "The inward move multiplier, how much the mesh is allowed to shrink its silhouette perimeter.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonInwardMoveMultiplierEx(dynamic jsonData) : base("InwardMoveMultiplier")
            {
                Type = "real";
                HelpText = "The inward move multiplier, how much the mesh is allowed to shrink its silhouette perimeter.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"InwardMoveMultiplier: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"InwardMoveMultiplier: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonInwardMoveMultiplierEx DeepCopy()
            {
                return (SimplygonInwardMoveMultiplierEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.InwardMoveMultiplier;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool UseHighQualityNormalCalculation { get { return _UseHighQualityNormalCalculation; } set { _UseHighQualityNormalCalculation = value; OnPropertyChanged(); } }
        private bool _UseHighQualityNormalCalculation;
        public SimplygonUseHighQualityNormalCalculationEx UseHighQualityNormalCalculationUI { get; set; }
        public class SimplygonUseHighQualityNormalCalculationEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseHighQualityNormalCalculation;
                }

                set
                {
                    bool needReload = Parent.UseHighQualityNormalCalculation != value;
                    Parent.UseHighQualityNormalCalculation = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseHighQualityNormalCalculationEx() : base("UseHighQualityNormalCalculation")
            {
                Type = "bool";
                HelpText = "Set to true and the reducer will do a much more precise way of calculating the vertex normals. It will however be slower. Set to false and it will do a much more rough estimation of what the vertex normals will look like, but faster.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseHighQualityNormalCalculationEx(dynamic jsonData) : base("UseHighQualityNormalCalculation")
            {
                Type = "bool";
                HelpText = "Set to true and the reducer will do a much more precise way of calculating the vertex normals. It will however be slower. Set to false and it will do a much more rough estimation of what the vertex normals will look like, but faster.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseHighQualityNormalCalculationEx DeepCopy()
            {
                return (SimplygonUseHighQualityNormalCalculationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseHighQualityNormalCalculation;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool MergeGeometries { get { return _MergeGeometries; } set { _MergeGeometries = value; OnPropertyChanged(); } }
        private bool _MergeGeometries;
        public SimplygonMergeGeometriesEx MergeGeometriesUI { get; set; }
        public class SimplygonMergeGeometriesEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.MergeGeometries;
                }

                set
                {
                    bool needReload = Parent.MergeGeometries != value;
                    Parent.MergeGeometries = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonMergeGeometriesEx() : base("MergeGeometries")
            {
                Type = "bool";
                HelpText = "The processor will merge all the geometries in the scene into a single geometry if MergeGeometries is enabled.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonMergeGeometriesEx(dynamic jsonData) : base("MergeGeometries")
            {
                Type = "bool";
                HelpText = "The processor will merge all the geometries in the scene into a single geometry if MergeGeometries is enabled.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMergeGeometriesEx DeepCopy()
            {
                return (SimplygonMergeGeometriesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.MergeGeometries;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool KeepUnprocessedSceneMeshes { get { return _KeepUnprocessedSceneMeshes; } set { _KeepUnprocessedSceneMeshes = value; OnPropertyChanged(); } }
        private bool _KeepUnprocessedSceneMeshes;
        public SimplygonKeepUnprocessedSceneMeshesEx KeepUnprocessedSceneMeshesUI { get; set; }
        public class SimplygonKeepUnprocessedSceneMeshesEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.KeepUnprocessedSceneMeshes;
                }

                set
                {
                    bool needReload = Parent.KeepUnprocessedSceneMeshes != value;
                    Parent.KeepUnprocessedSceneMeshes = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonKeepUnprocessedSceneMeshesEx() : base("KeepUnprocessedSceneMeshes")
            {
                Type = "bool";
                HelpText = "If false, the processor will remove all geometry and scene meshes which were not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated, while the rest of the scene tree is kept intact. New geometry is always added as the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonKeepUnprocessedSceneMeshesEx(dynamic jsonData) : base("KeepUnprocessedSceneMeshes")
            {
                Type = "bool";
                HelpText = "If false, the processor will remove all geometry and scene meshes which were not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated, while the rest of the scene tree is kept intact. New geometry is always added as the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonKeepUnprocessedSceneMeshesEx DeepCopy()
            {
                return (SimplygonKeepUnprocessedSceneMeshesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.KeepUnprocessedSceneMeshes;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool LockGeometricBorder { get { return _LockGeometricBorder; } set { _LockGeometricBorder = value; OnPropertyChanged(); } }
        private bool _LockGeometricBorder;
        public SimplygonLockGeometricBorderEx LockGeometricBorderUI { get; set; }
        public class SimplygonLockGeometricBorderEx : SimplygonSettingsProperty
        {
            public SimplygonReductionSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.LockGeometricBorder;
                }

                set
                {
                    bool needReload = Parent.LockGeometricBorder != value;
                    Parent.LockGeometricBorder = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonLockGeometricBorderEx() : base("LockGeometricBorder")
            {
                Type = "bool";
                HelpText = "If set, will lock the geometric border of the geometry, and not reduce at all. This setting might be useful if the geometry needs to fit a neighbor geometry, but will reduce overall reduction quality (geometric quality over reduction ratio)";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonLockGeometricBorderEx(dynamic jsonData) : base("LockGeometricBorder")
            {
                Type = "bool";
                HelpText = "If set, will lock the geometric border of the geometry, and not reduce at all. This setting might be useful if the geometry needs to fit a neighbor geometry, but will reduce overall reduction quality (geometric quality over reduction ratio)";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonLockGeometricBorderEx DeepCopy()
            {
                return (SimplygonLockGeometricBorderEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.LockGeometricBorder;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonReductionSettings() : base("ReductionSettings")
        {
            Visible = true;
            ReductionTargetTriangleRatioEnabledUI = new SimplygonReductionTargetTriangleRatioEnabledEx();
            ReductionTargetTriangleRatioEnabledUI.Parent = this;
            ReductionTargetTriangleRatioEnabled = ReductionTargetTriangleRatioEnabledUI.DefaultValue;
            Items.Add(ReductionTargetTriangleRatioEnabledUI);
            ReductionTargetTriangleRatioUI = new SimplygonReductionTargetTriangleRatioEx();
            ReductionTargetTriangleRatioUI.Parent = this;
            ReductionTargetTriangleRatio = ReductionTargetTriangleRatioUI.DefaultValue;
            Items.Add(ReductionTargetTriangleRatioUI);
            ReductionTargetTriangleCountEnabledUI = new SimplygonReductionTargetTriangleCountEnabledEx();
            ReductionTargetTriangleCountEnabledUI.Parent = this;
            ReductionTargetTriangleCountEnabled = ReductionTargetTriangleCountEnabledUI.DefaultValue;
            Items.Add(ReductionTargetTriangleCountEnabledUI);
            ReductionTargetTriangleCountUI = new SimplygonReductionTargetTriangleCountEx();
            ReductionTargetTriangleCountUI.Parent = this;
            ReductionTargetTriangleCount = ReductionTargetTriangleCountUI.DefaultValue;
            Items.Add(ReductionTargetTriangleCountUI);
            ReductionTargetMaxDeviationEnabledUI = new SimplygonReductionTargetMaxDeviationEnabledEx();
            ReductionTargetMaxDeviationEnabledUI.Parent = this;
            ReductionTargetMaxDeviationEnabled = ReductionTargetMaxDeviationEnabledUI.DefaultValue;
            Items.Add(ReductionTargetMaxDeviationEnabledUI);
            ReductionTargetMaxDeviationUI = new SimplygonReductionTargetMaxDeviationEx();
            ReductionTargetMaxDeviationUI.Parent = this;
            ReductionTargetMaxDeviation = ReductionTargetMaxDeviationUI.DefaultValue;
            Items.Add(ReductionTargetMaxDeviationUI);
            ReductionTargetOnScreenSizeEnabledUI = new SimplygonReductionTargetOnScreenSizeEnabledEx();
            ReductionTargetOnScreenSizeEnabledUI.Parent = this;
            ReductionTargetOnScreenSizeEnabled = ReductionTargetOnScreenSizeEnabledUI.DefaultValue;
            Items.Add(ReductionTargetOnScreenSizeEnabledUI);
            ReductionTargetOnScreenSizeUI = new SimplygonReductionTargetOnScreenSizeEx();
            ReductionTargetOnScreenSizeUI.Parent = this;
            ReductionTargetOnScreenSize = ReductionTargetOnScreenSizeUI.DefaultValue;
            Items.Add(ReductionTargetOnScreenSizeUI);
            ReductionTargetStopConditionUI = new SimplygonReductionTargetStopConditionEx();
            ReductionTargetStopConditionUI.Parent = this;
            ReductionTargetStopCondition = ReductionTargetStopConditionUI.DefaultValue;
            Items.Add(ReductionTargetStopConditionUI);
            ReductionHeuristicsUI = new SimplygonReductionHeuristicsEx();
            ReductionHeuristicsUI.Parent = this;
            ReductionHeuristics = ReductionHeuristicsUI.DefaultValue;
            Items.Add(ReductionHeuristicsUI);
            GeometryImportanceUI = new SimplygonGeometryImportanceEx();
            GeometryImportanceUI.Parent = this;
            GeometryImportance = GeometryImportanceUI.DefaultValue;
            Items.Add(GeometryImportanceUI);
            MaterialImportanceUI = new SimplygonMaterialImportanceEx();
            MaterialImportanceUI.Parent = this;
            MaterialImportance = MaterialImportanceUI.DefaultValue;
            Items.Add(MaterialImportanceUI);
            TextureImportanceUI = new SimplygonTextureImportanceEx();
            TextureImportanceUI.Parent = this;
            TextureImportance = TextureImportanceUI.DefaultValue;
            Items.Add(TextureImportanceUI);
            ShadingImportanceUI = new SimplygonShadingImportanceEx();
            ShadingImportanceUI.Parent = this;
            ShadingImportance = ShadingImportanceUI.DefaultValue;
            Items.Add(ShadingImportanceUI);
            GroupImportanceUI = new SimplygonGroupImportanceEx();
            GroupImportanceUI.Parent = this;
            GroupImportance = GroupImportanceUI.DefaultValue;
            Items.Add(GroupImportanceUI);
            VertexColorImportanceUI = new SimplygonVertexColorImportanceEx();
            VertexColorImportanceUI.Parent = this;
            VertexColorImportance = VertexColorImportanceUI.DefaultValue;
            Items.Add(VertexColorImportanceUI);
            EdgeSetImportanceUI = new SimplygonEdgeSetImportanceEx();
            EdgeSetImportanceUI.Parent = this;
            EdgeSetImportance = EdgeSetImportanceUI.DefaultValue;
            Items.Add(EdgeSetImportanceUI);
            SkinningImportanceUI = new SimplygonSkinningImportanceEx();
            SkinningImportanceUI.Parent = this;
            SkinningImportance = SkinningImportanceUI.DefaultValue;
            Items.Add(SkinningImportanceUI);
            CurvatureImportanceUI = new SimplygonCurvatureImportanceEx();
            CurvatureImportanceUI.Parent = this;
            CurvatureImportance = CurvatureImportanceUI.DefaultValue;
            Items.Add(CurvatureImportanceUI);
            OutwardMoveMultiplierUI = new SimplygonOutwardMoveMultiplierEx();
            OutwardMoveMultiplierUI.Parent = this;
            OutwardMoveMultiplier = OutwardMoveMultiplierUI.DefaultValue;
            Items.Add(OutwardMoveMultiplierUI);
            InwardMoveMultiplierUI = new SimplygonInwardMoveMultiplierEx();
            InwardMoveMultiplierUI.Parent = this;
            InwardMoveMultiplier = InwardMoveMultiplierUI.DefaultValue;
            Items.Add(InwardMoveMultiplierUI);
            KeepSymmetryUI = new SimplygonKeepSymmetryEx();
            KeepSymmetryUI.Parent = this;
            KeepSymmetry = KeepSymmetryUI.DefaultValue;
            Items.Add(KeepSymmetryUI);
            UseSymmetryQuadRetriangulatorUI = new SimplygonUseSymmetryQuadRetriangulatorEx();
            UseSymmetryQuadRetriangulatorUI.Parent = this;
            UseSymmetryQuadRetriangulator = UseSymmetryQuadRetriangulatorUI.DefaultValue;
            Items.Add(UseSymmetryQuadRetriangulatorUI);
            UseAutomaticSymmetryDetectionUI = new SimplygonUseAutomaticSymmetryDetectionEx();
            UseAutomaticSymmetryDetectionUI.Parent = this;
            UseAutomaticSymmetryDetection = UseAutomaticSymmetryDetectionUI.DefaultValue;
            Items.Add(UseAutomaticSymmetryDetectionUI);
            SymmetryDetectionToleranceUI = new SimplygonSymmetryDetectionToleranceEx();
            SymmetryDetectionToleranceUI.Parent = this;
            SymmetryDetectionTolerance = SymmetryDetectionToleranceUI.DefaultValue;
            Items.Add(SymmetryDetectionToleranceUI);
            SymmetryAxisUI = new SimplygonSymmetryAxisEx();
            SymmetryAxisUI.Parent = this;
            SymmetryAxis = SymmetryAxisUI.DefaultValue;
            Items.Add(SymmetryAxisUI);
            SymmetryOffsetUI = new SimplygonSymmetryOffsetEx();
            SymmetryOffsetUI.Parent = this;
            SymmetryOffset = SymmetryOffsetUI.DefaultValue;
            Items.Add(SymmetryOffsetUI);
            CreateGeomorphGeometryUI = new SimplygonCreateGeomorphGeometryEx();
            CreateGeomorphGeometryUI.Parent = this;
            CreateGeomorphGeometry = CreateGeomorphGeometryUI.DefaultValue;
            Items.Add(CreateGeomorphGeometryUI);
            DataCreationPreferencesUI = new SimplygonDataCreationPreferencesEx();
            DataCreationPreferencesUI.Parent = this;
            DataCreationPreferences = DataCreationPreferencesUI.DefaultValue;
            Items.Add(DataCreationPreferencesUI);
            UseHighQualityNormalCalculationUI = new SimplygonUseHighQualityNormalCalculationEx();
            UseHighQualityNormalCalculationUI.Parent = this;
            UseHighQualityNormalCalculation = UseHighQualityNormalCalculationUI.DefaultValue;
            Items.Add(UseHighQualityNormalCalculationUI);
            LockGeometricBorderUI = new SimplygonLockGeometricBorderEx();
            LockGeometricBorderUI.Parent = this;
            LockGeometricBorder = LockGeometricBorderUI.DefaultValue;
            Items.Add(LockGeometricBorderUI);
            MergeGeometriesUI = new SimplygonMergeGeometriesEx();
            MergeGeometriesUI.Parent = this;
            MergeGeometries = MergeGeometriesUI.DefaultValue;
            Items.Add(MergeGeometriesUI);
            AllowDegenerateTexCoordsUI = new SimplygonAllowDegenerateTexCoordsEx();
            AllowDegenerateTexCoordsUI.Parent = this;
            AllowDegenerateTexCoords = AllowDegenerateTexCoordsUI.DefaultValue;
            Items.Add(AllowDegenerateTexCoordsUI);
            KeepUnprocessedSceneMeshesUI = new SimplygonKeepUnprocessedSceneMeshesEx();
            KeepUnprocessedSceneMeshesUI.Parent = this;
            KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshesUI.DefaultValue;
            Items.Add(KeepUnprocessedSceneMeshesUI);
        }

        public SimplygonReductionSettings(dynamic jsonData) : base("ReductionSettings")
        {
            Visible = true;
            ReductionTargetTriangleRatioEnabledUI = new SimplygonReductionTargetTriangleRatioEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetTriangleRatioEnabledUI") != null ? jsonData.ReductionTargetTriangleRatioEnabledUI : null);
            ReductionTargetTriangleRatioEnabledUI.Parent = this;
            ReductionTargetTriangleRatioEnabled = ReductionTargetTriangleRatioEnabledUI.DefaultValue;
            Items.Add(ReductionTargetTriangleRatioEnabledUI);
            ReductionTargetTriangleRatioUI = new SimplygonReductionTargetTriangleRatioEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetTriangleRatioUI") != null ? jsonData.ReductionTargetTriangleRatioUI : null);
            ReductionTargetTriangleRatioUI.Parent = this;
            ReductionTargetTriangleRatio = ReductionTargetTriangleRatioUI.DefaultValue;
            Items.Add(ReductionTargetTriangleRatioUI);
            ReductionTargetTriangleCountEnabledUI = new SimplygonReductionTargetTriangleCountEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetTriangleCountEnabledUI") != null ? jsonData.ReductionTargetTriangleCountEnabledUI : null);
            ReductionTargetTriangleCountEnabledUI.Parent = this;
            ReductionTargetTriangleCountEnabled = ReductionTargetTriangleCountEnabledUI.DefaultValue;
            Items.Add(ReductionTargetTriangleCountEnabledUI);
            ReductionTargetTriangleCountUI = new SimplygonReductionTargetTriangleCountEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetTriangleCountUI") != null ? jsonData.ReductionTargetTriangleCountUI : null);
            ReductionTargetTriangleCountUI.Parent = this;
            ReductionTargetTriangleCount = ReductionTargetTriangleCountUI.DefaultValue;
            Items.Add(ReductionTargetTriangleCountUI);
            ReductionTargetMaxDeviationEnabledUI = new SimplygonReductionTargetMaxDeviationEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetMaxDeviationEnabledUI") != null ? jsonData.ReductionTargetMaxDeviationEnabledUI : null);
            ReductionTargetMaxDeviationEnabledUI.Parent = this;
            ReductionTargetMaxDeviationEnabled = ReductionTargetMaxDeviationEnabledUI.DefaultValue;
            Items.Add(ReductionTargetMaxDeviationEnabledUI);
            ReductionTargetMaxDeviationUI = new SimplygonReductionTargetMaxDeviationEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetMaxDeviationUI") != null ? jsonData.ReductionTargetMaxDeviationUI : null);
            ReductionTargetMaxDeviationUI.Parent = this;
            ReductionTargetMaxDeviation = ReductionTargetMaxDeviationUI.DefaultValue;
            Items.Add(ReductionTargetMaxDeviationUI);
            ReductionTargetOnScreenSizeEnabledUI = new SimplygonReductionTargetOnScreenSizeEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetOnScreenSizeEnabledUI") != null ? jsonData.ReductionTargetOnScreenSizeEnabledUI : null);
            ReductionTargetOnScreenSizeEnabledUI.Parent = this;
            ReductionTargetOnScreenSizeEnabled = ReductionTargetOnScreenSizeEnabledUI.DefaultValue;
            Items.Add(ReductionTargetOnScreenSizeEnabledUI);
            ReductionTargetOnScreenSizeUI = new SimplygonReductionTargetOnScreenSizeEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetOnScreenSizeUI") != null ? jsonData.ReductionTargetOnScreenSizeUI : null);
            ReductionTargetOnScreenSizeUI.Parent = this;
            ReductionTargetOnScreenSize = ReductionTargetOnScreenSizeUI.DefaultValue;
            Items.Add(ReductionTargetOnScreenSizeUI);
            ReductionTargetStopConditionUI = new SimplygonReductionTargetStopConditionEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionTargetStopConditionUI") != null ? jsonData.ReductionTargetStopConditionUI : null);
            ReductionTargetStopConditionUI.Parent = this;
            ReductionTargetStopCondition = ReductionTargetStopConditionUI.DefaultValue;
            Items.Add(ReductionTargetStopConditionUI);
            ReductionHeuristicsUI = new SimplygonReductionHeuristicsEx(jsonData != null && ((JObject)jsonData).GetValue("ReductionHeuristicsUI") != null ? jsonData.ReductionHeuristicsUI : null);
            ReductionHeuristicsUI.Parent = this;
            ReductionHeuristics = ReductionHeuristicsUI.DefaultValue;
            Items.Add(ReductionHeuristicsUI);
            GeometryImportanceUI = new SimplygonGeometryImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("GeometryImportanceUI") != null ? jsonData.GeometryImportanceUI : null);
            GeometryImportanceUI.Parent = this;
            GeometryImportance = GeometryImportanceUI.DefaultValue;
            Items.Add(GeometryImportanceUI);
            MaterialImportanceUI = new SimplygonMaterialImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialImportanceUI") != null ? jsonData.MaterialImportanceUI : null);
            MaterialImportanceUI.Parent = this;
            MaterialImportance = MaterialImportanceUI.DefaultValue;
            Items.Add(MaterialImportanceUI);
            TextureImportanceUI = new SimplygonTextureImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("TextureImportanceUI") != null ? jsonData.TextureImportanceUI : null);
            TextureImportanceUI.Parent = this;
            TextureImportance = TextureImportanceUI.DefaultValue;
            Items.Add(TextureImportanceUI);
            ShadingImportanceUI = new SimplygonShadingImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("ShadingImportanceUI") != null ? jsonData.ShadingImportanceUI : null);
            ShadingImportanceUI.Parent = this;
            ShadingImportance = ShadingImportanceUI.DefaultValue;
            Items.Add(ShadingImportanceUI);
            GroupImportanceUI = new SimplygonGroupImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("GroupImportanceUI") != null ? jsonData.GroupImportanceUI : null);
            GroupImportanceUI.Parent = this;
            GroupImportance = GroupImportanceUI.DefaultValue;
            Items.Add(GroupImportanceUI);
            VertexColorImportanceUI = new SimplygonVertexColorImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("VertexColorImportanceUI") != null ? jsonData.VertexColorImportanceUI : null);
            VertexColorImportanceUI.Parent = this;
            VertexColorImportance = VertexColorImportanceUI.DefaultValue;
            Items.Add(VertexColorImportanceUI);
            EdgeSetImportanceUI = new SimplygonEdgeSetImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("EdgeSetImportanceUI") != null ? jsonData.EdgeSetImportanceUI : null);
            EdgeSetImportanceUI.Parent = this;
            EdgeSetImportance = EdgeSetImportanceUI.DefaultValue;
            Items.Add(EdgeSetImportanceUI);
            SkinningImportanceUI = new SimplygonSkinningImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("SkinningImportanceUI") != null ? jsonData.SkinningImportanceUI : null);
            SkinningImportanceUI.Parent = this;
            SkinningImportance = SkinningImportanceUI.DefaultValue;
            Items.Add(SkinningImportanceUI);
            CurvatureImportanceUI = new SimplygonCurvatureImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("CurvatureImportanceUI") != null ? jsonData.CurvatureImportanceUI : null);
            CurvatureImportanceUI.Parent = this;
            CurvatureImportance = CurvatureImportanceUI.DefaultValue;
            Items.Add(CurvatureImportanceUI);
            OutwardMoveMultiplierUI = new SimplygonOutwardMoveMultiplierEx(jsonData != null && ((JObject)jsonData).GetValue("OutwardMoveMultiplierUI") != null ? jsonData.OutwardMoveMultiplierUI : null);
            OutwardMoveMultiplierUI.Parent = this;
            OutwardMoveMultiplier = OutwardMoveMultiplierUI.DefaultValue;
            Items.Add(OutwardMoveMultiplierUI);
            InwardMoveMultiplierUI = new SimplygonInwardMoveMultiplierEx(jsonData != null && ((JObject)jsonData).GetValue("InwardMoveMultiplierUI") != null ? jsonData.InwardMoveMultiplierUI : null);
            InwardMoveMultiplierUI.Parent = this;
            InwardMoveMultiplier = InwardMoveMultiplierUI.DefaultValue;
            Items.Add(InwardMoveMultiplierUI);
            KeepSymmetryUI = new SimplygonKeepSymmetryEx(jsonData != null && ((JObject)jsonData).GetValue("KeepSymmetryUI") != null ? jsonData.KeepSymmetryUI : null);
            KeepSymmetryUI.Parent = this;
            KeepSymmetry = KeepSymmetryUI.DefaultValue;
            Items.Add(KeepSymmetryUI);
            UseSymmetryQuadRetriangulatorUI = new SimplygonUseSymmetryQuadRetriangulatorEx(jsonData != null && ((JObject)jsonData).GetValue("UseSymmetryQuadRetriangulatorUI") != null ? jsonData.UseSymmetryQuadRetriangulatorUI : null);
            UseSymmetryQuadRetriangulatorUI.Parent = this;
            UseSymmetryQuadRetriangulator = UseSymmetryQuadRetriangulatorUI.DefaultValue;
            Items.Add(UseSymmetryQuadRetriangulatorUI);
            UseAutomaticSymmetryDetectionUI = new SimplygonUseAutomaticSymmetryDetectionEx(jsonData != null && ((JObject)jsonData).GetValue("UseAutomaticSymmetryDetectionUI") != null ? jsonData.UseAutomaticSymmetryDetectionUI : null);
            UseAutomaticSymmetryDetectionUI.Parent = this;
            UseAutomaticSymmetryDetection = UseAutomaticSymmetryDetectionUI.DefaultValue;
            Items.Add(UseAutomaticSymmetryDetectionUI);
            SymmetryDetectionToleranceUI = new SimplygonSymmetryDetectionToleranceEx(jsonData != null && ((JObject)jsonData).GetValue("SymmetryDetectionToleranceUI") != null ? jsonData.SymmetryDetectionToleranceUI : null);
            SymmetryDetectionToleranceUI.Parent = this;
            SymmetryDetectionTolerance = SymmetryDetectionToleranceUI.DefaultValue;
            Items.Add(SymmetryDetectionToleranceUI);
            SymmetryAxisUI = new SimplygonSymmetryAxisEx(jsonData != null && ((JObject)jsonData).GetValue("SymmetryAxisUI") != null ? jsonData.SymmetryAxisUI : null);
            SymmetryAxisUI.Parent = this;
            SymmetryAxis = SymmetryAxisUI.DefaultValue;
            Items.Add(SymmetryAxisUI);
            SymmetryOffsetUI = new SimplygonSymmetryOffsetEx(jsonData != null && ((JObject)jsonData).GetValue("SymmetryOffsetUI") != null ? jsonData.SymmetryOffsetUI : null);
            SymmetryOffsetUI.Parent = this;
            SymmetryOffset = SymmetryOffsetUI.DefaultValue;
            Items.Add(SymmetryOffsetUI);
            CreateGeomorphGeometryUI = new SimplygonCreateGeomorphGeometryEx(jsonData != null && ((JObject)jsonData).GetValue("CreateGeomorphGeometryUI") != null ? jsonData.CreateGeomorphGeometryUI : null);
            CreateGeomorphGeometryUI.Parent = this;
            CreateGeomorphGeometry = CreateGeomorphGeometryUI.DefaultValue;
            Items.Add(CreateGeomorphGeometryUI);
            DataCreationPreferencesUI = new SimplygonDataCreationPreferencesEx(jsonData != null && ((JObject)jsonData).GetValue("DataCreationPreferencesUI") != null ? jsonData.DataCreationPreferencesUI : null);
            DataCreationPreferencesUI.Parent = this;
            DataCreationPreferences = DataCreationPreferencesUI.DefaultValue;
            Items.Add(DataCreationPreferencesUI);
            UseHighQualityNormalCalculationUI = new SimplygonUseHighQualityNormalCalculationEx(jsonData != null && ((JObject)jsonData).GetValue("UseHighQualityNormalCalculationUI") != null ? jsonData.UseHighQualityNormalCalculationUI : null);
            UseHighQualityNormalCalculationUI.Parent = this;
            UseHighQualityNormalCalculation = UseHighQualityNormalCalculationUI.DefaultValue;
            Items.Add(UseHighQualityNormalCalculationUI);
            LockGeometricBorderUI = new SimplygonLockGeometricBorderEx(jsonData != null && ((JObject)jsonData).GetValue("LockGeometricBorderUI") != null ? jsonData.LockGeometricBorderUI : null);
            LockGeometricBorderUI.Parent = this;
            LockGeometricBorder = LockGeometricBorderUI.DefaultValue;
            Items.Add(LockGeometricBorderUI);
            MergeGeometriesUI = new SimplygonMergeGeometriesEx(jsonData != null && ((JObject)jsonData).GetValue("MergeGeometriesUI") != null ? jsonData.MergeGeometriesUI : null);
            MergeGeometriesUI.Parent = this;
            MergeGeometries = MergeGeometriesUI.DefaultValue;
            Items.Add(MergeGeometriesUI);
            AllowDegenerateTexCoordsUI = new SimplygonAllowDegenerateTexCoordsEx(jsonData != null && ((JObject)jsonData).GetValue("AllowDegenerateTexCoordsUI") != null ? jsonData.AllowDegenerateTexCoordsUI : null);
            AllowDegenerateTexCoordsUI.Parent = this;
            AllowDegenerateTexCoords = AllowDegenerateTexCoordsUI.DefaultValue;
            Items.Add(AllowDegenerateTexCoordsUI);
            KeepUnprocessedSceneMeshesUI = new SimplygonKeepUnprocessedSceneMeshesEx(jsonData != null && ((JObject)jsonData).GetValue("KeepUnprocessedSceneMeshesUI") != null ? jsonData.KeepUnprocessedSceneMeshesUI : null);
            KeepUnprocessedSceneMeshesUI.Parent = this;
            KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshesUI.DefaultValue;
            Items.Add(KeepUnprocessedSceneMeshesUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonReductionSettings();
            copy.Items.Clear();
            copy.ReductionTargetTriangleRatioEnabledUI = this.ReductionTargetTriangleRatioEnabledUI.DeepCopy();
            copy.ReductionTargetTriangleRatioEnabledUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetTriangleRatioEnabledUI);
            copy.ReductionTargetTriangleRatioUI = this.ReductionTargetTriangleRatioUI.DeepCopy();
            copy.ReductionTargetTriangleRatioUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetTriangleRatioUI);
            copy.ReductionTargetTriangleCountEnabledUI = this.ReductionTargetTriangleCountEnabledUI.DeepCopy();
            copy.ReductionTargetTriangleCountEnabledUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetTriangleCountEnabledUI);
            copy.ReductionTargetTriangleCountUI = this.ReductionTargetTriangleCountUI.DeepCopy();
            copy.ReductionTargetTriangleCountUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetTriangleCountUI);
            copy.ReductionTargetMaxDeviationEnabledUI = this.ReductionTargetMaxDeviationEnabledUI.DeepCopy();
            copy.ReductionTargetMaxDeviationEnabledUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetMaxDeviationEnabledUI);
            copy.ReductionTargetMaxDeviationUI = this.ReductionTargetMaxDeviationUI.DeepCopy();
            copy.ReductionTargetMaxDeviationUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetMaxDeviationUI);
            copy.ReductionTargetOnScreenSizeEnabledUI = this.ReductionTargetOnScreenSizeEnabledUI.DeepCopy();
            copy.ReductionTargetOnScreenSizeEnabledUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetOnScreenSizeEnabledUI);
            copy.ReductionTargetOnScreenSizeUI = this.ReductionTargetOnScreenSizeUI.DeepCopy();
            copy.ReductionTargetOnScreenSizeUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetOnScreenSizeUI);
            copy.ReductionTargetStopConditionUI = this.ReductionTargetStopConditionUI.DeepCopy();
            copy.ReductionTargetStopConditionUI.Parent = copy;
            copy.Items.Add(copy.ReductionTargetStopConditionUI);
            copy.ReductionHeuristicsUI = this.ReductionHeuristicsUI.DeepCopy();
            copy.ReductionHeuristicsUI.Parent = copy;
            copy.Items.Add(copy.ReductionHeuristicsUI);
            copy.GeometryImportanceUI = this.GeometryImportanceUI.DeepCopy();
            copy.GeometryImportanceUI.Parent = copy;
            copy.Items.Add(copy.GeometryImportanceUI);
            copy.MaterialImportanceUI = this.MaterialImportanceUI.DeepCopy();
            copy.MaterialImportanceUI.Parent = copy;
            copy.Items.Add(copy.MaterialImportanceUI);
            copy.TextureImportanceUI = this.TextureImportanceUI.DeepCopy();
            copy.TextureImportanceUI.Parent = copy;
            copy.Items.Add(copy.TextureImportanceUI);
            copy.ShadingImportanceUI = this.ShadingImportanceUI.DeepCopy();
            copy.ShadingImportanceUI.Parent = copy;
            copy.Items.Add(copy.ShadingImportanceUI);
            copy.GroupImportanceUI = this.GroupImportanceUI.DeepCopy();
            copy.GroupImportanceUI.Parent = copy;
            copy.Items.Add(copy.GroupImportanceUI);
            copy.VertexColorImportanceUI = this.VertexColorImportanceUI.DeepCopy();
            copy.VertexColorImportanceUI.Parent = copy;
            copy.Items.Add(copy.VertexColorImportanceUI);
            copy.EdgeSetImportanceUI = this.EdgeSetImportanceUI.DeepCopy();
            copy.EdgeSetImportanceUI.Parent = copy;
            copy.Items.Add(copy.EdgeSetImportanceUI);
            copy.SkinningImportanceUI = this.SkinningImportanceUI.DeepCopy();
            copy.SkinningImportanceUI.Parent = copy;
            copy.Items.Add(copy.SkinningImportanceUI);
            copy.CurvatureImportanceUI = this.CurvatureImportanceUI.DeepCopy();
            copy.CurvatureImportanceUI.Parent = copy;
            copy.Items.Add(copy.CurvatureImportanceUI);
            copy.OutwardMoveMultiplierUI = this.OutwardMoveMultiplierUI.DeepCopy();
            copy.OutwardMoveMultiplierUI.Parent = copy;
            copy.Items.Add(copy.OutwardMoveMultiplierUI);
            copy.InwardMoveMultiplierUI = this.InwardMoveMultiplierUI.DeepCopy();
            copy.InwardMoveMultiplierUI.Parent = copy;
            copy.Items.Add(copy.InwardMoveMultiplierUI);
            copy.KeepSymmetryUI = this.KeepSymmetryUI.DeepCopy();
            copy.KeepSymmetryUI.Parent = copy;
            copy.Items.Add(copy.KeepSymmetryUI);
            copy.UseSymmetryQuadRetriangulatorUI = this.UseSymmetryQuadRetriangulatorUI.DeepCopy();
            copy.UseSymmetryQuadRetriangulatorUI.Parent = copy;
            copy.Items.Add(copy.UseSymmetryQuadRetriangulatorUI);
            copy.UseAutomaticSymmetryDetectionUI = this.UseAutomaticSymmetryDetectionUI.DeepCopy();
            copy.UseAutomaticSymmetryDetectionUI.Parent = copy;
            copy.Items.Add(copy.UseAutomaticSymmetryDetectionUI);
            copy.SymmetryDetectionToleranceUI = this.SymmetryDetectionToleranceUI.DeepCopy();
            copy.SymmetryDetectionToleranceUI.Parent = copy;
            copy.Items.Add(copy.SymmetryDetectionToleranceUI);
            copy.SymmetryAxisUI = this.SymmetryAxisUI.DeepCopy();
            copy.SymmetryAxisUI.Parent = copy;
            copy.Items.Add(copy.SymmetryAxisUI);
            copy.SymmetryOffsetUI = this.SymmetryOffsetUI.DeepCopy();
            copy.SymmetryOffsetUI.Parent = copy;
            copy.Items.Add(copy.SymmetryOffsetUI);
            copy.CreateGeomorphGeometryUI = this.CreateGeomorphGeometryUI.DeepCopy();
            copy.CreateGeomorphGeometryUI.Parent = copy;
            copy.Items.Add(copy.CreateGeomorphGeometryUI);
            copy.DataCreationPreferencesUI = this.DataCreationPreferencesUI.DeepCopy();
            copy.DataCreationPreferencesUI.Parent = copy;
            copy.Items.Add(copy.DataCreationPreferencesUI);
            copy.UseHighQualityNormalCalculationUI = this.UseHighQualityNormalCalculationUI.DeepCopy();
            copy.UseHighQualityNormalCalculationUI.Parent = copy;
            copy.Items.Add(copy.UseHighQualityNormalCalculationUI);
            copy.LockGeometricBorderUI = this.LockGeometricBorderUI.DeepCopy();
            copy.LockGeometricBorderUI.Parent = copy;
            copy.Items.Add(copy.LockGeometricBorderUI);
            copy.MergeGeometriesUI = this.MergeGeometriesUI.DeepCopy();
            copy.MergeGeometriesUI.Parent = copy;
            copy.Items.Add(copy.MergeGeometriesUI);
            copy.AllowDegenerateTexCoordsUI = this.AllowDegenerateTexCoordsUI.DeepCopy();
            copy.AllowDegenerateTexCoordsUI.Parent = copy;
            copy.Items.Add(copy.AllowDegenerateTexCoordsUI);
            copy.KeepUnprocessedSceneMeshesUI = this.KeepUnprocessedSceneMeshesUI.DeepCopy();
            copy.KeepUnprocessedSceneMeshesUI.Parent = copy;
            copy.Items.Add(copy.KeepUnprocessedSceneMeshesUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ReductionTargetTriangleRatioEnabled = ReductionTargetTriangleRatioEnabled;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetTriangleRatioEnabledUI = ReductionTargetTriangleRatioEnabledUI.SaveJson();
            }

            jsonData.ReductionTargetTriangleRatio = ReductionTargetTriangleRatio;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetTriangleRatioUI = ReductionTargetTriangleRatioUI.SaveJson();
            }

            jsonData.ReductionTargetTriangleCountEnabled = ReductionTargetTriangleCountEnabled;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetTriangleCountEnabledUI = ReductionTargetTriangleCountEnabledUI.SaveJson();
            }

            jsonData.ReductionTargetTriangleCount = ReductionTargetTriangleCount;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetTriangleCountUI = ReductionTargetTriangleCountUI.SaveJson();
            }

            jsonData.ReductionTargetMaxDeviationEnabled = ReductionTargetMaxDeviationEnabled;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetMaxDeviationEnabledUI = ReductionTargetMaxDeviationEnabledUI.SaveJson();
            }

            jsonData.ReductionTargetMaxDeviation = ReductionTargetMaxDeviation;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetMaxDeviationUI = ReductionTargetMaxDeviationUI.SaveJson();
            }

            jsonData.ReductionTargetOnScreenSizeEnabled = ReductionTargetOnScreenSizeEnabled;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetOnScreenSizeEnabledUI = ReductionTargetOnScreenSizeEnabledUI.SaveJson();
            }

            jsonData.ReductionTargetOnScreenSize = ReductionTargetOnScreenSize;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetOnScreenSizeUI = ReductionTargetOnScreenSizeUI.SaveJson();
            }

            jsonData.ReductionTargetStopCondition = (int)ReductionTargetStopCondition;
            if(serializeUIComponents)
            {
                jsonData.ReductionTargetStopConditionUI = ReductionTargetStopConditionUI.SaveJson();
            }

            jsonData.ReductionHeuristics = (int)ReductionHeuristics;
            if(serializeUIComponents)
            {
                jsonData.ReductionHeuristicsUI = ReductionHeuristicsUI.SaveJson();
            }

            jsonData.GeometryImportance = GeometryImportance;
            if(serializeUIComponents)
            {
                jsonData.GeometryImportanceUI = GeometryImportanceUI.SaveJson();
            }

            jsonData.MaterialImportance = MaterialImportance;
            if(serializeUIComponents)
            {
                jsonData.MaterialImportanceUI = MaterialImportanceUI.SaveJson();
            }

            jsonData.TextureImportance = TextureImportance;
            if(serializeUIComponents)
            {
                jsonData.TextureImportanceUI = TextureImportanceUI.SaveJson();
            }

            jsonData.ShadingImportance = ShadingImportance;
            if(serializeUIComponents)
            {
                jsonData.ShadingImportanceUI = ShadingImportanceUI.SaveJson();
            }

            jsonData.GroupImportance = GroupImportance;
            if(serializeUIComponents)
            {
                jsonData.GroupImportanceUI = GroupImportanceUI.SaveJson();
            }

            jsonData.VertexColorImportance = VertexColorImportance;
            if(serializeUIComponents)
            {
                jsonData.VertexColorImportanceUI = VertexColorImportanceUI.SaveJson();
            }

            jsonData.EdgeSetImportance = EdgeSetImportance;
            if(serializeUIComponents)
            {
                jsonData.EdgeSetImportanceUI = EdgeSetImportanceUI.SaveJson();
            }

            jsonData.SkinningImportance = SkinningImportance;
            if(serializeUIComponents)
            {
                jsonData.SkinningImportanceUI = SkinningImportanceUI.SaveJson();
            }

            jsonData.CurvatureImportance = CurvatureImportance;
            if(serializeUIComponents)
            {
                jsonData.CurvatureImportanceUI = CurvatureImportanceUI.SaveJson();
            }

            jsonData.CreateGeomorphGeometry = CreateGeomorphGeometry;
            if(serializeUIComponents)
            {
                jsonData.CreateGeomorphGeometryUI = CreateGeomorphGeometryUI.SaveJson();
            }

            jsonData.AllowDegenerateTexCoords = AllowDegenerateTexCoords;
            if(serializeUIComponents)
            {
                jsonData.AllowDegenerateTexCoordsUI = AllowDegenerateTexCoordsUI.SaveJson();
            }

            jsonData.KeepSymmetry = KeepSymmetry;
            if(serializeUIComponents)
            {
                jsonData.KeepSymmetryUI = KeepSymmetryUI.SaveJson();
            }

            jsonData.UseAutomaticSymmetryDetection = UseAutomaticSymmetryDetection;
            if(serializeUIComponents)
            {
                jsonData.UseAutomaticSymmetryDetectionUI = UseAutomaticSymmetryDetectionUI.SaveJson();
            }

            jsonData.UseSymmetryQuadRetriangulator = UseSymmetryQuadRetriangulator;
            if(serializeUIComponents)
            {
                jsonData.UseSymmetryQuadRetriangulatorUI = UseSymmetryQuadRetriangulatorUI.SaveJson();
            }

            jsonData.SymmetryAxis = (int)SymmetryAxis;
            if(serializeUIComponents)
            {
                jsonData.SymmetryAxisUI = SymmetryAxisUI.SaveJson();
            }

            jsonData.SymmetryOffset = SymmetryOffset;
            if(serializeUIComponents)
            {
                jsonData.SymmetryOffsetUI = SymmetryOffsetUI.SaveJson();
            }

            jsonData.SymmetryDetectionTolerance = SymmetryDetectionTolerance;
            if(serializeUIComponents)
            {
                jsonData.SymmetryDetectionToleranceUI = SymmetryDetectionToleranceUI.SaveJson();
            }

            jsonData.DataCreationPreferences = (int)DataCreationPreferences;
            if(serializeUIComponents)
            {
                jsonData.DataCreationPreferencesUI = DataCreationPreferencesUI.SaveJson();
            }

            jsonData.OutwardMoveMultiplier = OutwardMoveMultiplier;
            if(serializeUIComponents)
            {
                jsonData.OutwardMoveMultiplierUI = OutwardMoveMultiplierUI.SaveJson();
            }

            jsonData.InwardMoveMultiplier = InwardMoveMultiplier;
            if(serializeUIComponents)
            {
                jsonData.InwardMoveMultiplierUI = InwardMoveMultiplierUI.SaveJson();
            }

            jsonData.UseHighQualityNormalCalculation = UseHighQualityNormalCalculation;
            if(serializeUIComponents)
            {
                jsonData.UseHighQualityNormalCalculationUI = UseHighQualityNormalCalculationUI.SaveJson();
            }

            jsonData.MergeGeometries = MergeGeometries;
            if(serializeUIComponents)
            {
                jsonData.MergeGeometriesUI = MergeGeometriesUI.SaveJson();
            }

            jsonData.KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshes;
            if(serializeUIComponents)
            {
                jsonData.KeepUnprocessedSceneMeshesUI = KeepUnprocessedSceneMeshesUI.SaveJson();
            }

            jsonData.LockGeometricBorder = LockGeometricBorder;
            if(serializeUIComponents)
            {
                jsonData.LockGeometricBorderUI = LockGeometricBorderUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("ReductionTargetTriangleRatioEnabled") != null)
            {
                ReductionTargetTriangleRatioEnabled = (bool)jsonData.ReductionTargetTriangleRatioEnabled;
            }

            if(jsonData.GetValue("ReductionTargetTriangleRatio") != null)
            {
                float newReductionTargetTriangleRatio = (float)jsonData.ReductionTargetTriangleRatio;
                if (newReductionTargetTriangleRatio >= ReductionTargetTriangleRatioUI.DefaultMinValue && newReductionTargetTriangleRatio <= ReductionTargetTriangleRatioUI.DefaultMaxValue)
                {
                    ReductionTargetTriangleRatio = newReductionTargetTriangleRatio;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetTriangleRatio: Invalid value {newReductionTargetTriangleRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ReductionTargetTriangleRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ReductionTargetTriangleCountEnabled") != null)
            {
                ReductionTargetTriangleCountEnabled = (bool)jsonData.ReductionTargetTriangleCountEnabled;
            }

            if(jsonData.GetValue("ReductionTargetTriangleCount") != null)
            {
                var newReductionTargetTriangleCount = (int)jsonData.ReductionTargetTriangleCount;
                if (newReductionTargetTriangleCount >= ReductionTargetTriangleCountUI.DefaultMinValue && newReductionTargetTriangleCount <= ReductionTargetTriangleCountUI.DefaultMaxValue)
                {
                    ReductionTargetTriangleCount = newReductionTargetTriangleCount;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetTriangleCount: Invalid value {newReductionTargetTriangleCount}, using default value {ReductionTargetTriangleCount.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ReductionTargetMaxDeviationEnabled") != null)
            {
                ReductionTargetMaxDeviationEnabled = (bool)jsonData.ReductionTargetMaxDeviationEnabled;
            }

            if(jsonData.GetValue("ReductionTargetMaxDeviation") != null)
            {
                float newReductionTargetMaxDeviation = (float)jsonData.ReductionTargetMaxDeviation;
                if (newReductionTargetMaxDeviation >= ReductionTargetMaxDeviationUI.DefaultMinValue && newReductionTargetMaxDeviation <= ReductionTargetMaxDeviationUI.DefaultMaxValue)
                {
                    ReductionTargetMaxDeviation = newReductionTargetMaxDeviation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetMaxDeviation: Invalid value {newReductionTargetMaxDeviation.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ReductionTargetMaxDeviation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ReductionTargetOnScreenSizeEnabled") != null)
            {
                ReductionTargetOnScreenSizeEnabled = (bool)jsonData.ReductionTargetOnScreenSizeEnabled;
            }

            if(jsonData.GetValue("ReductionTargetOnScreenSize") != null)
            {
                var newReductionTargetOnScreenSize = (int)jsonData.ReductionTargetOnScreenSize;
                if (newReductionTargetOnScreenSize >= ReductionTargetOnScreenSizeUI.DefaultMinValue && newReductionTargetOnScreenSize <= ReductionTargetOnScreenSizeUI.DefaultMaxValue)
                {
                    ReductionTargetOnScreenSize = newReductionTargetOnScreenSize;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ReductionTargetOnScreenSize: Invalid value {newReductionTargetOnScreenSize}, using default value {ReductionTargetOnScreenSize.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ReductionTargetStopCondition") != null)
            {
                ReductionTargetStopCondition = (EStopCondition)jsonData.ReductionTargetStopCondition;
            }

            if(jsonData.GetValue("ReductionHeuristics") != null)
            {
                ReductionHeuristics = (EReductionHeuristics)jsonData.ReductionHeuristics;
            }

            if(jsonData.GetValue("GeometryImportance") != null)
            {
                float newGeometryImportance = (float)jsonData.GeometryImportance;
                if (newGeometryImportance >= GeometryImportanceUI.DefaultMinValue && newGeometryImportance <= GeometryImportanceUI.DefaultMaxValue)
                {
                    GeometryImportance = newGeometryImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"GeometryImportance: Invalid value {newGeometryImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {GeometryImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MaterialImportance") != null)
            {
                float newMaterialImportance = (float)jsonData.MaterialImportance;
                if (newMaterialImportance >= MaterialImportanceUI.DefaultMinValue && newMaterialImportance <= MaterialImportanceUI.DefaultMaxValue)
                {
                    MaterialImportance = newMaterialImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MaterialImportance: Invalid value {newMaterialImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MaterialImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("TextureImportance") != null)
            {
                float newTextureImportance = (float)jsonData.TextureImportance;
                if (newTextureImportance >= TextureImportanceUI.DefaultMinValue && newTextureImportance <= TextureImportanceUI.DefaultMaxValue)
                {
                    TextureImportance = newTextureImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TextureImportance: Invalid value {newTextureImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {TextureImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ShadingImportance") != null)
            {
                float newShadingImportance = (float)jsonData.ShadingImportance;
                if (newShadingImportance >= ShadingImportanceUI.DefaultMinValue && newShadingImportance <= ShadingImportanceUI.DefaultMaxValue)
                {
                    ShadingImportance = newShadingImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ShadingImportance: Invalid value {newShadingImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ShadingImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("GroupImportance") != null)
            {
                float newGroupImportance = (float)jsonData.GroupImportance;
                if (newGroupImportance >= GroupImportanceUI.DefaultMinValue && newGroupImportance <= GroupImportanceUI.DefaultMaxValue)
                {
                    GroupImportance = newGroupImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"GroupImportance: Invalid value {newGroupImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {GroupImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("VertexColorImportance") != null)
            {
                float newVertexColorImportance = (float)jsonData.VertexColorImportance;
                if (newVertexColorImportance >= VertexColorImportanceUI.DefaultMinValue && newVertexColorImportance <= VertexColorImportanceUI.DefaultMaxValue)
                {
                    VertexColorImportance = newVertexColorImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"VertexColorImportance: Invalid value {newVertexColorImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {VertexColorImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("EdgeSetImportance") != null)
            {
                float newEdgeSetImportance = (float)jsonData.EdgeSetImportance;
                if (newEdgeSetImportance >= EdgeSetImportanceUI.DefaultMinValue && newEdgeSetImportance <= EdgeSetImportanceUI.DefaultMaxValue)
                {
                    EdgeSetImportance = newEdgeSetImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"EdgeSetImportance: Invalid value {newEdgeSetImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {EdgeSetImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("SkinningImportance") != null)
            {
                float newSkinningImportance = (float)jsonData.SkinningImportance;
                if (newSkinningImportance >= SkinningImportanceUI.DefaultMinValue && newSkinningImportance <= SkinningImportanceUI.DefaultMaxValue)
                {
                    SkinningImportance = newSkinningImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SkinningImportance: Invalid value {newSkinningImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {SkinningImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("CurvatureImportance") != null)
            {
                float newCurvatureImportance = (float)jsonData.CurvatureImportance;
                if (newCurvatureImportance >= CurvatureImportanceUI.DefaultMinValue && newCurvatureImportance <= CurvatureImportanceUI.DefaultMaxValue)
                {
                    CurvatureImportance = newCurvatureImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"CurvatureImportance: Invalid value {newCurvatureImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {CurvatureImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("CreateGeomorphGeometry") != null)
            {
                CreateGeomorphGeometry = (bool)jsonData.CreateGeomorphGeometry;
            }

            if(jsonData.GetValue("AllowDegenerateTexCoords") != null)
            {
                AllowDegenerateTexCoords = (bool)jsonData.AllowDegenerateTexCoords;
            }

            if(jsonData.GetValue("KeepSymmetry") != null)
            {
                KeepSymmetry = (bool)jsonData.KeepSymmetry;
            }

            if(jsonData.GetValue("UseAutomaticSymmetryDetection") != null)
            {
                UseAutomaticSymmetryDetection = (bool)jsonData.UseAutomaticSymmetryDetection;
            }

            if(jsonData.GetValue("UseSymmetryQuadRetriangulator") != null)
            {
                UseSymmetryQuadRetriangulator = (bool)jsonData.UseSymmetryQuadRetriangulator;
            }

            if(jsonData.GetValue("SymmetryAxis") != null)
            {
                SymmetryAxis = (ESymmetryAxis)jsonData.SymmetryAxis;
            }

            if(jsonData.GetValue("SymmetryOffset") != null)
            {
                float newSymmetryOffset = (float)jsonData.SymmetryOffset;
                if (newSymmetryOffset >= SymmetryOffsetUI.DefaultMinValue && newSymmetryOffset <= SymmetryOffsetUI.DefaultMaxValue)
                {
                    SymmetryOffset = newSymmetryOffset;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SymmetryOffset: Invalid value {newSymmetryOffset.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {SymmetryOffset.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("SymmetryDetectionTolerance") != null)
            {
                float newSymmetryDetectionTolerance = (float)jsonData.SymmetryDetectionTolerance;
                if (newSymmetryDetectionTolerance >= SymmetryDetectionToleranceUI.DefaultMinValue && newSymmetryDetectionTolerance <= SymmetryDetectionToleranceUI.DefaultMaxValue)
                {
                    SymmetryDetectionTolerance = newSymmetryDetectionTolerance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SymmetryDetectionTolerance: Invalid value {newSymmetryDetectionTolerance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {SymmetryDetectionTolerance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("DataCreationPreferences") != null)
            {
                DataCreationPreferences = (EDataCreationPreferences)jsonData.DataCreationPreferences;
            }

            if(jsonData.GetValue("OutwardMoveMultiplier") != null)
            {
                float newOutwardMoveMultiplier = (float)jsonData.OutwardMoveMultiplier;
                if (newOutwardMoveMultiplier >= OutwardMoveMultiplierUI.DefaultMinValue && newOutwardMoveMultiplier <= OutwardMoveMultiplierUI.DefaultMaxValue)
                {
                    OutwardMoveMultiplier = newOutwardMoveMultiplier;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OutwardMoveMultiplier: Invalid value {newOutwardMoveMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {OutwardMoveMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("InwardMoveMultiplier") != null)
            {
                float newInwardMoveMultiplier = (float)jsonData.InwardMoveMultiplier;
                if (newInwardMoveMultiplier >= InwardMoveMultiplierUI.DefaultMinValue && newInwardMoveMultiplier <= InwardMoveMultiplierUI.DefaultMaxValue)
                {
                    InwardMoveMultiplier = newInwardMoveMultiplier;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"InwardMoveMultiplier: Invalid value {newInwardMoveMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {InwardMoveMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UseHighQualityNormalCalculation") != null)
            {
                UseHighQualityNormalCalculation = (bool)jsonData.UseHighQualityNormalCalculation;
            }

            if(jsonData.GetValue("MergeGeometries") != null)
            {
                MergeGeometries = (bool)jsonData.MergeGeometries;
            }

            if(jsonData.GetValue("KeepUnprocessedSceneMeshes") != null)
            {
                KeepUnprocessedSceneMeshes = (bool)jsonData.KeepUnprocessedSceneMeshes;
            }

            if(jsonData.GetValue("LockGeometricBorder") != null)
            {
                LockGeometricBorder = (bool)jsonData.LockGeometricBorder;
            }

        }

        public override void Reset()
        {
            ReductionTargetTriangleRatioEnabledUI.Reset();
            ReductionTargetTriangleRatioUI.Reset();
            ReductionTargetTriangleCountEnabledUI.Reset();
            ReductionTargetTriangleCountUI.Reset();
            ReductionTargetMaxDeviationEnabledUI.Reset();
            ReductionTargetMaxDeviationUI.Reset();
            ReductionTargetOnScreenSizeEnabledUI.Reset();
            ReductionTargetOnScreenSizeUI.Reset();
            ReductionTargetStopConditionUI.Reset();
            ReductionHeuristicsUI.Reset();
            GeometryImportanceUI.Reset();
            MaterialImportanceUI.Reset();
            TextureImportanceUI.Reset();
            ShadingImportanceUI.Reset();
            GroupImportanceUI.Reset();
            VertexColorImportanceUI.Reset();
            EdgeSetImportanceUI.Reset();
            SkinningImportanceUI.Reset();
            CurvatureImportanceUI.Reset();
            CreateGeomorphGeometryUI.Reset();
            AllowDegenerateTexCoordsUI.Reset();
            KeepSymmetryUI.Reset();
            UseAutomaticSymmetryDetectionUI.Reset();
            UseSymmetryQuadRetriangulatorUI.Reset();
            SymmetryAxisUI.Reset();
            SymmetryOffsetUI.Reset();
            SymmetryDetectionToleranceUI.Reset();
            DataCreationPreferencesUI.Reset();
            OutwardMoveMultiplierUI.Reset();
            InwardMoveMultiplierUI.Reset();
            UseHighQualityNormalCalculationUI.Reset();
            MergeGeometriesUI.Reset();
            KeepUnprocessedSceneMeshesUI.Reset();
            LockGeometricBorderUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            ReductionTargetTriangleRatioEnabledUI.IsEditEnabled = isEditEnabled;
            ReductionTargetTriangleRatioUI.IsEditEnabled = isEditEnabled;
            ReductionTargetTriangleCountEnabledUI.IsEditEnabled = isEditEnabled;
            ReductionTargetTriangleCountUI.IsEditEnabled = isEditEnabled;
            ReductionTargetMaxDeviationEnabledUI.IsEditEnabled = isEditEnabled;
            ReductionTargetMaxDeviationUI.IsEditEnabled = isEditEnabled;
            ReductionTargetOnScreenSizeEnabledUI.IsEditEnabled = isEditEnabled;
            ReductionTargetOnScreenSizeUI.IsEditEnabled = isEditEnabled;
            ReductionTargetStopConditionUI.IsEditEnabled = isEditEnabled;
            ReductionHeuristicsUI.IsEditEnabled = isEditEnabled;
            GeometryImportanceUI.IsEditEnabled = isEditEnabled;
            MaterialImportanceUI.IsEditEnabled = isEditEnabled;
            TextureImportanceUI.IsEditEnabled = isEditEnabled;
            ShadingImportanceUI.IsEditEnabled = isEditEnabled;
            GroupImportanceUI.IsEditEnabled = isEditEnabled;
            VertexColorImportanceUI.IsEditEnabled = isEditEnabled;
            EdgeSetImportanceUI.IsEditEnabled = isEditEnabled;
            SkinningImportanceUI.IsEditEnabled = isEditEnabled;
            CurvatureImportanceUI.IsEditEnabled = isEditEnabled;
            CreateGeomorphGeometryUI.IsEditEnabled = isEditEnabled;
            AllowDegenerateTexCoordsUI.IsEditEnabled = isEditEnabled;
            KeepSymmetryUI.IsEditEnabled = isEditEnabled;
            UseAutomaticSymmetryDetectionUI.IsEditEnabled = isEditEnabled;
            UseSymmetryQuadRetriangulatorUI.IsEditEnabled = isEditEnabled;
            SymmetryAxisUI.IsEditEnabled = isEditEnabled;
            SymmetryOffsetUI.IsEditEnabled = isEditEnabled;
            SymmetryDetectionToleranceUI.IsEditEnabled = isEditEnabled;
            DataCreationPreferencesUI.IsEditEnabled = isEditEnabled;
            OutwardMoveMultiplierUI.IsEditEnabled = isEditEnabled;
            InwardMoveMultiplierUI.IsEditEnabled = isEditEnabled;
            UseHighQualityNormalCalculationUI.IsEditEnabled = isEditEnabled;
            MergeGeometriesUI.IsEditEnabled = isEditEnabled;
            KeepUnprocessedSceneMeshesUI.IsEditEnabled = isEditEnabled;
            LockGeometricBorderUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            ReductionTargetTriangleRatioEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetTriangleRatioUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetTriangleCountEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetTriangleCountUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetMaxDeviationEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetMaxDeviationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetOnScreenSizeEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetOnScreenSizeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionTargetStopConditionUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReductionHeuristicsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GeometryImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MaterialImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TextureImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ShadingImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GroupImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            VertexColorImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            EdgeSetImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SkinningImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            CurvatureImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutwardMoveMultiplierUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            InwardMoveMultiplierUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            KeepSymmetryUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseSymmetryQuadRetriangulatorUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseAutomaticSymmetryDetectionUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SymmetryDetectionToleranceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SymmetryAxisUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SymmetryOffsetUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            CreateGeomorphGeometryUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DataCreationPreferencesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseHighQualityNormalCalculationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            LockGeometricBorderUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MergeGeometriesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            AllowDegenerateTexCoordsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            KeepUnprocessedSceneMeshesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonRepairSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(UseTJunctionRemoverUI.Visible) return true;
                if(TJuncDistUI.Visible) return true;
                if(WeldDistUI.Visible) return true;
                if(WeldOnlyBorderVerticesUI.Visible) return true;
                if(WeldOnlyWithinMaterialUI.Visible) return true;
                if(WeldOnlyWithinSceneNodeUI.Visible) return true;
                if(WeldOnlyBetweenSceneNodesUI.Visible) return true;
                if(UseWeldingUI.Visible) return true;
                if(ProgressivePassesUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool UseTJunctionRemover { get { return _UseTJunctionRemover; } set { _UseTJunctionRemover = value; OnPropertyChanged(); } }
        private bool _UseTJunctionRemover;
        public SimplygonUseTJunctionRemoverEx UseTJunctionRemoverUI { get; set; }
        public class SimplygonUseTJunctionRemoverEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseTJunctionRemover;
                }

                set
                {
                    bool needReload = Parent.UseTJunctionRemover != value;
                    Parent.UseTJunctionRemover = value;
                    Parent.TJuncDistUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseTJunctionRemoverEx() : base("UseTJunctionRemover")
            {
                Type = "bool";
                HelpText = "If set, t-junctions will be removed. If enabled, it also requires UseWelding to be on.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseTJunctionRemoverEx(dynamic jsonData) : base("UseTJunctionRemover")
            {
                Type = "bool";
                HelpText = "If set, t-junctions will be removed. If enabled, it also requires UseWelding to be on.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseTJunctionRemoverEx DeepCopy()
            {
                return (SimplygonUseTJunctionRemoverEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseTJunctionRemover;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float TJuncDist { get { return _TJuncDist; } set { _TJuncDist = value; OnPropertyChanged(); } }
        private float _TJuncDist;
        public SimplygonTJuncDistEx TJuncDistUI { get; set; }
        public class SimplygonTJuncDistEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.TJuncDist;
                }

                set
                {
                    bool needReload = Parent.TJuncDist != value;
                    Parent.TJuncDist = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public override bool Visible { get { if( Parent.UseTJunctionRemoverUI != null ) { return Parent.UseTJunctionRemover && Parent.UseTJunctionRemoverUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonTJuncDistEx() : base("TJuncDist")
            {
                Type = "real";
                HelpText = "The T-Junction distance, below which, the T-Junctions will be welded.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonTJuncDistEx(dynamic jsonData) : base("TJuncDist")
            {
                Type = "real";
                HelpText = "The T-Junction distance, below which, the T-Junctions will be welded.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TJuncDist: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TJuncDist: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTJuncDistEx DeepCopy()
            {
                return (SimplygonTJuncDistEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.UseTJunctionRemoverUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.TJuncDist;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float WeldDist { get { return _WeldDist; } set { _WeldDist = value; OnPropertyChanged(); } }
        private float _WeldDist;
        public SimplygonWeldDistEx WeldDistUI { get; set; }
        public class SimplygonWeldDistEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.WeldDist;
                }

                set
                {
                    bool needReload = Parent.WeldDist != value;
                    Parent.WeldDist = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public override bool Visible { get { if( Parent.UseWeldingUI != null ) { return Parent.UseWelding && Parent.UseWeldingUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonWeldDistEx() : base("WeldDist")
            {
                Type = "real";
                HelpText = "The welding distance below which the vertices will be welded.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonWeldDistEx(dynamic jsonData) : base("WeldDist")
            {
                Type = "real";
                HelpText = "The welding distance below which the vertices will be welded.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"WeldDist: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"WeldDist: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeldDistEx DeepCopy()
            {
                return (SimplygonWeldDistEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.UseWeldingUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.WeldDist;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool WeldOnlyBorderVertices { get { return _WeldOnlyBorderVertices; } set { _WeldOnlyBorderVertices = value; OnPropertyChanged(); } }
        private bool _WeldOnlyBorderVertices;
        public SimplygonWeldOnlyBorderVerticesEx WeldOnlyBorderVerticesUI { get; set; }
        public class SimplygonWeldOnlyBorderVerticesEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.WeldOnlyBorderVertices;
                }

                set
                {
                    bool needReload = Parent.WeldOnlyBorderVertices != value;
                    Parent.WeldOnlyBorderVertices = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.UseWeldingUI != null ) { return Parent.UseWelding && Parent.UseWeldingUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonWeldOnlyBorderVerticesEx() : base("WeldOnlyBorderVertices")
            {
                Type = "bool";
                HelpText = "If set, only vertices that are on the border (as reported by the VertexBorder boolean field) are considered for the welding.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonWeldOnlyBorderVerticesEx(dynamic jsonData) : base("WeldOnlyBorderVertices")
            {
                Type = "bool";
                HelpText = "If set, only vertices that are on the border (as reported by the VertexBorder boolean field) are considered for the welding.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeldOnlyBorderVerticesEx DeepCopy()
            {
                return (SimplygonWeldOnlyBorderVerticesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.UseWeldingUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.WeldOnlyBorderVertices;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool WeldOnlyWithinMaterial { get { return _WeldOnlyWithinMaterial; } set { _WeldOnlyWithinMaterial = value; OnPropertyChanged(); } }
        private bool _WeldOnlyWithinMaterial;
        public SimplygonWeldOnlyWithinMaterialEx WeldOnlyWithinMaterialUI { get; set; }
        public class SimplygonWeldOnlyWithinMaterialEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.WeldOnlyWithinMaterial;
                }

                set
                {
                    bool needReload = Parent.WeldOnlyWithinMaterial != value;
                    Parent.WeldOnlyWithinMaterial = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.UseWeldingUI != null ) { return Parent.UseWelding && Parent.UseWeldingUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonWeldOnlyWithinMaterialEx() : base("WeldOnlyWithinMaterial")
            {
                Type = "bool";
                HelpText = "If set, only vertices that are within the same material are welded. Vertices on material borders are locked.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonWeldOnlyWithinMaterialEx(dynamic jsonData) : base("WeldOnlyWithinMaterial")
            {
                Type = "bool";
                HelpText = "If set, only vertices that are within the same material are welded. Vertices on material borders are locked.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeldOnlyWithinMaterialEx DeepCopy()
            {
                return (SimplygonWeldOnlyWithinMaterialEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.UseWeldingUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.WeldOnlyWithinMaterial;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool WeldOnlyWithinSceneNode { get { return _WeldOnlyWithinSceneNode; } set { _WeldOnlyWithinSceneNode = value; OnPropertyChanged(); } }
        private bool _WeldOnlyWithinSceneNode;
        public SimplygonWeldOnlyWithinSceneNodeEx WeldOnlyWithinSceneNodeUI { get; set; }
        public class SimplygonWeldOnlyWithinSceneNodeEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.WeldOnlyWithinSceneNode;
                }

                set
                {
                    bool needReload = Parent.WeldOnlyWithinSceneNode != value;
                    Parent.WeldOnlyWithinSceneNode = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.UseWeldingUI != null ) { return Parent.UseWelding && Parent.UseWeldingUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonWeldOnlyWithinSceneNodeEx() : base("WeldOnlyWithinSceneNode")
            {
                Type = "bool";
                HelpText = "If set, only vertices that are within the same scene node are welded.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonWeldOnlyWithinSceneNodeEx(dynamic jsonData) : base("WeldOnlyWithinSceneNode")
            {
                Type = "bool";
                HelpText = "If set, only vertices that are within the same scene node are welded.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeldOnlyWithinSceneNodeEx DeepCopy()
            {
                return (SimplygonWeldOnlyWithinSceneNodeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.UseWeldingUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.WeldOnlyWithinSceneNode;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool WeldOnlyBetweenSceneNodes { get { return _WeldOnlyBetweenSceneNodes; } set { _WeldOnlyBetweenSceneNodes = value; OnPropertyChanged(); } }
        private bool _WeldOnlyBetweenSceneNodes;
        public SimplygonWeldOnlyBetweenSceneNodesEx WeldOnlyBetweenSceneNodesUI { get; set; }
        public class SimplygonWeldOnlyBetweenSceneNodesEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.WeldOnlyBetweenSceneNodes;
                }

                set
                {
                    bool needReload = Parent.WeldOnlyBetweenSceneNodes != value;
                    Parent.WeldOnlyBetweenSceneNodes = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.UseWeldingUI != null ) { return Parent.UseWelding && Parent.UseWeldingUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonWeldOnlyBetweenSceneNodesEx() : base("WeldOnlyBetweenSceneNodes")
            {
                Type = "bool";
                HelpText = "If set, only vertices that belong to different scene nodes are considered for the welding. Affects both welder and t-junction remover.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonWeldOnlyBetweenSceneNodesEx(dynamic jsonData) : base("WeldOnlyBetweenSceneNodes")
            {
                Type = "bool";
                HelpText = "If set, only vertices that belong to different scene nodes are considered for the welding. Affects both welder and t-junction remover.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeldOnlyBetweenSceneNodesEx DeepCopy()
            {
                return (SimplygonWeldOnlyBetweenSceneNodesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.UseWeldingUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.WeldOnlyBetweenSceneNodes;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseWelding { get { return _UseWelding; } set { _UseWelding = value; OnPropertyChanged(); } }
        private bool _UseWelding;
        public SimplygonUseWeldingEx UseWeldingUI { get; set; }
        public class SimplygonUseWeldingEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseWelding;
                }

                set
                {
                    bool needReload = Parent.UseWelding != value;
                    Parent.UseWelding = value;
                    Parent.WeldDistUI.Visible = Visible;
                    Parent.WeldOnlyBorderVerticesUI.Visible = Visible;
                    Parent.WeldOnlyWithinMaterialUI.Visible = Visible;
                    Parent.WeldOnlyWithinSceneNodeUI.Visible = Visible;
                    Parent.WeldOnlyBetweenSceneNodesUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseWeldingEx() : base("UseWelding")
            {
                Type = "bool";
                HelpText = "If set, vertices within each others welding distance will be welded together.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseWeldingEx(dynamic jsonData) : base("UseWelding")
            {
                Type = "bool";
                HelpText = "If set, vertices within each others welding distance will be welded together.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseWeldingEx DeepCopy()
            {
                return (SimplygonUseWeldingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseWelding;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int ProgressivePasses { get { return _ProgressivePasses; } set { _ProgressivePasses = value; OnPropertyChanged(); } }
        private int _ProgressivePasses;
        public SimplygonProgressivePassesEx ProgressivePassesUI { get; set; }
        public class SimplygonProgressivePassesEx : SimplygonSettingsProperty
        {
            public SimplygonRepairSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.ProgressivePasses;
                }

                set
                {
                    bool needReload = Parent.ProgressivePasses != value;
                    Parent.ProgressivePasses = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonProgressivePassesEx() : base("ProgressivePasses")
            {
                Type = "uint";
                HelpText = "The number of progressive passes. Minimum is 1, but higher numbers give a better quality, at the expense of longer running time.";
                TypeOverride = "";
                DefaultValue = 3;
                MinValue = 1;
                MaxValue = 10;
                DefaultMinValue = 1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonProgressivePassesEx(dynamic jsonData) : base("ProgressivePasses")
            {
                Type = "uint";
                HelpText = "The number of progressive passes. Minimum is 1, but higher numbers give a better quality, at the expense of longer running time.";
                TypeOverride = "";
                DefaultValue = 3;
                MinValue = 1;
                DefaultMinValue = 1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ProgressivePasses: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ProgressivePasses: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonProgressivePassesEx DeepCopy()
            {
                return (SimplygonProgressivePassesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.ProgressivePasses;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonRepairSettings() : base("RepairSettings")
        {
            Visible = true;
            UseTJunctionRemoverUI = new SimplygonUseTJunctionRemoverEx();
            UseTJunctionRemoverUI.Parent = this;
            UseTJunctionRemover = UseTJunctionRemoverUI.DefaultValue;
            Items.Add(UseTJunctionRemoverUI);
            TJuncDistUI = new SimplygonTJuncDistEx();
            TJuncDistUI.Parent = this;
            TJuncDist = TJuncDistUI.DefaultValue;
            Items.Add(TJuncDistUI);
            UseWeldingUI = new SimplygonUseWeldingEx();
            UseWeldingUI.Parent = this;
            UseWelding = UseWeldingUI.DefaultValue;
            Items.Add(UseWeldingUI);
            WeldOnlyBorderVerticesUI = new SimplygonWeldOnlyBorderVerticesEx();
            WeldOnlyBorderVerticesUI.Parent = this;
            WeldOnlyBorderVertices = WeldOnlyBorderVerticesUI.DefaultValue;
            Items.Add(WeldOnlyBorderVerticesUI);
            WeldOnlyWithinMaterialUI = new SimplygonWeldOnlyWithinMaterialEx();
            WeldOnlyWithinMaterialUI.Parent = this;
            WeldOnlyWithinMaterial = WeldOnlyWithinMaterialUI.DefaultValue;
            Items.Add(WeldOnlyWithinMaterialUI);
            WeldOnlyWithinSceneNodeUI = new SimplygonWeldOnlyWithinSceneNodeEx();
            WeldOnlyWithinSceneNodeUI.Parent = this;
            WeldOnlyWithinSceneNode = WeldOnlyWithinSceneNodeUI.DefaultValue;
            Items.Add(WeldOnlyWithinSceneNodeUI);
            WeldOnlyBetweenSceneNodesUI = new SimplygonWeldOnlyBetweenSceneNodesEx();
            WeldOnlyBetweenSceneNodesUI.Parent = this;
            WeldOnlyBetweenSceneNodes = WeldOnlyBetweenSceneNodesUI.DefaultValue;
            Items.Add(WeldOnlyBetweenSceneNodesUI);
            WeldDistUI = new SimplygonWeldDistEx();
            WeldDistUI.Parent = this;
            WeldDist = WeldDistUI.DefaultValue;
            Items.Add(WeldDistUI);
            ProgressivePassesUI = new SimplygonProgressivePassesEx();
            ProgressivePassesUI.Parent = this;
            ProgressivePasses = ProgressivePassesUI.DefaultValue;
            Items.Add(ProgressivePassesUI);
        }

        public SimplygonRepairSettings(dynamic jsonData) : base("RepairSettings")
        {
            Visible = true;
            UseTJunctionRemoverUI = new SimplygonUseTJunctionRemoverEx(jsonData != null && ((JObject)jsonData).GetValue("UseTJunctionRemoverUI") != null ? jsonData.UseTJunctionRemoverUI : null);
            UseTJunctionRemoverUI.Parent = this;
            UseTJunctionRemover = UseTJunctionRemoverUI.DefaultValue;
            Items.Add(UseTJunctionRemoverUI);
            TJuncDistUI = new SimplygonTJuncDistEx(jsonData != null && ((JObject)jsonData).GetValue("TJuncDistUI") != null ? jsonData.TJuncDistUI : null);
            TJuncDistUI.Parent = this;
            TJuncDist = TJuncDistUI.DefaultValue;
            Items.Add(TJuncDistUI);
            UseWeldingUI = new SimplygonUseWeldingEx(jsonData != null && ((JObject)jsonData).GetValue("UseWeldingUI") != null ? jsonData.UseWeldingUI : null);
            UseWeldingUI.Parent = this;
            UseWelding = UseWeldingUI.DefaultValue;
            Items.Add(UseWeldingUI);
            WeldOnlyBorderVerticesUI = new SimplygonWeldOnlyBorderVerticesEx(jsonData != null && ((JObject)jsonData).GetValue("WeldOnlyBorderVerticesUI") != null ? jsonData.WeldOnlyBorderVerticesUI : null);
            WeldOnlyBorderVerticesUI.Parent = this;
            WeldOnlyBorderVertices = WeldOnlyBorderVerticesUI.DefaultValue;
            Items.Add(WeldOnlyBorderVerticesUI);
            WeldOnlyWithinMaterialUI = new SimplygonWeldOnlyWithinMaterialEx(jsonData != null && ((JObject)jsonData).GetValue("WeldOnlyWithinMaterialUI") != null ? jsonData.WeldOnlyWithinMaterialUI : null);
            WeldOnlyWithinMaterialUI.Parent = this;
            WeldOnlyWithinMaterial = WeldOnlyWithinMaterialUI.DefaultValue;
            Items.Add(WeldOnlyWithinMaterialUI);
            WeldOnlyWithinSceneNodeUI = new SimplygonWeldOnlyWithinSceneNodeEx(jsonData != null && ((JObject)jsonData).GetValue("WeldOnlyWithinSceneNodeUI") != null ? jsonData.WeldOnlyWithinSceneNodeUI : null);
            WeldOnlyWithinSceneNodeUI.Parent = this;
            WeldOnlyWithinSceneNode = WeldOnlyWithinSceneNodeUI.DefaultValue;
            Items.Add(WeldOnlyWithinSceneNodeUI);
            WeldOnlyBetweenSceneNodesUI = new SimplygonWeldOnlyBetweenSceneNodesEx(jsonData != null && ((JObject)jsonData).GetValue("WeldOnlyBetweenSceneNodesUI") != null ? jsonData.WeldOnlyBetweenSceneNodesUI : null);
            WeldOnlyBetweenSceneNodesUI.Parent = this;
            WeldOnlyBetweenSceneNodes = WeldOnlyBetweenSceneNodesUI.DefaultValue;
            Items.Add(WeldOnlyBetweenSceneNodesUI);
            WeldDistUI = new SimplygonWeldDistEx(jsonData != null && ((JObject)jsonData).GetValue("WeldDistUI") != null ? jsonData.WeldDistUI : null);
            WeldDistUI.Parent = this;
            WeldDist = WeldDistUI.DefaultValue;
            Items.Add(WeldDistUI);
            ProgressivePassesUI = new SimplygonProgressivePassesEx(jsonData != null && ((JObject)jsonData).GetValue("ProgressivePassesUI") != null ? jsonData.ProgressivePassesUI : null);
            ProgressivePassesUI.Parent = this;
            ProgressivePasses = ProgressivePassesUI.DefaultValue;
            Items.Add(ProgressivePassesUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonRepairSettings();
            copy.Items.Clear();
            copy.UseTJunctionRemoverUI = this.UseTJunctionRemoverUI.DeepCopy();
            copy.UseTJunctionRemoverUI.Parent = copy;
            copy.Items.Add(copy.UseTJunctionRemoverUI);
            copy.TJuncDistUI = this.TJuncDistUI.DeepCopy();
            copy.TJuncDistUI.Parent = copy;
            copy.Items.Add(copy.TJuncDistUI);
            copy.UseWeldingUI = this.UseWeldingUI.DeepCopy();
            copy.UseWeldingUI.Parent = copy;
            copy.Items.Add(copy.UseWeldingUI);
            copy.WeldOnlyBorderVerticesUI = this.WeldOnlyBorderVerticesUI.DeepCopy();
            copy.WeldOnlyBorderVerticesUI.Parent = copy;
            copy.Items.Add(copy.WeldOnlyBorderVerticesUI);
            copy.WeldOnlyWithinMaterialUI = this.WeldOnlyWithinMaterialUI.DeepCopy();
            copy.WeldOnlyWithinMaterialUI.Parent = copy;
            copy.Items.Add(copy.WeldOnlyWithinMaterialUI);
            copy.WeldOnlyWithinSceneNodeUI = this.WeldOnlyWithinSceneNodeUI.DeepCopy();
            copy.WeldOnlyWithinSceneNodeUI.Parent = copy;
            copy.Items.Add(copy.WeldOnlyWithinSceneNodeUI);
            copy.WeldOnlyBetweenSceneNodesUI = this.WeldOnlyBetweenSceneNodesUI.DeepCopy();
            copy.WeldOnlyBetweenSceneNodesUI.Parent = copy;
            copy.Items.Add(copy.WeldOnlyBetweenSceneNodesUI);
            copy.WeldDistUI = this.WeldDistUI.DeepCopy();
            copy.WeldDistUI.Parent = copy;
            copy.Items.Add(copy.WeldDistUI);
            copy.ProgressivePassesUI = this.ProgressivePassesUI.DeepCopy();
            copy.ProgressivePassesUI.Parent = copy;
            copy.Items.Add(copy.ProgressivePassesUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.UseTJunctionRemover = UseTJunctionRemover;
            if(serializeUIComponents)
            {
                jsonData.UseTJunctionRemoverUI = UseTJunctionRemoverUI.SaveJson();
            }

            jsonData.TJuncDist = TJuncDist;
            if(serializeUIComponents)
            {
                jsonData.TJuncDistUI = TJuncDistUI.SaveJson();
            }

            jsonData.WeldDist = WeldDist;
            if(serializeUIComponents)
            {
                jsonData.WeldDistUI = WeldDistUI.SaveJson();
            }

            jsonData.WeldOnlyBorderVertices = WeldOnlyBorderVertices;
            if(serializeUIComponents)
            {
                jsonData.WeldOnlyBorderVerticesUI = WeldOnlyBorderVerticesUI.SaveJson();
            }

            jsonData.WeldOnlyWithinMaterial = WeldOnlyWithinMaterial;
            if(serializeUIComponents)
            {
                jsonData.WeldOnlyWithinMaterialUI = WeldOnlyWithinMaterialUI.SaveJson();
            }

            jsonData.WeldOnlyWithinSceneNode = WeldOnlyWithinSceneNode;
            if(serializeUIComponents)
            {
                jsonData.WeldOnlyWithinSceneNodeUI = WeldOnlyWithinSceneNodeUI.SaveJson();
            }

            jsonData.WeldOnlyBetweenSceneNodes = WeldOnlyBetweenSceneNodes;
            if(serializeUIComponents)
            {
                jsonData.WeldOnlyBetweenSceneNodesUI = WeldOnlyBetweenSceneNodesUI.SaveJson();
            }

            jsonData.UseWelding = UseWelding;
            if(serializeUIComponents)
            {
                jsonData.UseWeldingUI = UseWeldingUI.SaveJson();
            }

            jsonData.ProgressivePasses = ProgressivePasses;
            if(serializeUIComponents)
            {
                jsonData.ProgressivePassesUI = ProgressivePassesUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("UseTJunctionRemover") != null)
            {
                UseTJunctionRemover = (bool)jsonData.UseTJunctionRemover;
            }

            if(jsonData.GetValue("TJuncDist") != null)
            {
                float newTJuncDist = (float)jsonData.TJuncDist;
                if (newTJuncDist >= TJuncDistUI.DefaultMinValue && newTJuncDist <= TJuncDistUI.DefaultMaxValue)
                {
                    TJuncDist = newTJuncDist;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TJuncDist: Invalid value {newTJuncDist.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {TJuncDist.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("WeldDist") != null)
            {
                float newWeldDist = (float)jsonData.WeldDist;
                if (newWeldDist >= WeldDistUI.DefaultMinValue && newWeldDist <= WeldDistUI.DefaultMaxValue)
                {
                    WeldDist = newWeldDist;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"WeldDist: Invalid value {newWeldDist.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {WeldDist.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("WeldOnlyBorderVertices") != null)
            {
                WeldOnlyBorderVertices = (bool)jsonData.WeldOnlyBorderVertices;
            }

            if(jsonData.GetValue("WeldOnlyWithinMaterial") != null)
            {
                WeldOnlyWithinMaterial = (bool)jsonData.WeldOnlyWithinMaterial;
            }

            if(jsonData.GetValue("WeldOnlyWithinSceneNode") != null)
            {
                WeldOnlyWithinSceneNode = (bool)jsonData.WeldOnlyWithinSceneNode;
            }

            if(jsonData.GetValue("WeldOnlyBetweenSceneNodes") != null)
            {
                WeldOnlyBetweenSceneNodes = (bool)jsonData.WeldOnlyBetweenSceneNodes;
            }

            if(jsonData.GetValue("UseWelding") != null)
            {
                UseWelding = (bool)jsonData.UseWelding;
            }

            if(jsonData.GetValue("ProgressivePasses") != null)
            {
                var newProgressivePasses = (int)jsonData.ProgressivePasses;
                if (newProgressivePasses >= ProgressivePassesUI.DefaultMinValue && newProgressivePasses <= ProgressivePassesUI.DefaultMaxValue)
                {
                    ProgressivePasses = newProgressivePasses;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ProgressivePasses: Invalid value {newProgressivePasses}, using default value {ProgressivePasses.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            UseTJunctionRemoverUI.Reset();
            TJuncDistUI.Reset();
            WeldDistUI.Reset();
            WeldOnlyBorderVerticesUI.Reset();
            WeldOnlyWithinMaterialUI.Reset();
            WeldOnlyWithinSceneNodeUI.Reset();
            WeldOnlyBetweenSceneNodesUI.Reset();
            UseWeldingUI.Reset();
            ProgressivePassesUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            UseTJunctionRemoverUI.IsEditEnabled = isEditEnabled;
            TJuncDistUI.IsEditEnabled = isEditEnabled;
            WeldDistUI.IsEditEnabled = isEditEnabled;
            WeldOnlyBorderVerticesUI.IsEditEnabled = isEditEnabled;
            WeldOnlyWithinMaterialUI.IsEditEnabled = isEditEnabled;
            WeldOnlyWithinSceneNodeUI.IsEditEnabled = isEditEnabled;
            WeldOnlyBetweenSceneNodesUI.IsEditEnabled = isEditEnabled;
            UseWeldingUI.IsEditEnabled = isEditEnabled;
            ProgressivePassesUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            UseTJunctionRemoverUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TJuncDistUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseWeldingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeldOnlyBorderVerticesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeldOnlyWithinMaterialUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeldOnlyWithinSceneNodeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeldOnlyBetweenSceneNodesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeldDistUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ProgressivePassesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonNormalCalculationSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(ReplaceNormalsUI.Visible) return true;
                if(ReplaceTangentsUI.Visible) return true;
                if(HardEdgeAngleUI.Visible) return true;
                if(RepairInvalidNormalsUI.Visible) return true;
                if(ReorthogonalizeTangentSpaceUI.Visible) return true;
                if(ScaleByAreaUI.Visible) return true;
                if(ScaleByAngleUI.Visible) return true;
                if(SnapNormalsToFlatSurfacesUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool ReplaceNormals { get { return _ReplaceNormals; } set { _ReplaceNormals = value; OnPropertyChanged(); } }
        private bool _ReplaceNormals;
        public SimplygonReplaceNormalsEx ReplaceNormalsUI { get; set; }
        public class SimplygonReplaceNormalsEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ReplaceNormals;
                }

                set
                {
                    bool needReload = Parent.ReplaceNormals != value;
                    Parent.ReplaceNormals = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonReplaceNormalsEx() : base("ReplaceNormals")
            {
                Type = "bool";
                HelpText = "If set, it will generate new normals for the Geometry, and if not set, it will keep the normals from the original normal set (or not add normals at all if none were present). Please note that if the original geometry contains normals, the normal repairer will replace invalid normals even if ReplaceNormals is set to false.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonReplaceNormalsEx(dynamic jsonData) : base("ReplaceNormals")
            {
                Type = "bool";
                HelpText = "If set, it will generate new normals for the Geometry, and if not set, it will keep the normals from the original normal set (or not add normals at all if none were present). Please note that if the original geometry contains normals, the normal repairer will replace invalid normals even if ReplaceNormals is set to false.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReplaceNormalsEx DeepCopy()
            {
                return (SimplygonReplaceNormalsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ReplaceNormals;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool ReplaceTangents { get { return _ReplaceTangents; } set { _ReplaceTangents = value; OnPropertyChanged(); } }
        private bool _ReplaceTangents;
        public SimplygonReplaceTangentsEx ReplaceTangentsUI { get; set; }
        public class SimplygonReplaceTangentsEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ReplaceTangents;
                }

                set
                {
                    bool needReload = Parent.ReplaceTangents != value;
                    Parent.ReplaceTangents = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonReplaceTangentsEx() : base("ReplaceTangents")
            {
                Type = "bool";
                HelpText = "If set, it will generate new tangents and bitangents for the Geometry, and if not set, it will keep the new tangents and bitangents from the original normal set (or not add tangents and bitangents at all if none were present).";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonReplaceTangentsEx(dynamic jsonData) : base("ReplaceTangents")
            {
                Type = "bool";
                HelpText = "If set, it will generate new tangents and bitangents for the Geometry, and if not set, it will keep the new tangents and bitangents from the original normal set (or not add tangents and bitangents at all if none were present).";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReplaceTangentsEx DeepCopy()
            {
                return (SimplygonReplaceTangentsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ReplaceTangents;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float HardEdgeAngle { get { return _HardEdgeAngle; } set { _HardEdgeAngle = value; OnPropertyChanged(); } }
        private float _HardEdgeAngle;
        public SimplygonHardEdgeAngleEx HardEdgeAngleUI { get; set; }
        public class SimplygonHardEdgeAngleEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.HardEdgeAngle;
                }

                set
                {
                    bool needReload = Parent.HardEdgeAngle != value;
                    Parent.HardEdgeAngle = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonHardEdgeAngleEx() : base("HardEdgeAngle")
            {
                Type = "real";
                HelpText = "Set HardEdgeAngle in degrees. If the angle between two triangles are above this value, the normals will not be smooth over the edge between those two triangles.";
                TypeOverride = "";
                DefaultValue = 75f;
                MinValue = 0f;
                MaxValue = 180f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 180f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonHardEdgeAngleEx(dynamic jsonData) : base("HardEdgeAngle")
            {
                Type = "real";
                HelpText = "Set HardEdgeAngle in degrees. If the angle between two triangles are above this value, the normals will not be smooth over the edge between those two triangles.";
                TypeOverride = "";
                DefaultValue = 75f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"HardEdgeAngle: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 180f;
                DefaultMaxValue = 180f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"HardEdgeAngle: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonHardEdgeAngleEx DeepCopy()
            {
                return (SimplygonHardEdgeAngleEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.HardEdgeAngle;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool RepairInvalidNormals { get { return _RepairInvalidNormals; } set { _RepairInvalidNormals = value; OnPropertyChanged(); } }
        private bool _RepairInvalidNormals;
        public SimplygonRepairInvalidNormalsEx RepairInvalidNormalsUI { get; set; }
        public class SimplygonRepairInvalidNormalsEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.RepairInvalidNormals;
                }

                set
                {
                    bool needReload = Parent.RepairInvalidNormals != value;
                    Parent.RepairInvalidNormals = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonRepairInvalidNormalsEx() : base("RepairInvalidNormals")
            {
                Type = "bool";
                HelpText = "If set, normals that are invalid will be replaced. All others are left intact. Bad normals are those that are either zero length, or simply points away from the surface.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonRepairInvalidNormalsEx(dynamic jsonData) : base("RepairInvalidNormals")
            {
                Type = "bool";
                HelpText = "If set, normals that are invalid will be replaced. All others are left intact. Bad normals are those that are either zero length, or simply points away from the surface.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRepairInvalidNormalsEx DeepCopy()
            {
                return (SimplygonRepairInvalidNormalsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.RepairInvalidNormals;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool ReorthogonalizeTangentSpace { get { return _ReorthogonalizeTangentSpace; } set { _ReorthogonalizeTangentSpace = value; OnPropertyChanged(); } }
        private bool _ReorthogonalizeTangentSpace;
        public SimplygonReorthogonalizeTangentSpaceEx ReorthogonalizeTangentSpaceUI { get; set; }
        public class SimplygonReorthogonalizeTangentSpaceEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ReorthogonalizeTangentSpace;
                }

                set
                {
                    bool needReload = Parent.ReorthogonalizeTangentSpace != value;
                    Parent.ReorthogonalizeTangentSpace = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonReorthogonalizeTangentSpaceEx() : base("ReorthogonalizeTangentSpace")
            {
                Type = "bool";
                HelpText = "If set, the tangentspaces already existing in the scene will be readjusted so that the tangent and binormal are both orthogonal to the normal. Will be needed since most of the time the normals are changed in the reduction process.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonReorthogonalizeTangentSpaceEx(dynamic jsonData) : base("ReorthogonalizeTangentSpace")
            {
                Type = "bool";
                HelpText = "If set, the tangentspaces already existing in the scene will be readjusted so that the tangent and binormal are both orthogonal to the normal. Will be needed since most of the time the normals are changed in the reduction process.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonReorthogonalizeTangentSpaceEx DeepCopy()
            {
                return (SimplygonReorthogonalizeTangentSpaceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ReorthogonalizeTangentSpace;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool ScaleByArea { get { return _ScaleByArea; } set { _ScaleByArea = value; OnPropertyChanged(); } }
        private bool _ScaleByArea;
        public SimplygonScaleByAreaEx ScaleByAreaUI { get; set; }
        public class SimplygonScaleByAreaEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ScaleByArea;
                }

                set
                {
                    bool needReload = Parent.ScaleByArea != value;
                    Parent.ScaleByArea = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonScaleByAreaEx() : base("ScaleByArea")
            {
                Type = "bool";
                HelpText = "If set, the influence of a triangle normal upon the vertex normals is scaled by the area of the triangle.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonScaleByAreaEx(dynamic jsonData) : base("ScaleByArea")
            {
                Type = "bool";
                HelpText = "If set, the influence of a triangle normal upon the vertex normals is scaled by the area of the triangle.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonScaleByAreaEx DeepCopy()
            {
                return (SimplygonScaleByAreaEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ScaleByArea;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool ScaleByAngle { get { return _ScaleByAngle; } set { _ScaleByAngle = value; OnPropertyChanged(); } }
        private bool _ScaleByAngle;
        public SimplygonScaleByAngleEx ScaleByAngleUI { get; set; }
        public class SimplygonScaleByAngleEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ScaleByAngle;
                }

                set
                {
                    bool needReload = Parent.ScaleByAngle != value;
                    Parent.ScaleByAngle = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonScaleByAngleEx() : base("ScaleByAngle")
            {
                Type = "bool";
                HelpText = "If set, the influence of a triangle normal upon the vertex normals is scaled by the angle of the corner at the vertex.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonScaleByAngleEx(dynamic jsonData) : base("ScaleByAngle")
            {
                Type = "bool";
                HelpText = "If set, the influence of a triangle normal upon the vertex normals is scaled by the angle of the corner at the vertex.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonScaleByAngleEx DeepCopy()
            {
                return (SimplygonScaleByAngleEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ScaleByAngle;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool SnapNormalsToFlatSurfaces { get { return _SnapNormalsToFlatSurfaces; } set { _SnapNormalsToFlatSurfaces = value; OnPropertyChanged(); } }
        private bool _SnapNormalsToFlatSurfaces;
        public SimplygonSnapNormalsToFlatSurfacesEx SnapNormalsToFlatSurfacesUI { get; set; }
        public class SimplygonSnapNormalsToFlatSurfacesEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCalculationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.SnapNormalsToFlatSurfaces;
                }

                set
                {
                    bool needReload = Parent.SnapNormalsToFlatSurfaces != value;
                    Parent.SnapNormalsToFlatSurfaces = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonSnapNormalsToFlatSurfacesEx() : base("SnapNormalsToFlatSurfaces")
            {
                Type = "bool";
                HelpText = "If set, perfectly flat shaded surfaces will be created, where possible. Normals adjacent to perfectly geometrically flat surfaces will be recalculated to have the same direction as for those of the adjacent flat surface.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonSnapNormalsToFlatSurfacesEx(dynamic jsonData) : base("SnapNormalsToFlatSurfaces")
            {
                Type = "bool";
                HelpText = "If set, perfectly flat shaded surfaces will be created, where possible. Normals adjacent to perfectly geometrically flat surfaces will be recalculated to have the same direction as for those of the adjacent flat surface.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSnapNormalsToFlatSurfacesEx DeepCopy()
            {
                return (SimplygonSnapNormalsToFlatSurfacesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.SnapNormalsToFlatSurfaces;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonNormalCalculationSettings() : base("NormalCalculationSettings")
        {
            Visible = true;
            ReplaceNormalsUI = new SimplygonReplaceNormalsEx();
            ReplaceNormalsUI.Parent = this;
            ReplaceNormals = ReplaceNormalsUI.DefaultValue;
            Items.Add(ReplaceNormalsUI);
            RepairInvalidNormalsUI = new SimplygonRepairInvalidNormalsEx();
            RepairInvalidNormalsUI.Parent = this;
            RepairInvalidNormals = RepairInvalidNormalsUI.DefaultValue;
            Items.Add(RepairInvalidNormalsUI);
            HardEdgeAngleUI = new SimplygonHardEdgeAngleEx();
            HardEdgeAngleUI.Parent = this;
            HardEdgeAngle = HardEdgeAngleUI.DefaultValue;
            Items.Add(HardEdgeAngleUI);
            ReplaceTangentsUI = new SimplygonReplaceTangentsEx();
            ReplaceTangentsUI.Parent = this;
            ReplaceTangents = ReplaceTangentsUI.DefaultValue;
            Items.Add(ReplaceTangentsUI);
            ReorthogonalizeTangentSpaceUI = new SimplygonReorthogonalizeTangentSpaceEx();
            ReorthogonalizeTangentSpaceUI.Parent = this;
            ReorthogonalizeTangentSpace = ReorthogonalizeTangentSpaceUI.DefaultValue;
            Items.Add(ReorthogonalizeTangentSpaceUI);
            ScaleByAreaUI = new SimplygonScaleByAreaEx();
            ScaleByAreaUI.Parent = this;
            ScaleByArea = ScaleByAreaUI.DefaultValue;
            Items.Add(ScaleByAreaUI);
            ScaleByAngleUI = new SimplygonScaleByAngleEx();
            ScaleByAngleUI.Parent = this;
            ScaleByAngle = ScaleByAngleUI.DefaultValue;
            Items.Add(ScaleByAngleUI);
            SnapNormalsToFlatSurfacesUI = new SimplygonSnapNormalsToFlatSurfacesEx();
            SnapNormalsToFlatSurfacesUI.Parent = this;
            SnapNormalsToFlatSurfaces = SnapNormalsToFlatSurfacesUI.DefaultValue;
            Items.Add(SnapNormalsToFlatSurfacesUI);
        }

        public SimplygonNormalCalculationSettings(dynamic jsonData) : base("NormalCalculationSettings")
        {
            Visible = true;
            ReplaceNormalsUI = new SimplygonReplaceNormalsEx(jsonData != null && ((JObject)jsonData).GetValue("ReplaceNormalsUI") != null ? jsonData.ReplaceNormalsUI : null);
            ReplaceNormalsUI.Parent = this;
            ReplaceNormals = ReplaceNormalsUI.DefaultValue;
            Items.Add(ReplaceNormalsUI);
            RepairInvalidNormalsUI = new SimplygonRepairInvalidNormalsEx(jsonData != null && ((JObject)jsonData).GetValue("RepairInvalidNormalsUI") != null ? jsonData.RepairInvalidNormalsUI : null);
            RepairInvalidNormalsUI.Parent = this;
            RepairInvalidNormals = RepairInvalidNormalsUI.DefaultValue;
            Items.Add(RepairInvalidNormalsUI);
            HardEdgeAngleUI = new SimplygonHardEdgeAngleEx(jsonData != null && ((JObject)jsonData).GetValue("HardEdgeAngleUI") != null ? jsonData.HardEdgeAngleUI : null);
            HardEdgeAngleUI.Parent = this;
            HardEdgeAngle = HardEdgeAngleUI.DefaultValue;
            Items.Add(HardEdgeAngleUI);
            ReplaceTangentsUI = new SimplygonReplaceTangentsEx(jsonData != null && ((JObject)jsonData).GetValue("ReplaceTangentsUI") != null ? jsonData.ReplaceTangentsUI : null);
            ReplaceTangentsUI.Parent = this;
            ReplaceTangents = ReplaceTangentsUI.DefaultValue;
            Items.Add(ReplaceTangentsUI);
            ReorthogonalizeTangentSpaceUI = new SimplygonReorthogonalizeTangentSpaceEx(jsonData != null && ((JObject)jsonData).GetValue("ReorthogonalizeTangentSpaceUI") != null ? jsonData.ReorthogonalizeTangentSpaceUI : null);
            ReorthogonalizeTangentSpaceUI.Parent = this;
            ReorthogonalizeTangentSpace = ReorthogonalizeTangentSpaceUI.DefaultValue;
            Items.Add(ReorthogonalizeTangentSpaceUI);
            ScaleByAreaUI = new SimplygonScaleByAreaEx(jsonData != null && ((JObject)jsonData).GetValue("ScaleByAreaUI") != null ? jsonData.ScaleByAreaUI : null);
            ScaleByAreaUI.Parent = this;
            ScaleByArea = ScaleByAreaUI.DefaultValue;
            Items.Add(ScaleByAreaUI);
            ScaleByAngleUI = new SimplygonScaleByAngleEx(jsonData != null && ((JObject)jsonData).GetValue("ScaleByAngleUI") != null ? jsonData.ScaleByAngleUI : null);
            ScaleByAngleUI.Parent = this;
            ScaleByAngle = ScaleByAngleUI.DefaultValue;
            Items.Add(ScaleByAngleUI);
            SnapNormalsToFlatSurfacesUI = new SimplygonSnapNormalsToFlatSurfacesEx(jsonData != null && ((JObject)jsonData).GetValue("SnapNormalsToFlatSurfacesUI") != null ? jsonData.SnapNormalsToFlatSurfacesUI : null);
            SnapNormalsToFlatSurfacesUI.Parent = this;
            SnapNormalsToFlatSurfaces = SnapNormalsToFlatSurfacesUI.DefaultValue;
            Items.Add(SnapNormalsToFlatSurfacesUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonNormalCalculationSettings();
            copy.Items.Clear();
            copy.ReplaceNormalsUI = this.ReplaceNormalsUI.DeepCopy();
            copy.ReplaceNormalsUI.Parent = copy;
            copy.Items.Add(copy.ReplaceNormalsUI);
            copy.RepairInvalidNormalsUI = this.RepairInvalidNormalsUI.DeepCopy();
            copy.RepairInvalidNormalsUI.Parent = copy;
            copy.Items.Add(copy.RepairInvalidNormalsUI);
            copy.HardEdgeAngleUI = this.HardEdgeAngleUI.DeepCopy();
            copy.HardEdgeAngleUI.Parent = copy;
            copy.Items.Add(copy.HardEdgeAngleUI);
            copy.ReplaceTangentsUI = this.ReplaceTangentsUI.DeepCopy();
            copy.ReplaceTangentsUI.Parent = copy;
            copy.Items.Add(copy.ReplaceTangentsUI);
            copy.ReorthogonalizeTangentSpaceUI = this.ReorthogonalizeTangentSpaceUI.DeepCopy();
            copy.ReorthogonalizeTangentSpaceUI.Parent = copy;
            copy.Items.Add(copy.ReorthogonalizeTangentSpaceUI);
            copy.ScaleByAreaUI = this.ScaleByAreaUI.DeepCopy();
            copy.ScaleByAreaUI.Parent = copy;
            copy.Items.Add(copy.ScaleByAreaUI);
            copy.ScaleByAngleUI = this.ScaleByAngleUI.DeepCopy();
            copy.ScaleByAngleUI.Parent = copy;
            copy.Items.Add(copy.ScaleByAngleUI);
            copy.SnapNormalsToFlatSurfacesUI = this.SnapNormalsToFlatSurfacesUI.DeepCopy();
            copy.SnapNormalsToFlatSurfacesUI.Parent = copy;
            copy.Items.Add(copy.SnapNormalsToFlatSurfacesUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ReplaceNormals = ReplaceNormals;
            if(serializeUIComponents)
            {
                jsonData.ReplaceNormalsUI = ReplaceNormalsUI.SaveJson();
            }

            jsonData.ReplaceTangents = ReplaceTangents;
            if(serializeUIComponents)
            {
                jsonData.ReplaceTangentsUI = ReplaceTangentsUI.SaveJson();
            }

            jsonData.HardEdgeAngle = HardEdgeAngle;
            if(serializeUIComponents)
            {
                jsonData.HardEdgeAngleUI = HardEdgeAngleUI.SaveJson();
            }

            jsonData.RepairInvalidNormals = RepairInvalidNormals;
            if(serializeUIComponents)
            {
                jsonData.RepairInvalidNormalsUI = RepairInvalidNormalsUI.SaveJson();
            }

            jsonData.ReorthogonalizeTangentSpace = ReorthogonalizeTangentSpace;
            if(serializeUIComponents)
            {
                jsonData.ReorthogonalizeTangentSpaceUI = ReorthogonalizeTangentSpaceUI.SaveJson();
            }

            jsonData.ScaleByArea = ScaleByArea;
            if(serializeUIComponents)
            {
                jsonData.ScaleByAreaUI = ScaleByAreaUI.SaveJson();
            }

            jsonData.ScaleByAngle = ScaleByAngle;
            if(serializeUIComponents)
            {
                jsonData.ScaleByAngleUI = ScaleByAngleUI.SaveJson();
            }

            jsonData.SnapNormalsToFlatSurfaces = SnapNormalsToFlatSurfaces;
            if(serializeUIComponents)
            {
                jsonData.SnapNormalsToFlatSurfacesUI = SnapNormalsToFlatSurfacesUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("ReplaceNormals") != null)
            {
                ReplaceNormals = (bool)jsonData.ReplaceNormals;
            }

            if(jsonData.GetValue("ReplaceTangents") != null)
            {
                ReplaceTangents = (bool)jsonData.ReplaceTangents;
            }

            if(jsonData.GetValue("HardEdgeAngle") != null)
            {
                float newHardEdgeAngle = (float)jsonData.HardEdgeAngle;
                if (newHardEdgeAngle >= HardEdgeAngleUI.DefaultMinValue && newHardEdgeAngle <= HardEdgeAngleUI.DefaultMaxValue)
                {
                    HardEdgeAngle = newHardEdgeAngle;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"HardEdgeAngle: Invalid value {newHardEdgeAngle.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {HardEdgeAngle.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("RepairInvalidNormals") != null)
            {
                RepairInvalidNormals = (bool)jsonData.RepairInvalidNormals;
            }

            if(jsonData.GetValue("ReorthogonalizeTangentSpace") != null)
            {
                ReorthogonalizeTangentSpace = (bool)jsonData.ReorthogonalizeTangentSpace;
            }

            if(jsonData.GetValue("ScaleByArea") != null)
            {
                ScaleByArea = (bool)jsonData.ScaleByArea;
            }

            if(jsonData.GetValue("ScaleByAngle") != null)
            {
                ScaleByAngle = (bool)jsonData.ScaleByAngle;
            }

            if(jsonData.GetValue("SnapNormalsToFlatSurfaces") != null)
            {
                SnapNormalsToFlatSurfaces = (bool)jsonData.SnapNormalsToFlatSurfaces;
            }

        }

        public override void Reset()
        {
            ReplaceNormalsUI.Reset();
            ReplaceTangentsUI.Reset();
            HardEdgeAngleUI.Reset();
            RepairInvalidNormalsUI.Reset();
            ReorthogonalizeTangentSpaceUI.Reset();
            ScaleByAreaUI.Reset();
            ScaleByAngleUI.Reset();
            SnapNormalsToFlatSurfacesUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            ReplaceNormalsUI.IsEditEnabled = isEditEnabled;
            ReplaceTangentsUI.IsEditEnabled = isEditEnabled;
            HardEdgeAngleUI.IsEditEnabled = isEditEnabled;
            RepairInvalidNormalsUI.IsEditEnabled = isEditEnabled;
            ReorthogonalizeTangentSpaceUI.IsEditEnabled = isEditEnabled;
            ScaleByAreaUI.IsEditEnabled = isEditEnabled;
            ScaleByAngleUI.IsEditEnabled = isEditEnabled;
            SnapNormalsToFlatSurfacesUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            ReplaceNormalsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RepairInvalidNormalsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            HardEdgeAngleUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReplaceTangentsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ReorthogonalizeTangentSpaceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ScaleByAreaUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ScaleByAngleUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SnapNormalsToFlatSurfacesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonVisibilitySettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(UseVisibilityWeightsInReducerUI.Visible) return true;
                if(UseVisibilityWeightsInTexcoordGeneratorUI.Visible) return true;
                if(VisibilityWeightsPowerUI.Visible) return true;
                if(CullOccludedGeometryUI.Visible) return true;
                if(ForceVisibilityCalculationUI.Visible) return true;
                if(UseBackfaceCullingUI.Visible) return true;
                if(CameraSelectionSetNameUI.Visible) return true;
                if(OccluderSelectionSetNameUI.Visible) return true;
                if(FillNonVisibleAreaThresholdUI.Visible) return true;
                if(RemoveTrianglesNotOccludingOtherTrianglesUI.Visible) return true;
                if(ConservativeModeUI.Visible) return true;
                if(ComputeVisibilityModeUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool UseVisibilityWeightsInReducer { get { return _UseVisibilityWeightsInReducer; } set { _UseVisibilityWeightsInReducer = value; OnPropertyChanged(); } }
        private bool _UseVisibilityWeightsInReducer;
        public SimplygonUseVisibilityWeightsInReducerEx UseVisibilityWeightsInReducerUI { get; set; }
        public class SimplygonUseVisibilityWeightsInReducerEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseVisibilityWeightsInReducer;
                }

                set
                {
                    bool needReload = Parent.UseVisibilityWeightsInReducer != value;
                    Parent.UseVisibilityWeightsInReducer = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseVisibilityWeightsInReducerEx() : base("UseVisibilityWeightsInReducer")
            {
                Type = "bool";
                HelpText = "If set to true, visibility weights will be used in the reducer.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseVisibilityWeightsInReducerEx(dynamic jsonData) : base("UseVisibilityWeightsInReducer")
            {
                Type = "bool";
                HelpText = "If set to true, visibility weights will be used in the reducer.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseVisibilityWeightsInReducerEx DeepCopy()
            {
                return (SimplygonUseVisibilityWeightsInReducerEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseVisibilityWeightsInReducer;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseVisibilityWeightsInTexcoordGenerator { get { return _UseVisibilityWeightsInTexcoordGenerator; } set { _UseVisibilityWeightsInTexcoordGenerator = value; OnPropertyChanged(); } }
        private bool _UseVisibilityWeightsInTexcoordGenerator;
        public SimplygonUseVisibilityWeightsInTexcoordGeneratorEx UseVisibilityWeightsInTexcoordGeneratorUI { get; set; }
        public class SimplygonUseVisibilityWeightsInTexcoordGeneratorEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseVisibilityWeightsInTexcoordGenerator;
                }

                set
                {
                    bool needReload = Parent.UseVisibilityWeightsInTexcoordGenerator != value;
                    Parent.UseVisibilityWeightsInTexcoordGenerator = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseVisibilityWeightsInTexcoordGeneratorEx() : base("UseVisibilityWeightsInTexcoordGenerator")
            {
                Type = "bool";
                HelpText = "If set to true, visibility weights will be used when generating new texture coordinates.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseVisibilityWeightsInTexcoordGeneratorEx(dynamic jsonData) : base("UseVisibilityWeightsInTexcoordGenerator")
            {
                Type = "bool";
                HelpText = "If set to true, visibility weights will be used when generating new texture coordinates.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseVisibilityWeightsInTexcoordGeneratorEx DeepCopy()
            {
                return (SimplygonUseVisibilityWeightsInTexcoordGeneratorEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseVisibilityWeightsInTexcoordGenerator;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float VisibilityWeightsPower { get { return _VisibilityWeightsPower; } set { _VisibilityWeightsPower = value; OnPropertyChanged(); } }
        private float _VisibilityWeightsPower;
        public SimplygonVisibilityWeightsPowerEx VisibilityWeightsPowerUI { get; set; }
        public class SimplygonVisibilityWeightsPowerEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.VisibilityWeightsPower;
                }

                set
                {
                    bool needReload = Parent.VisibilityWeightsPower != value;
                    Parent.VisibilityWeightsPower = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonVisibilityWeightsPowerEx() : base("VisibilityWeightsPower")
            {
                Type = "real";
                HelpText = "Set how aggressively reducer should handle low visibility weights.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonVisibilityWeightsPowerEx(dynamic jsonData) : base("VisibilityWeightsPower")
            {
                Type = "real";
                HelpText = "Set how aggressively reducer should handle low visibility weights.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"VisibilityWeightsPower: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"VisibilityWeightsPower: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonVisibilityWeightsPowerEx DeepCopy()
            {
                return (SimplygonVisibilityWeightsPowerEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.VisibilityWeightsPower;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool CullOccludedGeometry { get { return _CullOccludedGeometry; } set { _CullOccludedGeometry = value; OnPropertyChanged(); } }
        private bool _CullOccludedGeometry;
        public SimplygonCullOccludedGeometryEx CullOccludedGeometryUI { get; set; }
        public class SimplygonCullOccludedGeometryEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.CullOccludedGeometry;
                }

                set
                {
                    bool needReload = Parent.CullOccludedGeometry != value;
                    Parent.CullOccludedGeometry = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonCullOccludedGeometryEx() : base("CullOccludedGeometry")
            {
                Type = "bool";
                HelpText = "If set to true, geometry that is not visible will be removed.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonCullOccludedGeometryEx(dynamic jsonData) : base("CullOccludedGeometry")
            {
                Type = "bool";
                HelpText = "If set to true, geometry that is not visible will be removed.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonCullOccludedGeometryEx DeepCopy()
            {
                return (SimplygonCullOccludedGeometryEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.CullOccludedGeometry;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool ForceVisibilityCalculation { get { return _ForceVisibilityCalculation; } set { _ForceVisibilityCalculation = value; OnPropertyChanged(); } }
        private bool _ForceVisibilityCalculation;
        public SimplygonForceVisibilityCalculationEx ForceVisibilityCalculationUI { get; set; }
        public class SimplygonForceVisibilityCalculationEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ForceVisibilityCalculation;
                }

                set
                {
                    bool needReload = Parent.ForceVisibilityCalculation != value;
                    Parent.ForceVisibilityCalculation = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonForceVisibilityCalculationEx() : base("ForceVisibilityCalculation")
            {
                Type = "bool";
                HelpText = "Set the ForceVisibilityCalculation if true, visibility weights will definitely be computed for the geometry, even if the visibility isn't specifically being used for reduction/materialLOD/culling according to the VisibilitySettings.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonForceVisibilityCalculationEx(dynamic jsonData) : base("ForceVisibilityCalculation")
            {
                Type = "bool";
                HelpText = "Set the ForceVisibilityCalculation if true, visibility weights will definitely be computed for the geometry, even if the visibility isn't specifically being used for reduction/materialLOD/culling according to the VisibilitySettings.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonForceVisibilityCalculationEx DeepCopy()
            {
                return (SimplygonForceVisibilityCalculationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ForceVisibilityCalculation;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseBackfaceCulling { get { return _UseBackfaceCulling; } set { _UseBackfaceCulling = value; OnPropertyChanged(); } }
        private bool _UseBackfaceCulling;
        public SimplygonUseBackfaceCullingEx UseBackfaceCullingUI { get; set; }
        public class SimplygonUseBackfaceCullingEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseBackfaceCulling;
                }

                set
                {
                    bool needReload = Parent.UseBackfaceCulling != value;
                    Parent.UseBackfaceCulling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseBackfaceCullingEx() : base("UseBackfaceCulling")
            {
                Type = "bool";
                HelpText = "Set whether triangles should be regarded visible when viewed from the back.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseBackfaceCullingEx(dynamic jsonData) : base("UseBackfaceCulling")
            {
                Type = "bool";
                HelpText = "Set whether triangles should be regarded visible when viewed from the back.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseBackfaceCullingEx DeepCopy()
            {
                return (SimplygonUseBackfaceCullingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseBackfaceCulling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public string CameraSelectionSetName { get { return _CameraSelectionSetName; } set { _CameraSelectionSetName = value; OnPropertyChanged(); } }
        private string _CameraSelectionSetName;
        public SimplygonCameraSelectionSetNameEx CameraSelectionSetNameUI { get; set; }
        public class SimplygonCameraSelectionSetNameEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.CameraSelectionSetName;
                }

                set
                {
                    bool needReload = Parent.CameraSelectionSetName != value;
                    Parent.CameraSelectionSetName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonCameraSelectionSetNameEx() : base("CameraSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set containing all the scene cameras and scene meshes used when computing visibility. If scene meshes are added, all their vertices will be used as omni-directional cameras. If set to null, all cameras in the scene will be used. If both selection set name and ID are set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonCameraSelectionSetNameEx(dynamic jsonData) : base("CameraSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set containing all the scene cameras and scene meshes used when computing visibility. If scene meshes are added, all their vertices will be used as omni-directional cameras. If set to null, all cameras in the scene will be used. If both selection set name and ID are set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonCameraSelectionSetNameEx DeepCopy()
            {
                return (SimplygonCameraSelectionSetNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.CameraSelectionSetName;
                int selectedIndex = 0;
                string[] sets = Simplygon.Unity.EditorPlugin.SimplygonUtils.GetCameraObjectNamesInScene();
                List<GUIContent> selectionSets = new List<GUIContent>();
                selectionSets.Add(new GUIContent("Not used"));
                for(int i = 0; i < sets.Length; ++i)
                {
                    if(value == sets[i]) selectedIndex = i+1;
                    selectionSets.Add(new GUIContent(sets[i]));
                }

                selectedIndex = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), selectedIndex, selectionSets.ToArray());
                Parent.CameraSelectionSetName = selectedIndex == 0 ? "" : selectionSets[selectedIndex].text;
            }

        }

        public string OccluderSelectionSetName { get { return _OccluderSelectionSetName; } set { _OccluderSelectionSetName = value; OnPropertyChanged(); } }
        private string _OccluderSelectionSetName;
        public SimplygonOccluderSelectionSetNameEx OccluderSelectionSetNameUI { get; set; }
        public class SimplygonOccluderSelectionSetNameEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OccluderSelectionSetName;
                }

                set
                {
                    bool needReload = Parent.OccluderSelectionSetName != value;
                    Parent.OccluderSelectionSetName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOccluderSelectionSetNameEx() : base("OccluderSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set containing all the scene meshes used when computing visibility. If set to null, no occluders in the scene will be used. If both selection set name and ID are set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonOccluderSelectionSetNameEx(dynamic jsonData) : base("OccluderSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set containing all the scene meshes used when computing visibility. If set to null, no occluders in the scene will be used. If both selection set name and ID are set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOccluderSelectionSetNameEx DeepCopy()
            {
                return (SimplygonOccluderSelectionSetNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OccluderSelectionSetName;
                int selectedIndex = 0;
                string[] sets = Simplygon.Unity.EditorPlugin.SimplygonUtils.GetSelectionSetNamesInSelection();
                List<GUIContent> selectionSets = new List<GUIContent>();
                selectionSets.Add(new GUIContent("Not used"));
                for(int i = 0; i < sets.Length; ++i)
                {
                    if(value == sets[i]) selectedIndex = i+1;
                    selectionSets.Add(new GUIContent(sets[i]));
                }

                selectedIndex = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), selectedIndex, selectionSets.ToArray());
                Parent.OccluderSelectionSetName = selectedIndex == 0 ? "" : selectionSets[selectedIndex].text;
            }

        }

        public float FillNonVisibleAreaThreshold { get { return _FillNonVisibleAreaThreshold; } set { _FillNonVisibleAreaThreshold = value; OnPropertyChanged(); } }
        private float _FillNonVisibleAreaThreshold;
        public SimplygonFillNonVisibleAreaThresholdEx FillNonVisibleAreaThresholdUI { get; set; }
        public class SimplygonFillNonVisibleAreaThresholdEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.FillNonVisibleAreaThreshold;
                }

                set
                {
                    bool needReload = Parent.FillNonVisibleAreaThreshold != value;
                    Parent.FillNonVisibleAreaThreshold = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonFillNonVisibleAreaThresholdEx() : base("FillNonVisibleAreaThreshold")
            {
                Type = "real";
                HelpText = "If a group of non-visible triangles (connected to visible triangles) has an area below the FillNonVisibleAreaThreshold - it will receive the same visibility as the neighboring visible triangles. Set to zero to skip filling nonvisible regions.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                MaxValue = 100f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 100f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonFillNonVisibleAreaThresholdEx(dynamic jsonData) : base("FillNonVisibleAreaThreshold")
            {
                Type = "real";
                HelpText = "If a group of non-visible triangles (connected to visible triangles) has an area below the FillNonVisibleAreaThreshold - it will receive the same visibility as the neighboring visible triangles. Set to zero to skip filling nonvisible regions.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"FillNonVisibleAreaThreshold: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 100f;
                DefaultMaxValue = 100f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"FillNonVisibleAreaThreshold: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillNonVisibleAreaThresholdEx DeepCopy()
            {
                return (SimplygonFillNonVisibleAreaThresholdEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.FillNonVisibleAreaThreshold;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool RemoveTrianglesNotOccludingOtherTriangles { get { return _RemoveTrianglesNotOccludingOtherTriangles; } set { _RemoveTrianglesNotOccludingOtherTriangles = value; OnPropertyChanged(); } }
        private bool _RemoveTrianglesNotOccludingOtherTriangles;
        public SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx RemoveTrianglesNotOccludingOtherTrianglesUI { get; set; }
        public class SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.RemoveTrianglesNotOccludingOtherTriangles;
                }

                set
                {
                    bool needReload = Parent.RemoveTrianglesNotOccludingOtherTriangles != value;
                    Parent.RemoveTrianglesNotOccludingOtherTriangles = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx() : base("RemoveTrianglesNotOccludingOtherTriangles")
            {
                Type = "bool";
                HelpText = "If enabled, will remove all the visible triangles that are not occluding any other triangle. It will also remove all non-visible triangles.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx(dynamic jsonData) : base("RemoveTrianglesNotOccludingOtherTriangles")
            {
                Type = "bool";
                HelpText = "If enabled, will remove all the visible triangles that are not occluding any other triangle. It will also remove all non-visible triangles.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx DeepCopy()
            {
                return (SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.RemoveTrianglesNotOccludingOtherTriangles;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool ConservativeMode { get { return _ConservativeMode; } set { _ConservativeMode = value; OnPropertyChanged(); } }
        private bool _ConservativeMode;
        public SimplygonConservativeModeEx ConservativeModeUI { get; set; }
        public class SimplygonConservativeModeEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ConservativeMode;
                }

                set
                {
                    bool needReload = Parent.ConservativeMode != value;
                    Parent.ConservativeMode = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonConservativeModeEx() : base("ConservativeMode")
            {
                Type = "bool";
                HelpText = "If enabled, will compute the visibility conservatively - meaning that triangles that are visible will be tagged as visible but some non-visible triangles might also be tagged as visible. If this is turned off, then it is no longer guaranteed that all visible triangles are found - but more non-visible triangles will be identified as non-visible.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonConservativeModeEx(dynamic jsonData) : base("ConservativeMode")
            {
                Type = "bool";
                HelpText = "If enabled, will compute the visibility conservatively - meaning that triangles that are visible will be tagged as visible but some non-visible triangles might also be tagged as visible. If this is turned off, then it is no longer guaranteed that all visible triangles are found - but more non-visible triangles will be identified as non-visible.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonConservativeModeEx DeepCopy()
            {
                return (SimplygonConservativeModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ConservativeMode;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EComputeVisibilityMode ComputeVisibilityMode { get { return _ComputeVisibilityMode; } set { _ComputeVisibilityMode = value; OnPropertyChanged(); } }
        private EComputeVisibilityMode _ComputeVisibilityMode;
        public SimplygonComputeVisibilityModeEx ComputeVisibilityModeUI { get; set; }
        public class SimplygonComputeVisibilityModeEx : SimplygonSettingsProperty
        {
            public SimplygonVisibilitySettings Parent { get; set; }
            public EComputeVisibilityMode Value
            {
                get
                {
                    return Parent.ComputeVisibilityMode;
                }

                set
                {
                    bool needReload = Parent.ComputeVisibilityMode != value;
                    Parent.ComputeVisibilityMode = value;
                    OnPropertyChanged();
                }

            }

            public EComputeVisibilityMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EComputeVisibilityMode)); } }

            public SimplygonComputeVisibilityModeEx() : base("ComputeVisibilityMode")
            {
                Type = "enum";
                HelpText = "Specifies the renderer type when computing visibility.";
                TypeOverride = "";
                DefaultValue = EComputeVisibilityMode.DirectX;
                Visible = true;
            }

            public SimplygonComputeVisibilityModeEx(dynamic jsonData) : base("ComputeVisibilityMode")
            {
                Type = "enum";
                HelpText = "Specifies the renderer type when computing visibility.";
                TypeOverride = "";
                DefaultValue = EComputeVisibilityMode.DirectX;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonComputeVisibilityModeEx DeepCopy()
            {
                return (SimplygonComputeVisibilityModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.ComputeVisibilityMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EComputeVisibilityMode)value;
            }

        }


        public SimplygonVisibilitySettings() : base("VisibilitySettings")
        {
            Visible = true;
            UseVisibilityWeightsInReducerUI = new SimplygonUseVisibilityWeightsInReducerEx();
            UseVisibilityWeightsInReducerUI.Parent = this;
            UseVisibilityWeightsInReducer = UseVisibilityWeightsInReducerUI.DefaultValue;
            Items.Add(UseVisibilityWeightsInReducerUI);
            UseVisibilityWeightsInTexcoordGeneratorUI = new SimplygonUseVisibilityWeightsInTexcoordGeneratorEx();
            UseVisibilityWeightsInTexcoordGeneratorUI.Parent = this;
            UseVisibilityWeightsInTexcoordGenerator = UseVisibilityWeightsInTexcoordGeneratorUI.DefaultValue;
            Items.Add(UseVisibilityWeightsInTexcoordGeneratorUI);
            VisibilityWeightsPowerUI = new SimplygonVisibilityWeightsPowerEx();
            VisibilityWeightsPowerUI.Parent = this;
            VisibilityWeightsPower = VisibilityWeightsPowerUI.DefaultValue;
            Items.Add(VisibilityWeightsPowerUI);
            CullOccludedGeometryUI = new SimplygonCullOccludedGeometryEx();
            CullOccludedGeometryUI.Parent = this;
            CullOccludedGeometry = CullOccludedGeometryUI.DefaultValue;
            Items.Add(CullOccludedGeometryUI);
            ForceVisibilityCalculationUI = new SimplygonForceVisibilityCalculationEx();
            ForceVisibilityCalculationUI.Parent = this;
            ForceVisibilityCalculation = ForceVisibilityCalculationUI.DefaultValue;
            Items.Add(ForceVisibilityCalculationUI);
            UseBackfaceCullingUI = new SimplygonUseBackfaceCullingEx();
            UseBackfaceCullingUI.Parent = this;
            UseBackfaceCulling = UseBackfaceCullingUI.DefaultValue;
            Items.Add(UseBackfaceCullingUI);
            CameraSelectionSetNameUI = new SimplygonCameraSelectionSetNameEx();
            CameraSelectionSetNameUI.Parent = this;
            CameraSelectionSetName = CameraSelectionSetNameUI.DefaultValue;
            Items.Add(CameraSelectionSetNameUI);
            OccluderSelectionSetNameUI = new SimplygonOccluderSelectionSetNameEx();
            OccluderSelectionSetNameUI.Parent = this;
            OccluderSelectionSetName = OccluderSelectionSetNameUI.DefaultValue;
            Items.Add(OccluderSelectionSetNameUI);
            FillNonVisibleAreaThresholdUI = new SimplygonFillNonVisibleAreaThresholdEx();
            FillNonVisibleAreaThresholdUI.Parent = this;
            FillNonVisibleAreaThreshold = FillNonVisibleAreaThresholdUI.DefaultValue;
            Items.Add(FillNonVisibleAreaThresholdUI);
            RemoveTrianglesNotOccludingOtherTrianglesUI = new SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx();
            RemoveTrianglesNotOccludingOtherTrianglesUI.Parent = this;
            RemoveTrianglesNotOccludingOtherTriangles = RemoveTrianglesNotOccludingOtherTrianglesUI.DefaultValue;
            Items.Add(RemoveTrianglesNotOccludingOtherTrianglesUI);
            ConservativeModeUI = new SimplygonConservativeModeEx();
            ConservativeModeUI.Parent = this;
            ConservativeMode = ConservativeModeUI.DefaultValue;
            Items.Add(ConservativeModeUI);
            ComputeVisibilityModeUI = new SimplygonComputeVisibilityModeEx();
            ComputeVisibilityModeUI.Parent = this;
            ComputeVisibilityMode = ComputeVisibilityModeUI.DefaultValue;
            Items.Add(ComputeVisibilityModeUI);
        }

        public SimplygonVisibilitySettings(dynamic jsonData) : base("VisibilitySettings")
        {
            Visible = true;
            UseVisibilityWeightsInReducerUI = new SimplygonUseVisibilityWeightsInReducerEx(jsonData != null && ((JObject)jsonData).GetValue("UseVisibilityWeightsInReducerUI") != null ? jsonData.UseVisibilityWeightsInReducerUI : null);
            UseVisibilityWeightsInReducerUI.Parent = this;
            UseVisibilityWeightsInReducer = UseVisibilityWeightsInReducerUI.DefaultValue;
            Items.Add(UseVisibilityWeightsInReducerUI);
            UseVisibilityWeightsInTexcoordGeneratorUI = new SimplygonUseVisibilityWeightsInTexcoordGeneratorEx(jsonData != null && ((JObject)jsonData).GetValue("UseVisibilityWeightsInTexcoordGeneratorUI") != null ? jsonData.UseVisibilityWeightsInTexcoordGeneratorUI : null);
            UseVisibilityWeightsInTexcoordGeneratorUI.Parent = this;
            UseVisibilityWeightsInTexcoordGenerator = UseVisibilityWeightsInTexcoordGeneratorUI.DefaultValue;
            Items.Add(UseVisibilityWeightsInTexcoordGeneratorUI);
            VisibilityWeightsPowerUI = new SimplygonVisibilityWeightsPowerEx(jsonData != null && ((JObject)jsonData).GetValue("VisibilityWeightsPowerUI") != null ? jsonData.VisibilityWeightsPowerUI : null);
            VisibilityWeightsPowerUI.Parent = this;
            VisibilityWeightsPower = VisibilityWeightsPowerUI.DefaultValue;
            Items.Add(VisibilityWeightsPowerUI);
            CullOccludedGeometryUI = new SimplygonCullOccludedGeometryEx(jsonData != null && ((JObject)jsonData).GetValue("CullOccludedGeometryUI") != null ? jsonData.CullOccludedGeometryUI : null);
            CullOccludedGeometryUI.Parent = this;
            CullOccludedGeometry = CullOccludedGeometryUI.DefaultValue;
            Items.Add(CullOccludedGeometryUI);
            ForceVisibilityCalculationUI = new SimplygonForceVisibilityCalculationEx(jsonData != null && ((JObject)jsonData).GetValue("ForceVisibilityCalculationUI") != null ? jsonData.ForceVisibilityCalculationUI : null);
            ForceVisibilityCalculationUI.Parent = this;
            ForceVisibilityCalculation = ForceVisibilityCalculationUI.DefaultValue;
            Items.Add(ForceVisibilityCalculationUI);
            UseBackfaceCullingUI = new SimplygonUseBackfaceCullingEx(jsonData != null && ((JObject)jsonData).GetValue("UseBackfaceCullingUI") != null ? jsonData.UseBackfaceCullingUI : null);
            UseBackfaceCullingUI.Parent = this;
            UseBackfaceCulling = UseBackfaceCullingUI.DefaultValue;
            Items.Add(UseBackfaceCullingUI);
            CameraSelectionSetNameUI = new SimplygonCameraSelectionSetNameEx(jsonData != null && ((JObject)jsonData).GetValue("CameraSelectionSetNameUI") != null ? jsonData.CameraSelectionSetNameUI : null);
            CameraSelectionSetNameUI.Parent = this;
            CameraSelectionSetName = CameraSelectionSetNameUI.DefaultValue;
            Items.Add(CameraSelectionSetNameUI);
            OccluderSelectionSetNameUI = new SimplygonOccluderSelectionSetNameEx(jsonData != null && ((JObject)jsonData).GetValue("OccluderSelectionSetNameUI") != null ? jsonData.OccluderSelectionSetNameUI : null);
            OccluderSelectionSetNameUI.Parent = this;
            OccluderSelectionSetName = OccluderSelectionSetNameUI.DefaultValue;
            Items.Add(OccluderSelectionSetNameUI);
            FillNonVisibleAreaThresholdUI = new SimplygonFillNonVisibleAreaThresholdEx(jsonData != null && ((JObject)jsonData).GetValue("FillNonVisibleAreaThresholdUI") != null ? jsonData.FillNonVisibleAreaThresholdUI : null);
            FillNonVisibleAreaThresholdUI.Parent = this;
            FillNonVisibleAreaThreshold = FillNonVisibleAreaThresholdUI.DefaultValue;
            Items.Add(FillNonVisibleAreaThresholdUI);
            RemoveTrianglesNotOccludingOtherTrianglesUI = new SimplygonRemoveTrianglesNotOccludingOtherTrianglesEx(jsonData != null && ((JObject)jsonData).GetValue("RemoveTrianglesNotOccludingOtherTrianglesUI") != null ? jsonData.RemoveTrianglesNotOccludingOtherTrianglesUI : null);
            RemoveTrianglesNotOccludingOtherTrianglesUI.Parent = this;
            RemoveTrianglesNotOccludingOtherTriangles = RemoveTrianglesNotOccludingOtherTrianglesUI.DefaultValue;
            Items.Add(RemoveTrianglesNotOccludingOtherTrianglesUI);
            ConservativeModeUI = new SimplygonConservativeModeEx(jsonData != null && ((JObject)jsonData).GetValue("ConservativeModeUI") != null ? jsonData.ConservativeModeUI : null);
            ConservativeModeUI.Parent = this;
            ConservativeMode = ConservativeModeUI.DefaultValue;
            Items.Add(ConservativeModeUI);
            ComputeVisibilityModeUI = new SimplygonComputeVisibilityModeEx(jsonData != null && ((JObject)jsonData).GetValue("ComputeVisibilityModeUI") != null ? jsonData.ComputeVisibilityModeUI : null);
            ComputeVisibilityModeUI.Parent = this;
            ComputeVisibilityMode = ComputeVisibilityModeUI.DefaultValue;
            Items.Add(ComputeVisibilityModeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonVisibilitySettings();
            copy.Items.Clear();
            copy.UseVisibilityWeightsInReducerUI = this.UseVisibilityWeightsInReducerUI.DeepCopy();
            copy.UseVisibilityWeightsInReducerUI.Parent = copy;
            copy.Items.Add(copy.UseVisibilityWeightsInReducerUI);
            copy.UseVisibilityWeightsInTexcoordGeneratorUI = this.UseVisibilityWeightsInTexcoordGeneratorUI.DeepCopy();
            copy.UseVisibilityWeightsInTexcoordGeneratorUI.Parent = copy;
            copy.Items.Add(copy.UseVisibilityWeightsInTexcoordGeneratorUI);
            copy.VisibilityWeightsPowerUI = this.VisibilityWeightsPowerUI.DeepCopy();
            copy.VisibilityWeightsPowerUI.Parent = copy;
            copy.Items.Add(copy.VisibilityWeightsPowerUI);
            copy.CullOccludedGeometryUI = this.CullOccludedGeometryUI.DeepCopy();
            copy.CullOccludedGeometryUI.Parent = copy;
            copy.Items.Add(copy.CullOccludedGeometryUI);
            copy.ForceVisibilityCalculationUI = this.ForceVisibilityCalculationUI.DeepCopy();
            copy.ForceVisibilityCalculationUI.Parent = copy;
            copy.Items.Add(copy.ForceVisibilityCalculationUI);
            copy.UseBackfaceCullingUI = this.UseBackfaceCullingUI.DeepCopy();
            copy.UseBackfaceCullingUI.Parent = copy;
            copy.Items.Add(copy.UseBackfaceCullingUI);
            copy.CameraSelectionSetNameUI = this.CameraSelectionSetNameUI.DeepCopy();
            copy.CameraSelectionSetNameUI.Parent = copy;
            copy.Items.Add(copy.CameraSelectionSetNameUI);
            copy.OccluderSelectionSetNameUI = this.OccluderSelectionSetNameUI.DeepCopy();
            copy.OccluderSelectionSetNameUI.Parent = copy;
            copy.Items.Add(copy.OccluderSelectionSetNameUI);
            copy.FillNonVisibleAreaThresholdUI = this.FillNonVisibleAreaThresholdUI.DeepCopy();
            copy.FillNonVisibleAreaThresholdUI.Parent = copy;
            copy.Items.Add(copy.FillNonVisibleAreaThresholdUI);
            copy.RemoveTrianglesNotOccludingOtherTrianglesUI = this.RemoveTrianglesNotOccludingOtherTrianglesUI.DeepCopy();
            copy.RemoveTrianglesNotOccludingOtherTrianglesUI.Parent = copy;
            copy.Items.Add(copy.RemoveTrianglesNotOccludingOtherTrianglesUI);
            copy.ConservativeModeUI = this.ConservativeModeUI.DeepCopy();
            copy.ConservativeModeUI.Parent = copy;
            copy.Items.Add(copy.ConservativeModeUI);
            copy.ComputeVisibilityModeUI = this.ComputeVisibilityModeUI.DeepCopy();
            copy.ComputeVisibilityModeUI.Parent = copy;
            copy.Items.Add(copy.ComputeVisibilityModeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.UseVisibilityWeightsInReducer = UseVisibilityWeightsInReducer;
            if(serializeUIComponents)
            {
                jsonData.UseVisibilityWeightsInReducerUI = UseVisibilityWeightsInReducerUI.SaveJson();
            }

            jsonData.UseVisibilityWeightsInTexcoordGenerator = UseVisibilityWeightsInTexcoordGenerator;
            if(serializeUIComponents)
            {
                jsonData.UseVisibilityWeightsInTexcoordGeneratorUI = UseVisibilityWeightsInTexcoordGeneratorUI.SaveJson();
            }

            jsonData.VisibilityWeightsPower = VisibilityWeightsPower;
            if(serializeUIComponents)
            {
                jsonData.VisibilityWeightsPowerUI = VisibilityWeightsPowerUI.SaveJson();
            }

            jsonData.CullOccludedGeometry = CullOccludedGeometry;
            if(serializeUIComponents)
            {
                jsonData.CullOccludedGeometryUI = CullOccludedGeometryUI.SaveJson();
            }

            jsonData.ForceVisibilityCalculation = ForceVisibilityCalculation;
            if(serializeUIComponents)
            {
                jsonData.ForceVisibilityCalculationUI = ForceVisibilityCalculationUI.SaveJson();
            }

            jsonData.UseBackfaceCulling = UseBackfaceCulling;
            if(serializeUIComponents)
            {
                jsonData.UseBackfaceCullingUI = UseBackfaceCullingUI.SaveJson();
            }

            jsonData.CameraSelectionSetName = CameraSelectionSetName;
            if(serializeUIComponents)
            {
                jsonData.CameraSelectionSetNameUI = CameraSelectionSetNameUI.SaveJson();
            }

            jsonData.OccluderSelectionSetName = OccluderSelectionSetName;
            if(serializeUIComponents)
            {
                jsonData.OccluderSelectionSetNameUI = OccluderSelectionSetNameUI.SaveJson();
            }

            jsonData.FillNonVisibleAreaThreshold = FillNonVisibleAreaThreshold;
            if(serializeUIComponents)
            {
                jsonData.FillNonVisibleAreaThresholdUI = FillNonVisibleAreaThresholdUI.SaveJson();
            }

            jsonData.RemoveTrianglesNotOccludingOtherTriangles = RemoveTrianglesNotOccludingOtherTriangles;
            if(serializeUIComponents)
            {
                jsonData.RemoveTrianglesNotOccludingOtherTrianglesUI = RemoveTrianglesNotOccludingOtherTrianglesUI.SaveJson();
            }

            jsonData.ConservativeMode = ConservativeMode;
            if(serializeUIComponents)
            {
                jsonData.ConservativeModeUI = ConservativeModeUI.SaveJson();
            }

            jsonData.ComputeVisibilityMode = (int)ComputeVisibilityMode;
            if(serializeUIComponents)
            {
                jsonData.ComputeVisibilityModeUI = ComputeVisibilityModeUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("UseVisibilityWeightsInReducer") != null)
            {
                UseVisibilityWeightsInReducer = (bool)jsonData.UseVisibilityWeightsInReducer;
            }

            if(jsonData.GetValue("UseVisibilityWeightsInTexcoordGenerator") != null)
            {
                UseVisibilityWeightsInTexcoordGenerator = (bool)jsonData.UseVisibilityWeightsInTexcoordGenerator;
            }

            if(jsonData.GetValue("VisibilityWeightsPower") != null)
            {
                float newVisibilityWeightsPower = (float)jsonData.VisibilityWeightsPower;
                if (newVisibilityWeightsPower >= VisibilityWeightsPowerUI.DefaultMinValue && newVisibilityWeightsPower <= VisibilityWeightsPowerUI.DefaultMaxValue)
                {
                    VisibilityWeightsPower = newVisibilityWeightsPower;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"VisibilityWeightsPower: Invalid value {newVisibilityWeightsPower.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {VisibilityWeightsPower.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("CullOccludedGeometry") != null)
            {
                CullOccludedGeometry = (bool)jsonData.CullOccludedGeometry;
            }

            if(jsonData.GetValue("ForceVisibilityCalculation") != null)
            {
                ForceVisibilityCalculation = (bool)jsonData.ForceVisibilityCalculation;
            }

            if(jsonData.GetValue("UseBackfaceCulling") != null)
            {
                UseBackfaceCulling = (bool)jsonData.UseBackfaceCulling;
            }

            if(jsonData.GetValue("CameraSelectionSetName") != null)
            {
                CameraSelectionSetName = (string)jsonData.CameraSelectionSetName;
            }

            if(jsonData.GetValue("OccluderSelectionSetName") != null)
            {
                OccluderSelectionSetName = (string)jsonData.OccluderSelectionSetName;
            }

            if(jsonData.GetValue("FillNonVisibleAreaThreshold") != null)
            {
                float newFillNonVisibleAreaThreshold = (float)jsonData.FillNonVisibleAreaThreshold;
                if (newFillNonVisibleAreaThreshold >= FillNonVisibleAreaThresholdUI.DefaultMinValue && newFillNonVisibleAreaThreshold <= FillNonVisibleAreaThresholdUI.DefaultMaxValue)
                {
                    FillNonVisibleAreaThreshold = newFillNonVisibleAreaThreshold;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"FillNonVisibleAreaThreshold: Invalid value {newFillNonVisibleAreaThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {FillNonVisibleAreaThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("RemoveTrianglesNotOccludingOtherTriangles") != null)
            {
                RemoveTrianglesNotOccludingOtherTriangles = (bool)jsonData.RemoveTrianglesNotOccludingOtherTriangles;
            }

            if(jsonData.GetValue("ConservativeMode") != null)
            {
                ConservativeMode = (bool)jsonData.ConservativeMode;
            }

            if(jsonData.GetValue("ComputeVisibilityMode") != null)
            {
                ComputeVisibilityMode = (EComputeVisibilityMode)jsonData.ComputeVisibilityMode;
            }

        }

        public override void Reset()
        {
            UseVisibilityWeightsInReducerUI.Reset();
            UseVisibilityWeightsInTexcoordGeneratorUI.Reset();
            VisibilityWeightsPowerUI.Reset();
            CullOccludedGeometryUI.Reset();
            ForceVisibilityCalculationUI.Reset();
            UseBackfaceCullingUI.Reset();
            CameraSelectionSetNameUI.Reset();
            OccluderSelectionSetNameUI.Reset();
            FillNonVisibleAreaThresholdUI.Reset();
            RemoveTrianglesNotOccludingOtherTrianglesUI.Reset();
            ConservativeModeUI.Reset();
            ComputeVisibilityModeUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            UseVisibilityWeightsInReducerUI.IsEditEnabled = isEditEnabled;
            UseVisibilityWeightsInTexcoordGeneratorUI.IsEditEnabled = isEditEnabled;
            VisibilityWeightsPowerUI.IsEditEnabled = isEditEnabled;
            CullOccludedGeometryUI.IsEditEnabled = isEditEnabled;
            ForceVisibilityCalculationUI.IsEditEnabled = isEditEnabled;
            UseBackfaceCullingUI.IsEditEnabled = isEditEnabled;
            CameraSelectionSetNameUI.IsEditEnabled = isEditEnabled;
            OccluderSelectionSetNameUI.IsEditEnabled = isEditEnabled;
            FillNonVisibleAreaThresholdUI.IsEditEnabled = isEditEnabled;
            RemoveTrianglesNotOccludingOtherTrianglesUI.IsEditEnabled = isEditEnabled;
            ConservativeModeUI.IsEditEnabled = isEditEnabled;
            ComputeVisibilityModeUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            UseVisibilityWeightsInReducerUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseVisibilityWeightsInTexcoordGeneratorUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            VisibilityWeightsPowerUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            CullOccludedGeometryUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ForceVisibilityCalculationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseBackfaceCullingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            CameraSelectionSetNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OccluderSelectionSetNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillNonVisibleAreaThresholdUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RemoveTrianglesNotOccludingOtherTrianglesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ConservativeModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ComputeVisibilityModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonBoneSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(UseBoneReducerUI.Visible) return true;
                if(BoneReductionTargetBoneRatioEnabledUI.Visible) return true;
                if(RemoveUnusedBonesUI.Visible) return true;
                if(LimitBonesPerVertexUI.Visible) return true;
                if(BoneReductionTargetBoneCountEnabledUI.Visible) return true;
                if(BoneReductionTargetMaxDeviationEnabledUI.Visible) return true;
                if(MaxBonePerVertexUI.Visible) return true;
                if(BoneReductionTargetOnScreenSizeEnabledUI.Visible) return true;
                if(BoneReductionTargetStopConditionUI.Visible) return true;
                if(BoneReductionTargetBoneRatioUI.Visible) return true;
                if(BoneReductionTargetBoneCountUI.Visible) return true;
                if(BoneReductionTargetMaxDeviationUI.Visible) return true;
                if(BoneReductionTargetOnScreenSizeUI.Visible) return true;
                if(LockBoneSelectionSetNameUI.Visible) return true;
                if(RemoveBoneSelectionSetNameUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool UseBoneReducer { get { return _UseBoneReducer; } set { _UseBoneReducer = value; OnPropertyChanged(); } }
        private bool _UseBoneReducer;
        public SimplygonUseBoneReducerEx UseBoneReducerUI { get; set; }
        public class SimplygonUseBoneReducerEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseBoneReducer;
                }

                set
                {
                    bool needReload = Parent.UseBoneReducer != value;
                    Parent.UseBoneReducer = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseBoneReducerEx() : base("UseBoneReducer")
            {
                Type = "bool";
                HelpText = "Enables or disables the bone reduction processing that actually removes bones. Even with this flag off, the bones per vertex can still be limited.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseBoneReducerEx(dynamic jsonData) : base("UseBoneReducer")
            {
                Type = "bool";
                HelpText = "Enables or disables the bone reduction processing that actually removes bones. Even with this flag off, the bones per vertex can still be limited.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseBoneReducerEx DeepCopy()
            {
                return (SimplygonUseBoneReducerEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseBoneReducer;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool BoneReductionTargetBoneRatioEnabled { get { return _BoneReductionTargetBoneRatioEnabled; } set { _BoneReductionTargetBoneRatioEnabled = value; OnPropertyChanged(); } }
        private bool _BoneReductionTargetBoneRatioEnabled;
        public SimplygonBoneReductionTargetBoneRatioEnabledEx BoneReductionTargetBoneRatioEnabledUI { get; set; }
        public class SimplygonBoneReductionTargetBoneRatioEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.BoneReductionTargetBoneRatioEnabled;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetBoneRatioEnabled != value;
                    Parent.BoneReductionTargetBoneRatioEnabled = value;
                    Parent.BoneReductionTargetBoneRatioUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetBoneRatioEnabledEx() : base("BoneReductionTargetBoneRatioEnabled")
            {
                Type = "bool";
                HelpText = "Enable bone ratio as a reduction target. The reducer will stop when the set bone-ratio has been reached.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonBoneReductionTargetBoneRatioEnabledEx(dynamic jsonData) : base("BoneReductionTargetBoneRatioEnabled")
            {
                Type = "bool";
                HelpText = "Enable bone ratio as a reduction target. The reducer will stop when the set bone-ratio has been reached.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetBoneRatioEnabledEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetBoneRatioEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.BoneReductionTargetBoneRatioEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool RemoveUnusedBones { get { return _RemoveUnusedBones; } set { _RemoveUnusedBones = value; OnPropertyChanged(); } }
        private bool _RemoveUnusedBones;
        public SimplygonRemoveUnusedBonesEx RemoveUnusedBonesUI { get; set; }
        public class SimplygonRemoveUnusedBonesEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.RemoveUnusedBones;
                }

                set
                {
                    bool needReload = Parent.RemoveUnusedBones != value;
                    Parent.RemoveUnusedBones = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonRemoveUnusedBonesEx() : base("RemoveUnusedBones")
            {
                Type = "bool";
                HelpText = "Decides whether unused bones should be removed.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonRemoveUnusedBonesEx(dynamic jsonData) : base("RemoveUnusedBones")
            {
                Type = "bool";
                HelpText = "Decides whether unused bones should be removed.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRemoveUnusedBonesEx DeepCopy()
            {
                return (SimplygonRemoveUnusedBonesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.RemoveUnusedBones;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool LimitBonesPerVertex { get { return _LimitBonesPerVertex; } set { _LimitBonesPerVertex = value; OnPropertyChanged(); } }
        private bool _LimitBonesPerVertex;
        public SimplygonLimitBonesPerVertexEx LimitBonesPerVertexUI { get; set; }
        public class SimplygonLimitBonesPerVertexEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.LimitBonesPerVertex;
                }

                set
                {
                    bool needReload = Parent.LimitBonesPerVertex != value;
                    Parent.LimitBonesPerVertex = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonLimitBonesPerVertexEx() : base("LimitBonesPerVertex")
            {
                Type = "bool";
                HelpText = "Decides whether unused bones should be removed.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonLimitBonesPerVertexEx(dynamic jsonData) : base("LimitBonesPerVertex")
            {
                Type = "bool";
                HelpText = "Decides whether unused bones should be removed.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonLimitBonesPerVertexEx DeepCopy()
            {
                return (SimplygonLimitBonesPerVertexEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.LimitBonesPerVertex;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool BoneReductionTargetBoneCountEnabled { get { return _BoneReductionTargetBoneCountEnabled; } set { _BoneReductionTargetBoneCountEnabled = value; OnPropertyChanged(); } }
        private bool _BoneReductionTargetBoneCountEnabled;
        public SimplygonBoneReductionTargetBoneCountEnabledEx BoneReductionTargetBoneCountEnabledUI { get; set; }
        public class SimplygonBoneReductionTargetBoneCountEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.BoneReductionTargetBoneCountEnabled;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetBoneCountEnabled != value;
                    Parent.BoneReductionTargetBoneCountEnabled = value;
                    Parent.BoneReductionTargetBoneCountUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetBoneCountEnabledEx() : base("BoneReductionTargetBoneCountEnabled")
            {
                Type = "bool";
                HelpText = "Enable bone count as a reduction target. The reducer will stop when the set bone count has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonBoneReductionTargetBoneCountEnabledEx(dynamic jsonData) : base("BoneReductionTargetBoneCountEnabled")
            {
                Type = "bool";
                HelpText = "Enable bone count as a reduction target. The reducer will stop when the set bone count has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetBoneCountEnabledEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetBoneCountEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.BoneReductionTargetBoneCountEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool BoneReductionTargetMaxDeviationEnabled { get { return _BoneReductionTargetMaxDeviationEnabled; } set { _BoneReductionTargetMaxDeviationEnabled = value; OnPropertyChanged(); } }
        private bool _BoneReductionTargetMaxDeviationEnabled;
        public SimplygonBoneReductionTargetMaxDeviationEnabledEx BoneReductionTargetMaxDeviationEnabledUI { get; set; }
        public class SimplygonBoneReductionTargetMaxDeviationEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.BoneReductionTargetMaxDeviationEnabled;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetMaxDeviationEnabled != value;
                    Parent.BoneReductionTargetMaxDeviationEnabled = value;
                    Parent.BoneReductionTargetMaxDeviationUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetMaxDeviationEnabledEx() : base("BoneReductionTargetMaxDeviationEnabled")
            {
                Type = "bool";
                HelpText = "Enable max deviation as a reduction target. The reducer will stop when the set max deviation has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonBoneReductionTargetMaxDeviationEnabledEx(dynamic jsonData) : base("BoneReductionTargetMaxDeviationEnabled")
            {
                Type = "bool";
                HelpText = "Enable max deviation as a reduction target. The reducer will stop when the set max deviation has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetMaxDeviationEnabledEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetMaxDeviationEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.BoneReductionTargetMaxDeviationEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int MaxBonePerVertex { get { return _MaxBonePerVertex; } set { _MaxBonePerVertex = value; OnPropertyChanged(); } }
        private int _MaxBonePerVertex;
        public SimplygonMaxBonePerVertexEx MaxBonePerVertexUI { get; set; }
        public class SimplygonMaxBonePerVertexEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.MaxBonePerVertex;
                }

                set
                {
                    bool needReload = Parent.MaxBonePerVertex != value;
                    Parent.MaxBonePerVertex = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonMaxBonePerVertexEx() : base("MaxBonePerVertex")
            {
                Type = "uint";
                HelpText = "Decides the maximum limit of how many bones can be connected to each vertex. If for example set to 1, then each vertex will only be linked to 1 bone.";
                TypeOverride = "";
                DefaultValue = 16;
                MinValue = 0;
                MaxValue = 16;
                DefaultMinValue = 0;
                DefaultMaxValue = 16;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonMaxBonePerVertexEx(dynamic jsonData) : base("MaxBonePerVertex")
            {
                Type = "uint";
                HelpText = "Decides the maximum limit of how many bones can be connected to each vertex. If for example set to 1, then each vertex will only be linked to 1 bone.";
                TypeOverride = "";
                DefaultValue = 16;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaxBonePerVertex: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 16;
                DefaultMaxValue = 16;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaxBonePerVertex: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaxBonePerVertexEx DeepCopy()
            {
                return (SimplygonMaxBonePerVertexEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.MaxBonePerVertex;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool BoneReductionTargetOnScreenSizeEnabled { get { return _BoneReductionTargetOnScreenSizeEnabled; } set { _BoneReductionTargetOnScreenSizeEnabled = value; OnPropertyChanged(); } }
        private bool _BoneReductionTargetOnScreenSizeEnabled;
        public SimplygonBoneReductionTargetOnScreenSizeEnabledEx BoneReductionTargetOnScreenSizeEnabledUI { get; set; }
        public class SimplygonBoneReductionTargetOnScreenSizeEnabledEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.BoneReductionTargetOnScreenSizeEnabled;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetOnScreenSizeEnabled != value;
                    Parent.BoneReductionTargetOnScreenSizeEnabled = value;
                    Parent.BoneReductionTargetOnScreenSizeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }
            public override bool Visible { get { return false; } set { OnPropertyChanged(); } }
            public override bool IsEditEnabled { get { return false; } set { OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetOnScreenSizeEnabledEx() : base("BoneReductionTargetOnScreenSizeEnabled")
            {
                Type = "bool";
                HelpText = "Enable on screen size as a reduction target. The reducer will stop when the set on screen size has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonBoneReductionTargetOnScreenSizeEnabledEx(dynamic jsonData) : base("BoneReductionTargetOnScreenSizeEnabled")
            {
                Type = "bool";
                HelpText = "Enable on screen size as a reduction target. The reducer will stop when the set on screen size has been reached.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetOnScreenSizeEnabledEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetOnScreenSizeEnabledEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.BoneReductionTargetOnScreenSizeEnabled;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EStopCondition BoneReductionTargetStopCondition { get { return _BoneReductionTargetStopCondition; } set { _BoneReductionTargetStopCondition = value; OnPropertyChanged(); } }
        private EStopCondition _BoneReductionTargetStopCondition;
        public SimplygonBoneReductionTargetStopConditionEx BoneReductionTargetStopConditionUI { get; set; }
        public class SimplygonBoneReductionTargetStopConditionEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public EStopCondition Value
            {
                get
                {
                    return Parent.BoneReductionTargetStopCondition;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetStopCondition != value;
                    Parent.BoneReductionTargetStopCondition = value;
                    OnPropertyChanged();
                }

            }

            public EStopCondition DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EStopCondition)); } }

            public SimplygonBoneReductionTargetStopConditionEx() : base("BoneReductionTargetStopCondition")
            {
                Type = "enum";
                HelpText = "The stop condition for the bone reducer. Any: the reducer will stop when any single one of the set reduction targets have been reached. All: the reducer will stop when all enabled reduction targets have been set.";
                TypeOverride = "";
                DefaultValue = EStopCondition.All;
                Visible = true;
            }

            public SimplygonBoneReductionTargetStopConditionEx(dynamic jsonData) : base("BoneReductionTargetStopCondition")
            {
                Type = "enum";
                HelpText = "The stop condition for the bone reducer. Any: the reducer will stop when any single one of the set reduction targets have been reached. All: the reducer will stop when all enabled reduction targets have been set.";
                TypeOverride = "";
                DefaultValue = EStopCondition.All;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetStopConditionEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetStopConditionEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.BoneReductionTargetStopCondition;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EStopCondition)value;
            }

        }

        public float BoneReductionTargetBoneRatio { get { return _BoneReductionTargetBoneRatio; } set { _BoneReductionTargetBoneRatio = value; OnPropertyChanged(); } }
        private float _BoneReductionTargetBoneRatio;
        public SimplygonBoneReductionTargetBoneRatioEx BoneReductionTargetBoneRatioUI { get; set; }
        public class SimplygonBoneReductionTargetBoneRatioEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.BoneReductionTargetBoneRatio;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetBoneRatio != value;
                    Parent.BoneReductionTargetBoneRatio = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.BoneReductionTargetBoneRatioEnabled; } set { Parent.BoneReductionTargetBoneRatioEnabled = value; OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetBoneRatioEx() : base("BoneReductionTargetBoneRatio")
            {
                Type = "real";
                HelpText = "The desired bone reduction ratio. The range is 0->1.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonBoneReductionTargetBoneRatioEx(dynamic jsonData) : base("BoneReductionTargetBoneRatio")
            {
                Type = "real";
                HelpText = "The desired bone reduction ratio. The range is 0->1.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetBoneRatio: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetBoneRatio: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetBoneRatioEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetBoneRatioEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.BoneReductionTargetBoneRatioEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    float value = Parent.BoneReductionTargetBoneRatio;
                    value = EditorGUI.Slider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public int BoneReductionTargetBoneCount { get { return _BoneReductionTargetBoneCount; } set { _BoneReductionTargetBoneCount = value; OnPropertyChanged(); } }
        private int _BoneReductionTargetBoneCount;
        public SimplygonBoneReductionTargetBoneCountEx BoneReductionTargetBoneCountUI { get; set; }
        public class SimplygonBoneReductionTargetBoneCountEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.BoneReductionTargetBoneCount;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetBoneCount != value;
                    Parent.BoneReductionTargetBoneCount = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.BoneReductionTargetBoneCountEnabled; } set { Parent.BoneReductionTargetBoneCountEnabled = value; OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetBoneCountEx() : base("BoneReductionTargetBoneCount")
            {
                Type = "uint";
                HelpText = "The desired bone count. The range is 0->inf.";
                TypeOverride = "";
                DefaultValue = 100;
                MinValue = 0;
                MaxValue = 500;
                DefaultMinValue = 0;
                DefaultMaxValue = 500;
                TicksFrequencyValue = 1;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonBoneReductionTargetBoneCountEx(dynamic jsonData) : base("BoneReductionTargetBoneCount")
            {
                Type = "uint";
                HelpText = "The desired bone count. The range is 0->inf.";
                TypeOverride = "";
                DefaultValue = 100;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetBoneCount: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 500;
                DefaultMaxValue = 500;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetBoneCount: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetBoneCountEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetBoneCountEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.BoneReductionTargetBoneCountEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    int value = Parent.BoneReductionTargetBoneCount;
                    value = EditorGUI.IntSlider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public float BoneReductionTargetMaxDeviation { get { return _BoneReductionTargetMaxDeviation; } set { _BoneReductionTargetMaxDeviation = value; OnPropertyChanged(); } }
        private float _BoneReductionTargetMaxDeviation;
        public SimplygonBoneReductionTargetMaxDeviationEx BoneReductionTargetMaxDeviationUI { get; set; }
        public class SimplygonBoneReductionTargetMaxDeviationEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.BoneReductionTargetMaxDeviation;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetMaxDeviation != value;
                    Parent.BoneReductionTargetMaxDeviation = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.BoneReductionTargetMaxDeviationEnabled; } set { Parent.BoneReductionTargetMaxDeviationEnabled = value; OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetMaxDeviationEx() : base("BoneReductionTargetMaxDeviation")
            {
                Type = "real";
                HelpText = "The MaxDeviation value, the maximum surface-deviation between the reduced geometry and the original.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                MaxValue = 100f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 100f;
                TicksFrequencyValue = 0.1f;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonBoneReductionTargetMaxDeviationEx(dynamic jsonData) : base("BoneReductionTargetMaxDeviation")
            {
                Type = "real";
                HelpText = "The MaxDeviation value, the maximum surface-deviation between the reduced geometry and the original.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetMaxDeviation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 100f;
                DefaultMaxValue = 100f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetMaxDeviation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetMaxDeviationEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetMaxDeviationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.BoneReductionTargetMaxDeviationEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    float value = Parent.BoneReductionTargetMaxDeviation;
                    value = EditorGUI.Slider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public int BoneReductionTargetOnScreenSize { get { return _BoneReductionTargetOnScreenSize; } set { _BoneReductionTargetOnScreenSize = value; OnPropertyChanged(); } }
        private int _BoneReductionTargetOnScreenSize;
        public SimplygonBoneReductionTargetOnScreenSizeEx BoneReductionTargetOnScreenSizeUI { get; set; }
        public class SimplygonBoneReductionTargetOnScreenSizeEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.BoneReductionTargetOnScreenSize;
                }

                set
                {
                    bool needReload = Parent.BoneReductionTargetOnScreenSize != value;
                    Parent.BoneReductionTargetOnScreenSize = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }
            public bool DependencyObject { get { return Parent.BoneReductionTargetOnScreenSizeEnabled; } set { Parent.BoneReductionTargetOnScreenSizeEnabled = value; OnPropertyChanged(); } }

            public SimplygonBoneReductionTargetOnScreenSizeEx() : base("BoneReductionTargetOnScreenSize")
            {
                Type = "uint";
                HelpText = "The OnScreenSize value, the maximum surface-deviation between the reduced geometry and the original.";
                TypeOverride = "";
                DefaultValue = 300;
                MinValue = 20;
                MaxValue = 4000;
                DefaultMinValue = 20;
                DefaultMaxValue = 4000;
                TicksFrequencyValue = 10;
                HasDependencyObject = true;
                Visible = true;
            }

            public SimplygonBoneReductionTargetOnScreenSizeEx(dynamic jsonData) : base("BoneReductionTargetOnScreenSize")
            {
                Type = "uint";
                HelpText = "The OnScreenSize value, the maximum surface-deviation between the reduced geometry and the original.";
                TypeOverride = "";
                DefaultValue = 300;
                MinValue = 20;
                DefaultMinValue = 20;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetOnScreenSize: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 4000;
                DefaultMaxValue = 4000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetOnScreenSize: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10;
                }

                HasDependencyObject = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBoneReductionTargetOnScreenSizeEx DeepCopy()
            {
                return (SimplygonBoneReductionTargetOnScreenSizeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.BoneReductionTargetOnScreenSizeEnabledUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                DependencyObject = EditorGUI.Toggle(new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth + 25, rect.height), new GUIContent(nameUI, HelpText), DependencyObject);
                if(DependencyObject)
                {
                    int value = Parent.BoneReductionTargetOnScreenSize;
                    value = EditorGUI.IntSlider(new Rect(rect.x + EditorGUIUtility.labelWidth + 25, rect.y, rect.width - (EditorGUIUtility.labelWidth + 25), rect.height), value, MinValue, MaxValue);
                    Value = value;
                }

            }

        }

        public string LockBoneSelectionSetName { get { return _LockBoneSelectionSetName; } set { _LockBoneSelectionSetName = value; OnPropertyChanged(); } }
        private string _LockBoneSelectionSetName;
        public SimplygonLockBoneSelectionSetNameEx LockBoneSelectionSetNameUI { get; set; }
        public class SimplygonLockBoneSelectionSetNameEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.LockBoneSelectionSetName;
                }

                set
                {
                    bool needReload = Parent.LockBoneSelectionSetName != value;
                    Parent.LockBoneSelectionSetName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonLockBoneSelectionSetNameEx() : base("LockBoneSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set that contains all of the bones that will be locked, and cannot be removed in the BoneLOD process. If a bone is locked, all its ancestors will be locked also. If both name and id are set for the locked selection set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonLockBoneSelectionSetNameEx(dynamic jsonData) : base("LockBoneSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set that contains all of the bones that will be locked, and cannot be removed in the BoneLOD process. If a bone is locked, all its ancestors will be locked also. If both name and id are set for the locked selection set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonLockBoneSelectionSetNameEx DeepCopy()
            {
                return (SimplygonLockBoneSelectionSetNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.LockBoneSelectionSetName;
                int selectedIndex = 0;
                string[] sets = Simplygon.Unity.EditorPlugin.SimplygonUtils.GetSelectionSetNamesInSelection();
                List<GUIContent> selectionSets = new List<GUIContent>();
                selectionSets.Add(new GUIContent("Not used"));
                for(int i = 0; i < sets.Length; ++i)
                {
                    if(value == sets[i]) selectedIndex = i+1;
                    selectionSets.Add(new GUIContent(sets[i]));
                }

                selectedIndex = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), selectedIndex, selectionSets.ToArray());
                Parent.LockBoneSelectionSetName = selectedIndex == 0 ? "" : selectionSets[selectedIndex].text;
            }

        }

        public string RemoveBoneSelectionSetName { get { return _RemoveBoneSelectionSetName; } set { _RemoveBoneSelectionSetName = value; OnPropertyChanged(); } }
        private string _RemoveBoneSelectionSetName;
        public SimplygonRemoveBoneSelectionSetNameEx RemoveBoneSelectionSetNameUI { get; set; }
        public class SimplygonRemoveBoneSelectionSetNameEx : SimplygonSettingsProperty
        {
            public SimplygonBoneSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.RemoveBoneSelectionSetName;
                }

                set
                {
                    bool needReload = Parent.RemoveBoneSelectionSetName != value;
                    Parent.RemoveBoneSelectionSetName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonRemoveBoneSelectionSetNameEx() : base("RemoveBoneSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set that contains all of the bones that will be forced to be removed in the BoneLOD process, UNLESS they are locked. If a bone is set to be removed, all its descendants will be removed also. If both name and id are set for the remove selection set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonRemoveBoneSelectionSetNameEx(dynamic jsonData) : base("RemoveBoneSelectionSetName")
            {
                Type = "string";
                HelpText = "The name of the selection set that contains all of the bones that will be forced to be removed in the BoneLOD process, UNLESS they are locked. If a bone is set to be removed, all its descendants will be removed also. If both name and id are set for the remove selection set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRemoveBoneSelectionSetNameEx DeepCopy()
            {
                return (SimplygonRemoveBoneSelectionSetNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.RemoveBoneSelectionSetName;
                int selectedIndex = 0;
                string[] sets = Simplygon.Unity.EditorPlugin.SimplygonUtils.GetSelectionSetNamesInSelection();
                List<GUIContent> selectionSets = new List<GUIContent>();
                selectionSets.Add(new GUIContent("Not used"));
                for(int i = 0; i < sets.Length; ++i)
                {
                    if(value == sets[i]) selectedIndex = i+1;
                    selectionSets.Add(new GUIContent(sets[i]));
                }

                selectedIndex = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), selectedIndex, selectionSets.ToArray());
                Parent.RemoveBoneSelectionSetName = selectedIndex == 0 ? "" : selectionSets[selectedIndex].text;
            }

        }


        public SimplygonBoneSettings() : base("BoneSettings")
        {
            Visible = true;
            UseBoneReducerUI = new SimplygonUseBoneReducerEx();
            UseBoneReducerUI.Parent = this;
            UseBoneReducer = UseBoneReducerUI.DefaultValue;
            Items.Add(UseBoneReducerUI);
            RemoveUnusedBonesUI = new SimplygonRemoveUnusedBonesEx();
            RemoveUnusedBonesUI.Parent = this;
            RemoveUnusedBones = RemoveUnusedBonesUI.DefaultValue;
            Items.Add(RemoveUnusedBonesUI);
            LimitBonesPerVertexUI = new SimplygonLimitBonesPerVertexEx();
            LimitBonesPerVertexUI.Parent = this;
            LimitBonesPerVertex = LimitBonesPerVertexUI.DefaultValue;
            Items.Add(LimitBonesPerVertexUI);
            MaxBonePerVertexUI = new SimplygonMaxBonePerVertexEx();
            MaxBonePerVertexUI.Parent = this;
            MaxBonePerVertex = MaxBonePerVertexUI.DefaultValue;
            Items.Add(MaxBonePerVertexUI);
            BoneReductionTargetBoneRatioEnabledUI = new SimplygonBoneReductionTargetBoneRatioEnabledEx();
            BoneReductionTargetBoneRatioEnabledUI.Parent = this;
            BoneReductionTargetBoneRatioEnabled = BoneReductionTargetBoneRatioEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneRatioEnabledUI);
            BoneReductionTargetBoneRatioUI = new SimplygonBoneReductionTargetBoneRatioEx();
            BoneReductionTargetBoneRatioUI.Parent = this;
            BoneReductionTargetBoneRatio = BoneReductionTargetBoneRatioUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneRatioUI);
            BoneReductionTargetBoneCountEnabledUI = new SimplygonBoneReductionTargetBoneCountEnabledEx();
            BoneReductionTargetBoneCountEnabledUI.Parent = this;
            BoneReductionTargetBoneCountEnabled = BoneReductionTargetBoneCountEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneCountEnabledUI);
            BoneReductionTargetBoneCountUI = new SimplygonBoneReductionTargetBoneCountEx();
            BoneReductionTargetBoneCountUI.Parent = this;
            BoneReductionTargetBoneCount = BoneReductionTargetBoneCountUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneCountUI);
            BoneReductionTargetMaxDeviationEnabledUI = new SimplygonBoneReductionTargetMaxDeviationEnabledEx();
            BoneReductionTargetMaxDeviationEnabledUI.Parent = this;
            BoneReductionTargetMaxDeviationEnabled = BoneReductionTargetMaxDeviationEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetMaxDeviationEnabledUI);
            BoneReductionTargetMaxDeviationUI = new SimplygonBoneReductionTargetMaxDeviationEx();
            BoneReductionTargetMaxDeviationUI.Parent = this;
            BoneReductionTargetMaxDeviation = BoneReductionTargetMaxDeviationUI.DefaultValue;
            Items.Add(BoneReductionTargetMaxDeviationUI);
            BoneReductionTargetOnScreenSizeEnabledUI = new SimplygonBoneReductionTargetOnScreenSizeEnabledEx();
            BoneReductionTargetOnScreenSizeEnabledUI.Parent = this;
            BoneReductionTargetOnScreenSizeEnabled = BoneReductionTargetOnScreenSizeEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetOnScreenSizeEnabledUI);
            BoneReductionTargetOnScreenSizeUI = new SimplygonBoneReductionTargetOnScreenSizeEx();
            BoneReductionTargetOnScreenSizeUI.Parent = this;
            BoneReductionTargetOnScreenSize = BoneReductionTargetOnScreenSizeUI.DefaultValue;
            Items.Add(BoneReductionTargetOnScreenSizeUI);
            BoneReductionTargetStopConditionUI = new SimplygonBoneReductionTargetStopConditionEx();
            BoneReductionTargetStopConditionUI.Parent = this;
            BoneReductionTargetStopCondition = BoneReductionTargetStopConditionUI.DefaultValue;
            Items.Add(BoneReductionTargetStopConditionUI);
            LockBoneSelectionSetNameUI = new SimplygonLockBoneSelectionSetNameEx();
            LockBoneSelectionSetNameUI.Parent = this;
            LockBoneSelectionSetName = LockBoneSelectionSetNameUI.DefaultValue;
            Items.Add(LockBoneSelectionSetNameUI);
            RemoveBoneSelectionSetNameUI = new SimplygonRemoveBoneSelectionSetNameEx();
            RemoveBoneSelectionSetNameUI.Parent = this;
            RemoveBoneSelectionSetName = RemoveBoneSelectionSetNameUI.DefaultValue;
            Items.Add(RemoveBoneSelectionSetNameUI);
        }

        public SimplygonBoneSettings(dynamic jsonData) : base("BoneSettings")
        {
            Visible = true;
            UseBoneReducerUI = new SimplygonUseBoneReducerEx(jsonData != null && ((JObject)jsonData).GetValue("UseBoneReducerUI") != null ? jsonData.UseBoneReducerUI : null);
            UseBoneReducerUI.Parent = this;
            UseBoneReducer = UseBoneReducerUI.DefaultValue;
            Items.Add(UseBoneReducerUI);
            RemoveUnusedBonesUI = new SimplygonRemoveUnusedBonesEx(jsonData != null && ((JObject)jsonData).GetValue("RemoveUnusedBonesUI") != null ? jsonData.RemoveUnusedBonesUI : null);
            RemoveUnusedBonesUI.Parent = this;
            RemoveUnusedBones = RemoveUnusedBonesUI.DefaultValue;
            Items.Add(RemoveUnusedBonesUI);
            LimitBonesPerVertexUI = new SimplygonLimitBonesPerVertexEx(jsonData != null && ((JObject)jsonData).GetValue("LimitBonesPerVertexUI") != null ? jsonData.LimitBonesPerVertexUI : null);
            LimitBonesPerVertexUI.Parent = this;
            LimitBonesPerVertex = LimitBonesPerVertexUI.DefaultValue;
            Items.Add(LimitBonesPerVertexUI);
            MaxBonePerVertexUI = new SimplygonMaxBonePerVertexEx(jsonData != null && ((JObject)jsonData).GetValue("MaxBonePerVertexUI") != null ? jsonData.MaxBonePerVertexUI : null);
            MaxBonePerVertexUI.Parent = this;
            MaxBonePerVertex = MaxBonePerVertexUI.DefaultValue;
            Items.Add(MaxBonePerVertexUI);
            BoneReductionTargetBoneRatioEnabledUI = new SimplygonBoneReductionTargetBoneRatioEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetBoneRatioEnabledUI") != null ? jsonData.BoneReductionTargetBoneRatioEnabledUI : null);
            BoneReductionTargetBoneRatioEnabledUI.Parent = this;
            BoneReductionTargetBoneRatioEnabled = BoneReductionTargetBoneRatioEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneRatioEnabledUI);
            BoneReductionTargetBoneRatioUI = new SimplygonBoneReductionTargetBoneRatioEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetBoneRatioUI") != null ? jsonData.BoneReductionTargetBoneRatioUI : null);
            BoneReductionTargetBoneRatioUI.Parent = this;
            BoneReductionTargetBoneRatio = BoneReductionTargetBoneRatioUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneRatioUI);
            BoneReductionTargetBoneCountEnabledUI = new SimplygonBoneReductionTargetBoneCountEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetBoneCountEnabledUI") != null ? jsonData.BoneReductionTargetBoneCountEnabledUI : null);
            BoneReductionTargetBoneCountEnabledUI.Parent = this;
            BoneReductionTargetBoneCountEnabled = BoneReductionTargetBoneCountEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneCountEnabledUI);
            BoneReductionTargetBoneCountUI = new SimplygonBoneReductionTargetBoneCountEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetBoneCountUI") != null ? jsonData.BoneReductionTargetBoneCountUI : null);
            BoneReductionTargetBoneCountUI.Parent = this;
            BoneReductionTargetBoneCount = BoneReductionTargetBoneCountUI.DefaultValue;
            Items.Add(BoneReductionTargetBoneCountUI);
            BoneReductionTargetMaxDeviationEnabledUI = new SimplygonBoneReductionTargetMaxDeviationEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetMaxDeviationEnabledUI") != null ? jsonData.BoneReductionTargetMaxDeviationEnabledUI : null);
            BoneReductionTargetMaxDeviationEnabledUI.Parent = this;
            BoneReductionTargetMaxDeviationEnabled = BoneReductionTargetMaxDeviationEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetMaxDeviationEnabledUI);
            BoneReductionTargetMaxDeviationUI = new SimplygonBoneReductionTargetMaxDeviationEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetMaxDeviationUI") != null ? jsonData.BoneReductionTargetMaxDeviationUI : null);
            BoneReductionTargetMaxDeviationUI.Parent = this;
            BoneReductionTargetMaxDeviation = BoneReductionTargetMaxDeviationUI.DefaultValue;
            Items.Add(BoneReductionTargetMaxDeviationUI);
            BoneReductionTargetOnScreenSizeEnabledUI = new SimplygonBoneReductionTargetOnScreenSizeEnabledEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetOnScreenSizeEnabledUI") != null ? jsonData.BoneReductionTargetOnScreenSizeEnabledUI : null);
            BoneReductionTargetOnScreenSizeEnabledUI.Parent = this;
            BoneReductionTargetOnScreenSizeEnabled = BoneReductionTargetOnScreenSizeEnabledUI.DefaultValue;
            Items.Add(BoneReductionTargetOnScreenSizeEnabledUI);
            BoneReductionTargetOnScreenSizeUI = new SimplygonBoneReductionTargetOnScreenSizeEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetOnScreenSizeUI") != null ? jsonData.BoneReductionTargetOnScreenSizeUI : null);
            BoneReductionTargetOnScreenSizeUI.Parent = this;
            BoneReductionTargetOnScreenSize = BoneReductionTargetOnScreenSizeUI.DefaultValue;
            Items.Add(BoneReductionTargetOnScreenSizeUI);
            BoneReductionTargetStopConditionUI = new SimplygonBoneReductionTargetStopConditionEx(jsonData != null && ((JObject)jsonData).GetValue("BoneReductionTargetStopConditionUI") != null ? jsonData.BoneReductionTargetStopConditionUI : null);
            BoneReductionTargetStopConditionUI.Parent = this;
            BoneReductionTargetStopCondition = BoneReductionTargetStopConditionUI.DefaultValue;
            Items.Add(BoneReductionTargetStopConditionUI);
            LockBoneSelectionSetNameUI = new SimplygonLockBoneSelectionSetNameEx(jsonData != null && ((JObject)jsonData).GetValue("LockBoneSelectionSetNameUI") != null ? jsonData.LockBoneSelectionSetNameUI : null);
            LockBoneSelectionSetNameUI.Parent = this;
            LockBoneSelectionSetName = LockBoneSelectionSetNameUI.DefaultValue;
            Items.Add(LockBoneSelectionSetNameUI);
            RemoveBoneSelectionSetNameUI = new SimplygonRemoveBoneSelectionSetNameEx(jsonData != null && ((JObject)jsonData).GetValue("RemoveBoneSelectionSetNameUI") != null ? jsonData.RemoveBoneSelectionSetNameUI : null);
            RemoveBoneSelectionSetNameUI.Parent = this;
            RemoveBoneSelectionSetName = RemoveBoneSelectionSetNameUI.DefaultValue;
            Items.Add(RemoveBoneSelectionSetNameUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonBoneSettings();
            copy.Items.Clear();
            copy.UseBoneReducerUI = this.UseBoneReducerUI.DeepCopy();
            copy.UseBoneReducerUI.Parent = copy;
            copy.Items.Add(copy.UseBoneReducerUI);
            copy.RemoveUnusedBonesUI = this.RemoveUnusedBonesUI.DeepCopy();
            copy.RemoveUnusedBonesUI.Parent = copy;
            copy.Items.Add(copy.RemoveUnusedBonesUI);
            copy.LimitBonesPerVertexUI = this.LimitBonesPerVertexUI.DeepCopy();
            copy.LimitBonesPerVertexUI.Parent = copy;
            copy.Items.Add(copy.LimitBonesPerVertexUI);
            copy.MaxBonePerVertexUI = this.MaxBonePerVertexUI.DeepCopy();
            copy.MaxBonePerVertexUI.Parent = copy;
            copy.Items.Add(copy.MaxBonePerVertexUI);
            copy.BoneReductionTargetBoneRatioEnabledUI = this.BoneReductionTargetBoneRatioEnabledUI.DeepCopy();
            copy.BoneReductionTargetBoneRatioEnabledUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetBoneRatioEnabledUI);
            copy.BoneReductionTargetBoneRatioUI = this.BoneReductionTargetBoneRatioUI.DeepCopy();
            copy.BoneReductionTargetBoneRatioUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetBoneRatioUI);
            copy.BoneReductionTargetBoneCountEnabledUI = this.BoneReductionTargetBoneCountEnabledUI.DeepCopy();
            copy.BoneReductionTargetBoneCountEnabledUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetBoneCountEnabledUI);
            copy.BoneReductionTargetBoneCountUI = this.BoneReductionTargetBoneCountUI.DeepCopy();
            copy.BoneReductionTargetBoneCountUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetBoneCountUI);
            copy.BoneReductionTargetMaxDeviationEnabledUI = this.BoneReductionTargetMaxDeviationEnabledUI.DeepCopy();
            copy.BoneReductionTargetMaxDeviationEnabledUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetMaxDeviationEnabledUI);
            copy.BoneReductionTargetMaxDeviationUI = this.BoneReductionTargetMaxDeviationUI.DeepCopy();
            copy.BoneReductionTargetMaxDeviationUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetMaxDeviationUI);
            copy.BoneReductionTargetOnScreenSizeEnabledUI = this.BoneReductionTargetOnScreenSizeEnabledUI.DeepCopy();
            copy.BoneReductionTargetOnScreenSizeEnabledUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetOnScreenSizeEnabledUI);
            copy.BoneReductionTargetOnScreenSizeUI = this.BoneReductionTargetOnScreenSizeUI.DeepCopy();
            copy.BoneReductionTargetOnScreenSizeUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetOnScreenSizeUI);
            copy.BoneReductionTargetStopConditionUI = this.BoneReductionTargetStopConditionUI.DeepCopy();
            copy.BoneReductionTargetStopConditionUI.Parent = copy;
            copy.Items.Add(copy.BoneReductionTargetStopConditionUI);
            copy.LockBoneSelectionSetNameUI = this.LockBoneSelectionSetNameUI.DeepCopy();
            copy.LockBoneSelectionSetNameUI.Parent = copy;
            copy.Items.Add(copy.LockBoneSelectionSetNameUI);
            copy.RemoveBoneSelectionSetNameUI = this.RemoveBoneSelectionSetNameUI.DeepCopy();
            copy.RemoveBoneSelectionSetNameUI.Parent = copy;
            copy.Items.Add(copy.RemoveBoneSelectionSetNameUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.UseBoneReducer = UseBoneReducer;
            if(serializeUIComponents)
            {
                jsonData.UseBoneReducerUI = UseBoneReducerUI.SaveJson();
            }

            jsonData.BoneReductionTargetBoneRatioEnabled = BoneReductionTargetBoneRatioEnabled;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetBoneRatioEnabledUI = BoneReductionTargetBoneRatioEnabledUI.SaveJson();
            }

            jsonData.RemoveUnusedBones = RemoveUnusedBones;
            if(serializeUIComponents)
            {
                jsonData.RemoveUnusedBonesUI = RemoveUnusedBonesUI.SaveJson();
            }

            jsonData.LimitBonesPerVertex = LimitBonesPerVertex;
            if(serializeUIComponents)
            {
                jsonData.LimitBonesPerVertexUI = LimitBonesPerVertexUI.SaveJson();
            }

            jsonData.BoneReductionTargetBoneCountEnabled = BoneReductionTargetBoneCountEnabled;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetBoneCountEnabledUI = BoneReductionTargetBoneCountEnabledUI.SaveJson();
            }

            jsonData.BoneReductionTargetMaxDeviationEnabled = BoneReductionTargetMaxDeviationEnabled;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetMaxDeviationEnabledUI = BoneReductionTargetMaxDeviationEnabledUI.SaveJson();
            }

            jsonData.MaxBonePerVertex = MaxBonePerVertex;
            if(serializeUIComponents)
            {
                jsonData.MaxBonePerVertexUI = MaxBonePerVertexUI.SaveJson();
            }

            jsonData.BoneReductionTargetOnScreenSizeEnabled = BoneReductionTargetOnScreenSizeEnabled;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetOnScreenSizeEnabledUI = BoneReductionTargetOnScreenSizeEnabledUI.SaveJson();
            }

            jsonData.BoneReductionTargetStopCondition = (int)BoneReductionTargetStopCondition;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetStopConditionUI = BoneReductionTargetStopConditionUI.SaveJson();
            }

            jsonData.BoneReductionTargetBoneRatio = BoneReductionTargetBoneRatio;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetBoneRatioUI = BoneReductionTargetBoneRatioUI.SaveJson();
            }

            jsonData.BoneReductionTargetBoneCount = BoneReductionTargetBoneCount;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetBoneCountUI = BoneReductionTargetBoneCountUI.SaveJson();
            }

            jsonData.BoneReductionTargetMaxDeviation = BoneReductionTargetMaxDeviation;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetMaxDeviationUI = BoneReductionTargetMaxDeviationUI.SaveJson();
            }

            jsonData.BoneReductionTargetOnScreenSize = BoneReductionTargetOnScreenSize;
            if(serializeUIComponents)
            {
                jsonData.BoneReductionTargetOnScreenSizeUI = BoneReductionTargetOnScreenSizeUI.SaveJson();
            }

            jsonData.LockBoneSelectionSetName = LockBoneSelectionSetName;
            if(serializeUIComponents)
            {
                jsonData.LockBoneSelectionSetNameUI = LockBoneSelectionSetNameUI.SaveJson();
            }

            jsonData.RemoveBoneSelectionSetName = RemoveBoneSelectionSetName;
            if(serializeUIComponents)
            {
                jsonData.RemoveBoneSelectionSetNameUI = RemoveBoneSelectionSetNameUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("UseBoneReducer") != null)
            {
                UseBoneReducer = (bool)jsonData.UseBoneReducer;
            }

            if(jsonData.GetValue("BoneReductionTargetBoneRatioEnabled") != null)
            {
                BoneReductionTargetBoneRatioEnabled = (bool)jsonData.BoneReductionTargetBoneRatioEnabled;
            }

            if(jsonData.GetValue("RemoveUnusedBones") != null)
            {
                RemoveUnusedBones = (bool)jsonData.RemoveUnusedBones;
            }

            if(jsonData.GetValue("LimitBonesPerVertex") != null)
            {
                LimitBonesPerVertex = (bool)jsonData.LimitBonesPerVertex;
            }

            if(jsonData.GetValue("BoneReductionTargetBoneCountEnabled") != null)
            {
                BoneReductionTargetBoneCountEnabled = (bool)jsonData.BoneReductionTargetBoneCountEnabled;
            }

            if(jsonData.GetValue("BoneReductionTargetMaxDeviationEnabled") != null)
            {
                BoneReductionTargetMaxDeviationEnabled = (bool)jsonData.BoneReductionTargetMaxDeviationEnabled;
            }

            if(jsonData.GetValue("MaxBonePerVertex") != null)
            {
                var newMaxBonePerVertex = (int)jsonData.MaxBonePerVertex;
                if (newMaxBonePerVertex >= MaxBonePerVertexUI.DefaultMinValue && newMaxBonePerVertex <= MaxBonePerVertexUI.DefaultMaxValue)
                {
                    MaxBonePerVertex = newMaxBonePerVertex;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MaxBonePerVertex: Invalid value {newMaxBonePerVertex}, using default value {MaxBonePerVertex.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("BoneReductionTargetOnScreenSizeEnabled") != null)
            {
                BoneReductionTargetOnScreenSizeEnabled = (bool)jsonData.BoneReductionTargetOnScreenSizeEnabled;
            }

            if(jsonData.GetValue("BoneReductionTargetStopCondition") != null)
            {
                BoneReductionTargetStopCondition = (EStopCondition)jsonData.BoneReductionTargetStopCondition;
            }

            if(jsonData.GetValue("BoneReductionTargetBoneRatio") != null)
            {
                float newBoneReductionTargetBoneRatio = (float)jsonData.BoneReductionTargetBoneRatio;
                if (newBoneReductionTargetBoneRatio >= BoneReductionTargetBoneRatioUI.DefaultMinValue && newBoneReductionTargetBoneRatio <= BoneReductionTargetBoneRatioUI.DefaultMaxValue)
                {
                    BoneReductionTargetBoneRatio = newBoneReductionTargetBoneRatio;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetBoneRatio: Invalid value {newBoneReductionTargetBoneRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {BoneReductionTargetBoneRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("BoneReductionTargetBoneCount") != null)
            {
                var newBoneReductionTargetBoneCount = (int)jsonData.BoneReductionTargetBoneCount;
                if (newBoneReductionTargetBoneCount >= BoneReductionTargetBoneCountUI.DefaultMinValue && newBoneReductionTargetBoneCount <= BoneReductionTargetBoneCountUI.DefaultMaxValue)
                {
                    BoneReductionTargetBoneCount = newBoneReductionTargetBoneCount;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetBoneCount: Invalid value {newBoneReductionTargetBoneCount}, using default value {BoneReductionTargetBoneCount.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("BoneReductionTargetMaxDeviation") != null)
            {
                float newBoneReductionTargetMaxDeviation = (float)jsonData.BoneReductionTargetMaxDeviation;
                if (newBoneReductionTargetMaxDeviation >= BoneReductionTargetMaxDeviationUI.DefaultMinValue && newBoneReductionTargetMaxDeviation <= BoneReductionTargetMaxDeviationUI.DefaultMaxValue)
                {
                    BoneReductionTargetMaxDeviation = newBoneReductionTargetMaxDeviation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetMaxDeviation: Invalid value {newBoneReductionTargetMaxDeviation.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {BoneReductionTargetMaxDeviation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("BoneReductionTargetOnScreenSize") != null)
            {
                var newBoneReductionTargetOnScreenSize = (int)jsonData.BoneReductionTargetOnScreenSize;
                if (newBoneReductionTargetOnScreenSize >= BoneReductionTargetOnScreenSizeUI.DefaultMinValue && newBoneReductionTargetOnScreenSize <= BoneReductionTargetOnScreenSizeUI.DefaultMaxValue)
                {
                    BoneReductionTargetOnScreenSize = newBoneReductionTargetOnScreenSize;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"BoneReductionTargetOnScreenSize: Invalid value {newBoneReductionTargetOnScreenSize}, using default value {BoneReductionTargetOnScreenSize.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("LockBoneSelectionSetName") != null)
            {
                LockBoneSelectionSetName = (string)jsonData.LockBoneSelectionSetName;
            }

            if(jsonData.GetValue("RemoveBoneSelectionSetName") != null)
            {
                RemoveBoneSelectionSetName = (string)jsonData.RemoveBoneSelectionSetName;
            }

        }

        public override void Reset()
        {
            UseBoneReducerUI.Reset();
            BoneReductionTargetBoneRatioEnabledUI.Reset();
            RemoveUnusedBonesUI.Reset();
            LimitBonesPerVertexUI.Reset();
            BoneReductionTargetBoneCountEnabledUI.Reset();
            BoneReductionTargetMaxDeviationEnabledUI.Reset();
            MaxBonePerVertexUI.Reset();
            BoneReductionTargetOnScreenSizeEnabledUI.Reset();
            BoneReductionTargetStopConditionUI.Reset();
            BoneReductionTargetBoneRatioUI.Reset();
            BoneReductionTargetBoneCountUI.Reset();
            BoneReductionTargetMaxDeviationUI.Reset();
            BoneReductionTargetOnScreenSizeUI.Reset();
            LockBoneSelectionSetNameUI.Reset();
            RemoveBoneSelectionSetNameUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            UseBoneReducerUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetBoneRatioEnabledUI.IsEditEnabled = isEditEnabled;
            RemoveUnusedBonesUI.IsEditEnabled = isEditEnabled;
            LimitBonesPerVertexUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetBoneCountEnabledUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetMaxDeviationEnabledUI.IsEditEnabled = isEditEnabled;
            MaxBonePerVertexUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetOnScreenSizeEnabledUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetStopConditionUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetBoneRatioUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetBoneCountUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetMaxDeviationUI.IsEditEnabled = isEditEnabled;
            BoneReductionTargetOnScreenSizeUI.IsEditEnabled = isEditEnabled;
            LockBoneSelectionSetNameUI.IsEditEnabled = isEditEnabled;
            RemoveBoneSelectionSetNameUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            UseBoneReducerUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RemoveUnusedBonesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            LimitBonesPerVertexUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MaxBonePerVertexUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetBoneRatioEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetBoneRatioUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetBoneCountEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetBoneCountUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetMaxDeviationEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetMaxDeviationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetOnScreenSizeEnabledUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetOnScreenSizeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BoneReductionTargetStopConditionUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            LockBoneSelectionSetNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RemoveBoneSelectionSetNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonVertexWeightSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(UseVertexWeightsInReducerUI.Visible) return true;
                if(UseVertexWeightsInTexcoordGeneratorUI.Visible) return true;
                if(WeightsFromColorNameUI.Visible) return true;
                if(WeightsFromColorLevelUI.Visible) return true;
                if(WeightsFromColorComponentUI.Visible) return true;
                if(WeightsFromColorMultiplierUI.Visible) return true;
                if(WeightsFromColorModeUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool UseVertexWeightsInReducer { get { return _UseVertexWeightsInReducer; } set { _UseVertexWeightsInReducer = value; OnPropertyChanged(); } }
        private bool _UseVertexWeightsInReducer;
        public SimplygonUseVertexWeightsInReducerEx UseVertexWeightsInReducerUI { get; set; }
        public class SimplygonUseVertexWeightsInReducerEx : SimplygonSettingsProperty
        {
            public SimplygonVertexWeightSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseVertexWeightsInReducer;
                }

                set
                {
                    bool needReload = Parent.UseVertexWeightsInReducer != value;
                    Parent.UseVertexWeightsInReducer = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseVertexWeightsInReducerEx() : base("UseVertexWeightsInReducer")
            {
                Type = "bool";
                HelpText = "If set, and using the reduction processor, the reduction will be weighted based on the weights in the 'VertexWeights' vertex field.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseVertexWeightsInReducerEx(dynamic jsonData) : base("UseVertexWeightsInReducer")
            {
                Type = "bool";
                HelpText = "If set, and using the reduction processor, the reduction will be weighted based on the weights in the 'VertexWeights' vertex field.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseVertexWeightsInReducerEx DeepCopy()
            {
                return (SimplygonUseVertexWeightsInReducerEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseVertexWeightsInReducer;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseVertexWeightsInTexcoordGenerator { get { return _UseVertexWeightsInTexcoordGenerator; } set { _UseVertexWeightsInTexcoordGenerator = value; OnPropertyChanged(); } }
        private bool _UseVertexWeightsInTexcoordGenerator;
        public SimplygonUseVertexWeightsInTexcoordGeneratorEx UseVertexWeightsInTexcoordGeneratorUI { get; set; }
        public class SimplygonUseVertexWeightsInTexcoordGeneratorEx : SimplygonSettingsProperty
        {
            public SimplygonVertexWeightSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseVertexWeightsInTexcoordGenerator;
                }

                set
                {
                    bool needReload = Parent.UseVertexWeightsInTexcoordGenerator != value;
                    Parent.UseVertexWeightsInTexcoordGenerator = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseVertexWeightsInTexcoordGeneratorEx() : base("UseVertexWeightsInTexcoordGenerator")
            {
                Type = "bool";
                HelpText = "If set, and generating new texcoords using either the parameterizeror the chart aggregator, the relative sizes of the output charts will be scaled using the weights in the 'VertexWeights' vertex field.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseVertexWeightsInTexcoordGeneratorEx(dynamic jsonData) : base("UseVertexWeightsInTexcoordGenerator")
            {
                Type = "bool";
                HelpText = "If set, and generating new texcoords using either the parameterizeror the chart aggregator, the relative sizes of the output charts will be scaled using the weights in the 'VertexWeights' vertex field.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseVertexWeightsInTexcoordGeneratorEx DeepCopy()
            {
                return (SimplygonUseVertexWeightsInTexcoordGeneratorEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseVertexWeightsInTexcoordGenerator;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public string WeightsFromColorName { get { return _WeightsFromColorName; } set { _WeightsFromColorName = value; OnPropertyChanged(); } }
        private string _WeightsFromColorName;
        public SimplygonWeightsFromColorNameEx WeightsFromColorNameUI { get; set; }
        public class SimplygonWeightsFromColorNameEx : SimplygonSettingsProperty
        {
            public SimplygonVertexWeightSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.WeightsFromColorName;
                }

                set
                {
                    bool needReload = Parent.WeightsFromColorName != value;
                    Parent.WeightsFromColorName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonWeightsFromColorNameEx() : base("WeightsFromColorName")
            {
                Type = "string";
                HelpText = "If the name of an existing vertex color field in the input geometry is set here, the existing VertexWeights field will be overwritten by a set created by converting the selected color field according to the other WeightsFromColor settings in this settings object. If both ColorName and the corresponding ColorLevel is set, the processors will prioritize the name.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonWeightsFromColorNameEx(dynamic jsonData) : base("WeightsFromColorName")
            {
                Type = "string";
                HelpText = "If the name of an existing vertex color field in the input geometry is set here, the existing VertexWeights field will be overwritten by a set created by converting the selected color field according to the other WeightsFromColor settings in this settings object. If both ColorName and the corresponding ColorLevel is set, the processors will prioritize the name.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeightsFromColorNameEx DeepCopy()
            {
                return (SimplygonWeightsFromColorNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.WeightsFromColorName;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int WeightsFromColorLevel { get { return _WeightsFromColorLevel; } set { _WeightsFromColorLevel = value; OnPropertyChanged(); } }
        private int _WeightsFromColorLevel;
        public SimplygonWeightsFromColorLevelEx WeightsFromColorLevelUI { get; set; }
        public class SimplygonWeightsFromColorLevelEx : SimplygonSettingsProperty
        {
            public SimplygonVertexWeightSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.WeightsFromColorLevel;
                }

                set
                {
                    bool needReload = Parent.WeightsFromColorLevel != value;
                    Parent.WeightsFromColorLevel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonWeightsFromColorLevelEx() : base("WeightsFromColorLevel")
            {
                Type = "rid";
                HelpText = "If the index of an existing vertex color field in the input geometry is set here, the existing VertexWeights field will be overwritten by a set created by converting the selected color field according to the other WeightsFromColor settings in this settings object. If both this and the corresponding ColorName is set, the processors will prioritize the name.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                MaxValue = 10;
                DefaultMinValue = -1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonWeightsFromColorLevelEx(dynamic jsonData) : base("WeightsFromColorLevel")
            {
                Type = "rid";
                HelpText = "If the index of an existing vertex color field in the input geometry is set here, the existing VertexWeights field will be overwritten by a set created by converting the selected color field according to the other WeightsFromColor settings in this settings object. If both this and the corresponding ColorName is set, the processors will prioritize the name.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                DefaultMinValue = -1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"WeightsFromColorLevel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"WeightsFromColorLevel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeightsFromColorLevelEx DeepCopy()
            {
                return (SimplygonWeightsFromColorLevelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.WeightsFromColorLevel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EColorComponent WeightsFromColorComponent { get { return _WeightsFromColorComponent; } set { _WeightsFromColorComponent = value; OnPropertyChanged(); } }
        private EColorComponent _WeightsFromColorComponent;
        public SimplygonWeightsFromColorComponentEx WeightsFromColorComponentUI { get; set; }
        public class SimplygonWeightsFromColorComponentEx : SimplygonSettingsProperty
        {
            public SimplygonVertexWeightSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.WeightsFromColorComponent;
                }

                set
                {
                    bool needReload = Parent.WeightsFromColorComponent != value;
                    Parent.WeightsFromColorComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonWeightsFromColorComponentEx() : base("WeightsFromColorComponent")
            {
                Type = "enum";
                HelpText = "If converting vertex colors to weights, this setting controls which color component is used to create the weights.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonWeightsFromColorComponentEx(dynamic jsonData) : base("WeightsFromColorComponent")
            {
                Type = "enum";
                HelpText = "If converting vertex colors to weights, this setting controls which color component is used to create the weights.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeightsFromColorComponentEx DeepCopy()
            {
                return (SimplygonWeightsFromColorComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.WeightsFromColorComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public float WeightsFromColorMultiplier { get { return _WeightsFromColorMultiplier; } set { _WeightsFromColorMultiplier = value; OnPropertyChanged(); } }
        private float _WeightsFromColorMultiplier;
        public SimplygonWeightsFromColorMultiplierEx WeightsFromColorMultiplierUI { get; set; }
        public class SimplygonWeightsFromColorMultiplierEx : SimplygonSettingsProperty
        {
            public SimplygonVertexWeightSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.WeightsFromColorMultiplier;
                }

                set
                {
                    bool needReload = Parent.WeightsFromColorMultiplier != value;
                    Parent.WeightsFromColorMultiplier = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonWeightsFromColorMultiplierEx() : base("WeightsFromColorMultiplier")
            {
                Type = "real";
                HelpText = "If converting vertex colors to weights, this setting controls the max and min resulting vertex weights generated by the input color.";
                TypeOverride = "";
                DefaultValue = 4f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonWeightsFromColorMultiplierEx(dynamic jsonData) : base("WeightsFromColorMultiplier")
            {
                Type = "real";
                HelpText = "If converting vertex colors to weights, this setting controls the max and min resulting vertex weights generated by the input color.";
                TypeOverride = "";
                DefaultValue = 4f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"WeightsFromColorMultiplier: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"WeightsFromColorMultiplier: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeightsFromColorMultiplierEx DeepCopy()
            {
                return (SimplygonWeightsFromColorMultiplierEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.WeightsFromColorMultiplier;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EWeightsFromColorMode WeightsFromColorMode { get { return _WeightsFromColorMode; } set { _WeightsFromColorMode = value; OnPropertyChanged(); } }
        private EWeightsFromColorMode _WeightsFromColorMode;
        public SimplygonWeightsFromColorModeEx WeightsFromColorModeUI { get; set; }
        public class SimplygonWeightsFromColorModeEx : SimplygonSettingsProperty
        {
            public SimplygonVertexWeightSettings Parent { get; set; }
            public EWeightsFromColorMode Value
            {
                get
                {
                    return Parent.WeightsFromColorMode;
                }

                set
                {
                    bool needReload = Parent.WeightsFromColorMode != value;
                    Parent.WeightsFromColorMode = value;
                    OnPropertyChanged();
                }

            }

            public EWeightsFromColorMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EWeightsFromColorMode)); } }

            public SimplygonWeightsFromColorModeEx() : base("WeightsFromColorMode")
            {
                Type = "enum";
                HelpText = "If converting vertex colors to weights, this setting along with WeightsFromColorMultiplier controls how to map the RGBA intensity between 0-1 to weights. Standard mode maps color intensity [0-1] to vertex weight [1/Multiplier - Multiplier]. High mode maps color intensity [0-1] to vertex weight [1 - Multiplier]. Low mode maps color intensity [0-1] to vertex weight [1/Multiplier - 1].";
                TypeOverride = "";
                DefaultValue = EWeightsFromColorMode.Standard;
                Visible = true;
            }

            public SimplygonWeightsFromColorModeEx(dynamic jsonData) : base("WeightsFromColorMode")
            {
                Type = "enum";
                HelpText = "If converting vertex colors to weights, this setting along with WeightsFromColorMultiplier controls how to map the RGBA intensity between 0-1 to weights. Standard mode maps color intensity [0-1] to vertex weight [1/Multiplier - Multiplier]. High mode maps color intensity [0-1] to vertex weight [1 - Multiplier]. Low mode maps color intensity [0-1] to vertex weight [1/Multiplier - 1].";
                TypeOverride = "";
                DefaultValue = EWeightsFromColorMode.Standard;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonWeightsFromColorModeEx DeepCopy()
            {
                return (SimplygonWeightsFromColorModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.WeightsFromColorMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EWeightsFromColorMode)value;
            }

        }


        public SimplygonVertexWeightSettings() : base("VertexWeightSettings")
        {
            Visible = true;
            UseVertexWeightsInReducerUI = new SimplygonUseVertexWeightsInReducerEx();
            UseVertexWeightsInReducerUI.Parent = this;
            UseVertexWeightsInReducer = UseVertexWeightsInReducerUI.DefaultValue;
            Items.Add(UseVertexWeightsInReducerUI);
            UseVertexWeightsInTexcoordGeneratorUI = new SimplygonUseVertexWeightsInTexcoordGeneratorEx();
            UseVertexWeightsInTexcoordGeneratorUI.Parent = this;
            UseVertexWeightsInTexcoordGenerator = UseVertexWeightsInTexcoordGeneratorUI.DefaultValue;
            Items.Add(UseVertexWeightsInTexcoordGeneratorUI);
            WeightsFromColorLevelUI = new SimplygonWeightsFromColorLevelEx();
            WeightsFromColorLevelUI.Parent = this;
            WeightsFromColorLevel = WeightsFromColorLevelUI.DefaultValue;
            Items.Add(WeightsFromColorLevelUI);
            WeightsFromColorNameUI = new SimplygonWeightsFromColorNameEx();
            WeightsFromColorNameUI.Parent = this;
            WeightsFromColorName = WeightsFromColorNameUI.DefaultValue;
            Items.Add(WeightsFromColorNameUI);
            WeightsFromColorComponentUI = new SimplygonWeightsFromColorComponentEx();
            WeightsFromColorComponentUI.Parent = this;
            WeightsFromColorComponent = WeightsFromColorComponentUI.DefaultValue;
            Items.Add(WeightsFromColorComponentUI);
            WeightsFromColorMultiplierUI = new SimplygonWeightsFromColorMultiplierEx();
            WeightsFromColorMultiplierUI.Parent = this;
            WeightsFromColorMultiplier = WeightsFromColorMultiplierUI.DefaultValue;
            Items.Add(WeightsFromColorMultiplierUI);
            WeightsFromColorModeUI = new SimplygonWeightsFromColorModeEx();
            WeightsFromColorModeUI.Parent = this;
            WeightsFromColorMode = WeightsFromColorModeUI.DefaultValue;
            Items.Add(WeightsFromColorModeUI);
        }

        public SimplygonVertexWeightSettings(dynamic jsonData) : base("VertexWeightSettings")
        {
            Visible = true;
            UseVertexWeightsInReducerUI = new SimplygonUseVertexWeightsInReducerEx(jsonData != null && ((JObject)jsonData).GetValue("UseVertexWeightsInReducerUI") != null ? jsonData.UseVertexWeightsInReducerUI : null);
            UseVertexWeightsInReducerUI.Parent = this;
            UseVertexWeightsInReducer = UseVertexWeightsInReducerUI.DefaultValue;
            Items.Add(UseVertexWeightsInReducerUI);
            UseVertexWeightsInTexcoordGeneratorUI = new SimplygonUseVertexWeightsInTexcoordGeneratorEx(jsonData != null && ((JObject)jsonData).GetValue("UseVertexWeightsInTexcoordGeneratorUI") != null ? jsonData.UseVertexWeightsInTexcoordGeneratorUI : null);
            UseVertexWeightsInTexcoordGeneratorUI.Parent = this;
            UseVertexWeightsInTexcoordGenerator = UseVertexWeightsInTexcoordGeneratorUI.DefaultValue;
            Items.Add(UseVertexWeightsInTexcoordGeneratorUI);
            WeightsFromColorLevelUI = new SimplygonWeightsFromColorLevelEx(jsonData != null && ((JObject)jsonData).GetValue("WeightsFromColorLevelUI") != null ? jsonData.WeightsFromColorLevelUI : null);
            WeightsFromColorLevelUI.Parent = this;
            WeightsFromColorLevel = WeightsFromColorLevelUI.DefaultValue;
            Items.Add(WeightsFromColorLevelUI);
            WeightsFromColorNameUI = new SimplygonWeightsFromColorNameEx(jsonData != null && ((JObject)jsonData).GetValue("WeightsFromColorNameUI") != null ? jsonData.WeightsFromColorNameUI : null);
            WeightsFromColorNameUI.Parent = this;
            WeightsFromColorName = WeightsFromColorNameUI.DefaultValue;
            Items.Add(WeightsFromColorNameUI);
            WeightsFromColorComponentUI = new SimplygonWeightsFromColorComponentEx(jsonData != null && ((JObject)jsonData).GetValue("WeightsFromColorComponentUI") != null ? jsonData.WeightsFromColorComponentUI : null);
            WeightsFromColorComponentUI.Parent = this;
            WeightsFromColorComponent = WeightsFromColorComponentUI.DefaultValue;
            Items.Add(WeightsFromColorComponentUI);
            WeightsFromColorMultiplierUI = new SimplygonWeightsFromColorMultiplierEx(jsonData != null && ((JObject)jsonData).GetValue("WeightsFromColorMultiplierUI") != null ? jsonData.WeightsFromColorMultiplierUI : null);
            WeightsFromColorMultiplierUI.Parent = this;
            WeightsFromColorMultiplier = WeightsFromColorMultiplierUI.DefaultValue;
            Items.Add(WeightsFromColorMultiplierUI);
            WeightsFromColorModeUI = new SimplygonWeightsFromColorModeEx(jsonData != null && ((JObject)jsonData).GetValue("WeightsFromColorModeUI") != null ? jsonData.WeightsFromColorModeUI : null);
            WeightsFromColorModeUI.Parent = this;
            WeightsFromColorMode = WeightsFromColorModeUI.DefaultValue;
            Items.Add(WeightsFromColorModeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonVertexWeightSettings();
            copy.Items.Clear();
            copy.UseVertexWeightsInReducerUI = this.UseVertexWeightsInReducerUI.DeepCopy();
            copy.UseVertexWeightsInReducerUI.Parent = copy;
            copy.Items.Add(copy.UseVertexWeightsInReducerUI);
            copy.UseVertexWeightsInTexcoordGeneratorUI = this.UseVertexWeightsInTexcoordGeneratorUI.DeepCopy();
            copy.UseVertexWeightsInTexcoordGeneratorUI.Parent = copy;
            copy.Items.Add(copy.UseVertexWeightsInTexcoordGeneratorUI);
            copy.WeightsFromColorLevelUI = this.WeightsFromColorLevelUI.DeepCopy();
            copy.WeightsFromColorLevelUI.Parent = copy;
            copy.Items.Add(copy.WeightsFromColorLevelUI);
            copy.WeightsFromColorNameUI = this.WeightsFromColorNameUI.DeepCopy();
            copy.WeightsFromColorNameUI.Parent = copy;
            copy.Items.Add(copy.WeightsFromColorNameUI);
            copy.WeightsFromColorComponentUI = this.WeightsFromColorComponentUI.DeepCopy();
            copy.WeightsFromColorComponentUI.Parent = copy;
            copy.Items.Add(copy.WeightsFromColorComponentUI);
            copy.WeightsFromColorMultiplierUI = this.WeightsFromColorMultiplierUI.DeepCopy();
            copy.WeightsFromColorMultiplierUI.Parent = copy;
            copy.Items.Add(copy.WeightsFromColorMultiplierUI);
            copy.WeightsFromColorModeUI = this.WeightsFromColorModeUI.DeepCopy();
            copy.WeightsFromColorModeUI.Parent = copy;
            copy.Items.Add(copy.WeightsFromColorModeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.UseVertexWeightsInReducer = UseVertexWeightsInReducer;
            if(serializeUIComponents)
            {
                jsonData.UseVertexWeightsInReducerUI = UseVertexWeightsInReducerUI.SaveJson();
            }

            jsonData.UseVertexWeightsInTexcoordGenerator = UseVertexWeightsInTexcoordGenerator;
            if(serializeUIComponents)
            {
                jsonData.UseVertexWeightsInTexcoordGeneratorUI = UseVertexWeightsInTexcoordGeneratorUI.SaveJson();
            }

            jsonData.WeightsFromColorName = WeightsFromColorName;
            if(serializeUIComponents)
            {
                jsonData.WeightsFromColorNameUI = WeightsFromColorNameUI.SaveJson();
            }

            jsonData.WeightsFromColorLevel = WeightsFromColorLevel;
            if(serializeUIComponents)
            {
                jsonData.WeightsFromColorLevelUI = WeightsFromColorLevelUI.SaveJson();
            }

            jsonData.WeightsFromColorComponent = (int)WeightsFromColorComponent;
            if(serializeUIComponents)
            {
                jsonData.WeightsFromColorComponentUI = WeightsFromColorComponentUI.SaveJson();
            }

            jsonData.WeightsFromColorMultiplier = WeightsFromColorMultiplier;
            if(serializeUIComponents)
            {
                jsonData.WeightsFromColorMultiplierUI = WeightsFromColorMultiplierUI.SaveJson();
            }

            jsonData.WeightsFromColorMode = (int)WeightsFromColorMode;
            if(serializeUIComponents)
            {
                jsonData.WeightsFromColorModeUI = WeightsFromColorModeUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("UseVertexWeightsInReducer") != null)
            {
                UseVertexWeightsInReducer = (bool)jsonData.UseVertexWeightsInReducer;
            }

            if(jsonData.GetValue("UseVertexWeightsInTexcoordGenerator") != null)
            {
                UseVertexWeightsInTexcoordGenerator = (bool)jsonData.UseVertexWeightsInTexcoordGenerator;
            }

            if(jsonData.GetValue("WeightsFromColorName") != null)
            {
                WeightsFromColorName = (string)jsonData.WeightsFromColorName;
            }

            if(jsonData.GetValue("WeightsFromColorLevel") != null)
            {
                var newWeightsFromColorLevel = (int)jsonData.WeightsFromColorLevel;
                if (newWeightsFromColorLevel >= WeightsFromColorLevelUI.DefaultMinValue && newWeightsFromColorLevel <= WeightsFromColorLevelUI.DefaultMaxValue)
                {
                    WeightsFromColorLevel = newWeightsFromColorLevel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"WeightsFromColorLevel: Invalid value {newWeightsFromColorLevel}, using default value {WeightsFromColorLevel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("WeightsFromColorComponent") != null)
            {
                WeightsFromColorComponent = (EColorComponent)jsonData.WeightsFromColorComponent;
            }

            if(jsonData.GetValue("WeightsFromColorMultiplier") != null)
            {
                float newWeightsFromColorMultiplier = (float)jsonData.WeightsFromColorMultiplier;
                if (newWeightsFromColorMultiplier >= WeightsFromColorMultiplierUI.DefaultMinValue && newWeightsFromColorMultiplier <= WeightsFromColorMultiplierUI.DefaultMaxValue)
                {
                    WeightsFromColorMultiplier = newWeightsFromColorMultiplier;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"WeightsFromColorMultiplier: Invalid value {newWeightsFromColorMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {WeightsFromColorMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("WeightsFromColorMode") != null)
            {
                WeightsFromColorMode = (EWeightsFromColorMode)jsonData.WeightsFromColorMode;
            }

        }

        public override void Reset()
        {
            UseVertexWeightsInReducerUI.Reset();
            UseVertexWeightsInTexcoordGeneratorUI.Reset();
            WeightsFromColorNameUI.Reset();
            WeightsFromColorLevelUI.Reset();
            WeightsFromColorComponentUI.Reset();
            WeightsFromColorMultiplierUI.Reset();
            WeightsFromColorModeUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            UseVertexWeightsInReducerUI.IsEditEnabled = isEditEnabled;
            UseVertexWeightsInTexcoordGeneratorUI.IsEditEnabled = isEditEnabled;
            WeightsFromColorNameUI.IsEditEnabled = isEditEnabled;
            WeightsFromColorLevelUI.IsEditEnabled = isEditEnabled;
            WeightsFromColorComponentUI.IsEditEnabled = isEditEnabled;
            WeightsFromColorMultiplierUI.IsEditEnabled = isEditEnabled;
            WeightsFromColorModeUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            UseVertexWeightsInReducerUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseVertexWeightsInTexcoordGeneratorUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeightsFromColorLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeightsFromColorNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeightsFromColorComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeightsFromColorMultiplierUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            WeightsFromColorModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonPipelineSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(TextureOutputPathUI.Visible) return true;
                if(SimplygonBatchPathUI.Visible) return true;
                if(OutputMaterialNameUI.Visible) return true;
                if(OutputUniqueMaterialNamesUI.Visible) return true;
                if(EmbedReferencesUI.Visible) return true;
                if(IntermediateStepUI.Visible) return true;
                if(CascadedRunModeUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string TextureOutputPath { get { return _TextureOutputPath; } set { _TextureOutputPath = value; OnPropertyChanged(); } }
        private string _TextureOutputPath;
        public SimplygonTextureOutputPathEx TextureOutputPathUI { get; set; }
        public class SimplygonTextureOutputPathEx : SimplygonSettingsProperty
        {
            public SimplygonPipelineSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.TextureOutputPath;
                }

                set
                {
                    bool needReload = Parent.TextureOutputPath != value;
                    Parent.TextureOutputPath = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonTextureOutputPathEx() : base("TextureOutputPath")
            {
                Type = "string";
                HelpText = "The path where the pipeline will save any created textures from material casters. A relative path will be treated as relative to the scene file output path if the pipeline is executed with scene file paths (RunSceneFromFile), or from the current working directory if the pipeline is executed with a scene object (RunScene). The directory must exist, it will not be created.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonTextureOutputPathEx(dynamic jsonData) : base("TextureOutputPath")
            {
                Type = "string";
                HelpText = "The path where the pipeline will save any created textures from material casters. A relative path will be treated as relative to the scene file output path if the pipeline is executed with scene file paths (RunSceneFromFile), or from the current working directory if the pipeline is executed with a scene object (RunScene). The directory must exist, it will not be created.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTextureOutputPathEx DeepCopy()
            {
                return (SimplygonTextureOutputPathEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.TextureOutputPath;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public string SimplygonBatchPath { get { return _SimplygonBatchPath; } set { _SimplygonBatchPath = value; OnPropertyChanged(); } }
        private string _SimplygonBatchPath;
        public SimplygonSimplygonBatchPathEx SimplygonBatchPathUI { get; set; }
        public class SimplygonSimplygonBatchPathEx : SimplygonSettingsProperty
        {
            public SimplygonPipelineSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.SimplygonBatchPath;
                }

                set
                {
                    bool needReload = Parent.SimplygonBatchPath != value;
                    Parent.SimplygonBatchPath = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonSimplygonBatchPathEx() : base("SimplygonBatchPath")
            {
                Type = "string";
                HelpText = "The path for the batch tool used when executing pipelines in a new/distributed process. This should be the path to the directory where the SimplygonBatch executable is located. If the tool is in the system path this setting should be an empty string.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonSimplygonBatchPathEx(dynamic jsonData) : base("SimplygonBatchPath")
            {
                Type = "string";
                HelpText = "The path for the batch tool used when executing pipelines in a new/distributed process. This should be the path to the directory where the SimplygonBatch executable is located. If the tool is in the system path this setting should be an empty string.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSimplygonBatchPathEx DeepCopy()
            {
                return (SimplygonSimplygonBatchPathEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.SimplygonBatchPath;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public string OutputMaterialName { get { return _OutputMaterialName; } set { _OutputMaterialName = value; OnPropertyChanged(); } }
        private string _OutputMaterialName;
        public SimplygonOutputMaterialNameEx OutputMaterialNameUI { get; set; }
        public class SimplygonOutputMaterialNameEx : SimplygonSettingsProperty
        {
            public SimplygonPipelineSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OutputMaterialName;
                }

                set
                {
                    bool needReload = Parent.OutputMaterialName != value;
                    Parent.OutputMaterialName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOutputMaterialNameEx() : base("OutputMaterialName")
            {
                Type = "string";
                HelpText = "The name of the output material. If the output material count is greater than one, an index separated with an underscore will be appended to the material names, such that MyMaterial becomes MyMaterial_0, MyMaterial_1 and so on.";
                TypeOverride = "";
                DefaultValue = "SimplygonCastMaterial";
                Visible = true;
            }

            public SimplygonOutputMaterialNameEx(dynamic jsonData) : base("OutputMaterialName")
            {
                Type = "string";
                HelpText = "The name of the output material. If the output material count is greater than one, an index separated with an underscore will be appended to the material names, such that MyMaterial becomes MyMaterial_0, MyMaterial_1 and so on.";
                TypeOverride = "";
                DefaultValue = "SimplygonCastMaterial";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputMaterialNameEx DeepCopy()
            {
                return (SimplygonOutputMaterialNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OutputMaterialName;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool OutputUniqueMaterialNames { get { return _OutputUniqueMaterialNames; } set { _OutputUniqueMaterialNames = value; OnPropertyChanged(); } }
        private bool _OutputUniqueMaterialNames;
        public SimplygonOutputUniqueMaterialNamesEx OutputUniqueMaterialNamesUI { get; set; }
        public class SimplygonOutputUniqueMaterialNamesEx : SimplygonSettingsProperty
        {
            public SimplygonPipelineSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.OutputUniqueMaterialNames;
                }

                set
                {
                    bool needReload = Parent.OutputUniqueMaterialNames != value;
                    Parent.OutputUniqueMaterialNames = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonOutputUniqueMaterialNamesEx() : base("OutputUniqueMaterialNames")
            {
                Type = "bool";
                HelpText = "Generate unique material names if set to true, by replacing the default scheme of appending a sequential material index to the name with appending a GUID. This will make the material names unique each time the pipeline is run, even on the same input scene.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonOutputUniqueMaterialNamesEx(dynamic jsonData) : base("OutputUniqueMaterialNames")
            {
                Type = "bool";
                HelpText = "Generate unique material names if set to true, by replacing the default scheme of appending a sequential material index to the name with appending a GUID. This will make the material names unique each time the pipeline is run, even on the same input scene.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputUniqueMaterialNamesEx DeepCopy()
            {
                return (SimplygonOutputUniqueMaterialNamesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.OutputUniqueMaterialNames;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool EmbedReferences { get { return _EmbedReferences; } set { _EmbedReferences = value; OnPropertyChanged(); } }
        private bool _EmbedReferences;
        public SimplygonEmbedReferencesEx EmbedReferencesUI { get; set; }
        public class SimplygonEmbedReferencesEx : SimplygonSettingsProperty
        {
            public SimplygonPipelineSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.EmbedReferences;
                }

                set
                {
                    bool needReload = Parent.EmbedReferences != value;
                    Parent.EmbedReferences = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonEmbedReferencesEx() : base("EmbedReferences")
            {
                Type = "bool";
                HelpText = "Set flag to control if output file formats that support embedding referenced resources (like textures) should do so.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonEmbedReferencesEx(dynamic jsonData) : base("EmbedReferences")
            {
                Type = "bool";
                HelpText = "Set flag to control if output file formats that support embedding referenced resources (like textures) should do so.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonEmbedReferencesEx DeepCopy()
            {
                return (SimplygonEmbedReferencesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.EmbedReferences;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool IntermediateStep { get { return _IntermediateStep; } set { _IntermediateStep = value; OnPropertyChanged(); } }
        private bool _IntermediateStep;
        public SimplygonIntermediateStepEx IntermediateStepUI { get; set; }
        public class SimplygonIntermediateStepEx : SimplygonSettingsProperty
        {
            public SimplygonPipelineSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.IntermediateStep;
                }

                set
                {
                    bool needReload = Parent.IntermediateStep != value;
                    Parent.IntermediateStep = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonIntermediateStepEx() : base("IntermediateStep")
            {
                Type = "bool";
                HelpText = "Set flag to control if this pipeline step is an intermediate step where the processed scene is only used as input to the next cascaded pipeline and not for export or further access. This will discard any processed data once all cascaded pipelines are done, and the scene will be ignored during export. Useful if you want to group two pipelines together for one output, for example an aggregation and a reduction pipeline where you only want the output from the combined aggregation + reduction.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonIntermediateStepEx(dynamic jsonData) : base("IntermediateStep")
            {
                Type = "bool";
                HelpText = "Set flag to control if this pipeline step is an intermediate step where the processed scene is only used as input to the next cascaded pipeline and not for export or further access. This will discard any processed data once all cascaded pipelines are done, and the scene will be ignored during export. Useful if you want to group two pipelines together for one output, for example an aggregation and a reduction pipeline where you only want the output from the combined aggregation + reduction.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonIntermediateStepEx DeepCopy()
            {
                return (SimplygonIntermediateStepEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.IntermediateStep;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EPipelineRunMode CascadedRunMode { get { return _CascadedRunMode; } set { _CascadedRunMode = value; OnPropertyChanged(); } }
        private EPipelineRunMode _CascadedRunMode;
        public SimplygonCascadedRunModeEx CascadedRunModeUI { get; set; }
        public class SimplygonCascadedRunModeEx : SimplygonSettingsProperty
        {
            public SimplygonPipelineSettings Parent { get; set; }
            public EPipelineRunMode Value
            {
                get
                {
                    return Parent.CascadedRunMode;
                }

                set
                {
                    bool needReload = Parent.CascadedRunMode != value;
                    Parent.CascadedRunMode = value;
                    OnPropertyChanged();
                }

            }

            public EPipelineRunMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPipelineRunMode)); } }

            public SimplygonCascadedRunModeEx() : base("CascadedRunMode")
            {
                Type = "enum";
                HelpText = "Set run mode to use for cascaded child pipelines.";
                TypeOverride = "";
                DefaultValue = EPipelineRunMode.RunInThisProcess;
                Visible = true;
            }

            public SimplygonCascadedRunModeEx(dynamic jsonData) : base("CascadedRunMode")
            {
                Type = "enum";
                HelpText = "Set run mode to use for cascaded child pipelines.";
                TypeOverride = "";
                DefaultValue = EPipelineRunMode.RunInThisProcess;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonCascadedRunModeEx DeepCopy()
            {
                return (SimplygonCascadedRunModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.CascadedRunMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPipelineRunMode)value;
            }

        }


        public SimplygonPipelineSettings() : base("PipelineSettings")
        {
            Visible = true;
            TextureOutputPathUI = new SimplygonTextureOutputPathEx();
            TextureOutputPathUI.Parent = this;
            TextureOutputPath = TextureOutputPathUI.DefaultValue;
            Items.Add(TextureOutputPathUI);
            SimplygonBatchPathUI = new SimplygonSimplygonBatchPathEx();
            SimplygonBatchPathUI.Parent = this;
            SimplygonBatchPath = SimplygonBatchPathUI.DefaultValue;
            Items.Add(SimplygonBatchPathUI);
            OutputMaterialNameUI = new SimplygonOutputMaterialNameEx();
            OutputMaterialNameUI.Parent = this;
            OutputMaterialName = OutputMaterialNameUI.DefaultValue;
            Items.Add(OutputMaterialNameUI);
            OutputUniqueMaterialNamesUI = new SimplygonOutputUniqueMaterialNamesEx();
            OutputUniqueMaterialNamesUI.Parent = this;
            OutputUniqueMaterialNames = OutputUniqueMaterialNamesUI.DefaultValue;
            Items.Add(OutputUniqueMaterialNamesUI);
            EmbedReferencesUI = new SimplygonEmbedReferencesEx();
            EmbedReferencesUI.Parent = this;
            EmbedReferences = EmbedReferencesUI.DefaultValue;
            Items.Add(EmbedReferencesUI);
            IntermediateStepUI = new SimplygonIntermediateStepEx();
            IntermediateStepUI.Parent = this;
            IntermediateStep = IntermediateStepUI.DefaultValue;
            Items.Add(IntermediateStepUI);
            CascadedRunModeUI = new SimplygonCascadedRunModeEx();
            CascadedRunModeUI.Parent = this;
            CascadedRunMode = CascadedRunModeUI.DefaultValue;
            Items.Add(CascadedRunModeUI);
        }

        public SimplygonPipelineSettings(dynamic jsonData) : base("PipelineSettings")
        {
            Visible = true;
            TextureOutputPathUI = new SimplygonTextureOutputPathEx(jsonData != null && ((JObject)jsonData).GetValue("TextureOutputPathUI") != null ? jsonData.TextureOutputPathUI : null);
            TextureOutputPathUI.Parent = this;
            TextureOutputPath = TextureOutputPathUI.DefaultValue;
            Items.Add(TextureOutputPathUI);
            SimplygonBatchPathUI = new SimplygonSimplygonBatchPathEx(jsonData != null && ((JObject)jsonData).GetValue("SimplygonBatchPathUI") != null ? jsonData.SimplygonBatchPathUI : null);
            SimplygonBatchPathUI.Parent = this;
            SimplygonBatchPath = SimplygonBatchPathUI.DefaultValue;
            Items.Add(SimplygonBatchPathUI);
            OutputMaterialNameUI = new SimplygonOutputMaterialNameEx(jsonData != null && ((JObject)jsonData).GetValue("OutputMaterialNameUI") != null ? jsonData.OutputMaterialNameUI : null);
            OutputMaterialNameUI.Parent = this;
            OutputMaterialName = OutputMaterialNameUI.DefaultValue;
            Items.Add(OutputMaterialNameUI);
            OutputUniqueMaterialNamesUI = new SimplygonOutputUniqueMaterialNamesEx(jsonData != null && ((JObject)jsonData).GetValue("OutputUniqueMaterialNamesUI") != null ? jsonData.OutputUniqueMaterialNamesUI : null);
            OutputUniqueMaterialNamesUI.Parent = this;
            OutputUniqueMaterialNames = OutputUniqueMaterialNamesUI.DefaultValue;
            Items.Add(OutputUniqueMaterialNamesUI);
            EmbedReferencesUI = new SimplygonEmbedReferencesEx(jsonData != null && ((JObject)jsonData).GetValue("EmbedReferencesUI") != null ? jsonData.EmbedReferencesUI : null);
            EmbedReferencesUI.Parent = this;
            EmbedReferences = EmbedReferencesUI.DefaultValue;
            Items.Add(EmbedReferencesUI);
            IntermediateStepUI = new SimplygonIntermediateStepEx(jsonData != null && ((JObject)jsonData).GetValue("IntermediateStepUI") != null ? jsonData.IntermediateStepUI : null);
            IntermediateStepUI.Parent = this;
            IntermediateStep = IntermediateStepUI.DefaultValue;
            Items.Add(IntermediateStepUI);
            CascadedRunModeUI = new SimplygonCascadedRunModeEx(jsonData != null && ((JObject)jsonData).GetValue("CascadedRunModeUI") != null ? jsonData.CascadedRunModeUI : null);
            CascadedRunModeUI.Parent = this;
            CascadedRunMode = CascadedRunModeUI.DefaultValue;
            Items.Add(CascadedRunModeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonPipelineSettings();
            copy.Items.Clear();
            copy.TextureOutputPathUI = this.TextureOutputPathUI.DeepCopy();
            copy.TextureOutputPathUI.Parent = copy;
            copy.Items.Add(copy.TextureOutputPathUI);
            copy.SimplygonBatchPathUI = this.SimplygonBatchPathUI.DeepCopy();
            copy.SimplygonBatchPathUI.Parent = copy;
            copy.Items.Add(copy.SimplygonBatchPathUI);
            copy.OutputMaterialNameUI = this.OutputMaterialNameUI.DeepCopy();
            copy.OutputMaterialNameUI.Parent = copy;
            copy.Items.Add(copy.OutputMaterialNameUI);
            copy.OutputUniqueMaterialNamesUI = this.OutputUniqueMaterialNamesUI.DeepCopy();
            copy.OutputUniqueMaterialNamesUI.Parent = copy;
            copy.Items.Add(copy.OutputUniqueMaterialNamesUI);
            copy.EmbedReferencesUI = this.EmbedReferencesUI.DeepCopy();
            copy.EmbedReferencesUI.Parent = copy;
            copy.Items.Add(copy.EmbedReferencesUI);
            copy.IntermediateStepUI = this.IntermediateStepUI.DeepCopy();
            copy.IntermediateStepUI.Parent = copy;
            copy.Items.Add(copy.IntermediateStepUI);
            copy.CascadedRunModeUI = this.CascadedRunModeUI.DeepCopy();
            copy.CascadedRunModeUI.Parent = copy;
            copy.Items.Add(copy.CascadedRunModeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.TextureOutputPath = TextureOutputPath;
            if(serializeUIComponents)
            {
                jsonData.TextureOutputPathUI = TextureOutputPathUI.SaveJson();
            }

            jsonData.SimplygonBatchPath = SimplygonBatchPath;
            if(serializeUIComponents)
            {
                jsonData.SimplygonBatchPathUI = SimplygonBatchPathUI.SaveJson();
            }

            jsonData.OutputMaterialName = OutputMaterialName;
            if(serializeUIComponents)
            {
                jsonData.OutputMaterialNameUI = OutputMaterialNameUI.SaveJson();
            }

            jsonData.OutputUniqueMaterialNames = OutputUniqueMaterialNames;
            if(serializeUIComponents)
            {
                jsonData.OutputUniqueMaterialNamesUI = OutputUniqueMaterialNamesUI.SaveJson();
            }

            jsonData.EmbedReferences = EmbedReferences;
            if(serializeUIComponents)
            {
                jsonData.EmbedReferencesUI = EmbedReferencesUI.SaveJson();
            }

            jsonData.IntermediateStep = IntermediateStep;
            if(serializeUIComponents)
            {
                jsonData.IntermediateStepUI = IntermediateStepUI.SaveJson();
            }

            jsonData.CascadedRunMode = (int)CascadedRunMode;
            if(serializeUIComponents)
            {
                jsonData.CascadedRunModeUI = CascadedRunModeUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("TextureOutputPath") != null)
            {
                TextureOutputPath = (string)jsonData.TextureOutputPath;
            }

            if(jsonData.GetValue("SimplygonBatchPath") != null)
            {
                SimplygonBatchPath = (string)jsonData.SimplygonBatchPath;
            }

            if(jsonData.GetValue("OutputMaterialName") != null)
            {
                OutputMaterialName = (string)jsonData.OutputMaterialName;
            }

            if(jsonData.GetValue("OutputUniqueMaterialNames") != null)
            {
                OutputUniqueMaterialNames = (bool)jsonData.OutputUniqueMaterialNames;
            }

            if(jsonData.GetValue("EmbedReferences") != null)
            {
                EmbedReferences = (bool)jsonData.EmbedReferences;
            }

            if(jsonData.GetValue("IntermediateStep") != null)
            {
                IntermediateStep = (bool)jsonData.IntermediateStep;
            }

            if(jsonData.GetValue("CascadedRunMode") != null)
            {
                CascadedRunMode = (EPipelineRunMode)jsonData.CascadedRunMode;
            }

        }

        public override void Reset()
        {
            TextureOutputPathUI.Reset();
            SimplygonBatchPathUI.Reset();
            OutputMaterialNameUI.Reset();
            OutputUniqueMaterialNamesUI.Reset();
            EmbedReferencesUI.Reset();
            IntermediateStepUI.Reset();
            CascadedRunModeUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            TextureOutputPathUI.IsEditEnabled = isEditEnabled;
            SimplygonBatchPathUI.IsEditEnabled = isEditEnabled;
            OutputMaterialNameUI.IsEditEnabled = isEditEnabled;
            OutputUniqueMaterialNamesUI.IsEditEnabled = isEditEnabled;
            EmbedReferencesUI.IsEditEnabled = isEditEnabled;
            IntermediateStepUI.IsEditEnabled = isEditEnabled;
            CascadedRunModeUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            TextureOutputPathUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SimplygonBatchPathUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputMaterialNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputUniqueMaterialNamesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            EmbedReferencesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            IntermediateStepUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            CascadedRunModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonMappingImageInputMaterialSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialMappingUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonMappingImageSettings Parent { get; set; }
        public int MaterialMapping { get { return _MaterialMapping; } set { _MaterialMapping = value; OnPropertyChanged(); } }
        private int _MaterialMapping;
        public SimplygonMaterialMappingEx MaterialMappingUI { get; set; }
        public class SimplygonMaterialMappingEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageInputMaterialSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.MaterialMapping;
                }

                set
                {
                    bool needReload = Parent.MaterialMapping != value;
                    Parent.MaterialMapping = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonMaterialMappingEx() : base("MaterialMapping")
            {
                Type = "int";
                HelpText = "The material mapping for the input material this setting object corresponds to, meaning what material of the generated LOD the corresponding input material will be baked into. Both InputMaterialCount and OutputMaterialCount need to be set for this mapping to work, and all original materials need to be mapped to an existing output id.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                MaxValue = 10;
                DefaultMinValue = -1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonMaterialMappingEx(dynamic jsonData) : base("MaterialMapping")
            {
                Type = "int";
                HelpText = "The material mapping for the input material this setting object corresponds to, meaning what material of the generated LOD the corresponding input material will be baked into. Both InputMaterialCount and OutputMaterialCount need to be set for this mapping to work, and all original materials need to be mapped to an existing output id.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                DefaultMinValue = -1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaterialMapping: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaterialMapping: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialMappingEx DeepCopy()
            {
                return (SimplygonMaterialMappingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.MaterialMapping;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonMappingImageInputMaterialSettings(SimplygonMappingImageSettings parent) : base("InputMaterialSettings")
        {
            Parent = parent;
            Visible = true;
            MaterialMappingUI = new SimplygonMaterialMappingEx();
            MaterialMappingUI.Parent = this;
            MaterialMapping = MaterialMappingUI.DefaultValue;
            Items.Add(MaterialMappingUI);
        }

        public SimplygonMappingImageInputMaterialSettings(SimplygonMappingImageSettings parent, dynamic jsonData) : base("InputMaterialSettings")
        {
            Parent = parent;
            Visible = true;
            MaterialMappingUI = new SimplygonMaterialMappingEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialMappingUI") != null ? jsonData.MaterialMappingUI : null);
            MaterialMappingUI.Parent = this;
            MaterialMapping = MaterialMappingUI.DefaultValue;
            Items.Add(MaterialMappingUI);
            LoadJson(jsonData);
        }

        public SimplygonSettings DeepCopy(SimplygonMappingImageSettings parent)
        {
            var copy = new SimplygonMappingImageInputMaterialSettings(parent);
            copy.Items.Clear();
            copy.MaterialMappingUI = this.MaterialMappingUI.DeepCopy();
            copy.MaterialMappingUI.Parent = copy;
            copy.Items.Add(copy.MaterialMappingUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialMapping = MaterialMapping;
            if(serializeUIComponents)
            {
                jsonData.MaterialMappingUI = MaterialMappingUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialMapping") != null)
            {
                var newMaterialMapping = (int)jsonData.MaterialMapping;
                if (newMaterialMapping >= MaterialMappingUI.DefaultMinValue && newMaterialMapping <= MaterialMappingUI.DefaultMaxValue)
                {
                    MaterialMapping = newMaterialMapping;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MaterialMapping: Invalid value {newMaterialMapping}, using default value {MaterialMapping.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            MaterialMappingUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialMappingUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialMappingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonMappingImageOutputMaterialSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(TextureWidthUI.Visible) return true;
                if(TextureHeightUI.Visible) return true;
                if(MultisamplingLevelUI.Visible) return true;
                if(GutterSpaceUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonMappingImageSettings Parent { get; set; }
        public int TextureWidth { get { return _TextureWidth; } set { _TextureWidth = value; OnPropertyChanged(); } }
        private int _TextureWidth;
        public SimplygonTextureWidthEx TextureWidthUI { get; set; }
        public class SimplygonTextureWidthEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageOutputMaterialSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.TextureWidth;
                }

                set
                {
                    bool needReload = Parent.TextureWidth != value;
                    Parent.TextureWidth = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonTextureWidthEx() : base("TextureWidth")
            {
                Type = "uint";
                HelpText = "The width of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 1024;
                MinValue = 0;
                MaxValue = 8192;
                DefaultMinValue = 0;
                DefaultMaxValue = 8192;
                TicksFrequencyValue = 256;
                Visible = true;
            }

            public SimplygonTextureWidthEx(dynamic jsonData) : base("TextureWidth")
            {
                Type = "uint";
                HelpText = "The width of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 1024;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureWidth: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 8192;
                DefaultMaxValue = 8192;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureWidth: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 256;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTextureWidthEx DeepCopy()
            {
                return (SimplygonTextureWidthEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.TextureWidth;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int TextureHeight { get { return _TextureHeight; } set { _TextureHeight = value; OnPropertyChanged(); } }
        private int _TextureHeight;
        public SimplygonTextureHeightEx TextureHeightUI { get; set; }
        public class SimplygonTextureHeightEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageOutputMaterialSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.TextureHeight;
                }

                set
                {
                    bool needReload = Parent.TextureHeight != value;
                    Parent.TextureHeight = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonTextureHeightEx() : base("TextureHeight")
            {
                Type = "uint";
                HelpText = "The height of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 1024;
                MinValue = 0;
                MaxValue = 8192;
                DefaultMinValue = 0;
                DefaultMaxValue = 8192;
                TicksFrequencyValue = 256;
                Visible = true;
            }

            public SimplygonTextureHeightEx(dynamic jsonData) : base("TextureHeight")
            {
                Type = "uint";
                HelpText = "The height of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 1024;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureHeight: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 8192;
                DefaultMaxValue = 8192;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureHeight: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 256;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTextureHeightEx DeepCopy()
            {
                return (SimplygonTextureHeightEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.TextureHeight;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int MultisamplingLevel { get { return _MultisamplingLevel; } set { _MultisamplingLevel = value; OnPropertyChanged(); } }
        private int _MultisamplingLevel;
        public SimplygonMultisamplingLevelEx MultisamplingLevelUI { get; set; }
        public class SimplygonMultisamplingLevelEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageOutputMaterialSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.MultisamplingLevel;
                }

                set
                {
                    bool needReload = Parent.MultisamplingLevel != value;
                    Parent.MultisamplingLevel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonMultisamplingLevelEx() : base("MultisamplingLevel")
            {
                Type = "uint";
                HelpText = "The multi-sampling level of the output mapping image. Values 1-8 are accepted.";
                TypeOverride = "";
                DefaultValue = 2;
                MinValue = 1;
                MaxValue = 8;
                DefaultMinValue = 1;
                DefaultMaxValue = 8;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonMultisamplingLevelEx(dynamic jsonData) : base("MultisamplingLevel")
            {
                Type = "uint";
                HelpText = "The multi-sampling level of the output mapping image. Values 1-8 are accepted.";
                TypeOverride = "";
                DefaultValue = 2;
                MinValue = 1;
                DefaultMinValue = 1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MultisamplingLevel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 8;
                DefaultMaxValue = 8;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MultisamplingLevel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMultisamplingLevelEx DeepCopy()
            {
                return (SimplygonMultisamplingLevelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.MultisamplingLevel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int GutterSpace { get { return _GutterSpace; } set { _GutterSpace = value; OnPropertyChanged(); } }
        private int _GutterSpace;
        public SimplygonGutterSpaceEx GutterSpaceUI { get; set; }
        public class SimplygonGutterSpaceEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageOutputMaterialSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.GutterSpace;
                }

                set
                {
                    bool needReload = Parent.GutterSpace != value;
                    Parent.GutterSpace = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonGutterSpaceEx() : base("GutterSpace")
            {
                Type = "uint";
                HelpText = "The minimum number of pixels between charts of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 4;
                MinValue = 1;
                MaxValue = 10;
                DefaultMinValue = 1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonGutterSpaceEx(dynamic jsonData) : base("GutterSpace")
            {
                Type = "uint";
                HelpText = "The minimum number of pixels between charts of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 4;
                MinValue = 1;
                DefaultMinValue = 1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GutterSpace: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GutterSpace: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGutterSpaceEx DeepCopy()
            {
                return (SimplygonGutterSpaceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.GutterSpace;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonMappingImageOutputMaterialSettings(SimplygonMappingImageSettings parent) : base("OutputMaterialSettings")
        {
            Parent = parent;
            Visible = true;
            TextureWidthUI = new SimplygonTextureWidthEx();
            TextureWidthUI.Parent = this;
            TextureWidth = TextureWidthUI.DefaultValue;
            Items.Add(TextureWidthUI);
            TextureHeightUI = new SimplygonTextureHeightEx();
            TextureHeightUI.Parent = this;
            TextureHeight = TextureHeightUI.DefaultValue;
            Items.Add(TextureHeightUI);
            MultisamplingLevelUI = new SimplygonMultisamplingLevelEx();
            MultisamplingLevelUI.Parent = this;
            MultisamplingLevel = MultisamplingLevelUI.DefaultValue;
            Items.Add(MultisamplingLevelUI);
            GutterSpaceUI = new SimplygonGutterSpaceEx();
            GutterSpaceUI.Parent = this;
            GutterSpace = GutterSpaceUI.DefaultValue;
            Items.Add(GutterSpaceUI);
        }

        public SimplygonMappingImageOutputMaterialSettings(SimplygonMappingImageSettings parent, dynamic jsonData) : base("OutputMaterialSettings")
        {
            Parent = parent;
            Visible = true;
            TextureWidthUI = new SimplygonTextureWidthEx(jsonData != null && ((JObject)jsonData).GetValue("TextureWidthUI") != null ? jsonData.TextureWidthUI : null);
            TextureWidthUI.Parent = this;
            TextureWidth = TextureWidthUI.DefaultValue;
            Items.Add(TextureWidthUI);
            TextureHeightUI = new SimplygonTextureHeightEx(jsonData != null && ((JObject)jsonData).GetValue("TextureHeightUI") != null ? jsonData.TextureHeightUI : null);
            TextureHeightUI.Parent = this;
            TextureHeight = TextureHeightUI.DefaultValue;
            Items.Add(TextureHeightUI);
            MultisamplingLevelUI = new SimplygonMultisamplingLevelEx(jsonData != null && ((JObject)jsonData).GetValue("MultisamplingLevelUI") != null ? jsonData.MultisamplingLevelUI : null);
            MultisamplingLevelUI.Parent = this;
            MultisamplingLevel = MultisamplingLevelUI.DefaultValue;
            Items.Add(MultisamplingLevelUI);
            GutterSpaceUI = new SimplygonGutterSpaceEx(jsonData != null && ((JObject)jsonData).GetValue("GutterSpaceUI") != null ? jsonData.GutterSpaceUI : null);
            GutterSpaceUI.Parent = this;
            GutterSpace = GutterSpaceUI.DefaultValue;
            Items.Add(GutterSpaceUI);
            LoadJson(jsonData);
        }

        public SimplygonSettings DeepCopy(SimplygonMappingImageSettings parent)
        {
            var copy = new SimplygonMappingImageOutputMaterialSettings(parent);
            copy.Items.Clear();
            copy.TextureWidthUI = this.TextureWidthUI.DeepCopy();
            copy.TextureWidthUI.Parent = copy;
            copy.Items.Add(copy.TextureWidthUI);
            copy.TextureHeightUI = this.TextureHeightUI.DeepCopy();
            copy.TextureHeightUI.Parent = copy;
            copy.Items.Add(copy.TextureHeightUI);
            copy.MultisamplingLevelUI = this.MultisamplingLevelUI.DeepCopy();
            copy.MultisamplingLevelUI.Parent = copy;
            copy.Items.Add(copy.MultisamplingLevelUI);
            copy.GutterSpaceUI = this.GutterSpaceUI.DeepCopy();
            copy.GutterSpaceUI.Parent = copy;
            copy.Items.Add(copy.GutterSpaceUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.TextureWidth = TextureWidth;
            if(serializeUIComponents)
            {
                jsonData.TextureWidthUI = TextureWidthUI.SaveJson();
            }

            jsonData.TextureHeight = TextureHeight;
            if(serializeUIComponents)
            {
                jsonData.TextureHeightUI = TextureHeightUI.SaveJson();
            }

            jsonData.MultisamplingLevel = MultisamplingLevel;
            if(serializeUIComponents)
            {
                jsonData.MultisamplingLevelUI = MultisamplingLevelUI.SaveJson();
            }

            jsonData.GutterSpace = GutterSpace;
            if(serializeUIComponents)
            {
                jsonData.GutterSpaceUI = GutterSpaceUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("TextureWidth") != null)
            {
                var newTextureWidth = (int)jsonData.TextureWidth;
                if (newTextureWidth >= TextureWidthUI.DefaultMinValue && newTextureWidth <= TextureWidthUI.DefaultMaxValue)
                {
                    TextureWidth = newTextureWidth;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TextureWidth: Invalid value {newTextureWidth}, using default value {TextureWidth.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("TextureHeight") != null)
            {
                var newTextureHeight = (int)jsonData.TextureHeight;
                if (newTextureHeight >= TextureHeightUI.DefaultMinValue && newTextureHeight <= TextureHeightUI.DefaultMaxValue)
                {
                    TextureHeight = newTextureHeight;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TextureHeight: Invalid value {newTextureHeight}, using default value {TextureHeight.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MultisamplingLevel") != null)
            {
                var newMultisamplingLevel = (int)jsonData.MultisamplingLevel;
                if (newMultisamplingLevel >= MultisamplingLevelUI.DefaultMinValue && newMultisamplingLevel <= MultisamplingLevelUI.DefaultMaxValue)
                {
                    MultisamplingLevel = newMultisamplingLevel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MultisamplingLevel: Invalid value {newMultisamplingLevel}, using default value {MultisamplingLevel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("GutterSpace") != null)
            {
                var newGutterSpace = (int)jsonData.GutterSpace;
                if (newGutterSpace >= GutterSpaceUI.DefaultMinValue && newGutterSpace <= GutterSpaceUI.DefaultMaxValue)
                {
                    GutterSpace = newGutterSpace;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"GutterSpace: Invalid value {newGutterSpace}, using default value {GutterSpace.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            TextureWidthUI.Reset();
            TextureHeightUI.Reset();
            MultisamplingLevelUI.Reset();
            GutterSpaceUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            TextureWidthUI.IsEditEnabled = isEditEnabled;
            TextureHeightUI.IsEditEnabled = isEditEnabled;
            MultisamplingLevelUI.IsEditEnabled = isEditEnabled;
            GutterSpaceUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            TextureWidthUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TextureHeightUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MultisamplingLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GutterSpaceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonChartAggregatorSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if( Parent.TexCoordGeneratorTypeUI != null )
                {
                    return Parent.TexCoordGeneratorType == ETexcoordGeneratorType.ChartAggregator && Parent.TexCoordGeneratorTypeUI.Visible;
                }

                else
                {
                    return visible;
                }

            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonMappingImageSettings Parent { get; set; }
        public EChartAggregatorMode ChartAggregatorMode { get { return _ChartAggregatorMode; } set { _ChartAggregatorMode = value; OnPropertyChanged(); } }
        private EChartAggregatorMode _ChartAggregatorMode;
        public SimplygonChartAggregatorModeEx ChartAggregatorModeUI { get; set; }
        public class SimplygonChartAggregatorModeEx : SimplygonSettingsProperty
        {
            public SimplygonChartAggregatorSettings Parent { get; set; }
            public EChartAggregatorMode Value
            {
                get
                {
                    return Parent.ChartAggregatorMode;
                }

                set
                {
                    bool needReload = Parent.ChartAggregatorMode != value;
                    Parent.ChartAggregatorMode = value;
                    OnPropertyChanged();
                }

            }

            public EChartAggregatorMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EChartAggregatorMode)); } }

            public SimplygonChartAggregatorModeEx() : base("ChartAggregatorMode")
            {
                Type = "enum";
                HelpText = "Determines which method to use when aggregating the UVs. TextureSizeProportions - Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps. SurfaceArea - Aggregated UV charts will have their size set based on its actual geometrical size. OriginalPixelDensity - The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size. UVSizeProportions - Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in.";
                TypeOverride = "";
                DefaultValue = EChartAggregatorMode.TextureSizeProportions;
                Visible = true;
            }

            public SimplygonChartAggregatorModeEx(dynamic jsonData) : base("ChartAggregatorMode")
            {
                Type = "enum";
                HelpText = "Determines which method to use when aggregating the UVs. TextureSizeProportions - Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps. SurfaceArea - Aggregated UV charts will have their size set based on its actual geometrical size. OriginalPixelDensity - The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size. UVSizeProportions - Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in.";
                TypeOverride = "";
                DefaultValue = EChartAggregatorMode.TextureSizeProportions;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonChartAggregatorModeEx DeepCopy()
            {
                return (SimplygonChartAggregatorModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.ChartAggregatorMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EChartAggregatorMode)value;
            }

        }

        public ESurfaceAreaScale SurfaceAreaScale { get { return _SurfaceAreaScale; } set { _SurfaceAreaScale = value; OnPropertyChanged(); } }
        private ESurfaceAreaScale _SurfaceAreaScale;
        public SimplygonSurfaceAreaScaleEx SurfaceAreaScaleUI { get; set; }
        public class SimplygonSurfaceAreaScaleEx : SimplygonSettingsProperty
        {
            public SimplygonChartAggregatorSettings Parent { get; set; }
            public ESurfaceAreaScale Value
            {
                get
                {
                    return Parent.SurfaceAreaScale;
                }

                set
                {
                    bool needReload = Parent.SurfaceAreaScale != value;
                    Parent.SurfaceAreaScale = value;
                    OnPropertyChanged();
                }

            }

            public ESurfaceAreaScale DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(ESurfaceAreaScale)); } }

            public SimplygonSurfaceAreaScaleEx() : base("SurfaceAreaScale")
            {
                Type = "enum";
                HelpText = "If multiple UV charts overlap and have the same material, SurfaceAreaScale specifies which of those instances determines the the output scale. It is only valid when the ChartAggregatorMode is SurfaceArea and SeparateOverlappingCharts is false.";
                TypeOverride = "";
                DefaultValue = ESurfaceAreaScale.LargestInstance;
                Visible = true;
            }

            public SimplygonSurfaceAreaScaleEx(dynamic jsonData) : base("SurfaceAreaScale")
            {
                Type = "enum";
                HelpText = "If multiple UV charts overlap and have the same material, SurfaceAreaScale specifies which of those instances determines the the output scale. It is only valid when the ChartAggregatorMode is SurfaceArea and SeparateOverlappingCharts is false.";
                TypeOverride = "";
                DefaultValue = ESurfaceAreaScale.LargestInstance;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSurfaceAreaScaleEx DeepCopy()
            {
                return (SimplygonSurfaceAreaScaleEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.SurfaceAreaScale;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (ESurfaceAreaScale)value;
            }

        }

        public int OriginalTexCoordLevel { get { return _OriginalTexCoordLevel; } set { _OriginalTexCoordLevel = value; OnPropertyChanged(); } }
        private int _OriginalTexCoordLevel;
        public SimplygonOriginalTexCoordLevelEx OriginalTexCoordLevelUI { get; set; }
        public class SimplygonOriginalTexCoordLevelEx : SimplygonSettingsProperty
        {
            public SimplygonChartAggregatorSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.OriginalTexCoordLevel;
                }

                set
                {
                    bool needReload = Parent.OriginalTexCoordLevel != value;
                    Parent.OriginalTexCoordLevel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonOriginalTexCoordLevelEx() : base("OriginalTexCoordLevel")
            {
                Type = "rid";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. Set the texture coordinate level to get charts from. If the ChartAggregatorOriginalTexCoordName ha been set, the ChartAggregatorOriginalTexCoordLevel is not used.";
                TypeOverride = "";
                DefaultValue = 0;
                MinValue = -1;
                MaxValue = 10;
                DefaultMinValue = -1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonOriginalTexCoordLevelEx(dynamic jsonData) : base("OriginalTexCoordLevel")
            {
                Type = "rid";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. Set the texture coordinate level to get charts from. If the ChartAggregatorOriginalTexCoordName ha been set, the ChartAggregatorOriginalTexCoordLevel is not used.";
                TypeOverride = "";
                DefaultValue = 0;
                MinValue = -1;
                DefaultMinValue = -1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OriginalTexCoordLevel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OriginalTexCoordLevel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOriginalTexCoordLevelEx DeepCopy()
            {
                return (SimplygonOriginalTexCoordLevelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.OriginalTexCoordLevel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public string OriginalTexCoordName { get { return _OriginalTexCoordName; } set { _OriginalTexCoordName = value; OnPropertyChanged(); } }
        private string _OriginalTexCoordName;
        public SimplygonOriginalTexCoordNameEx OriginalTexCoordNameUI { get; set; }
        public class SimplygonOriginalTexCoordNameEx : SimplygonSettingsProperty
        {
            public SimplygonChartAggregatorSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OriginalTexCoordName;
                }

                set
                {
                    bool needReload = Parent.OriginalTexCoordName != value;
                    Parent.OriginalTexCoordName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOriginalTexCoordNameEx() : base("OriginalTexCoordName")
            {
                Type = "string";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. Set the name of the texture coordinate level to get charts from. If not set, it will use the ChartAggregatorOriginalTexCoordLevel (index) instead.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonOriginalTexCoordNameEx(dynamic jsonData) : base("OriginalTexCoordName")
            {
                Type = "string";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. Set the name of the texture coordinate level to get charts from. If not set, it will use the ChartAggregatorOriginalTexCoordLevel (index) instead.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOriginalTexCoordNameEx DeepCopy()
            {
                return (SimplygonOriginalTexCoordNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OriginalTexCoordName;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool SeparateOverlappingCharts { get { return _SeparateOverlappingCharts; } set { _SeparateOverlappingCharts = value; OnPropertyChanged(); } }
        private bool _SeparateOverlappingCharts;
        public SimplygonSeparateOverlappingChartsEx SeparateOverlappingChartsUI { get; set; }
        public class SimplygonSeparateOverlappingChartsEx : SimplygonSettingsProperty
        {
            public SimplygonChartAggregatorSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.SeparateOverlappingCharts;
                }

                set
                {
                    bool needReload = Parent.SeparateOverlappingCharts != value;
                    Parent.SeparateOverlappingCharts = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonSeparateOverlappingChartsEx() : base("SeparateOverlappingCharts")
            {
                Type = "bool";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. If set, charts that are overlapping in the original texture coords will be separated.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonSeparateOverlappingChartsEx(dynamic jsonData) : base("SeparateOverlappingCharts")
            {
                Type = "bool";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. If set, charts that are overlapping in the original texture coords will be separated.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSeparateOverlappingChartsEx DeepCopy()
            {
                return (SimplygonSeparateOverlappingChartsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.SeparateOverlappingCharts;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public string OriginalChartProportionsChannel { get { return _OriginalChartProportionsChannel; } set { _OriginalChartProportionsChannel = value; OnPropertyChanged(); } }
        private string _OriginalChartProportionsChannel;
        public SimplygonOriginalChartProportionsChannelEx OriginalChartProportionsChannelUI { get; set; }
        public class SimplygonOriginalChartProportionsChannelEx : SimplygonSettingsProperty
        {
            public SimplygonChartAggregatorSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OriginalChartProportionsChannel;
                }

                set
                {
                    bool needReload = Parent.OriginalChartProportionsChannel != value;
                    Parent.OriginalChartProportionsChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOriginalChartProportionsChannelEx() : base("OriginalChartProportionsChannel")
            {
                Type = "string";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. Set ChartAggregatorKeepOriginalChartProportionsFromChannel to an SG_MATERIAL_CHANNEL_[...]. This channel determines which texture channel to look at when determining which chart proportions to keep.";
                TypeOverride = "";
                DefaultValue = "Diffuse";
                Visible = true;
            }

            public SimplygonOriginalChartProportionsChannelEx(dynamic jsonData) : base("OriginalChartProportionsChannel")
            {
                Type = "string";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. Set ChartAggregatorKeepOriginalChartProportionsFromChannel to an SG_MATERIAL_CHANNEL_[...]. This channel determines which texture channel to look at when determining which chart proportions to keep.";
                TypeOverride = "";
                DefaultValue = "Diffuse";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOriginalChartProportionsChannelEx DeepCopy()
            {
                return (SimplygonOriginalChartProportionsChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OriginalChartProportionsChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool LockUVRotation { get { return _LockUVRotation; } set { _LockUVRotation = value; OnPropertyChanged(); } }
        private bool _LockUVRotation;
        public SimplygonLockUVRotationEx LockUVRotationUI { get; set; }
        public class SimplygonLockUVRotationEx : SimplygonSettingsProperty
        {
            public SimplygonChartAggregatorSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.LockUVRotation;
                }

                set
                {
                    bool needReload = Parent.LockUVRotation != value;
                    Parent.LockUVRotation = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonLockUVRotationEx() : base("LockUVRotation")
            {
                Type = "bool";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. If ChartAggregatorLockUVRotation is enabled, only the original UV rotation will be used. Otherwise 4 rotations are used (90 degree rotations).";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonLockUVRotationEx(dynamic jsonData) : base("LockUVRotation")
            {
                Type = "bool";
                HelpText = "Only used when the TexCoordGeneratorType is ChartAggregator. If ChartAggregatorLockUVRotation is enabled, only the original UV rotation will be used. Otherwise 4 rotations are used (90 degree rotations).";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonLockUVRotationEx DeepCopy()
            {
                return (SimplygonLockUVRotationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.LockUVRotation;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonChartAggregatorSettings(SimplygonMappingImageSettings parent) : base("ChartAggregatorSettings")
        {
            Parent = parent;
            Visible = true;
            ChartAggregatorModeUI = new SimplygonChartAggregatorModeEx();
            ChartAggregatorModeUI.Parent = this;
            ChartAggregatorMode = ChartAggregatorModeUI.DefaultValue;
            Items.Add(ChartAggregatorModeUI);
            SurfaceAreaScaleUI = new SimplygonSurfaceAreaScaleEx();
            SurfaceAreaScaleUI.Parent = this;
            SurfaceAreaScale = SurfaceAreaScaleUI.DefaultValue;
            Items.Add(SurfaceAreaScaleUI);
            OriginalTexCoordLevelUI = new SimplygonOriginalTexCoordLevelEx();
            OriginalTexCoordLevelUI.Parent = this;
            OriginalTexCoordLevel = OriginalTexCoordLevelUI.DefaultValue;
            Items.Add(OriginalTexCoordLevelUI);
            OriginalTexCoordNameUI = new SimplygonOriginalTexCoordNameEx();
            OriginalTexCoordNameUI.Parent = this;
            OriginalTexCoordName = OriginalTexCoordNameUI.DefaultValue;
            Items.Add(OriginalTexCoordNameUI);
            SeparateOverlappingChartsUI = new SimplygonSeparateOverlappingChartsEx();
            SeparateOverlappingChartsUI.Parent = this;
            SeparateOverlappingCharts = SeparateOverlappingChartsUI.DefaultValue;
            Items.Add(SeparateOverlappingChartsUI);
            OriginalChartProportionsChannelUI = new SimplygonOriginalChartProportionsChannelEx();
            OriginalChartProportionsChannelUI.Parent = this;
            OriginalChartProportionsChannel = OriginalChartProportionsChannelUI.DefaultValue;
            Items.Add(OriginalChartProportionsChannelUI);
            LockUVRotationUI = new SimplygonLockUVRotationEx();
            LockUVRotationUI.Parent = this;
            LockUVRotation = LockUVRotationUI.DefaultValue;
            Items.Add(LockUVRotationUI);
        }

        public SimplygonChartAggregatorSettings(SimplygonMappingImageSettings parent, dynamic jsonData) : base("ChartAggregatorSettings")
        {
            Parent = parent;
            Visible = true;
            ChartAggregatorModeUI = new SimplygonChartAggregatorModeEx(jsonData != null && ((JObject)jsonData).GetValue("ChartAggregatorModeUI") != null ? jsonData.ChartAggregatorModeUI : null);
            ChartAggregatorModeUI.Parent = this;
            ChartAggregatorMode = ChartAggregatorModeUI.DefaultValue;
            Items.Add(ChartAggregatorModeUI);
            SurfaceAreaScaleUI = new SimplygonSurfaceAreaScaleEx(jsonData != null && ((JObject)jsonData).GetValue("SurfaceAreaScaleUI") != null ? jsonData.SurfaceAreaScaleUI : null);
            SurfaceAreaScaleUI.Parent = this;
            SurfaceAreaScale = SurfaceAreaScaleUI.DefaultValue;
            Items.Add(SurfaceAreaScaleUI);
            OriginalTexCoordLevelUI = new SimplygonOriginalTexCoordLevelEx(jsonData != null && ((JObject)jsonData).GetValue("OriginalTexCoordLevelUI") != null ? jsonData.OriginalTexCoordLevelUI : null);
            OriginalTexCoordLevelUI.Parent = this;
            OriginalTexCoordLevel = OriginalTexCoordLevelUI.DefaultValue;
            Items.Add(OriginalTexCoordLevelUI);
            OriginalTexCoordNameUI = new SimplygonOriginalTexCoordNameEx(jsonData != null && ((JObject)jsonData).GetValue("OriginalTexCoordNameUI") != null ? jsonData.OriginalTexCoordNameUI : null);
            OriginalTexCoordNameUI.Parent = this;
            OriginalTexCoordName = OriginalTexCoordNameUI.DefaultValue;
            Items.Add(OriginalTexCoordNameUI);
            SeparateOverlappingChartsUI = new SimplygonSeparateOverlappingChartsEx(jsonData != null && ((JObject)jsonData).GetValue("SeparateOverlappingChartsUI") != null ? jsonData.SeparateOverlappingChartsUI : null);
            SeparateOverlappingChartsUI.Parent = this;
            SeparateOverlappingCharts = SeparateOverlappingChartsUI.DefaultValue;
            Items.Add(SeparateOverlappingChartsUI);
            OriginalChartProportionsChannelUI = new SimplygonOriginalChartProportionsChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OriginalChartProportionsChannelUI") != null ? jsonData.OriginalChartProportionsChannelUI : null);
            OriginalChartProportionsChannelUI.Parent = this;
            OriginalChartProportionsChannel = OriginalChartProportionsChannelUI.DefaultValue;
            Items.Add(OriginalChartProportionsChannelUI);
            LockUVRotationUI = new SimplygonLockUVRotationEx(jsonData != null && ((JObject)jsonData).GetValue("LockUVRotationUI") != null ? jsonData.LockUVRotationUI : null);
            LockUVRotationUI.Parent = this;
            LockUVRotation = LockUVRotationUI.DefaultValue;
            Items.Add(LockUVRotationUI);
            LoadJson(jsonData);
        }

        public SimplygonSettings DeepCopy(SimplygonMappingImageSettings parent)
        {
            var copy = new SimplygonChartAggregatorSettings(parent);
            copy.Items.Clear();
            copy.ChartAggregatorModeUI = this.ChartAggregatorModeUI.DeepCopy();
            copy.ChartAggregatorModeUI.Parent = copy;
            copy.Items.Add(copy.ChartAggregatorModeUI);
            copy.SurfaceAreaScaleUI = this.SurfaceAreaScaleUI.DeepCopy();
            copy.SurfaceAreaScaleUI.Parent = copy;
            copy.Items.Add(copy.SurfaceAreaScaleUI);
            copy.OriginalTexCoordLevelUI = this.OriginalTexCoordLevelUI.DeepCopy();
            copy.OriginalTexCoordLevelUI.Parent = copy;
            copy.Items.Add(copy.OriginalTexCoordLevelUI);
            copy.OriginalTexCoordNameUI = this.OriginalTexCoordNameUI.DeepCopy();
            copy.OriginalTexCoordNameUI.Parent = copy;
            copy.Items.Add(copy.OriginalTexCoordNameUI);
            copy.SeparateOverlappingChartsUI = this.SeparateOverlappingChartsUI.DeepCopy();
            copy.SeparateOverlappingChartsUI.Parent = copy;
            copy.Items.Add(copy.SeparateOverlappingChartsUI);
            copy.OriginalChartProportionsChannelUI = this.OriginalChartProportionsChannelUI.DeepCopy();
            copy.OriginalChartProportionsChannelUI.Parent = copy;
            copy.Items.Add(copy.OriginalChartProportionsChannelUI);
            copy.LockUVRotationUI = this.LockUVRotationUI.DeepCopy();
            copy.LockUVRotationUI.Parent = copy;
            copy.Items.Add(copy.LockUVRotationUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ChartAggregatorMode = (int)ChartAggregatorMode;
            if(serializeUIComponents)
            {
                jsonData.ChartAggregatorModeUI = ChartAggregatorModeUI.SaveJson();
            }

            jsonData.SurfaceAreaScale = (int)SurfaceAreaScale;
            if(serializeUIComponents)
            {
                jsonData.SurfaceAreaScaleUI = SurfaceAreaScaleUI.SaveJson();
            }

            jsonData.OriginalTexCoordLevel = OriginalTexCoordLevel;
            if(serializeUIComponents)
            {
                jsonData.OriginalTexCoordLevelUI = OriginalTexCoordLevelUI.SaveJson();
            }

            jsonData.OriginalTexCoordName = OriginalTexCoordName;
            if(serializeUIComponents)
            {
                jsonData.OriginalTexCoordNameUI = OriginalTexCoordNameUI.SaveJson();
            }

            jsonData.SeparateOverlappingCharts = SeparateOverlappingCharts;
            if(serializeUIComponents)
            {
                jsonData.SeparateOverlappingChartsUI = SeparateOverlappingChartsUI.SaveJson();
            }

            jsonData.OriginalChartProportionsChannel = OriginalChartProportionsChannel;
            if(serializeUIComponents)
            {
                jsonData.OriginalChartProportionsChannelUI = OriginalChartProportionsChannelUI.SaveJson();
            }

            jsonData.LockUVRotation = LockUVRotation;
            if(serializeUIComponents)
            {
                jsonData.LockUVRotationUI = LockUVRotationUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("ChartAggregatorMode") != null)
            {
                ChartAggregatorMode = (EChartAggregatorMode)jsonData.ChartAggregatorMode;
            }

            if(jsonData.GetValue("SurfaceAreaScale") != null)
            {
                SurfaceAreaScale = (ESurfaceAreaScale)jsonData.SurfaceAreaScale;
            }

            if(jsonData.GetValue("OriginalTexCoordLevel") != null)
            {
                var newOriginalTexCoordLevel = (int)jsonData.OriginalTexCoordLevel;
                if (newOriginalTexCoordLevel >= OriginalTexCoordLevelUI.DefaultMinValue && newOriginalTexCoordLevel <= OriginalTexCoordLevelUI.DefaultMaxValue)
                {
                    OriginalTexCoordLevel = newOriginalTexCoordLevel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OriginalTexCoordLevel: Invalid value {newOriginalTexCoordLevel}, using default value {OriginalTexCoordLevel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OriginalTexCoordName") != null)
            {
                OriginalTexCoordName = (string)jsonData.OriginalTexCoordName;
            }

            if(jsonData.GetValue("SeparateOverlappingCharts") != null)
            {
                SeparateOverlappingCharts = (bool)jsonData.SeparateOverlappingCharts;
            }

            if(jsonData.GetValue("OriginalChartProportionsChannel") != null)
            {
                OriginalChartProportionsChannel = (string)jsonData.OriginalChartProportionsChannel;
            }

            if(jsonData.GetValue("LockUVRotation") != null)
            {
                LockUVRotation = (bool)jsonData.LockUVRotation;
            }

        }

        public override void Reset()
        {
            ChartAggregatorModeUI.Reset();
            SurfaceAreaScaleUI.Reset();
            OriginalTexCoordLevelUI.Reset();
            OriginalTexCoordNameUI.Reset();
            SeparateOverlappingChartsUI.Reset();
            OriginalChartProportionsChannelUI.Reset();
            LockUVRotationUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            ChartAggregatorModeUI.IsEditEnabled = isEditEnabled;
            SurfaceAreaScaleUI.IsEditEnabled = isEditEnabled;
            OriginalTexCoordLevelUI.IsEditEnabled = isEditEnabled;
            OriginalTexCoordNameUI.IsEditEnabled = isEditEnabled;
            SeparateOverlappingChartsUI.IsEditEnabled = isEditEnabled;
            OriginalChartProportionsChannelUI.IsEditEnabled = isEditEnabled;
            LockUVRotationUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            ChartAggregatorModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SurfaceAreaScaleUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OriginalTexCoordLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OriginalTexCoordNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SeparateOverlappingChartsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OriginalChartProportionsChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            LockUVRotationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonParameterizerSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if( Parent.TexCoordGeneratorTypeUI != null )
                {
                    return Parent.TexCoordGeneratorType == ETexcoordGeneratorType.Parameterizer && Parent.TexCoordGeneratorTypeUI.Visible;
                }

                else
                {
                    return visible;
                }

            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonMappingImageSettings Parent { get; set; }
        public float MaxStretch { get { return _MaxStretch; } set { _MaxStretch = value; OnPropertyChanged(); } }
        private float _MaxStretch;
        public SimplygonMaxStretchEx MaxStretchUI { get; set; }
        public class SimplygonMaxStretchEx : SimplygonSettingsProperty
        {
            public SimplygonParameterizerSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MaxStretch;
                }

                set
                {
                    bool needReload = Parent.MaxStretch != value;
                    Parent.MaxStretch = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMaxStretchEx() : base("MaxStretch")
            {
                Type = "real";
                HelpText = "Only used when the TexCoordGeneratorType is Parameterizer. The maximum allowed texture stretch. Range 0->1.";
                TypeOverride = "";
                DefaultValue = 0.33f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMaxStretchEx(dynamic jsonData) : base("MaxStretch")
            {
                Type = "real";
                HelpText = "Only used when the TexCoordGeneratorType is Parameterizer. The maximum allowed texture stretch. Range 0->1.";
                TypeOverride = "";
                DefaultValue = 0.33f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaxStretch: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaxStretch: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaxStretchEx DeepCopy()
            {
                return (SimplygonMaxStretchEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MaxStretch;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float LargeChartsImportance { get { return _LargeChartsImportance; } set { _LargeChartsImportance = value; OnPropertyChanged(); } }
        private float _LargeChartsImportance;
        public SimplygonLargeChartsImportanceEx LargeChartsImportanceUI { get; set; }
        public class SimplygonLargeChartsImportanceEx : SimplygonSettingsProperty
        {
            public SimplygonParameterizerSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.LargeChartsImportance;
                }

                set
                {
                    bool needReload = Parent.LargeChartsImportance != value;
                    Parent.LargeChartsImportance = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonLargeChartsImportanceEx() : base("LargeChartsImportance")
            {
                Type = "real";
                HelpText = "Only used when the TexCoordGeneratorType is Parameterizer. The importance value for trying to have as large and few charts as possible. The closer the value is to 1, the slower it is. Having 0 means no extra focus will be put on reducing the number of charts. Having value 1 means maximum focus will be put on reducing the number of charts and thereby increasing the size of the charts.";
                TypeOverride = "";
                DefaultValue = 0.2f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonLargeChartsImportanceEx(dynamic jsonData) : base("LargeChartsImportance")
            {
                Type = "real";
                HelpText = "Only used when the TexCoordGeneratorType is Parameterizer. The importance value for trying to have as large and few charts as possible. The closer the value is to 1, the slower it is. Having 0 means no extra focus will be put on reducing the number of charts. Having value 1 means maximum focus will be put on reducing the number of charts and thereby increasing the size of the charts.";
                TypeOverride = "";
                DefaultValue = 0.2f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"LargeChartsImportance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"LargeChartsImportance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonLargeChartsImportanceEx DeepCopy()
            {
                return (SimplygonLargeChartsImportanceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.LargeChartsImportance;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonParameterizerSettings(SimplygonMappingImageSettings parent) : base("ParameterizerSettings")
        {
            Parent = parent;
            Visible = true;
            MaxStretchUI = new SimplygonMaxStretchEx();
            MaxStretchUI.Parent = this;
            MaxStretch = MaxStretchUI.DefaultValue;
            Items.Add(MaxStretchUI);
            LargeChartsImportanceUI = new SimplygonLargeChartsImportanceEx();
            LargeChartsImportanceUI.Parent = this;
            LargeChartsImportance = LargeChartsImportanceUI.DefaultValue;
            Items.Add(LargeChartsImportanceUI);
        }

        public SimplygonParameterizerSettings(SimplygonMappingImageSettings parent, dynamic jsonData) : base("ParameterizerSettings")
        {
            Parent = parent;
            Visible = true;
            MaxStretchUI = new SimplygonMaxStretchEx(jsonData != null && ((JObject)jsonData).GetValue("MaxStretchUI") != null ? jsonData.MaxStretchUI : null);
            MaxStretchUI.Parent = this;
            MaxStretch = MaxStretchUI.DefaultValue;
            Items.Add(MaxStretchUI);
            LargeChartsImportanceUI = new SimplygonLargeChartsImportanceEx(jsonData != null && ((JObject)jsonData).GetValue("LargeChartsImportanceUI") != null ? jsonData.LargeChartsImportanceUI : null);
            LargeChartsImportanceUI.Parent = this;
            LargeChartsImportance = LargeChartsImportanceUI.DefaultValue;
            Items.Add(LargeChartsImportanceUI);
            LoadJson(jsonData);
        }

        public SimplygonSettings DeepCopy(SimplygonMappingImageSettings parent)
        {
            var copy = new SimplygonParameterizerSettings(parent);
            copy.Items.Clear();
            copy.MaxStretchUI = this.MaxStretchUI.DeepCopy();
            copy.MaxStretchUI.Parent = copy;
            copy.Items.Add(copy.MaxStretchUI);
            copy.LargeChartsImportanceUI = this.LargeChartsImportanceUI.DeepCopy();
            copy.LargeChartsImportanceUI.Parent = copy;
            copy.Items.Add(copy.LargeChartsImportanceUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaxStretch = MaxStretch;
            if(serializeUIComponents)
            {
                jsonData.MaxStretchUI = MaxStretchUI.SaveJson();
            }

            jsonData.LargeChartsImportance = LargeChartsImportance;
            if(serializeUIComponents)
            {
                jsonData.LargeChartsImportanceUI = LargeChartsImportanceUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaxStretch") != null)
            {
                float newMaxStretch = (float)jsonData.MaxStretch;
                if (newMaxStretch >= MaxStretchUI.DefaultMinValue && newMaxStretch <= MaxStretchUI.DefaultMaxValue)
                {
                    MaxStretch = newMaxStretch;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MaxStretch: Invalid value {newMaxStretch.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MaxStretch.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("LargeChartsImportance") != null)
            {
                float newLargeChartsImportance = (float)jsonData.LargeChartsImportance;
                if (newLargeChartsImportance >= LargeChartsImportanceUI.DefaultMinValue && newLargeChartsImportance <= LargeChartsImportanceUI.DefaultMaxValue)
                {
                    LargeChartsImportance = newLargeChartsImportance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"LargeChartsImportance: Invalid value {newLargeChartsImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {LargeChartsImportance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            MaxStretchUI.Reset();
            LargeChartsImportanceUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaxStretchUI.IsEditEnabled = isEditEnabled;
            LargeChartsImportanceUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaxStretchUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            LargeChartsImportanceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonMappingImageSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(GenerateMappingImageUI.Visible) return true;
                if(GenerateTexCoordsUI.Visible) return true;
                if(GenerateTangentsUI.Visible) return true;
                if(MaximumLayersUI.Visible) return true;
                if(UseFullRetexturingUI.Visible) return true;
                if(ApplyNewMaterialIdsUI.Visible) return true;
                if(AllowTransparencyMappingUI.Visible) return true;
                if(TexCoordLevelUI.Visible) return true;
                if(TexCoordNameUI.Visible) return true;
                if(UseAutomaticTextureSizeUI.Visible) return true;
                if(AutomaticTextureSizeMultiplierUI.Visible) return true;
                if(ForcePower2TextureUI.Visible) return true;
                if(TexCoordGeneratorTypeUI.Visible) return true;
                if(OnlyParameterizeInvalidUVsUI.Visible) return true;

                if(InputMaterialSettings != null && InputMaterialSettings.Visible) return true;
                if(OutputMaterialSettings != null && OutputMaterialSettings.Visible) return true;
                if(ChartAggregatorSettings != null && ChartAggregatorSettings.Visible) return true;
                if(ParameterizerSettings != null && ParameterizerSettings.Visible) return true;
                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public SimplygonMappingImageInputMaterialSettings InputMaterialSettings { get; set; }
        public SimplygonMappingImageOutputMaterialSettings OutputMaterialSettings { get; set; }
        public SimplygonChartAggregatorSettings ChartAggregatorSettings { get; set; }
        public SimplygonParameterizerSettings ParameterizerSettings { get; set; }
        public bool GenerateMappingImage { get { return _GenerateMappingImage; } set { _GenerateMappingImage = value; OnPropertyChanged(); } }
        private bool _GenerateMappingImage;
        public SimplygonGenerateMappingImageEx GenerateMappingImageUI { get; set; }
        public class SimplygonGenerateMappingImageEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.GenerateMappingImage;
                }

                set
                {
                    bool needReload = Parent.GenerateMappingImage != value;
                    Parent.GenerateMappingImage = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonGenerateMappingImageEx() : base("GenerateMappingImage")
            {
                Type = "bool";
                HelpText = "If set, the aggregation processor, reduction processor, or remeshing processor will create a mapping image that maps triangles on the reduced geometry back to triangles on the original geometry. The texture is insert into the MappingImage object. The image data will contain two fields: * RidArray, 'TriangleIds', TupleSize:1, The id of the triangle  * UnsignedShortArray, 'BarycentricCoords', TupleSize:2, Items A & B of the barycentric coordinate on the triangle. The user can control the size of the mapped texture using the values MappingTextureWidth and MappingTextureHeight.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonGenerateMappingImageEx(dynamic jsonData) : base("GenerateMappingImage")
            {
                Type = "bool";
                HelpText = "If set, the aggregation processor, reduction processor, or remeshing processor will create a mapping image that maps triangles on the reduced geometry back to triangles on the original geometry. The texture is insert into the MappingImage object. The image data will contain two fields: * RidArray, 'TriangleIds', TupleSize:1, The id of the triangle  * UnsignedShortArray, 'BarycentricCoords', TupleSize:2, Items A & B of the barycentric coordinate on the triangle. The user can control the size of the mapped texture using the values MappingTextureWidth and MappingTextureHeight.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGenerateMappingImageEx DeepCopy()
            {
                return (SimplygonGenerateMappingImageEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.GenerateMappingImage;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool GenerateTexCoords { get { return _GenerateTexCoords; } set { _GenerateTexCoords = value; OnPropertyChanged(); } }
        private bool _GenerateTexCoords;
        public SimplygonGenerateTexCoordsEx GenerateTexCoordsUI { get; set; }
        public class SimplygonGenerateTexCoordsEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.GenerateTexCoords;
                }

                set
                {
                    bool needReload = Parent.GenerateTexCoords != value;
                    Parent.GenerateTexCoords = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonGenerateTexCoordsEx() : base("GenerateTexCoords")
            {
                Type = "bool";
                HelpText = "If true, generates a new texcoords field at the position specified by TexCoordLevel. Will be ignored and always generate texcoords if none are available in the Geometry if GenerateMappingImage is enabled.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonGenerateTexCoordsEx(dynamic jsonData) : base("GenerateTexCoords")
            {
                Type = "bool";
                HelpText = "If true, generates a new texcoords field at the position specified by TexCoordLevel. Will be ignored and always generate texcoords if none are available in the Geometry if GenerateMappingImage is enabled.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGenerateTexCoordsEx DeepCopy()
            {
                return (SimplygonGenerateTexCoordsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.GenerateTexCoords;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool GenerateTangents { get { return _GenerateTangents; } set { _GenerateTangents = value; OnPropertyChanged(); } }
        private bool _GenerateTangents;
        public SimplygonGenerateTangentsEx GenerateTangentsUI { get; set; }
        public class SimplygonGenerateTangentsEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.GenerateTangents;
                }

                set
                {
                    bool needReload = Parent.GenerateTangents != value;
                    Parent.GenerateTangents = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonGenerateTangentsEx() : base("GenerateTangents")
            {
                Type = "bool";
                HelpText = "If true, generates a new tangent space fields at position specified by TexCoordLevel, based on the vertex normals and texture coordinates. Tangent space fields will always be created if missing, and GenerateMappingImage is enabled. If GenerateTexCoords is enabled, new tangents will always be generated.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonGenerateTangentsEx(dynamic jsonData) : base("GenerateTangents")
            {
                Type = "bool";
                HelpText = "If true, generates a new tangent space fields at position specified by TexCoordLevel, based on the vertex normals and texture coordinates. Tangent space fields will always be created if missing, and GenerateMappingImage is enabled. If GenerateTexCoords is enabled, new tangents will always be generated.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGenerateTangentsEx DeepCopy()
            {
                return (SimplygonGenerateTangentsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.GenerateTangents;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int MaximumLayers { get { return _MaximumLayers; } set { _MaximumLayers = value; OnPropertyChanged(); } }
        private int _MaximumLayers;
        public SimplygonMaximumLayersEx MaximumLayersUI { get; set; }
        public class SimplygonMaximumLayersEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.MaximumLayers;
                }

                set
                {
                    bool needReload = Parent.MaximumLayers != value;
                    Parent.MaximumLayers = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonMaximumLayersEx() : base("MaximumLayers")
            {
                Type = "uint";
                HelpText = "The maximum number of layers in the mapping image. If a remeshed geometry has a lot of transparent triangles, use a higher number to be able to find intersections on the inside of parts of the geometry. This setting only has effect in the remeshing, when running reduction the number of layers is always 1.";
                TypeOverride = "";
                DefaultValue = 3;
                MinValue = 0;
                MaxValue = 10;
                DefaultMinValue = 0;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonMaximumLayersEx(dynamic jsonData) : base("MaximumLayers")
            {
                Type = "uint";
                HelpText = "The maximum number of layers in the mapping image. If a remeshed geometry has a lot of transparent triangles, use a higher number to be able to find intersections on the inside of parts of the geometry. This setting only has effect in the remeshing, when running reduction the number of layers is always 1.";
                TypeOverride = "";
                DefaultValue = 3;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaximumLayers: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaximumLayers: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaximumLayersEx DeepCopy()
            {
                return (SimplygonMaximumLayersEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.MaximumLayers;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool UseFullRetexturing { get { return _UseFullRetexturing; } set { _UseFullRetexturing = value; OnPropertyChanged(); } }
        private bool _UseFullRetexturing;
        public SimplygonUseFullRetexturingEx UseFullRetexturingUI { get; set; }
        public class SimplygonUseFullRetexturingEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseFullRetexturing;
                }

                set
                {
                    bool needReload = Parent.UseFullRetexturing != value;
                    Parent.UseFullRetexturing = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseFullRetexturingEx() : base("UseFullRetexturing")
            {
                Type = "bool";
                HelpText = "If set, all original texcoord sets are replaced by a single new one which will be used for the mapping image. This means the output scene will be temporarily invalid before the materialtable has been updated to reflect the new changes. This flag has no effect on the remeshing, which always does a full retexturing.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseFullRetexturingEx(dynamic jsonData) : base("UseFullRetexturing")
            {
                Type = "bool";
                HelpText = "If set, all original texcoord sets are replaced by a single new one which will be used for the mapping image. This means the output scene will be temporarily invalid before the materialtable has been updated to reflect the new changes. This flag has no effect on the remeshing, which always does a full retexturing.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseFullRetexturingEx DeepCopy()
            {
                return (SimplygonUseFullRetexturingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseFullRetexturing;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool ApplyNewMaterialIds { get { return _ApplyNewMaterialIds; } set { _ApplyNewMaterialIds = value; OnPropertyChanged(); } }
        private bool _ApplyNewMaterialIds;
        public SimplygonApplyNewMaterialIdsEx ApplyNewMaterialIdsUI { get; set; }
        public class SimplygonApplyNewMaterialIdsEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ApplyNewMaterialIds;
                }

                set
                {
                    bool needReload = Parent.ApplyNewMaterialIds != value;
                    Parent.ApplyNewMaterialIds = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonApplyNewMaterialIdsEx() : base("ApplyNewMaterialIds")
            {
                Type = "bool";
                HelpText = "If true, and also generating one or more mapping images for material casting, the material IDs in the process geometry will be updated to reflect the new, not yet cast output materials. This means the output scene will be temporarily invalid before the materialtable has been updated to reflect the new changes.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonApplyNewMaterialIdsEx(dynamic jsonData) : base("ApplyNewMaterialIds")
            {
                Type = "bool";
                HelpText = "If true, and also generating one or more mapping images for material casting, the material IDs in the process geometry will be updated to reflect the new, not yet cast output materials. This means the output scene will be temporarily invalid before the materialtable has been updated to reflect the new changes.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonApplyNewMaterialIdsEx DeepCopy()
            {
                return (SimplygonApplyNewMaterialIdsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ApplyNewMaterialIds;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool AllowTransparencyMapping { get { return _AllowTransparencyMapping; } set { _AllowTransparencyMapping = value; OnPropertyChanged(); } }
        private bool _AllowTransparencyMapping;
        public SimplygonAllowTransparencyMappingEx AllowTransparencyMappingUI { get; set; }
        public class SimplygonAllowTransparencyMappingEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.AllowTransparencyMapping;
                }

                set
                {
                    bool needReload = Parent.AllowTransparencyMapping != value;
                    Parent.AllowTransparencyMapping = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonAllowTransparencyMappingEx() : base("AllowTransparencyMapping")
            {
                Type = "bool";
                HelpText = "If true, the remeshing processor will allow mapped transparency in the generated mapping image. This allows material casting where gaps filled by the remeshing processor will be cast as transparent.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonAllowTransparencyMappingEx(dynamic jsonData) : base("AllowTransparencyMapping")
            {
                Type = "bool";
                HelpText = "If true, the remeshing processor will allow mapped transparency in the generated mapping image. This allows material casting where gaps filled by the remeshing processor will be cast as transparent.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonAllowTransparencyMappingEx DeepCopy()
            {
                return (SimplygonAllowTransparencyMappingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.AllowTransparencyMapping;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int TexCoordLevel { get { return _TexCoordLevel; } set { _TexCoordLevel = value; OnPropertyChanged(); } }
        private int _TexCoordLevel;
        public SimplygonTexCoordLevelEx TexCoordLevelUI { get; set; }
        public class SimplygonTexCoordLevelEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.TexCoordLevel;
                }

                set
                {
                    bool needReload = Parent.TexCoordLevel != value;
                    Parent.TexCoordLevel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonTexCoordLevelEx() : base("TexCoordLevel")
            {
                Type = "rid";
                HelpText = "The texture coordinate level used for mapping image and texture generation. If the TexCoordName has been set, the TexCoordLevel is not used.";
                TypeOverride = "";
                DefaultValue = 0;
                MinValue = -1;
                MaxValue = 10;
                DefaultMinValue = -1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonTexCoordLevelEx(dynamic jsonData) : base("TexCoordLevel")
            {
                Type = "rid";
                HelpText = "The texture coordinate level used for mapping image and texture generation. If the TexCoordName has been set, the TexCoordLevel is not used.";
                TypeOverride = "";
                DefaultValue = 0;
                MinValue = -1;
                DefaultMinValue = -1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TexCoordLevel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TexCoordLevel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTexCoordLevelEx DeepCopy()
            {
                return (SimplygonTexCoordLevelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.TexCoordLevel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public string TexCoordName { get { return _TexCoordName; } set { _TexCoordName = value; OnPropertyChanged(); } }
        private string _TexCoordName;
        public SimplygonTexCoordNameEx TexCoordNameUI { get; set; }
        public class SimplygonTexCoordNameEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.TexCoordName;
                }

                set
                {
                    bool needReload = Parent.TexCoordName != value;
                    Parent.TexCoordName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonTexCoordNameEx() : base("TexCoordName")
            {
                Type = "string";
                HelpText = "The texture coordinate level name used for mapping image and texture generation. If new UVs are created, they will replace the old coordinates in the texture channel with the TexCoordName. If no texture level with this name exists. It will be created. If the TexCoordName is not set, the TexCoordLevel (index) will be used instead.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonTexCoordNameEx(dynamic jsonData) : base("TexCoordName")
            {
                Type = "string";
                HelpText = "The texture coordinate level name used for mapping image and texture generation. If new UVs are created, they will replace the old coordinates in the texture channel with the TexCoordName. If no texture level with this name exists. It will be created. If the TexCoordName is not set, the TexCoordLevel (index) will be used instead.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTexCoordNameEx DeepCopy()
            {
                return (SimplygonTexCoordNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.TexCoordName;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseAutomaticTextureSize { get { return _UseAutomaticTextureSize; } set { _UseAutomaticTextureSize = value; OnPropertyChanged(); } }
        private bool _UseAutomaticTextureSize;
        public SimplygonUseAutomaticTextureSizeEx UseAutomaticTextureSizeUI { get; set; }
        public class SimplygonUseAutomaticTextureSizeEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseAutomaticTextureSize;
                }

                set
                {
                    bool needReload = Parent.UseAutomaticTextureSize != value;
                    Parent.UseAutomaticTextureSize = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseAutomaticTextureSizeEx() : base("UseAutomaticTextureSize")
            {
                Type = "bool";
                HelpText = "The UseAutomaticTextureSize flag. If true, then texture sizes will be computed for the reduced mesh depending on its pixel size on screen.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseAutomaticTextureSizeEx(dynamic jsonData) : base("UseAutomaticTextureSize")
            {
                Type = "bool";
                HelpText = "The UseAutomaticTextureSize flag. If true, then texture sizes will be computed for the reduced mesh depending on its pixel size on screen.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseAutomaticTextureSizeEx DeepCopy()
            {
                return (SimplygonUseAutomaticTextureSizeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseAutomaticTextureSize;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float AutomaticTextureSizeMultiplier { get { return _AutomaticTextureSizeMultiplier; } set { _AutomaticTextureSizeMultiplier = value; OnPropertyChanged(); } }
        private float _AutomaticTextureSizeMultiplier;
        public SimplygonAutomaticTextureSizeMultiplierEx AutomaticTextureSizeMultiplierUI { get; set; }
        public class SimplygonAutomaticTextureSizeMultiplierEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.AutomaticTextureSizeMultiplier;
                }

                set
                {
                    bool needReload = Parent.AutomaticTextureSizeMultiplier != value;
                    Parent.AutomaticTextureSizeMultiplier = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonAutomaticTextureSizeMultiplierEx() : base("AutomaticTextureSizeMultiplier")
            {
                Type = "real";
                HelpText = "Texture dimension length multiplier for the automatic texture size.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonAutomaticTextureSizeMultiplierEx(dynamic jsonData) : base("AutomaticTextureSizeMultiplier")
            {
                Type = "real";
                HelpText = "Texture dimension length multiplier for the automatic texture size.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"AutomaticTextureSizeMultiplier: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"AutomaticTextureSizeMultiplier: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonAutomaticTextureSizeMultiplierEx DeepCopy()
            {
                return (SimplygonAutomaticTextureSizeMultiplierEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.AutomaticTextureSizeMultiplier;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool ForcePower2Texture { get { return _ForcePower2Texture; } set { _ForcePower2Texture = value; OnPropertyChanged(); } }
        private bool _ForcePower2Texture;
        public SimplygonForcePower2TextureEx ForcePower2TextureUI { get; set; }
        public class SimplygonForcePower2TextureEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ForcePower2Texture;
                }

                set
                {
                    bool needReload = Parent.ForcePower2Texture != value;
                    Parent.ForcePower2Texture = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonForcePower2TextureEx() : base("ForcePower2Texture")
            {
                Type = "bool";
                HelpText = "If automatic_texture_size is enabled, then force the texture sizes to be a power of 2.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonForcePower2TextureEx(dynamic jsonData) : base("ForcePower2Texture")
            {
                Type = "bool";
                HelpText = "If automatic_texture_size is enabled, then force the texture sizes to be a power of 2.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonForcePower2TextureEx DeepCopy()
            {
                return (SimplygonForcePower2TextureEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ForcePower2Texture;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public ETexcoordGeneratorType TexCoordGeneratorType { get { return _TexCoordGeneratorType; } set { _TexCoordGeneratorType = value; OnPropertyChanged(); } }
        private ETexcoordGeneratorType _TexCoordGeneratorType;
        public SimplygonTexCoordGeneratorTypeEx TexCoordGeneratorTypeUI { get; set; }
        public class SimplygonTexCoordGeneratorTypeEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public ETexcoordGeneratorType Value
            {
                get
                {
                    return Parent.TexCoordGeneratorType;
                }

                set
                {
                    bool needReload = Parent.TexCoordGeneratorType != value;
                    Parent.TexCoordGeneratorType = value;
                    Parent.ChartAggregatorSettings.Visible = Visible;
                    Parent.ParameterizerSettings.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public ETexcoordGeneratorType DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(ETexcoordGeneratorType)); } }

            public SimplygonTexCoordGeneratorTypeEx() : base("TexCoordGeneratorType")
            {
                Type = "enum";
                HelpText = "Determines which method to use when generating the texture coordinates. Parameterizer generate from scratch based on the geometry. ChartAggregator generate based on the original texture coordinates.";
                TypeOverride = "";
                DefaultValue = ETexcoordGeneratorType.Parameterizer;
                Visible = true;
            }

            public SimplygonTexCoordGeneratorTypeEx(dynamic jsonData) : base("TexCoordGeneratorType")
            {
                Type = "enum";
                HelpText = "Determines which method to use when generating the texture coordinates. Parameterizer generate from scratch based on the geometry. ChartAggregator generate based on the original texture coordinates.";
                TypeOverride = "";
                DefaultValue = ETexcoordGeneratorType.Parameterizer;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTexCoordGeneratorTypeEx DeepCopy()
            {
                return (SimplygonTexCoordGeneratorTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.TexCoordGeneratorType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (ETexcoordGeneratorType)value;
            }

        }

        public bool OnlyParameterizeInvalidUVs { get { return _OnlyParameterizeInvalidUVs; } set { _OnlyParameterizeInvalidUVs = value; OnPropertyChanged(); } }
        private bool _OnlyParameterizeInvalidUVs;
        public SimplygonOnlyParameterizeInvalidUVsEx OnlyParameterizeInvalidUVsUI { get; set; }
        public class SimplygonOnlyParameterizeInvalidUVsEx : SimplygonSettingsProperty
        {
            public SimplygonMappingImageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.OnlyParameterizeInvalidUVs;
                }

                set
                {
                    bool needReload = Parent.OnlyParameterizeInvalidUVs != value;
                    Parent.OnlyParameterizeInvalidUVs = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonOnlyParameterizeInvalidUVsEx() : base("OnlyParameterizeInvalidUVs")
            {
                Type = "bool";
                HelpText = "If enabled, will aggregate all the valid original UVs. If there are invalid original UVs, those parts will receive new parameterized UVs.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonOnlyParameterizeInvalidUVsEx(dynamic jsonData) : base("OnlyParameterizeInvalidUVs")
            {
                Type = "bool";
                HelpText = "If enabled, will aggregate all the valid original UVs. If there are invalid original UVs, those parts will receive new parameterized UVs.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOnlyParameterizeInvalidUVsEx DeepCopy()
            {
                return (SimplygonOnlyParameterizeInvalidUVsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.OnlyParameterizeInvalidUVs;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonMappingImageSettings() : base("MappingImageSettings")
        {
            Visible = true;
            GenerateMappingImageUI = new SimplygonGenerateMappingImageEx();
            GenerateMappingImageUI.Parent = this;
            GenerateMappingImage = GenerateMappingImageUI.DefaultValue;
            Items.Add(GenerateMappingImageUI);
            GenerateTexCoordsUI = new SimplygonGenerateTexCoordsEx();
            GenerateTexCoordsUI.Parent = this;
            GenerateTexCoords = GenerateTexCoordsUI.DefaultValue;
            Items.Add(GenerateTexCoordsUI);
            GenerateTangentsUI = new SimplygonGenerateTangentsEx();
            GenerateTangentsUI.Parent = this;
            GenerateTangents = GenerateTangentsUI.DefaultValue;
            Items.Add(GenerateTangentsUI);
            UseFullRetexturingUI = new SimplygonUseFullRetexturingEx();
            UseFullRetexturingUI.Parent = this;
            UseFullRetexturing = UseFullRetexturingUI.DefaultValue;
            Items.Add(UseFullRetexturingUI);
            ApplyNewMaterialIdsUI = new SimplygonApplyNewMaterialIdsEx();
            ApplyNewMaterialIdsUI.Parent = this;
            ApplyNewMaterialIds = ApplyNewMaterialIdsUI.DefaultValue;
            Items.Add(ApplyNewMaterialIdsUI);
            UseAutomaticTextureSizeUI = new SimplygonUseAutomaticTextureSizeEx();
            UseAutomaticTextureSizeUI.Parent = this;
            UseAutomaticTextureSize = UseAutomaticTextureSizeUI.DefaultValue;
            Items.Add(UseAutomaticTextureSizeUI);
            AutomaticTextureSizeMultiplierUI = new SimplygonAutomaticTextureSizeMultiplierEx();
            AutomaticTextureSizeMultiplierUI.Parent = this;
            AutomaticTextureSizeMultiplier = AutomaticTextureSizeMultiplierUI.DefaultValue;
            Items.Add(AutomaticTextureSizeMultiplierUI);
            ForcePower2TextureUI = new SimplygonForcePower2TextureEx();
            ForcePower2TextureUI.Parent = this;
            ForcePower2Texture = ForcePower2TextureUI.DefaultValue;
            Items.Add(ForcePower2TextureUI);
            OnlyParameterizeInvalidUVsUI = new SimplygonOnlyParameterizeInvalidUVsEx();
            OnlyParameterizeInvalidUVsUI.Parent = this;
            OnlyParameterizeInvalidUVs = OnlyParameterizeInvalidUVsUI.DefaultValue;
            Items.Add(OnlyParameterizeInvalidUVsUI);
            AllowTransparencyMappingUI = new SimplygonAllowTransparencyMappingEx();
            AllowTransparencyMappingUI.Parent = this;
            AllowTransparencyMapping = AllowTransparencyMappingUI.DefaultValue;
            Items.Add(AllowTransparencyMappingUI);
            MaximumLayersUI = new SimplygonMaximumLayersEx();
            MaximumLayersUI.Parent = this;
            MaximumLayers = MaximumLayersUI.DefaultValue;
            Items.Add(MaximumLayersUI);
            TexCoordLevelUI = new SimplygonTexCoordLevelEx();
            TexCoordLevelUI.Parent = this;
            TexCoordLevel = TexCoordLevelUI.DefaultValue;
            Items.Add(TexCoordLevelUI);
            TexCoordNameUI = new SimplygonTexCoordNameEx();
            TexCoordNameUI.Parent = this;
            TexCoordName = TexCoordNameUI.DefaultValue;
            Items.Add(TexCoordNameUI);
            TexCoordGeneratorTypeUI = new SimplygonTexCoordGeneratorTypeEx();
            TexCoordGeneratorTypeUI.Parent = this;
            TexCoordGeneratorType = TexCoordGeneratorTypeUI.DefaultValue;
            Items.Add(TexCoordGeneratorTypeUI);
            ChartAggregatorSettings = new SimplygonChartAggregatorSettings(this);
            Items.Add(ChartAggregatorSettings);
            ParameterizerSettings = new SimplygonParameterizerSettings(this);
            Items.Add(ParameterizerSettings);
            InputMaterialSettings = new SimplygonMappingImageInputMaterialSettings(this);
            Items.Add(InputMaterialSettings);
            OutputMaterialSettings = new SimplygonMappingImageOutputMaterialSettings(this);
            Items.Add(OutputMaterialSettings);
        }

        public SimplygonMappingImageSettings(dynamic jsonData) : base("MappingImageSettings")
        {
            Visible = true;
            GenerateMappingImageUI = new SimplygonGenerateMappingImageEx(jsonData != null && ((JObject)jsonData).GetValue("GenerateMappingImageUI") != null ? jsonData.GenerateMappingImageUI : null);
            GenerateMappingImageUI.Parent = this;
            GenerateMappingImage = GenerateMappingImageUI.DefaultValue;
            Items.Add(GenerateMappingImageUI);
            GenerateTexCoordsUI = new SimplygonGenerateTexCoordsEx(jsonData != null && ((JObject)jsonData).GetValue("GenerateTexCoordsUI") != null ? jsonData.GenerateTexCoordsUI : null);
            GenerateTexCoordsUI.Parent = this;
            GenerateTexCoords = GenerateTexCoordsUI.DefaultValue;
            Items.Add(GenerateTexCoordsUI);
            GenerateTangentsUI = new SimplygonGenerateTangentsEx(jsonData != null && ((JObject)jsonData).GetValue("GenerateTangentsUI") != null ? jsonData.GenerateTangentsUI : null);
            GenerateTangentsUI.Parent = this;
            GenerateTangents = GenerateTangentsUI.DefaultValue;
            Items.Add(GenerateTangentsUI);
            UseFullRetexturingUI = new SimplygonUseFullRetexturingEx(jsonData != null && ((JObject)jsonData).GetValue("UseFullRetexturingUI") != null ? jsonData.UseFullRetexturingUI : null);
            UseFullRetexturingUI.Parent = this;
            UseFullRetexturing = UseFullRetexturingUI.DefaultValue;
            Items.Add(UseFullRetexturingUI);
            ApplyNewMaterialIdsUI = new SimplygonApplyNewMaterialIdsEx(jsonData != null && ((JObject)jsonData).GetValue("ApplyNewMaterialIdsUI") != null ? jsonData.ApplyNewMaterialIdsUI : null);
            ApplyNewMaterialIdsUI.Parent = this;
            ApplyNewMaterialIds = ApplyNewMaterialIdsUI.DefaultValue;
            Items.Add(ApplyNewMaterialIdsUI);
            UseAutomaticTextureSizeUI = new SimplygonUseAutomaticTextureSizeEx(jsonData != null && ((JObject)jsonData).GetValue("UseAutomaticTextureSizeUI") != null ? jsonData.UseAutomaticTextureSizeUI : null);
            UseAutomaticTextureSizeUI.Parent = this;
            UseAutomaticTextureSize = UseAutomaticTextureSizeUI.DefaultValue;
            Items.Add(UseAutomaticTextureSizeUI);
            AutomaticTextureSizeMultiplierUI = new SimplygonAutomaticTextureSizeMultiplierEx(jsonData != null && ((JObject)jsonData).GetValue("AutomaticTextureSizeMultiplierUI") != null ? jsonData.AutomaticTextureSizeMultiplierUI : null);
            AutomaticTextureSizeMultiplierUI.Parent = this;
            AutomaticTextureSizeMultiplier = AutomaticTextureSizeMultiplierUI.DefaultValue;
            Items.Add(AutomaticTextureSizeMultiplierUI);
            ForcePower2TextureUI = new SimplygonForcePower2TextureEx(jsonData != null && ((JObject)jsonData).GetValue("ForcePower2TextureUI") != null ? jsonData.ForcePower2TextureUI : null);
            ForcePower2TextureUI.Parent = this;
            ForcePower2Texture = ForcePower2TextureUI.DefaultValue;
            Items.Add(ForcePower2TextureUI);
            OnlyParameterizeInvalidUVsUI = new SimplygonOnlyParameterizeInvalidUVsEx(jsonData != null && ((JObject)jsonData).GetValue("OnlyParameterizeInvalidUVsUI") != null ? jsonData.OnlyParameterizeInvalidUVsUI : null);
            OnlyParameterizeInvalidUVsUI.Parent = this;
            OnlyParameterizeInvalidUVs = OnlyParameterizeInvalidUVsUI.DefaultValue;
            Items.Add(OnlyParameterizeInvalidUVsUI);
            AllowTransparencyMappingUI = new SimplygonAllowTransparencyMappingEx(jsonData != null && ((JObject)jsonData).GetValue("AllowTransparencyMappingUI") != null ? jsonData.AllowTransparencyMappingUI : null);
            AllowTransparencyMappingUI.Parent = this;
            AllowTransparencyMapping = AllowTransparencyMappingUI.DefaultValue;
            Items.Add(AllowTransparencyMappingUI);
            MaximumLayersUI = new SimplygonMaximumLayersEx(jsonData != null && ((JObject)jsonData).GetValue("MaximumLayersUI") != null ? jsonData.MaximumLayersUI : null);
            MaximumLayersUI.Parent = this;
            MaximumLayers = MaximumLayersUI.DefaultValue;
            Items.Add(MaximumLayersUI);
            TexCoordLevelUI = new SimplygonTexCoordLevelEx(jsonData != null && ((JObject)jsonData).GetValue("TexCoordLevelUI") != null ? jsonData.TexCoordLevelUI : null);
            TexCoordLevelUI.Parent = this;
            TexCoordLevel = TexCoordLevelUI.DefaultValue;
            Items.Add(TexCoordLevelUI);
            TexCoordNameUI = new SimplygonTexCoordNameEx(jsonData != null && ((JObject)jsonData).GetValue("TexCoordNameUI") != null ? jsonData.TexCoordNameUI : null);
            TexCoordNameUI.Parent = this;
            TexCoordName = TexCoordNameUI.DefaultValue;
            Items.Add(TexCoordNameUI);
            TexCoordGeneratorTypeUI = new SimplygonTexCoordGeneratorTypeEx(jsonData != null && ((JObject)jsonData).GetValue("TexCoordGeneratorTypeUI") != null ? jsonData.TexCoordGeneratorTypeUI : null);
            TexCoordGeneratorTypeUI.Parent = this;
            TexCoordGeneratorType = TexCoordGeneratorTypeUI.DefaultValue;
            Items.Add(TexCoordGeneratorTypeUI);
            if(jsonData.GetValue("ChartAggregatorSettings") != null)
            {
                ChartAggregatorSettings = new SimplygonChartAggregatorSettings(this, jsonData.ChartAggregatorSettings);
                Items.Add(ChartAggregatorSettings);
            }

            if(jsonData.GetValue("ParameterizerSettings") != null)
            {
                ParameterizerSettings = new SimplygonParameterizerSettings(this, jsonData.ParameterizerSettings);
                Items.Add(ParameterizerSettings);
            }

            if(jsonData.GetValue("InputMaterialSettings") != null && jsonData.InputMaterialSettings.Count > 0)
            {
                InputMaterialSettings = new SimplygonMappingImageInputMaterialSettings(this, jsonData.InputMaterialSettings[0]);
                Items.Add(InputMaterialSettings);
            }

            if(jsonData.GetValue("OutputMaterialSettings") != null && jsonData.OutputMaterialSettings.Count > 0)
            {
                OutputMaterialSettings = new SimplygonMappingImageOutputMaterialSettings(this, jsonData.OutputMaterialSettings[0]);
                Items.Add(OutputMaterialSettings);
            }

            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonMappingImageSettings();
            copy.Items.Clear();
            copy.GenerateMappingImageUI = this.GenerateMappingImageUI.DeepCopy();
            copy.GenerateMappingImageUI.Parent = copy;
            copy.Items.Add(copy.GenerateMappingImageUI);
            copy.GenerateTexCoordsUI = this.GenerateTexCoordsUI.DeepCopy();
            copy.GenerateTexCoordsUI.Parent = copy;
            copy.Items.Add(copy.GenerateTexCoordsUI);
            copy.GenerateTangentsUI = this.GenerateTangentsUI.DeepCopy();
            copy.GenerateTangentsUI.Parent = copy;
            copy.Items.Add(copy.GenerateTangentsUI);
            copy.UseFullRetexturingUI = this.UseFullRetexturingUI.DeepCopy();
            copy.UseFullRetexturingUI.Parent = copy;
            copy.Items.Add(copy.UseFullRetexturingUI);
            copy.ApplyNewMaterialIdsUI = this.ApplyNewMaterialIdsUI.DeepCopy();
            copy.ApplyNewMaterialIdsUI.Parent = copy;
            copy.Items.Add(copy.ApplyNewMaterialIdsUI);
            copy.UseAutomaticTextureSizeUI = this.UseAutomaticTextureSizeUI.DeepCopy();
            copy.UseAutomaticTextureSizeUI.Parent = copy;
            copy.Items.Add(copy.UseAutomaticTextureSizeUI);
            copy.AutomaticTextureSizeMultiplierUI = this.AutomaticTextureSizeMultiplierUI.DeepCopy();
            copy.AutomaticTextureSizeMultiplierUI.Parent = copy;
            copy.Items.Add(copy.AutomaticTextureSizeMultiplierUI);
            copy.ForcePower2TextureUI = this.ForcePower2TextureUI.DeepCopy();
            copy.ForcePower2TextureUI.Parent = copy;
            copy.Items.Add(copy.ForcePower2TextureUI);
            copy.OnlyParameterizeInvalidUVsUI = this.OnlyParameterizeInvalidUVsUI.DeepCopy();
            copy.OnlyParameterizeInvalidUVsUI.Parent = copy;
            copy.Items.Add(copy.OnlyParameterizeInvalidUVsUI);
            copy.AllowTransparencyMappingUI = this.AllowTransparencyMappingUI.DeepCopy();
            copy.AllowTransparencyMappingUI.Parent = copy;
            copy.Items.Add(copy.AllowTransparencyMappingUI);
            copy.MaximumLayersUI = this.MaximumLayersUI.DeepCopy();
            copy.MaximumLayersUI.Parent = copy;
            copy.Items.Add(copy.MaximumLayersUI);
            copy.TexCoordLevelUI = this.TexCoordLevelUI.DeepCopy();
            copy.TexCoordLevelUI.Parent = copy;
            copy.Items.Add(copy.TexCoordLevelUI);
            copy.TexCoordNameUI = this.TexCoordNameUI.DeepCopy();
            copy.TexCoordNameUI.Parent = copy;
            copy.Items.Add(copy.TexCoordNameUI);
            copy.TexCoordGeneratorTypeUI = this.TexCoordGeneratorTypeUI.DeepCopy();
            copy.TexCoordGeneratorTypeUI.Parent = copy;
            copy.Items.Add(copy.TexCoordGeneratorTypeUI);
            if (ChartAggregatorSettings != null)
            {
                copy.ChartAggregatorSettings = (SimplygonChartAggregatorSettings)this.ChartAggregatorSettings.DeepCopy(copy);
                copy.Items.Add(copy.ChartAggregatorSettings);
            }

            if (ParameterizerSettings != null)
            {
                copy.ParameterizerSettings = (SimplygonParameterizerSettings)this.ParameterizerSettings.DeepCopy(copy);
                copy.Items.Add(copy.ParameterizerSettings);
            }

            if (InputMaterialSettings != null)
            {
                copy.InputMaterialSettings = (SimplygonMappingImageInputMaterialSettings)this.InputMaterialSettings.DeepCopy(copy);
                copy.Items.Add(copy.InputMaterialSettings);
            }

            if (OutputMaterialSettings != null)
            {
                copy.OutputMaterialSettings = (SimplygonMappingImageOutputMaterialSettings)this.OutputMaterialSettings.DeepCopy(copy);
                copy.Items.Add(copy.OutputMaterialSettings);
            }

            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.GenerateMappingImage = GenerateMappingImage;
            if(serializeUIComponents)
            {
                jsonData.GenerateMappingImageUI = GenerateMappingImageUI.SaveJson();
            }

            jsonData.GenerateTexCoords = GenerateTexCoords;
            if(serializeUIComponents)
            {
                jsonData.GenerateTexCoordsUI = GenerateTexCoordsUI.SaveJson();
            }

            jsonData.GenerateTangents = GenerateTangents;
            if(serializeUIComponents)
            {
                jsonData.GenerateTangentsUI = GenerateTangentsUI.SaveJson();
            }

            jsonData.MaximumLayers = MaximumLayers;
            if(serializeUIComponents)
            {
                jsonData.MaximumLayersUI = MaximumLayersUI.SaveJson();
            }

            jsonData.UseFullRetexturing = UseFullRetexturing;
            if(serializeUIComponents)
            {
                jsonData.UseFullRetexturingUI = UseFullRetexturingUI.SaveJson();
            }

            jsonData.ApplyNewMaterialIds = ApplyNewMaterialIds;
            if(serializeUIComponents)
            {
                jsonData.ApplyNewMaterialIdsUI = ApplyNewMaterialIdsUI.SaveJson();
            }

            jsonData.AllowTransparencyMapping = AllowTransparencyMapping;
            if(serializeUIComponents)
            {
                jsonData.AllowTransparencyMappingUI = AllowTransparencyMappingUI.SaveJson();
            }

            jsonData.TexCoordLevel = TexCoordLevel;
            if(serializeUIComponents)
            {
                jsonData.TexCoordLevelUI = TexCoordLevelUI.SaveJson();
            }

            jsonData.TexCoordName = TexCoordName;
            if(serializeUIComponents)
            {
                jsonData.TexCoordNameUI = TexCoordNameUI.SaveJson();
            }

            jsonData.UseAutomaticTextureSize = UseAutomaticTextureSize;
            if(serializeUIComponents)
            {
                jsonData.UseAutomaticTextureSizeUI = UseAutomaticTextureSizeUI.SaveJson();
            }

            jsonData.AutomaticTextureSizeMultiplier = AutomaticTextureSizeMultiplier;
            if(serializeUIComponents)
            {
                jsonData.AutomaticTextureSizeMultiplierUI = AutomaticTextureSizeMultiplierUI.SaveJson();
            }

            jsonData.ForcePower2Texture = ForcePower2Texture;
            if(serializeUIComponents)
            {
                jsonData.ForcePower2TextureUI = ForcePower2TextureUI.SaveJson();
            }

            jsonData.TexCoordGeneratorType = (int)TexCoordGeneratorType;
            if(serializeUIComponents)
            {
                jsonData.TexCoordGeneratorTypeUI = TexCoordGeneratorTypeUI.SaveJson();
            }

            jsonData.OnlyParameterizeInvalidUVs = OnlyParameterizeInvalidUVs;
            if(serializeUIComponents)
            {
                jsonData.OnlyParameterizeInvalidUVsUI = OnlyParameterizeInvalidUVsUI.SaveJson();
            }

            if (InputMaterialSettings != null)
            {
                jsonData.InputMaterialSettings = new JArray();
                jsonData.InputMaterialSettings.Add(InputMaterialSettings.SaveJson(serializeUIComponents));
            }

            if (OutputMaterialSettings != null)
            {
                jsonData.OutputMaterialSettings = new JArray();
                jsonData.OutputMaterialSettings.Add(OutputMaterialSettings.SaveJson(serializeUIComponents));
            }

            if (ChartAggregatorSettings != null)
            {
                jsonData.ChartAggregatorSettings = ChartAggregatorSettings.SaveJson(serializeUIComponents);
            }

            if (ParameterizerSettings != null)
            {
                jsonData.ParameterizerSettings = ParameterizerSettings.SaveJson(serializeUIComponents);
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("GenerateMappingImage") != null)
            {
                GenerateMappingImage = (bool)jsonData.GenerateMappingImage;
            }

            if(jsonData.GetValue("GenerateTexCoords") != null)
            {
                GenerateTexCoords = (bool)jsonData.GenerateTexCoords;
            }

            if(jsonData.GetValue("GenerateTangents") != null)
            {
                GenerateTangents = (bool)jsonData.GenerateTangents;
            }

            if(jsonData.GetValue("MaximumLayers") != null)
            {
                var newMaximumLayers = (int)jsonData.MaximumLayers;
                if (newMaximumLayers >= MaximumLayersUI.DefaultMinValue && newMaximumLayers <= MaximumLayersUI.DefaultMaxValue)
                {
                    MaximumLayers = newMaximumLayers;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MaximumLayers: Invalid value {newMaximumLayers}, using default value {MaximumLayers.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UseFullRetexturing") != null)
            {
                UseFullRetexturing = (bool)jsonData.UseFullRetexturing;
            }

            if(jsonData.GetValue("ApplyNewMaterialIds") != null)
            {
                ApplyNewMaterialIds = (bool)jsonData.ApplyNewMaterialIds;
            }

            if(jsonData.GetValue("AllowTransparencyMapping") != null)
            {
                AllowTransparencyMapping = (bool)jsonData.AllowTransparencyMapping;
            }

            if(jsonData.GetValue("TexCoordLevel") != null)
            {
                var newTexCoordLevel = (int)jsonData.TexCoordLevel;
                if (newTexCoordLevel >= TexCoordLevelUI.DefaultMinValue && newTexCoordLevel <= TexCoordLevelUI.DefaultMaxValue)
                {
                    TexCoordLevel = newTexCoordLevel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TexCoordLevel: Invalid value {newTexCoordLevel}, using default value {TexCoordLevel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("TexCoordName") != null)
            {
                TexCoordName = (string)jsonData.TexCoordName;
            }

            if(jsonData.GetValue("UseAutomaticTextureSize") != null)
            {
                UseAutomaticTextureSize = (bool)jsonData.UseAutomaticTextureSize;
            }

            if(jsonData.GetValue("AutomaticTextureSizeMultiplier") != null)
            {
                float newAutomaticTextureSizeMultiplier = (float)jsonData.AutomaticTextureSizeMultiplier;
                if (newAutomaticTextureSizeMultiplier >= AutomaticTextureSizeMultiplierUI.DefaultMinValue && newAutomaticTextureSizeMultiplier <= AutomaticTextureSizeMultiplierUI.DefaultMaxValue)
                {
                    AutomaticTextureSizeMultiplier = newAutomaticTextureSizeMultiplier;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"AutomaticTextureSizeMultiplier: Invalid value {newAutomaticTextureSizeMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {AutomaticTextureSizeMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ForcePower2Texture") != null)
            {
                ForcePower2Texture = (bool)jsonData.ForcePower2Texture;
            }

            if(jsonData.GetValue("TexCoordGeneratorType") != null)
            {
                TexCoordGeneratorType = (ETexcoordGeneratorType)jsonData.TexCoordGeneratorType;
            }

            if(jsonData.GetValue("OnlyParameterizeInvalidUVs") != null)
            {
                OnlyParameterizeInvalidUVs = (bool)jsonData.OnlyParameterizeInvalidUVs;
            }

        }

        public override void Reset()
        {
            GenerateMappingImageUI.Reset();
            GenerateTexCoordsUI.Reset();
            GenerateTangentsUI.Reset();
            MaximumLayersUI.Reset();
            UseFullRetexturingUI.Reset();
            ApplyNewMaterialIdsUI.Reset();
            AllowTransparencyMappingUI.Reset();
            TexCoordLevelUI.Reset();
            TexCoordNameUI.Reset();
            UseAutomaticTextureSizeUI.Reset();
            AutomaticTextureSizeMultiplierUI.Reset();
            ForcePower2TextureUI.Reset();
            TexCoordGeneratorTypeUI.Reset();
            OnlyParameterizeInvalidUVsUI.Reset();
            if (InputMaterialSettings != null)
            {
                InputMaterialSettings.Reset();
            }

            if (OutputMaterialSettings != null)
            {
                OutputMaterialSettings.Reset();
            }

            if (ChartAggregatorSettings != null)
            {
                ChartAggregatorSettings.Reset();
            }

            if (ParameterizerSettings != null)
            {
                ParameterizerSettings.Reset();
            }

        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            GenerateMappingImageUI.IsEditEnabled = isEditEnabled;
            GenerateTexCoordsUI.IsEditEnabled = isEditEnabled;
            GenerateTangentsUI.IsEditEnabled = isEditEnabled;
            MaximumLayersUI.IsEditEnabled = isEditEnabled;
            UseFullRetexturingUI.IsEditEnabled = isEditEnabled;
            ApplyNewMaterialIdsUI.IsEditEnabled = isEditEnabled;
            AllowTransparencyMappingUI.IsEditEnabled = isEditEnabled;
            TexCoordLevelUI.IsEditEnabled = isEditEnabled;
            TexCoordNameUI.IsEditEnabled = isEditEnabled;
            UseAutomaticTextureSizeUI.IsEditEnabled = isEditEnabled;
            AutomaticTextureSizeMultiplierUI.IsEditEnabled = isEditEnabled;
            ForcePower2TextureUI.IsEditEnabled = isEditEnabled;
            TexCoordGeneratorTypeUI.IsEditEnabled = isEditEnabled;
            OnlyParameterizeInvalidUVsUI.IsEditEnabled = isEditEnabled;
            if (InputMaterialSettings != null)
            {
                InputMaterialSettings.SetEditMode(isEditEnabled);
            }

            if (OutputMaterialSettings != null)
            {
                OutputMaterialSettings.SetEditMode(isEditEnabled);
            }

            if (ChartAggregatorSettings != null)
            {
                ChartAggregatorSettings.SetEditMode(isEditEnabled);
            }

            if (ParameterizerSettings != null)
            {
                ParameterizerSettings.SetEditMode(isEditEnabled);
            }

        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            GenerateMappingImageUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GenerateTexCoordsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GenerateTangentsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseFullRetexturingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ApplyNewMaterialIdsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseAutomaticTextureSizeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            AutomaticTextureSizeMultiplierUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ForcePower2TextureUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OnlyParameterizeInvalidUVsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            AllowTransparencyMappingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MaximumLayersUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TexCoordLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TexCoordNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TexCoordGeneratorTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (ChartAggregatorSettings != null)
            {
                ChartAggregatorSettings.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (ParameterizerSettings != null)
            {
                ParameterizerSettings.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (InputMaterialSettings != null)
            {
                InputMaterialSettings.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (OutputMaterialSettings != null)
            {
                OutputMaterialSettings.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonGlobalSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(DefaultTangentCalculatorTypeUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public ETangentSpaceMethod DefaultTangentCalculatorType { get { return _DefaultTangentCalculatorType; } set { _DefaultTangentCalculatorType = value; OnPropertyChanged(); } }
        private ETangentSpaceMethod _DefaultTangentCalculatorType;
        public SimplygonDefaultTangentCalculatorTypeEx DefaultTangentCalculatorTypeUI { get; set; }
        public class SimplygonDefaultTangentCalculatorTypeEx : SimplygonSettingsProperty
        {
            public SimplygonGlobalSettings Parent { get; set; }
            public ETangentSpaceMethod Value
            {
                get
                {
                    return Parent.DefaultTangentCalculatorType;
                }

                set
                {
                    bool needReload = Parent.DefaultTangentCalculatorType != value;
                    Parent.DefaultTangentCalculatorType = value;
                    OnPropertyChanged();
                }

            }

            public ETangentSpaceMethod DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(ETangentSpaceMethod)); } }

            public SimplygonDefaultTangentCalculatorTypeEx() : base("DefaultTangentCalculatorType")
            {
                Type = "enum";
                HelpText = "";
                TypeOverride = "";
                DefaultValue = ETangentSpaceMethod.MikkTSpace;
                Visible = true;
            }

            public SimplygonDefaultTangentCalculatorTypeEx(dynamic jsonData) : base("DefaultTangentCalculatorType")
            {
                Type = "enum";
                HelpText = "";
                TypeOverride = "";
                DefaultValue = ETangentSpaceMethod.MikkTSpace;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDefaultTangentCalculatorTypeEx DeepCopy()
            {
                return (SimplygonDefaultTangentCalculatorTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DefaultTangentCalculatorType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (ETangentSpaceMethod)value;
            }

        }


        public SimplygonGlobalSettings() : base("GlobalSettings")
        {
            Visible = true;
            DefaultTangentCalculatorTypeUI = new SimplygonDefaultTangentCalculatorTypeEx();
            DefaultTangentCalculatorTypeUI.Parent = this;
            DefaultTangentCalculatorType = DefaultTangentCalculatorTypeUI.DefaultValue;
            Items.Add(DefaultTangentCalculatorTypeUI);
        }

        public SimplygonGlobalSettings(dynamic jsonData) : base("GlobalSettings")
        {
            Visible = true;
            DefaultTangentCalculatorTypeUI = new SimplygonDefaultTangentCalculatorTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DefaultTangentCalculatorTypeUI") != null ? jsonData.DefaultTangentCalculatorTypeUI : null);
            DefaultTangentCalculatorTypeUI.Parent = this;
            DefaultTangentCalculatorType = DefaultTangentCalculatorTypeUI.DefaultValue;
            Items.Add(DefaultTangentCalculatorTypeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonGlobalSettings();
            copy.Items.Clear();
            copy.DefaultTangentCalculatorTypeUI = this.DefaultTangentCalculatorTypeUI.DeepCopy();
            copy.DefaultTangentCalculatorTypeUI.Parent = copy;
            copy.Items.Add(copy.DefaultTangentCalculatorTypeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.DefaultTangentCalculatorType = (int)DefaultTangentCalculatorType;
            if(serializeUIComponents)
            {
                jsonData.DefaultTangentCalculatorTypeUI = DefaultTangentCalculatorTypeUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("DefaultTangentCalculatorType") != null)
            {
                DefaultTangentCalculatorType = (ETangentSpaceMethod)jsonData.DefaultTangentCalculatorType;
            }

        }

        public override void Reset()
        {
            DefaultTangentCalculatorTypeUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            DefaultTangentCalculatorTypeUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            DefaultTangentCalculatorTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonRemeshingSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(RemeshingModeManualPositionZUI.Visible) return true;
                if(RemeshingModeManualPositionYUI.Visible) return true;
                if(RemeshingModeManualPositionXUI.Visible) return true;
                if(OnScreenSizeUI.Visible) return true;
                if(HoleFillingUI.Visible) return true;
                if(RemeshingModeUI.Visible) return true;
                if(SurfaceTransferModeUI.Visible) return true;
                if(HardEdgeAngleUI.Visible) return true;
                if(ForceSoftEdgesWithinTextureChartsUI.Visible) return true;
                if(TransferNormalsUI.Visible) return true;
                if(TransferColorsUI.Visible) return true;
                if(KeepUnprocessedSceneMeshesUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public float RemeshingModeManualPositionZ { get { return _RemeshingModeManualPositionZ; } set { _RemeshingModeManualPositionZ = value; OnPropertyChanged(); } }
        private float _RemeshingModeManualPositionZ;
        public SimplygonRemeshingModeManualPositionZEx RemeshingModeManualPositionZUI { get; set; }
        public class SimplygonRemeshingModeManualPositionZEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.RemeshingModeManualPositionZ;
                }

                set
                {
                    bool needReload = Parent.RemeshingModeManualPositionZ != value;
                    Parent.RemeshingModeManualPositionZ = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonRemeshingModeManualPositionZEx() : base("RemeshingModeManualPositionZ")
            {
                Type = "real";
                HelpText = "Z component was a 3-tuple real that acts as the marker designating remeshing processors starting position";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -3.402823E+38f;
                MaxValue = 3.402823E+38f;
                DefaultMinValue = -3.402823E+38f;
                DefaultMaxValue = 3.402823E+38f;
                TicksFrequencyValue = 10f;
                Visible = true;
            }

            public SimplygonRemeshingModeManualPositionZEx(dynamic jsonData) : base("RemeshingModeManualPositionZ")
            {
                Type = "real";
                HelpText = "Z component was a 3-tuple real that acts as the marker designating remeshing processors starting position";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -3.402823E+38f;
                DefaultMinValue = -3.402823E+38f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionZ: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 3.402823E+38f;
                DefaultMaxValue = 3.402823E+38f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionZ: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRemeshingModeManualPositionZEx DeepCopy()
            {
                return (SimplygonRemeshingModeManualPositionZEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.RemeshingModeManualPositionZ;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float RemeshingModeManualPositionY { get { return _RemeshingModeManualPositionY; } set { _RemeshingModeManualPositionY = value; OnPropertyChanged(); } }
        private float _RemeshingModeManualPositionY;
        public SimplygonRemeshingModeManualPositionYEx RemeshingModeManualPositionYUI { get; set; }
        public class SimplygonRemeshingModeManualPositionYEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.RemeshingModeManualPositionY;
                }

                set
                {
                    bool needReload = Parent.RemeshingModeManualPositionY != value;
                    Parent.RemeshingModeManualPositionY = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonRemeshingModeManualPositionYEx() : base("RemeshingModeManualPositionY")
            {
                Type = "real";
                HelpText = "Y component was a 3-tuple real that acts as the marker designating remeshing processors starting position";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -3.402823E+38f;
                MaxValue = 3.402823E+38f;
                DefaultMinValue = -3.402823E+38f;
                DefaultMaxValue = 3.402823E+38f;
                TicksFrequencyValue = 10f;
                Visible = true;
            }

            public SimplygonRemeshingModeManualPositionYEx(dynamic jsonData) : base("RemeshingModeManualPositionY")
            {
                Type = "real";
                HelpText = "Y component was a 3-tuple real that acts as the marker designating remeshing processors starting position";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -3.402823E+38f;
                DefaultMinValue = -3.402823E+38f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionY: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 3.402823E+38f;
                DefaultMaxValue = 3.402823E+38f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionY: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRemeshingModeManualPositionYEx DeepCopy()
            {
                return (SimplygonRemeshingModeManualPositionYEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.RemeshingModeManualPositionY;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float RemeshingModeManualPositionX { get { return _RemeshingModeManualPositionX; } set { _RemeshingModeManualPositionX = value; OnPropertyChanged(); } }
        private float _RemeshingModeManualPositionX;
        public SimplygonRemeshingModeManualPositionXEx RemeshingModeManualPositionXUI { get; set; }
        public class SimplygonRemeshingModeManualPositionXEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.RemeshingModeManualPositionX;
                }

                set
                {
                    bool needReload = Parent.RemeshingModeManualPositionX != value;
                    Parent.RemeshingModeManualPositionX = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonRemeshingModeManualPositionXEx() : base("RemeshingModeManualPositionX")
            {
                Type = "real";
                HelpText = "X component was a 3-tuple real that acts as the marker designating remeshing processors starting position";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -3.402823E+38f;
                MaxValue = 3.402823E+38f;
                DefaultMinValue = -3.402823E+38f;
                DefaultMaxValue = 3.402823E+38f;
                TicksFrequencyValue = 10f;
                Visible = true;
            }

            public SimplygonRemeshingModeManualPositionXEx(dynamic jsonData) : base("RemeshingModeManualPositionX")
            {
                Type = "real";
                HelpText = "X component was a 3-tuple real that acts as the marker designating remeshing processors starting position";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -3.402823E+38f;
                DefaultMinValue = -3.402823E+38f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionX: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 3.402823E+38f;
                DefaultMaxValue = 3.402823E+38f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionX: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRemeshingModeManualPositionXEx DeepCopy()
            {
                return (SimplygonRemeshingModeManualPositionXEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.RemeshingModeManualPositionX;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int OnScreenSize { get { return _OnScreenSize; } set { _OnScreenSize = value; OnPropertyChanged(); } }
        private int _OnScreenSize;
        public SimplygonOnScreenSizeEx OnScreenSizeUI { get; set; }
        public class SimplygonOnScreenSizeEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.OnScreenSize;
                }

                set
                {
                    bool needReload = Parent.OnScreenSize != value;
                    Parent.OnScreenSize = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonOnScreenSizeEx() : base("OnScreenSize")
            {
                Type = "uint";
                HelpText = "The on-screen rendering size of the geometry. Allowed values are in the range 20 to 10000 pixels.";
                TypeOverride = "";
                DefaultValue = 300;
                MinValue = 20;
                MaxValue = 10000;
                DefaultMinValue = 20;
                DefaultMaxValue = 10000;
                TicksFrequencyValue = 10;
                Visible = true;
            }

            public SimplygonOnScreenSizeEx(dynamic jsonData) : base("OnScreenSize")
            {
                Type = "uint";
                HelpText = "The on-screen rendering size of the geometry. Allowed values are in the range 20 to 10000 pixels.";
                TypeOverride = "";
                DefaultValue = 300;
                MinValue = 20;
                DefaultMinValue = 20;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenSize: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10000;
                DefaultMaxValue = 10000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenSize: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOnScreenSizeEx DeepCopy()
            {
                return (SimplygonOnScreenSizeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.OnScreenSize;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EHoleFilling HoleFilling { get { return _HoleFilling; } set { _HoleFilling = value; OnPropertyChanged(); } }
        private EHoleFilling _HoleFilling;
        public SimplygonHoleFillingEx HoleFillingUI { get; set; }
        public class SimplygonHoleFillingEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public EHoleFilling Value
            {
                get
                {
                    return Parent.HoleFilling;
                }

                set
                {
                    bool needReload = Parent.HoleFilling != value;
                    Parent.HoleFilling = value;
                    OnPropertyChanged();
                }

            }

            public EHoleFilling DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EHoleFilling)); } }

            public SimplygonHoleFillingEx() : base("HoleFilling")
            {
                Type = "enum";
                HelpText = "HoleFilling defines how aggressively the remesher will fill holes and cavities. What this does is to measure the volume and hole opening sizes of concavities in the input geometry and fill them in in the remeshing if the concavity is large enough with a small enough opening. This removes a lot of unnecessary geometry and is recommended to be kept at it's default rather than turning it off, it will in the vast majority of cases have a positive effect on the result.";
                TypeOverride = "";
                DefaultValue = EHoleFilling.Low;
                Visible = true;
            }

            public SimplygonHoleFillingEx(dynamic jsonData) : base("HoleFilling")
            {
                Type = "enum";
                HelpText = "HoleFilling defines how aggressively the remesher will fill holes and cavities. What this does is to measure the volume and hole opening sizes of concavities in the input geometry and fill them in in the remeshing if the concavity is large enough with a small enough opening. This removes a lot of unnecessary geometry and is recommended to be kept at it's default rather than turning it off, it will in the vast majority of cases have a positive effect on the result.";
                TypeOverride = "";
                DefaultValue = EHoleFilling.Low;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonHoleFillingEx DeepCopy()
            {
                return (SimplygonHoleFillingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.HoleFilling;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EHoleFilling)value;
            }

        }

        public ERemeshingMode RemeshingMode { get { return _RemeshingMode; } set { _RemeshingMode = value; OnPropertyChanged(); } }
        private ERemeshingMode _RemeshingMode;
        public SimplygonRemeshingModeEx RemeshingModeUI { get; set; }
        public class SimplygonRemeshingModeEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public ERemeshingMode Value
            {
                get
                {
                    return Parent.RemeshingMode;
                }

                set
                {
                    bool needReload = Parent.RemeshingMode != value;
                    Parent.RemeshingMode = value;
                    OnPropertyChanged();
                }

            }

            public ERemeshingMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(ERemeshingMode)); } }

            public SimplygonRemeshingModeEx() : base("RemeshingMode")
            {
                Type = "enum";
                HelpText = "The remeshing mode, options are Outside, Inside and Manual. RemeshingMode defines if the remeshing processor remeshes the outside or the inside of the input geometry. Manual needs the user to define a position in space that will be considered as outside for the purposes of the remeshing. Position is set with RemeshingModeManualPosition. Hole filling only works with the mode Outside.";
                TypeOverride = "";
                DefaultValue = ERemeshingMode.Outside;
                Visible = true;
            }

            public SimplygonRemeshingModeEx(dynamic jsonData) : base("RemeshingMode")
            {
                Type = "enum";
                HelpText = "The remeshing mode, options are Outside, Inside and Manual. RemeshingMode defines if the remeshing processor remeshes the outside or the inside of the input geometry. Manual needs the user to define a position in space that will be considered as outside for the purposes of the remeshing. Position is set with RemeshingModeManualPosition. Hole filling only works with the mode Outside.";
                TypeOverride = "";
                DefaultValue = ERemeshingMode.Outside;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRemeshingModeEx DeepCopy()
            {
                return (SimplygonRemeshingModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.RemeshingMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (ERemeshingMode)value;
            }

        }

        public ESurfaceTransferMode SurfaceTransferMode { get { return _SurfaceTransferMode; } set { _SurfaceTransferMode = value; OnPropertyChanged(); } }
        private ESurfaceTransferMode _SurfaceTransferMode;
        public SimplygonSurfaceTransferModeEx SurfaceTransferModeUI { get; set; }
        public class SimplygonSurfaceTransferModeEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public ESurfaceTransferMode Value
            {
                get
                {
                    return Parent.SurfaceTransferMode;
                }

                set
                {
                    bool needReload = Parent.SurfaceTransferMode != value;
                    Parent.SurfaceTransferMode = value;
                    OnPropertyChanged();
                }

            }

            public ESurfaceTransferMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(ESurfaceTransferMode)); } }

            public SimplygonSurfaceTransferModeEx() : base("SurfaceTransferMode")
            {
                Type = "enum";
                HelpText = "The surface transfer mode.";
                TypeOverride = "";
                DefaultValue = ESurfaceTransferMode.Accurate;
                Visible = true;
            }

            public SimplygonSurfaceTransferModeEx(dynamic jsonData) : base("SurfaceTransferMode")
            {
                Type = "enum";
                HelpText = "The surface transfer mode.";
                TypeOverride = "";
                DefaultValue = ESurfaceTransferMode.Accurate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSurfaceTransferModeEx DeepCopy()
            {
                return (SimplygonSurfaceTransferModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.SurfaceTransferMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (ESurfaceTransferMode)value;
            }

        }

        public float HardEdgeAngle { get { return _HardEdgeAngle; } set { _HardEdgeAngle = value; OnPropertyChanged(); } }
        private float _HardEdgeAngle;
        public SimplygonHardEdgeAngleEx HardEdgeAngleUI { get; set; }
        public class SimplygonHardEdgeAngleEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.HardEdgeAngle;
                }

                set
                {
                    bool needReload = Parent.HardEdgeAngle != value;
                    Parent.HardEdgeAngle = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonHardEdgeAngleEx() : base("HardEdgeAngle")
            {
                Type = "real";
                HelpText = "The normal hard angle cutoff in degrees.";
                TypeOverride = "";
                DefaultValue = 75f;
                MinValue = 0f;
                MaxValue = 180f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 180f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonHardEdgeAngleEx(dynamic jsonData) : base("HardEdgeAngle")
            {
                Type = "real";
                HelpText = "The normal hard angle cutoff in degrees.";
                TypeOverride = "";
                DefaultValue = 75f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"HardEdgeAngle: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 180f;
                DefaultMaxValue = 180f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"HardEdgeAngle: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonHardEdgeAngleEx DeepCopy()
            {
                return (SimplygonHardEdgeAngleEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.HardEdgeAngle;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool ForceSoftEdgesWithinTextureCharts { get { return _ForceSoftEdgesWithinTextureCharts; } set { _ForceSoftEdgesWithinTextureCharts = value; OnPropertyChanged(); } }
        private bool _ForceSoftEdgesWithinTextureCharts;
        public SimplygonForceSoftEdgesWithinTextureChartsEx ForceSoftEdgesWithinTextureChartsUI { get; set; }
        public class SimplygonForceSoftEdgesWithinTextureChartsEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.ForceSoftEdgesWithinTextureCharts;
                }

                set
                {
                    bool needReload = Parent.ForceSoftEdgesWithinTextureCharts != value;
                    Parent.ForceSoftEdgesWithinTextureCharts = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonForceSoftEdgesWithinTextureChartsEx() : base("ForceSoftEdgesWithinTextureCharts")
            {
                Type = "bool";
                HelpText = "If the flag is set, the normal calculation will only allow hard edges along texture borders. Any vertex normal within a texture chart (not along the border) will be forced soft. Caveat: If this is enabled, some normals might be highly interpolated, and deviate substantially from the triangle normal.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonForceSoftEdgesWithinTextureChartsEx(dynamic jsonData) : base("ForceSoftEdgesWithinTextureCharts")
            {
                Type = "bool";
                HelpText = "If the flag is set, the normal calculation will only allow hard edges along texture borders. Any vertex normal within a texture chart (not along the border) will be forced soft. Caveat: If this is enabled, some normals might be highly interpolated, and deviate substantially from the triangle normal.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonForceSoftEdgesWithinTextureChartsEx DeepCopy()
            {
                return (SimplygonForceSoftEdgesWithinTextureChartsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.ForceSoftEdgesWithinTextureCharts;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool TransferNormals { get { return _TransferNormals; } set { _TransferNormals = value; OnPropertyChanged(); } }
        private bool _TransferNormals;
        public SimplygonTransferNormalsEx TransferNormalsUI { get; set; }
        public class SimplygonTransferNormalsEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.TransferNormals;
                }

                set
                {
                    bool needReload = Parent.TransferNormals != value;
                    Parent.TransferNormals = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonTransferNormalsEx() : base("TransferNormals")
            {
                Type = "bool";
                HelpText = "If set, the vertex normals channel will be sampled from the original mesh.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonTransferNormalsEx(dynamic jsonData) : base("TransferNormals")
            {
                Type = "bool";
                HelpText = "If set, the vertex normals channel will be sampled from the original mesh.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTransferNormalsEx DeepCopy()
            {
                return (SimplygonTransferNormalsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.TransferNormals;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool TransferColors { get { return _TransferColors; } set { _TransferColors = value; OnPropertyChanged(); } }
        private bool _TransferColors;
        public SimplygonTransferColorsEx TransferColorsUI { get; set; }
        public class SimplygonTransferColorsEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.TransferColors;
                }

                set
                {
                    bool needReload = Parent.TransferColors != value;
                    Parent.TransferColors = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonTransferColorsEx() : base("TransferColors")
            {
                Type = "bool";
                HelpText = "If set, vertex color channels will be sampled from the original mesh.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonTransferColorsEx(dynamic jsonData) : base("TransferColors")
            {
                Type = "bool";
                HelpText = "If set, vertex color channels will be sampled from the original mesh.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTransferColorsEx DeepCopy()
            {
                return (SimplygonTransferColorsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.TransferColors;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool KeepUnprocessedSceneMeshes { get { return _KeepUnprocessedSceneMeshes; } set { _KeepUnprocessedSceneMeshes = value; OnPropertyChanged(); } }
        private bool _KeepUnprocessedSceneMeshes;
        public SimplygonKeepUnprocessedSceneMeshesEx KeepUnprocessedSceneMeshesUI { get; set; }
        public class SimplygonKeepUnprocessedSceneMeshesEx : SimplygonSettingsProperty
        {
            public SimplygonRemeshingSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.KeepUnprocessedSceneMeshes;
                }

                set
                {
                    bool needReload = Parent.KeepUnprocessedSceneMeshes != value;
                    Parent.KeepUnprocessedSceneMeshes = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonKeepUnprocessedSceneMeshesEx() : base("KeepUnprocessedSceneMeshes")
            {
                Type = "bool";
                HelpText = "If false, the processor will remove all geometry and scene nodes which was not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated. If old nodes are kept and a new geometry is added to the scene, it will always be the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonKeepUnprocessedSceneMeshesEx(dynamic jsonData) : base("KeepUnprocessedSceneMeshes")
            {
                Type = "bool";
                HelpText = "If false, the processor will remove all geometry and scene nodes which was not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated. If old nodes are kept and a new geometry is added to the scene, it will always be the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonKeepUnprocessedSceneMeshesEx DeepCopy()
            {
                return (SimplygonKeepUnprocessedSceneMeshesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.KeepUnprocessedSceneMeshes;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonRemeshingSettings() : base("RemeshingSettings")
        {
            Visible = true;
            RemeshingModeManualPositionZUI = new SimplygonRemeshingModeManualPositionZEx();
            RemeshingModeManualPositionZUI.Parent = this;
            RemeshingModeManualPositionZ = RemeshingModeManualPositionZUI.DefaultValue;
            Items.Add(RemeshingModeManualPositionZUI);
            RemeshingModeManualPositionYUI = new SimplygonRemeshingModeManualPositionYEx();
            RemeshingModeManualPositionYUI.Parent = this;
            RemeshingModeManualPositionY = RemeshingModeManualPositionYUI.DefaultValue;
            Items.Add(RemeshingModeManualPositionYUI);
            RemeshingModeManualPositionXUI = new SimplygonRemeshingModeManualPositionXEx();
            RemeshingModeManualPositionXUI.Parent = this;
            RemeshingModeManualPositionX = RemeshingModeManualPositionXUI.DefaultValue;
            Items.Add(RemeshingModeManualPositionXUI);
            OnScreenSizeUI = new SimplygonOnScreenSizeEx();
            OnScreenSizeUI.Parent = this;
            OnScreenSize = OnScreenSizeUI.DefaultValue;
            Items.Add(OnScreenSizeUI);
            HoleFillingUI = new SimplygonHoleFillingEx();
            HoleFillingUI.Parent = this;
            HoleFilling = HoleFillingUI.DefaultValue;
            Items.Add(HoleFillingUI);
            RemeshingModeUI = new SimplygonRemeshingModeEx();
            RemeshingModeUI.Parent = this;
            RemeshingMode = RemeshingModeUI.DefaultValue;
            Items.Add(RemeshingModeUI);
            SurfaceTransferModeUI = new SimplygonSurfaceTransferModeEx();
            SurfaceTransferModeUI.Parent = this;
            SurfaceTransferMode = SurfaceTransferModeUI.DefaultValue;
            Items.Add(SurfaceTransferModeUI);
            HardEdgeAngleUI = new SimplygonHardEdgeAngleEx();
            HardEdgeAngleUI.Parent = this;
            HardEdgeAngle = HardEdgeAngleUI.DefaultValue;
            Items.Add(HardEdgeAngleUI);
            TransferNormalsUI = new SimplygonTransferNormalsEx();
            TransferNormalsUI.Parent = this;
            TransferNormals = TransferNormalsUI.DefaultValue;
            Items.Add(TransferNormalsUI);
            TransferColorsUI = new SimplygonTransferColorsEx();
            TransferColorsUI.Parent = this;
            TransferColors = TransferColorsUI.DefaultValue;
            Items.Add(TransferColorsUI);
            ForceSoftEdgesWithinTextureChartsUI = new SimplygonForceSoftEdgesWithinTextureChartsEx();
            ForceSoftEdgesWithinTextureChartsUI.Parent = this;
            ForceSoftEdgesWithinTextureCharts = ForceSoftEdgesWithinTextureChartsUI.DefaultValue;
            Items.Add(ForceSoftEdgesWithinTextureChartsUI);
            KeepUnprocessedSceneMeshesUI = new SimplygonKeepUnprocessedSceneMeshesEx();
            KeepUnprocessedSceneMeshesUI.Parent = this;
            KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshesUI.DefaultValue;
            Items.Add(KeepUnprocessedSceneMeshesUI);
        }

        public SimplygonRemeshingSettings(dynamic jsonData) : base("RemeshingSettings")
        {
            Visible = true;
            RemeshingModeManualPositionZUI = new SimplygonRemeshingModeManualPositionZEx(jsonData != null && ((JObject)jsonData).GetValue("RemeshingModeManualPositionZUI") != null ? jsonData.RemeshingModeManualPositionZUI : null);
            RemeshingModeManualPositionZUI.Parent = this;
            RemeshingModeManualPositionZ = RemeshingModeManualPositionZUI.DefaultValue;
            Items.Add(RemeshingModeManualPositionZUI);
            RemeshingModeManualPositionYUI = new SimplygonRemeshingModeManualPositionYEx(jsonData != null && ((JObject)jsonData).GetValue("RemeshingModeManualPositionYUI") != null ? jsonData.RemeshingModeManualPositionYUI : null);
            RemeshingModeManualPositionYUI.Parent = this;
            RemeshingModeManualPositionY = RemeshingModeManualPositionYUI.DefaultValue;
            Items.Add(RemeshingModeManualPositionYUI);
            RemeshingModeManualPositionXUI = new SimplygonRemeshingModeManualPositionXEx(jsonData != null && ((JObject)jsonData).GetValue("RemeshingModeManualPositionXUI") != null ? jsonData.RemeshingModeManualPositionXUI : null);
            RemeshingModeManualPositionXUI.Parent = this;
            RemeshingModeManualPositionX = RemeshingModeManualPositionXUI.DefaultValue;
            Items.Add(RemeshingModeManualPositionXUI);
            OnScreenSizeUI = new SimplygonOnScreenSizeEx(jsonData != null && ((JObject)jsonData).GetValue("OnScreenSizeUI") != null ? jsonData.OnScreenSizeUI : null);
            OnScreenSizeUI.Parent = this;
            OnScreenSize = OnScreenSizeUI.DefaultValue;
            Items.Add(OnScreenSizeUI);
            HoleFillingUI = new SimplygonHoleFillingEx(jsonData != null && ((JObject)jsonData).GetValue("HoleFillingUI") != null ? jsonData.HoleFillingUI : null);
            HoleFillingUI.Parent = this;
            HoleFilling = HoleFillingUI.DefaultValue;
            Items.Add(HoleFillingUI);
            RemeshingModeUI = new SimplygonRemeshingModeEx(jsonData != null && ((JObject)jsonData).GetValue("RemeshingModeUI") != null ? jsonData.RemeshingModeUI : null);
            RemeshingModeUI.Parent = this;
            RemeshingMode = RemeshingModeUI.DefaultValue;
            Items.Add(RemeshingModeUI);
            SurfaceTransferModeUI = new SimplygonSurfaceTransferModeEx(jsonData != null && ((JObject)jsonData).GetValue("SurfaceTransferModeUI") != null ? jsonData.SurfaceTransferModeUI : null);
            SurfaceTransferModeUI.Parent = this;
            SurfaceTransferMode = SurfaceTransferModeUI.DefaultValue;
            Items.Add(SurfaceTransferModeUI);
            HardEdgeAngleUI = new SimplygonHardEdgeAngleEx(jsonData != null && ((JObject)jsonData).GetValue("HardEdgeAngleUI") != null ? jsonData.HardEdgeAngleUI : null);
            HardEdgeAngleUI.Parent = this;
            HardEdgeAngle = HardEdgeAngleUI.DefaultValue;
            Items.Add(HardEdgeAngleUI);
            TransferNormalsUI = new SimplygonTransferNormalsEx(jsonData != null && ((JObject)jsonData).GetValue("TransferNormalsUI") != null ? jsonData.TransferNormalsUI : null);
            TransferNormalsUI.Parent = this;
            TransferNormals = TransferNormalsUI.DefaultValue;
            Items.Add(TransferNormalsUI);
            TransferColorsUI = new SimplygonTransferColorsEx(jsonData != null && ((JObject)jsonData).GetValue("TransferColorsUI") != null ? jsonData.TransferColorsUI : null);
            TransferColorsUI.Parent = this;
            TransferColors = TransferColorsUI.DefaultValue;
            Items.Add(TransferColorsUI);
            ForceSoftEdgesWithinTextureChartsUI = new SimplygonForceSoftEdgesWithinTextureChartsEx(jsonData != null && ((JObject)jsonData).GetValue("ForceSoftEdgesWithinTextureChartsUI") != null ? jsonData.ForceSoftEdgesWithinTextureChartsUI : null);
            ForceSoftEdgesWithinTextureChartsUI.Parent = this;
            ForceSoftEdgesWithinTextureCharts = ForceSoftEdgesWithinTextureChartsUI.DefaultValue;
            Items.Add(ForceSoftEdgesWithinTextureChartsUI);
            KeepUnprocessedSceneMeshesUI = new SimplygonKeepUnprocessedSceneMeshesEx(jsonData != null && ((JObject)jsonData).GetValue("KeepUnprocessedSceneMeshesUI") != null ? jsonData.KeepUnprocessedSceneMeshesUI : null);
            KeepUnprocessedSceneMeshesUI.Parent = this;
            KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshesUI.DefaultValue;
            Items.Add(KeepUnprocessedSceneMeshesUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonRemeshingSettings();
            copy.Items.Clear();
            copy.RemeshingModeManualPositionZUI = this.RemeshingModeManualPositionZUI.DeepCopy();
            copy.RemeshingModeManualPositionZUI.Parent = copy;
            copy.Items.Add(copy.RemeshingModeManualPositionZUI);
            copy.RemeshingModeManualPositionYUI = this.RemeshingModeManualPositionYUI.DeepCopy();
            copy.RemeshingModeManualPositionYUI.Parent = copy;
            copy.Items.Add(copy.RemeshingModeManualPositionYUI);
            copy.RemeshingModeManualPositionXUI = this.RemeshingModeManualPositionXUI.DeepCopy();
            copy.RemeshingModeManualPositionXUI.Parent = copy;
            copy.Items.Add(copy.RemeshingModeManualPositionXUI);
            copy.OnScreenSizeUI = this.OnScreenSizeUI.DeepCopy();
            copy.OnScreenSizeUI.Parent = copy;
            copy.Items.Add(copy.OnScreenSizeUI);
            copy.HoleFillingUI = this.HoleFillingUI.DeepCopy();
            copy.HoleFillingUI.Parent = copy;
            copy.Items.Add(copy.HoleFillingUI);
            copy.RemeshingModeUI = this.RemeshingModeUI.DeepCopy();
            copy.RemeshingModeUI.Parent = copy;
            copy.Items.Add(copy.RemeshingModeUI);
            copy.SurfaceTransferModeUI = this.SurfaceTransferModeUI.DeepCopy();
            copy.SurfaceTransferModeUI.Parent = copy;
            copy.Items.Add(copy.SurfaceTransferModeUI);
            copy.HardEdgeAngleUI = this.HardEdgeAngleUI.DeepCopy();
            copy.HardEdgeAngleUI.Parent = copy;
            copy.Items.Add(copy.HardEdgeAngleUI);
            copy.TransferNormalsUI = this.TransferNormalsUI.DeepCopy();
            copy.TransferNormalsUI.Parent = copy;
            copy.Items.Add(copy.TransferNormalsUI);
            copy.TransferColorsUI = this.TransferColorsUI.DeepCopy();
            copy.TransferColorsUI.Parent = copy;
            copy.Items.Add(copy.TransferColorsUI);
            copy.ForceSoftEdgesWithinTextureChartsUI = this.ForceSoftEdgesWithinTextureChartsUI.DeepCopy();
            copy.ForceSoftEdgesWithinTextureChartsUI.Parent = copy;
            copy.Items.Add(copy.ForceSoftEdgesWithinTextureChartsUI);
            copy.KeepUnprocessedSceneMeshesUI = this.KeepUnprocessedSceneMeshesUI.DeepCopy();
            copy.KeepUnprocessedSceneMeshesUI.Parent = copy;
            copy.Items.Add(copy.KeepUnprocessedSceneMeshesUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.RemeshingModeManualPositionZ = RemeshingModeManualPositionZ;
            if(serializeUIComponents)
            {
                jsonData.RemeshingModeManualPositionZUI = RemeshingModeManualPositionZUI.SaveJson();
            }

            jsonData.RemeshingModeManualPositionY = RemeshingModeManualPositionY;
            if(serializeUIComponents)
            {
                jsonData.RemeshingModeManualPositionYUI = RemeshingModeManualPositionYUI.SaveJson();
            }

            jsonData.RemeshingModeManualPositionX = RemeshingModeManualPositionX;
            if(serializeUIComponents)
            {
                jsonData.RemeshingModeManualPositionXUI = RemeshingModeManualPositionXUI.SaveJson();
            }

            jsonData.OnScreenSize = OnScreenSize;
            if(serializeUIComponents)
            {
                jsonData.OnScreenSizeUI = OnScreenSizeUI.SaveJson();
            }

            jsonData.HoleFilling = (int)HoleFilling;
            if(serializeUIComponents)
            {
                jsonData.HoleFillingUI = HoleFillingUI.SaveJson();
            }

            jsonData.RemeshingMode = (int)RemeshingMode;
            if(serializeUIComponents)
            {
                jsonData.RemeshingModeUI = RemeshingModeUI.SaveJson();
            }

            jsonData.SurfaceTransferMode = (int)SurfaceTransferMode;
            if(serializeUIComponents)
            {
                jsonData.SurfaceTransferModeUI = SurfaceTransferModeUI.SaveJson();
            }

            jsonData.HardEdgeAngle = HardEdgeAngle;
            if(serializeUIComponents)
            {
                jsonData.HardEdgeAngleUI = HardEdgeAngleUI.SaveJson();
            }

            jsonData.ForceSoftEdgesWithinTextureCharts = ForceSoftEdgesWithinTextureCharts;
            if(serializeUIComponents)
            {
                jsonData.ForceSoftEdgesWithinTextureChartsUI = ForceSoftEdgesWithinTextureChartsUI.SaveJson();
            }

            jsonData.TransferNormals = TransferNormals;
            if(serializeUIComponents)
            {
                jsonData.TransferNormalsUI = TransferNormalsUI.SaveJson();
            }

            jsonData.TransferColors = TransferColors;
            if(serializeUIComponents)
            {
                jsonData.TransferColorsUI = TransferColorsUI.SaveJson();
            }

            jsonData.KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshes;
            if(serializeUIComponents)
            {
                jsonData.KeepUnprocessedSceneMeshesUI = KeepUnprocessedSceneMeshesUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("RemeshingModeManualPositionZ") != null)
            {
                float newRemeshingModeManualPositionZ = (float)jsonData.RemeshingModeManualPositionZ;
                if (newRemeshingModeManualPositionZ >= RemeshingModeManualPositionZUI.DefaultMinValue && newRemeshingModeManualPositionZ <= RemeshingModeManualPositionZUI.DefaultMaxValue)
                {
                    RemeshingModeManualPositionZ = newRemeshingModeManualPositionZ;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionZ: Invalid value {newRemeshingModeManualPositionZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {RemeshingModeManualPositionZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("RemeshingModeManualPositionY") != null)
            {
                float newRemeshingModeManualPositionY = (float)jsonData.RemeshingModeManualPositionY;
                if (newRemeshingModeManualPositionY >= RemeshingModeManualPositionYUI.DefaultMinValue && newRemeshingModeManualPositionY <= RemeshingModeManualPositionYUI.DefaultMaxValue)
                {
                    RemeshingModeManualPositionY = newRemeshingModeManualPositionY;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionY: Invalid value {newRemeshingModeManualPositionY.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {RemeshingModeManualPositionY.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("RemeshingModeManualPositionX") != null)
            {
                float newRemeshingModeManualPositionX = (float)jsonData.RemeshingModeManualPositionX;
                if (newRemeshingModeManualPositionX >= RemeshingModeManualPositionXUI.DefaultMinValue && newRemeshingModeManualPositionX <= RemeshingModeManualPositionXUI.DefaultMaxValue)
                {
                    RemeshingModeManualPositionX = newRemeshingModeManualPositionX;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"RemeshingModeManualPositionX: Invalid value {newRemeshingModeManualPositionX.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {RemeshingModeManualPositionX.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OnScreenSize") != null)
            {
                var newOnScreenSize = (int)jsonData.OnScreenSize;
                if (newOnScreenSize >= OnScreenSizeUI.DefaultMinValue && newOnScreenSize <= OnScreenSizeUI.DefaultMaxValue)
                {
                    OnScreenSize = newOnScreenSize;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenSize: Invalid value {newOnScreenSize}, using default value {OnScreenSize.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("HoleFilling") != null)
            {
                HoleFilling = (EHoleFilling)jsonData.HoleFilling;
            }

            if(jsonData.GetValue("RemeshingMode") != null)
            {
                RemeshingMode = (ERemeshingMode)jsonData.RemeshingMode;
            }

            if(jsonData.GetValue("SurfaceTransferMode") != null)
            {
                SurfaceTransferMode = (ESurfaceTransferMode)jsonData.SurfaceTransferMode;
            }

            if(jsonData.GetValue("HardEdgeAngle") != null)
            {
                float newHardEdgeAngle = (float)jsonData.HardEdgeAngle;
                if (newHardEdgeAngle >= HardEdgeAngleUI.DefaultMinValue && newHardEdgeAngle <= HardEdgeAngleUI.DefaultMaxValue)
                {
                    HardEdgeAngle = newHardEdgeAngle;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"HardEdgeAngle: Invalid value {newHardEdgeAngle.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {HardEdgeAngle.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ForceSoftEdgesWithinTextureCharts") != null)
            {
                ForceSoftEdgesWithinTextureCharts = (bool)jsonData.ForceSoftEdgesWithinTextureCharts;
            }

            if(jsonData.GetValue("TransferNormals") != null)
            {
                TransferNormals = (bool)jsonData.TransferNormals;
            }

            if(jsonData.GetValue("TransferColors") != null)
            {
                TransferColors = (bool)jsonData.TransferColors;
            }

            if(jsonData.GetValue("KeepUnprocessedSceneMeshes") != null)
            {
                KeepUnprocessedSceneMeshes = (bool)jsonData.KeepUnprocessedSceneMeshes;
            }

        }

        public override void Reset()
        {
            RemeshingModeManualPositionZUI.Reset();
            RemeshingModeManualPositionYUI.Reset();
            RemeshingModeManualPositionXUI.Reset();
            OnScreenSizeUI.Reset();
            HoleFillingUI.Reset();
            RemeshingModeUI.Reset();
            SurfaceTransferModeUI.Reset();
            HardEdgeAngleUI.Reset();
            ForceSoftEdgesWithinTextureChartsUI.Reset();
            TransferNormalsUI.Reset();
            TransferColorsUI.Reset();
            KeepUnprocessedSceneMeshesUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            RemeshingModeManualPositionZUI.IsEditEnabled = isEditEnabled;
            RemeshingModeManualPositionYUI.IsEditEnabled = isEditEnabled;
            RemeshingModeManualPositionXUI.IsEditEnabled = isEditEnabled;
            OnScreenSizeUI.IsEditEnabled = isEditEnabled;
            HoleFillingUI.IsEditEnabled = isEditEnabled;
            RemeshingModeUI.IsEditEnabled = isEditEnabled;
            SurfaceTransferModeUI.IsEditEnabled = isEditEnabled;
            HardEdgeAngleUI.IsEditEnabled = isEditEnabled;
            ForceSoftEdgesWithinTextureChartsUI.IsEditEnabled = isEditEnabled;
            TransferNormalsUI.IsEditEnabled = isEditEnabled;
            TransferColorsUI.IsEditEnabled = isEditEnabled;
            KeepUnprocessedSceneMeshesUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            RemeshingModeManualPositionZUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RemeshingModeManualPositionYUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RemeshingModeManualPositionXUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OnScreenSizeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            HoleFillingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RemeshingModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SurfaceTransferModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            HardEdgeAngleUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TransferNormalsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TransferColorsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ForceSoftEdgesWithinTextureChartsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            KeepUnprocessedSceneMeshesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonGeometryCullingSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(UseClippingGeometryUI.Visible) return true;
                if(ClippingGeometrySelectionSetNameUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool UseClippingGeometry { get { return _UseClippingGeometry; } set { _UseClippingGeometry = value; OnPropertyChanged(); } }
        private bool _UseClippingGeometry;
        public SimplygonUseClippingGeometryEx UseClippingGeometryUI { get; set; }
        public class SimplygonUseClippingGeometryEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryCullingSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseClippingGeometry;
                }

                set
                {
                    bool needReload = Parent.UseClippingGeometry != value;
                    Parent.UseClippingGeometry = value;
                    Parent.ClippingGeometrySelectionSetNameUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseClippingGeometryEx() : base("UseClippingGeometry")
            {
                Type = "bool";
                HelpText = "If set, the geometries defined in the matching selection set will be used to clip the process geometry. What side of the geometry that will be culled is determined by the triangle facing, so make sure your winding is correct and that triangles point 'up' toward the space you want to keep. Inconsistent triangle winding or meshes that do not have a clear local inside and outside will cause inconsistent results when used as clipping geometries.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseClippingGeometryEx(dynamic jsonData) : base("UseClippingGeometry")
            {
                Type = "bool";
                HelpText = "If set, the geometries defined in the matching selection set will be used to clip the process geometry. What side of the geometry that will be culled is determined by the triangle facing, so make sure your winding is correct and that triangles point 'up' toward the space you want to keep. Inconsistent triangle winding or meshes that do not have a clear local inside and outside will cause inconsistent results when used as clipping geometries.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseClippingGeometryEx DeepCopy()
            {
                return (SimplygonUseClippingGeometryEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseClippingGeometry;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public string ClippingGeometrySelectionSetName { get { return _ClippingGeometrySelectionSetName; } set { _ClippingGeometrySelectionSetName = value; OnPropertyChanged(); } }
        private string _ClippingGeometrySelectionSetName;
        public SimplygonClippingGeometrySelectionSetNameEx ClippingGeometrySelectionSetNameUI { get; set; }
        public class SimplygonClippingGeometrySelectionSetNameEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryCullingSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.ClippingGeometrySelectionSetName;
                }

                set
                {
                    bool needReload = Parent.ClippingGeometrySelectionSetName != value;
                    Parent.ClippingGeometrySelectionSetName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.UseClippingGeometryUI != null ) { return Parent.UseClippingGeometry && Parent.UseClippingGeometryUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonClippingGeometrySelectionSetNameEx() : base("ClippingGeometrySelectionSetName")
            {
                Type = "string";
                HelpText = "Which SelectionSet containing geometries will be used for clipping. Set name is prioritized over id if both are set.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonClippingGeometrySelectionSetNameEx(dynamic jsonData) : base("ClippingGeometrySelectionSetName")
            {
                Type = "string";
                HelpText = "Which SelectionSet containing geometries will be used for clipping. Set name is prioritized over id if both are set.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonClippingGeometrySelectionSetNameEx DeepCopy()
            {
                return (SimplygonClippingGeometrySelectionSetNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.UseClippingGeometryUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.ClippingGeometrySelectionSetName;
                int selectedIndex = 0;
                string[] sets = Simplygon.Unity.EditorPlugin.SimplygonUtils.GetSelectionSetNamesInSelection();
                List<GUIContent> selectionSets = new List<GUIContent>();
                selectionSets.Add(new GUIContent("Not used"));
                for(int i = 0; i < sets.Length; ++i)
                {
                    if(value == sets[i]) selectedIndex = i+1;
                    selectionSets.Add(new GUIContent(sets[i]));
                }

                selectedIndex = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), selectedIndex, selectionSets.ToArray());
                Parent.ClippingGeometrySelectionSetName = selectedIndex == 0 ? "" : selectionSets[selectedIndex].text;
            }

        }


        public SimplygonGeometryCullingSettings() : base("GeometryCullingSettings")
        {
            Visible = true;
            UseClippingGeometryUI = new SimplygonUseClippingGeometryEx();
            UseClippingGeometryUI.Parent = this;
            UseClippingGeometry = UseClippingGeometryUI.DefaultValue;
            Items.Add(UseClippingGeometryUI);
            ClippingGeometrySelectionSetNameUI = new SimplygonClippingGeometrySelectionSetNameEx();
            ClippingGeometrySelectionSetNameUI.Parent = this;
            ClippingGeometrySelectionSetName = ClippingGeometrySelectionSetNameUI.DefaultValue;
            Items.Add(ClippingGeometrySelectionSetNameUI);
        }

        public SimplygonGeometryCullingSettings(dynamic jsonData) : base("GeometryCullingSettings")
        {
            Visible = true;
            UseClippingGeometryUI = new SimplygonUseClippingGeometryEx(jsonData != null && ((JObject)jsonData).GetValue("UseClippingGeometryUI") != null ? jsonData.UseClippingGeometryUI : null);
            UseClippingGeometryUI.Parent = this;
            UseClippingGeometry = UseClippingGeometryUI.DefaultValue;
            Items.Add(UseClippingGeometryUI);
            ClippingGeometrySelectionSetNameUI = new SimplygonClippingGeometrySelectionSetNameEx(jsonData != null && ((JObject)jsonData).GetValue("ClippingGeometrySelectionSetNameUI") != null ? jsonData.ClippingGeometrySelectionSetNameUI : null);
            ClippingGeometrySelectionSetNameUI.Parent = this;
            ClippingGeometrySelectionSetName = ClippingGeometrySelectionSetNameUI.DefaultValue;
            Items.Add(ClippingGeometrySelectionSetNameUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonGeometryCullingSettings();
            copy.Items.Clear();
            copy.UseClippingGeometryUI = this.UseClippingGeometryUI.DeepCopy();
            copy.UseClippingGeometryUI.Parent = copy;
            copy.Items.Add(copy.UseClippingGeometryUI);
            copy.ClippingGeometrySelectionSetNameUI = this.ClippingGeometrySelectionSetNameUI.DeepCopy();
            copy.ClippingGeometrySelectionSetNameUI.Parent = copy;
            copy.Items.Add(copy.ClippingGeometrySelectionSetNameUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.UseClippingGeometry = UseClippingGeometry;
            if(serializeUIComponents)
            {
                jsonData.UseClippingGeometryUI = UseClippingGeometryUI.SaveJson();
            }

            jsonData.ClippingGeometrySelectionSetName = ClippingGeometrySelectionSetName;
            if(serializeUIComponents)
            {
                jsonData.ClippingGeometrySelectionSetNameUI = ClippingGeometrySelectionSetNameUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("UseClippingGeometry") != null)
            {
                UseClippingGeometry = (bool)jsonData.UseClippingGeometry;
            }

            if(jsonData.GetValue("ClippingGeometrySelectionSetName") != null)
            {
                ClippingGeometrySelectionSetName = (string)jsonData.ClippingGeometrySelectionSetName;
            }

        }

        public override void Reset()
        {
            UseClippingGeometryUI.Reset();
            ClippingGeometrySelectionSetNameUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            UseClippingGeometryUI.IsEditEnabled = isEditEnabled;
            ClippingGeometrySelectionSetNameUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            UseClippingGeometryUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ClippingGeometrySelectionSetNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonAggregationSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MergeGeometriesUI.Visible) return true;
                if(KeepUnprocessedSceneMeshesUI.Visible) return true;
                if(EnableGeometryCullingUI.Visible) return true;
                if(GeometryCullingPrecisionUI.Visible) return true;
                if(SubdivideGeometryBasedOnUVTilesUI.Visible) return true;
                if(SubdivisionTileSizeUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool MergeGeometries { get { return _MergeGeometries; } set { _MergeGeometries = value; OnPropertyChanged(); } }
        private bool _MergeGeometries;
        public SimplygonMergeGeometriesEx MergeGeometriesUI { get; set; }
        public class SimplygonMergeGeometriesEx : SimplygonSettingsProperty
        {
            public SimplygonAggregationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.MergeGeometries;
                }

                set
                {
                    bool needReload = Parent.MergeGeometries != value;
                    Parent.MergeGeometries = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonMergeGeometriesEx() : base("MergeGeometries")
            {
                Type = "bool";
                HelpText = "The processor will merge all the geometries in the scene into a single geometry if this is enabled.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonMergeGeometriesEx(dynamic jsonData) : base("MergeGeometries")
            {
                Type = "bool";
                HelpText = "The processor will merge all the geometries in the scene into a single geometry if this is enabled.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMergeGeometriesEx DeepCopy()
            {
                return (SimplygonMergeGeometriesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.MergeGeometries;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool KeepUnprocessedSceneMeshes { get { return _KeepUnprocessedSceneMeshes; } set { _KeepUnprocessedSceneMeshes = value; OnPropertyChanged(); } }
        private bool _KeepUnprocessedSceneMeshes;
        public SimplygonKeepUnprocessedSceneMeshesEx KeepUnprocessedSceneMeshesUI { get; set; }
        public class SimplygonKeepUnprocessedSceneMeshesEx : SimplygonSettingsProperty
        {
            public SimplygonAggregationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.KeepUnprocessedSceneMeshes;
                }

                set
                {
                    bool needReload = Parent.KeepUnprocessedSceneMeshes != value;
                    Parent.KeepUnprocessedSceneMeshes = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonKeepUnprocessedSceneMeshesEx() : base("KeepUnprocessedSceneMeshes")
            {
                Type = "bool";
                HelpText = "If false, the processor will remove all geometry and scene meshes which were not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated, while the rest of the scene tree is kept intact. New geometry is always added as the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonKeepUnprocessedSceneMeshesEx(dynamic jsonData) : base("KeepUnprocessedSceneMeshes")
            {
                Type = "bool";
                HelpText = "If false, the processor will remove all geometry and scene meshes which were not selected for processing from the scene. If true, only the geometry in the ProcessSelectionSet will be replaced or updated, while the rest of the scene tree is kept intact. New geometry is always added as the last child of the scene root. If generating a mappingimage to cast materials, new materialIds will also be appended to the end of the old material table instead of replacing the old ones.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonKeepUnprocessedSceneMeshesEx DeepCopy()
            {
                return (SimplygonKeepUnprocessedSceneMeshesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.KeepUnprocessedSceneMeshes;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool EnableGeometryCulling { get { return _EnableGeometryCulling; } set { _EnableGeometryCulling = value; OnPropertyChanged(); } }
        private bool _EnableGeometryCulling;
        public SimplygonEnableGeometryCullingEx EnableGeometryCullingUI { get; set; }
        public class SimplygonEnableGeometryCullingEx : SimplygonSettingsProperty
        {
            public SimplygonAggregationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.EnableGeometryCulling;
                }

                set
                {
                    bool needReload = Parent.EnableGeometryCulling != value;
                    Parent.EnableGeometryCulling = value;
                    Parent.GeometryCullingPrecisionUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonEnableGeometryCullingEx() : base("EnableGeometryCulling")
            {
                Type = "bool";
                HelpText = "Enables culling object insides and permits use of GeometryCullingSettings. If both this and visibility related culling is enabled, this is run first, then visibility.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonEnableGeometryCullingEx(dynamic jsonData) : base("EnableGeometryCulling")
            {
                Type = "bool";
                HelpText = "Enables culling object insides and permits use of GeometryCullingSettings. If both this and visibility related culling is enabled, this is run first, then visibility.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonEnableGeometryCullingEx DeepCopy()
            {
                return (SimplygonEnableGeometryCullingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.EnableGeometryCulling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float GeometryCullingPrecision { get { return _GeometryCullingPrecision; } set { _GeometryCullingPrecision = value; OnPropertyChanged(); } }
        private float _GeometryCullingPrecision;
        public SimplygonGeometryCullingPrecisionEx GeometryCullingPrecisionUI { get; set; }
        public class SimplygonGeometryCullingPrecisionEx : SimplygonSettingsProperty
        {
            public SimplygonAggregationSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.GeometryCullingPrecision;
                }

                set
                {
                    bool needReload = Parent.GeometryCullingPrecision != value;
                    Parent.GeometryCullingPrecision = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }
            public override bool Visible { get { if( Parent.EnableGeometryCullingUI != null ) { return Parent.EnableGeometryCulling && Parent.EnableGeometryCullingUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonGeometryCullingPrecisionEx() : base("GeometryCullingPrecision")
            {
                Type = "real";
                HelpText = "The accuracy of the triangle intersection math to find and cull insides used by the EnableTriangleCulling setting. Defined from 0 to 1 where 0 is max speed and 1 is max precision.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonGeometryCullingPrecisionEx(dynamic jsonData) : base("GeometryCullingPrecision")
            {
                Type = "real";
                HelpText = "The accuracy of the triangle intersection math to find and cull insides used by the EnableTriangleCulling setting. Defined from 0 to 1 where 0 is max speed and 1 is max precision.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometryCullingPrecision: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometryCullingPrecision: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGeometryCullingPrecisionEx DeepCopy()
            {
                return (SimplygonGeometryCullingPrecisionEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.EnableGeometryCullingUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.GeometryCullingPrecision;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool SubdivideGeometryBasedOnUVTiles { get { return _SubdivideGeometryBasedOnUVTiles; } set { _SubdivideGeometryBasedOnUVTiles = value; OnPropertyChanged(); } }
        private bool _SubdivideGeometryBasedOnUVTiles;
        public SimplygonSubdivideGeometryBasedOnUVTilesEx SubdivideGeometryBasedOnUVTilesUI { get; set; }
        public class SimplygonSubdivideGeometryBasedOnUVTilesEx : SimplygonSettingsProperty
        {
            public SimplygonAggregationSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.SubdivideGeometryBasedOnUVTiles;
                }

                set
                {
                    bool needReload = Parent.SubdivideGeometryBasedOnUVTiles != value;
                    Parent.SubdivideGeometryBasedOnUVTiles = value;
                    Parent.SubdivisionTileSizeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonSubdivideGeometryBasedOnUVTilesEx() : base("SubdivideGeometryBasedOnUVTiles")
            {
                Type = "bool";
                HelpText = "Subdivides the geometry based on the tiling texture coords. The cutting frequency 'SubdivisionTileSize' is a positive integer multiplier (i.e. the mesh will be cut each time its U or V texcoords crosses the SubdivisionTileSize). The output UVs will be in the range [(0,0),(SubdivisionTileSize,SubdivisionTileSize)].";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonSubdivideGeometryBasedOnUVTilesEx(dynamic jsonData) : base("SubdivideGeometryBasedOnUVTiles")
            {
                Type = "bool";
                HelpText = "Subdivides the geometry based on the tiling texture coords. The cutting frequency 'SubdivisionTileSize' is a positive integer multiplier (i.e. the mesh will be cut each time its U or V texcoords crosses the SubdivisionTileSize). The output UVs will be in the range [(0,0),(SubdivisionTileSize,SubdivisionTileSize)].";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSubdivideGeometryBasedOnUVTilesEx DeepCopy()
            {
                return (SimplygonSubdivideGeometryBasedOnUVTilesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.SubdivideGeometryBasedOnUVTiles;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int SubdivisionTileSize { get { return _SubdivisionTileSize; } set { _SubdivisionTileSize = value; OnPropertyChanged(); } }
        private int _SubdivisionTileSize;
        public SimplygonSubdivisionTileSizeEx SubdivisionTileSizeUI { get; set; }
        public class SimplygonSubdivisionTileSizeEx : SimplygonSettingsProperty
        {
            public SimplygonAggregationSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.SubdivisionTileSize;
                }

                set
                {
                    bool needReload = Parent.SubdivisionTileSize != value;
                    Parent.SubdivisionTileSize = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }
            public override bool Visible { get { if( Parent.SubdivideGeometryBasedOnUVTilesUI != null ) { return Parent.SubdivideGeometryBasedOnUVTiles && Parent.SubdivideGeometryBasedOnUVTilesUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }

            public SimplygonSubdivisionTileSizeEx() : base("SubdivisionTileSize")
            {
                Type = "uint";
                HelpText = "The cutting frequency used when SubdivideGeometryBasedOnUVTiles is enabled.";
                TypeOverride = "";
                DefaultValue = 1;
                MinValue = 0;
                MaxValue = 100;
                DefaultMinValue = 0;
                DefaultMaxValue = 100;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonSubdivisionTileSizeEx(dynamic jsonData) : base("SubdivisionTileSize")
            {
                Type = "uint";
                HelpText = "The cutting frequency used when SubdivideGeometryBasedOnUVTiles is enabled.";
                TypeOverride = "";
                DefaultValue = 1;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SubdivisionTileSize: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 100;
                DefaultMaxValue = 100;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SubdivisionTileSize: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSubdivisionTileSizeEx DeepCopy()
            {
                return (SimplygonSubdivisionTileSizeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.SubdivideGeometryBasedOnUVTilesUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.SubdivisionTileSize;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonAggregationSettings() : base("AggregationSettings")
        {
            Visible = true;
            MergeGeometriesUI = new SimplygonMergeGeometriesEx();
            MergeGeometriesUI.Parent = this;
            MergeGeometries = MergeGeometriesUI.DefaultValue;
            Items.Add(MergeGeometriesUI);
            EnableGeometryCullingUI = new SimplygonEnableGeometryCullingEx();
            EnableGeometryCullingUI.Parent = this;
            EnableGeometryCulling = EnableGeometryCullingUI.DefaultValue;
            Items.Add(EnableGeometryCullingUI);
            GeometryCullingPrecisionUI = new SimplygonGeometryCullingPrecisionEx();
            GeometryCullingPrecisionUI.Parent = this;
            GeometryCullingPrecision = GeometryCullingPrecisionUI.DefaultValue;
            Items.Add(GeometryCullingPrecisionUI);
            SubdivideGeometryBasedOnUVTilesUI = new SimplygonSubdivideGeometryBasedOnUVTilesEx();
            SubdivideGeometryBasedOnUVTilesUI.Parent = this;
            SubdivideGeometryBasedOnUVTiles = SubdivideGeometryBasedOnUVTilesUI.DefaultValue;
            Items.Add(SubdivideGeometryBasedOnUVTilesUI);
            SubdivisionTileSizeUI = new SimplygonSubdivisionTileSizeEx();
            SubdivisionTileSizeUI.Parent = this;
            SubdivisionTileSize = SubdivisionTileSizeUI.DefaultValue;
            Items.Add(SubdivisionTileSizeUI);
            KeepUnprocessedSceneMeshesUI = new SimplygonKeepUnprocessedSceneMeshesEx();
            KeepUnprocessedSceneMeshesUI.Parent = this;
            KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshesUI.DefaultValue;
            Items.Add(KeepUnprocessedSceneMeshesUI);
        }

        public SimplygonAggregationSettings(dynamic jsonData) : base("AggregationSettings")
        {
            Visible = true;
            MergeGeometriesUI = new SimplygonMergeGeometriesEx(jsonData != null && ((JObject)jsonData).GetValue("MergeGeometriesUI") != null ? jsonData.MergeGeometriesUI : null);
            MergeGeometriesUI.Parent = this;
            MergeGeometries = MergeGeometriesUI.DefaultValue;
            Items.Add(MergeGeometriesUI);
            EnableGeometryCullingUI = new SimplygonEnableGeometryCullingEx(jsonData != null && ((JObject)jsonData).GetValue("EnableGeometryCullingUI") != null ? jsonData.EnableGeometryCullingUI : null);
            EnableGeometryCullingUI.Parent = this;
            EnableGeometryCulling = EnableGeometryCullingUI.DefaultValue;
            Items.Add(EnableGeometryCullingUI);
            GeometryCullingPrecisionUI = new SimplygonGeometryCullingPrecisionEx(jsonData != null && ((JObject)jsonData).GetValue("GeometryCullingPrecisionUI") != null ? jsonData.GeometryCullingPrecisionUI : null);
            GeometryCullingPrecisionUI.Parent = this;
            GeometryCullingPrecision = GeometryCullingPrecisionUI.DefaultValue;
            Items.Add(GeometryCullingPrecisionUI);
            SubdivideGeometryBasedOnUVTilesUI = new SimplygonSubdivideGeometryBasedOnUVTilesEx(jsonData != null && ((JObject)jsonData).GetValue("SubdivideGeometryBasedOnUVTilesUI") != null ? jsonData.SubdivideGeometryBasedOnUVTilesUI : null);
            SubdivideGeometryBasedOnUVTilesUI.Parent = this;
            SubdivideGeometryBasedOnUVTiles = SubdivideGeometryBasedOnUVTilesUI.DefaultValue;
            Items.Add(SubdivideGeometryBasedOnUVTilesUI);
            SubdivisionTileSizeUI = new SimplygonSubdivisionTileSizeEx(jsonData != null && ((JObject)jsonData).GetValue("SubdivisionTileSizeUI") != null ? jsonData.SubdivisionTileSizeUI : null);
            SubdivisionTileSizeUI.Parent = this;
            SubdivisionTileSize = SubdivisionTileSizeUI.DefaultValue;
            Items.Add(SubdivisionTileSizeUI);
            KeepUnprocessedSceneMeshesUI = new SimplygonKeepUnprocessedSceneMeshesEx(jsonData != null && ((JObject)jsonData).GetValue("KeepUnprocessedSceneMeshesUI") != null ? jsonData.KeepUnprocessedSceneMeshesUI : null);
            KeepUnprocessedSceneMeshesUI.Parent = this;
            KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshesUI.DefaultValue;
            Items.Add(KeepUnprocessedSceneMeshesUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonAggregationSettings();
            copy.Items.Clear();
            copy.MergeGeometriesUI = this.MergeGeometriesUI.DeepCopy();
            copy.MergeGeometriesUI.Parent = copy;
            copy.Items.Add(copy.MergeGeometriesUI);
            copy.EnableGeometryCullingUI = this.EnableGeometryCullingUI.DeepCopy();
            copy.EnableGeometryCullingUI.Parent = copy;
            copy.Items.Add(copy.EnableGeometryCullingUI);
            copy.GeometryCullingPrecisionUI = this.GeometryCullingPrecisionUI.DeepCopy();
            copy.GeometryCullingPrecisionUI.Parent = copy;
            copy.Items.Add(copy.GeometryCullingPrecisionUI);
            copy.SubdivideGeometryBasedOnUVTilesUI = this.SubdivideGeometryBasedOnUVTilesUI.DeepCopy();
            copy.SubdivideGeometryBasedOnUVTilesUI.Parent = copy;
            copy.Items.Add(copy.SubdivideGeometryBasedOnUVTilesUI);
            copy.SubdivisionTileSizeUI = this.SubdivisionTileSizeUI.DeepCopy();
            copy.SubdivisionTileSizeUI.Parent = copy;
            copy.Items.Add(copy.SubdivisionTileSizeUI);
            copy.KeepUnprocessedSceneMeshesUI = this.KeepUnprocessedSceneMeshesUI.DeepCopy();
            copy.KeepUnprocessedSceneMeshesUI.Parent = copy;
            copy.Items.Add(copy.KeepUnprocessedSceneMeshesUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MergeGeometries = MergeGeometries;
            if(serializeUIComponents)
            {
                jsonData.MergeGeometriesUI = MergeGeometriesUI.SaveJson();
            }

            jsonData.KeepUnprocessedSceneMeshes = KeepUnprocessedSceneMeshes;
            if(serializeUIComponents)
            {
                jsonData.KeepUnprocessedSceneMeshesUI = KeepUnprocessedSceneMeshesUI.SaveJson();
            }

            jsonData.EnableGeometryCulling = EnableGeometryCulling;
            if(serializeUIComponents)
            {
                jsonData.EnableGeometryCullingUI = EnableGeometryCullingUI.SaveJson();
            }

            jsonData.GeometryCullingPrecision = GeometryCullingPrecision;
            if(serializeUIComponents)
            {
                jsonData.GeometryCullingPrecisionUI = GeometryCullingPrecisionUI.SaveJson();
            }

            jsonData.SubdivideGeometryBasedOnUVTiles = SubdivideGeometryBasedOnUVTiles;
            if(serializeUIComponents)
            {
                jsonData.SubdivideGeometryBasedOnUVTilesUI = SubdivideGeometryBasedOnUVTilesUI.SaveJson();
            }

            jsonData.SubdivisionTileSize = SubdivisionTileSize;
            if(serializeUIComponents)
            {
                jsonData.SubdivisionTileSizeUI = SubdivisionTileSizeUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MergeGeometries") != null)
            {
                MergeGeometries = (bool)jsonData.MergeGeometries;
            }

            if(jsonData.GetValue("KeepUnprocessedSceneMeshes") != null)
            {
                KeepUnprocessedSceneMeshes = (bool)jsonData.KeepUnprocessedSceneMeshes;
            }

            if(jsonData.GetValue("EnableGeometryCulling") != null)
            {
                EnableGeometryCulling = (bool)jsonData.EnableGeometryCulling;
            }

            if(jsonData.GetValue("GeometryCullingPrecision") != null)
            {
                float newGeometryCullingPrecision = (float)jsonData.GeometryCullingPrecision;
                if (newGeometryCullingPrecision >= GeometryCullingPrecisionUI.DefaultMinValue && newGeometryCullingPrecision <= GeometryCullingPrecisionUI.DefaultMaxValue)
                {
                    GeometryCullingPrecision = newGeometryCullingPrecision;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"GeometryCullingPrecision: Invalid value {newGeometryCullingPrecision.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {GeometryCullingPrecision.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("SubdivideGeometryBasedOnUVTiles") != null)
            {
                SubdivideGeometryBasedOnUVTiles = (bool)jsonData.SubdivideGeometryBasedOnUVTiles;
            }

            if(jsonData.GetValue("SubdivisionTileSize") != null)
            {
                var newSubdivisionTileSize = (int)jsonData.SubdivisionTileSize;
                if (newSubdivisionTileSize >= SubdivisionTileSizeUI.DefaultMinValue && newSubdivisionTileSize <= SubdivisionTileSizeUI.DefaultMaxValue)
                {
                    SubdivisionTileSize = newSubdivisionTileSize;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SubdivisionTileSize: Invalid value {newSubdivisionTileSize}, using default value {SubdivisionTileSize.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            MergeGeometriesUI.Reset();
            KeepUnprocessedSceneMeshesUI.Reset();
            EnableGeometryCullingUI.Reset();
            GeometryCullingPrecisionUI.Reset();
            SubdivideGeometryBasedOnUVTilesUI.Reset();
            SubdivisionTileSizeUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MergeGeometriesUI.IsEditEnabled = isEditEnabled;
            KeepUnprocessedSceneMeshesUI.IsEditEnabled = isEditEnabled;
            EnableGeometryCullingUI.IsEditEnabled = isEditEnabled;
            GeometryCullingPrecisionUI.IsEditEnabled = isEditEnabled;
            SubdivideGeometryBasedOnUVTilesUI.IsEditEnabled = isEditEnabled;
            SubdivisionTileSizeUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MergeGeometriesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            EnableGeometryCullingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GeometryCullingPrecisionUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SubdivideGeometryBasedOnUVTilesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SubdivisionTileSizeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            KeepUnprocessedSceneMeshesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonGenerateLightmapTexCoordSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(GenerateLightmapTexCoordUI.Visible) return true;
                if(LightmapTexCoordLevelUI.Visible) return true;
                if(LightmapTexCoordNameUI.Visible) return true;
                if(ChartAggregatorModeUI.Visible) return true;
                if(TextureWidthUI.Visible) return true;
                if(TextureHeightUI.Visible) return true;
                if(GutterSpaceUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool GenerateLightmapTexCoord { get { return _GenerateLightmapTexCoord; } set { _GenerateLightmapTexCoord = value; OnPropertyChanged(); } }
        private bool _GenerateLightmapTexCoord;
        public SimplygonGenerateLightmapTexCoordEx GenerateLightmapTexCoordUI { get; set; }
        public class SimplygonGenerateLightmapTexCoordEx : SimplygonSettingsProperty
        {
            public SimplygonGenerateLightmapTexCoordSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.GenerateLightmapTexCoord;
                }

                set
                {
                    bool needReload = Parent.GenerateLightmapTexCoord != value;
                    Parent.GenerateLightmapTexCoord = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonGenerateLightmapTexCoordEx() : base("GenerateLightmapTexCoord")
            {
                Type = "bool";
                HelpText = "Property for whether to generate an extra set of TexCoords for LightMapping.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonGenerateLightmapTexCoordEx(dynamic jsonData) : base("GenerateLightmapTexCoord")
            {
                Type = "bool";
                HelpText = "Property for whether to generate an extra set of TexCoords for LightMapping.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGenerateLightmapTexCoordEx DeepCopy()
            {
                return (SimplygonGenerateLightmapTexCoordEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.GenerateLightmapTexCoord;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int LightmapTexCoordLevel { get { return _LightmapTexCoordLevel; } set { _LightmapTexCoordLevel = value; OnPropertyChanged(); } }
        private int _LightmapTexCoordLevel;
        public SimplygonLightmapTexCoordLevelEx LightmapTexCoordLevelUI { get; set; }
        public class SimplygonLightmapTexCoordLevelEx : SimplygonSettingsProperty
        {
            public SimplygonGenerateLightmapTexCoordSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.LightmapTexCoordLevel;
                }

                set
                {
                    bool needReload = Parent.LightmapTexCoordLevel != value;
                    Parent.LightmapTexCoordLevel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonLightmapTexCoordLevelEx() : base("LightmapTexCoordLevel")
            {
                Type = "rid";
                HelpText = "The texture coordinate level used for storing the LightMap UVs. The texcoord name has priority over level. If neither name or level is set then output would be level 0.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                MaxValue = 10;
                DefaultMinValue = -1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonLightmapTexCoordLevelEx(dynamic jsonData) : base("LightmapTexCoordLevel")
            {
                Type = "rid";
                HelpText = "The texture coordinate level used for storing the LightMap UVs. The texcoord name has priority over level. If neither name or level is set then output would be level 0.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                DefaultMinValue = -1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"LightmapTexCoordLevel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"LightmapTexCoordLevel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonLightmapTexCoordLevelEx DeepCopy()
            {
                return (SimplygonLightmapTexCoordLevelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.LightmapTexCoordLevel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public string LightmapTexCoordName { get { return _LightmapTexCoordName; } set { _LightmapTexCoordName = value; OnPropertyChanged(); } }
        private string _LightmapTexCoordName;
        public SimplygonLightmapTexCoordNameEx LightmapTexCoordNameUI { get; set; }
        public class SimplygonLightmapTexCoordNameEx : SimplygonSettingsProperty
        {
            public SimplygonGenerateLightmapTexCoordSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.LightmapTexCoordName;
                }

                set
                {
                    bool needReload = Parent.LightmapTexCoordName != value;
                    Parent.LightmapTexCoordName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonLightmapTexCoordNameEx() : base("LightmapTexCoordName")
            {
                Type = "string";
                HelpText = "The texture coordinate level name used for storing the generated Lightmap UVs. If this is not set will default to level. If neither name or level is set then output would be level 0.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonLightmapTexCoordNameEx(dynamic jsonData) : base("LightmapTexCoordName")
            {
                Type = "string";
                HelpText = "The texture coordinate level name used for storing the generated Lightmap UVs. If this is not set will default to level. If neither name or level is set then output would be level 0.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonLightmapTexCoordNameEx DeepCopy()
            {
                return (SimplygonLightmapTexCoordNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.LightmapTexCoordName;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EChartAggregatorMode ChartAggregatorMode { get { return _ChartAggregatorMode; } set { _ChartAggregatorMode = value; OnPropertyChanged(); } }
        private EChartAggregatorMode _ChartAggregatorMode;
        public SimplygonChartAggregatorModeEx ChartAggregatorModeUI { get; set; }
        public class SimplygonChartAggregatorModeEx : SimplygonSettingsProperty
        {
            public SimplygonGenerateLightmapTexCoordSettings Parent { get; set; }
            public EChartAggregatorMode Value
            {
                get
                {
                    return Parent.ChartAggregatorMode;
                }

                set
                {
                    bool needReload = Parent.ChartAggregatorMode != value;
                    Parent.ChartAggregatorMode = value;
                    OnPropertyChanged();
                }

            }

            public EChartAggregatorMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EChartAggregatorMode)); } }

            public SimplygonChartAggregatorModeEx() : base("ChartAggregatorMode")
            {
                Type = "enum";
                HelpText = "Determines which method to use when aggregating the UVs. TextureSizeProportions - Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps. SurfaceArea - Aggregated UV charts will have their size set based on its actual geometrical size. OriginalPixelDensity - The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size. UVSizeProportions - Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in.');.";
                TypeOverride = "";
                DefaultValue = EChartAggregatorMode.SurfaceArea;
                Visible = true;
            }

            public SimplygonChartAggregatorModeEx(dynamic jsonData) : base("ChartAggregatorMode")
            {
                Type = "enum";
                HelpText = "Determines which method to use when aggregating the UVs. TextureSizeProportions - Aggregated UV charts will be scaled to keep their relative pixel density relative to all other UV charts. The user can still set the size of the output texture maps. SurfaceArea - Aggregated UV charts will have their size set based on its actual geometrical size. OriginalPixelDensity - The combined atlas will be resized to fit each chart so that all charts retain the same amount of pixels as they originally had. This will override any manually set texture size. UVSizeProportions - Aggregated UV charts will have their size set based on its original UV size, disregarding the size of the texture they are used in.');.";
                TypeOverride = "";
                DefaultValue = EChartAggregatorMode.SurfaceArea;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonChartAggregatorModeEx DeepCopy()
            {
                return (SimplygonChartAggregatorModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.ChartAggregatorMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EChartAggregatorMode)value;
            }

        }

        public int TextureWidth { get { return _TextureWidth; } set { _TextureWidth = value; OnPropertyChanged(); } }
        private int _TextureWidth;
        public SimplygonTextureWidthEx TextureWidthUI { get; set; }
        public class SimplygonTextureWidthEx : SimplygonSettingsProperty
        {
            public SimplygonGenerateLightmapTexCoordSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.TextureWidth;
                }

                set
                {
                    bool needReload = Parent.TextureWidth != value;
                    Parent.TextureWidth = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonTextureWidthEx() : base("TextureWidth")
            {
                Type = "uint";
                HelpText = "The width of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 512;
                MinValue = 0;
                MaxValue = 8192;
                DefaultMinValue = 0;
                DefaultMaxValue = 8192;
                TicksFrequencyValue = 256;
                Visible = true;
            }

            public SimplygonTextureWidthEx(dynamic jsonData) : base("TextureWidth")
            {
                Type = "uint";
                HelpText = "The width of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 512;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureWidth: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 8192;
                DefaultMaxValue = 8192;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureWidth: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 256;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTextureWidthEx DeepCopy()
            {
                return (SimplygonTextureWidthEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.TextureWidth;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int TextureHeight { get { return _TextureHeight; } set { _TextureHeight = value; OnPropertyChanged(); } }
        private int _TextureHeight;
        public SimplygonTextureHeightEx TextureHeightUI { get; set; }
        public class SimplygonTextureHeightEx : SimplygonSettingsProperty
        {
            public SimplygonGenerateLightmapTexCoordSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.TextureHeight;
                }

                set
                {
                    bool needReload = Parent.TextureHeight != value;
                    Parent.TextureHeight = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonTextureHeightEx() : base("TextureHeight")
            {
                Type = "uint";
                HelpText = "The height of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 512;
                MinValue = 0;
                MaxValue = 8192;
                DefaultMinValue = 0;
                DefaultMaxValue = 8192;
                TicksFrequencyValue = 256;
                Visible = true;
            }

            public SimplygonTextureHeightEx(dynamic jsonData) : base("TextureHeight")
            {
                Type = "uint";
                HelpText = "The height of the texture of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 512;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureHeight: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 8192;
                DefaultMaxValue = 8192;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TextureHeight: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 256;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTextureHeightEx DeepCopy()
            {
                return (SimplygonTextureHeightEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.TextureHeight;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int GutterSpace { get { return _GutterSpace; } set { _GutterSpace = value; OnPropertyChanged(); } }
        private int _GutterSpace;
        public SimplygonGutterSpaceEx GutterSpaceUI { get; set; }
        public class SimplygonGutterSpaceEx : SimplygonSettingsProperty
        {
            public SimplygonGenerateLightmapTexCoordSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.GutterSpace;
                }

                set
                {
                    bool needReload = Parent.GutterSpace != value;
                    Parent.GutterSpace = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonGutterSpaceEx() : base("GutterSpace")
            {
                Type = "uint";
                HelpText = "The minimum number of pixels between charts of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 4;
                MinValue = 0;
                MaxValue = 10;
                DefaultMinValue = 0;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonGutterSpaceEx(dynamic jsonData) : base("GutterSpace")
            {
                Type = "uint";
                HelpText = "The minimum number of pixels between charts of the output mapping image.";
                TypeOverride = "";
                DefaultValue = 4;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GutterSpace: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GutterSpace: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGutterSpaceEx DeepCopy()
            {
                return (SimplygonGutterSpaceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.GutterSpace;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonGenerateLightmapTexCoordSettings() : base("GenerateLightmapTexCoordSettings")
        {
            Visible = true;
            GenerateLightmapTexCoordUI = new SimplygonGenerateLightmapTexCoordEx();
            GenerateLightmapTexCoordUI.Parent = this;
            GenerateLightmapTexCoord = GenerateLightmapTexCoordUI.DefaultValue;
            Items.Add(GenerateLightmapTexCoordUI);
            LightmapTexCoordLevelUI = new SimplygonLightmapTexCoordLevelEx();
            LightmapTexCoordLevelUI.Parent = this;
            LightmapTexCoordLevel = LightmapTexCoordLevelUI.DefaultValue;
            Items.Add(LightmapTexCoordLevelUI);
            LightmapTexCoordNameUI = new SimplygonLightmapTexCoordNameEx();
            LightmapTexCoordNameUI.Parent = this;
            LightmapTexCoordName = LightmapTexCoordNameUI.DefaultValue;
            Items.Add(LightmapTexCoordNameUI);
            ChartAggregatorModeUI = new SimplygonChartAggregatorModeEx();
            ChartAggregatorModeUI.Parent = this;
            ChartAggregatorMode = ChartAggregatorModeUI.DefaultValue;
            Items.Add(ChartAggregatorModeUI);
            TextureWidthUI = new SimplygonTextureWidthEx();
            TextureWidthUI.Parent = this;
            TextureWidth = TextureWidthUI.DefaultValue;
            Items.Add(TextureWidthUI);
            TextureHeightUI = new SimplygonTextureHeightEx();
            TextureHeightUI.Parent = this;
            TextureHeight = TextureHeightUI.DefaultValue;
            Items.Add(TextureHeightUI);
            GutterSpaceUI = new SimplygonGutterSpaceEx();
            GutterSpaceUI.Parent = this;
            GutterSpace = GutterSpaceUI.DefaultValue;
            Items.Add(GutterSpaceUI);
        }

        public SimplygonGenerateLightmapTexCoordSettings(dynamic jsonData) : base("GenerateLightmapTexCoordSettings")
        {
            Visible = true;
            GenerateLightmapTexCoordUI = new SimplygonGenerateLightmapTexCoordEx(jsonData != null && ((JObject)jsonData).GetValue("GenerateLightmapTexCoordUI") != null ? jsonData.GenerateLightmapTexCoordUI : null);
            GenerateLightmapTexCoordUI.Parent = this;
            GenerateLightmapTexCoord = GenerateLightmapTexCoordUI.DefaultValue;
            Items.Add(GenerateLightmapTexCoordUI);
            LightmapTexCoordLevelUI = new SimplygonLightmapTexCoordLevelEx(jsonData != null && ((JObject)jsonData).GetValue("LightmapTexCoordLevelUI") != null ? jsonData.LightmapTexCoordLevelUI : null);
            LightmapTexCoordLevelUI.Parent = this;
            LightmapTexCoordLevel = LightmapTexCoordLevelUI.DefaultValue;
            Items.Add(LightmapTexCoordLevelUI);
            LightmapTexCoordNameUI = new SimplygonLightmapTexCoordNameEx(jsonData != null && ((JObject)jsonData).GetValue("LightmapTexCoordNameUI") != null ? jsonData.LightmapTexCoordNameUI : null);
            LightmapTexCoordNameUI.Parent = this;
            LightmapTexCoordName = LightmapTexCoordNameUI.DefaultValue;
            Items.Add(LightmapTexCoordNameUI);
            ChartAggregatorModeUI = new SimplygonChartAggregatorModeEx(jsonData != null && ((JObject)jsonData).GetValue("ChartAggregatorModeUI") != null ? jsonData.ChartAggregatorModeUI : null);
            ChartAggregatorModeUI.Parent = this;
            ChartAggregatorMode = ChartAggregatorModeUI.DefaultValue;
            Items.Add(ChartAggregatorModeUI);
            TextureWidthUI = new SimplygonTextureWidthEx(jsonData != null && ((JObject)jsonData).GetValue("TextureWidthUI") != null ? jsonData.TextureWidthUI : null);
            TextureWidthUI.Parent = this;
            TextureWidth = TextureWidthUI.DefaultValue;
            Items.Add(TextureWidthUI);
            TextureHeightUI = new SimplygonTextureHeightEx(jsonData != null && ((JObject)jsonData).GetValue("TextureHeightUI") != null ? jsonData.TextureHeightUI : null);
            TextureHeightUI.Parent = this;
            TextureHeight = TextureHeightUI.DefaultValue;
            Items.Add(TextureHeightUI);
            GutterSpaceUI = new SimplygonGutterSpaceEx(jsonData != null && ((JObject)jsonData).GetValue("GutterSpaceUI") != null ? jsonData.GutterSpaceUI : null);
            GutterSpaceUI.Parent = this;
            GutterSpace = GutterSpaceUI.DefaultValue;
            Items.Add(GutterSpaceUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonGenerateLightmapTexCoordSettings();
            copy.Items.Clear();
            copy.GenerateLightmapTexCoordUI = this.GenerateLightmapTexCoordUI.DeepCopy();
            copy.GenerateLightmapTexCoordUI.Parent = copy;
            copy.Items.Add(copy.GenerateLightmapTexCoordUI);
            copy.LightmapTexCoordLevelUI = this.LightmapTexCoordLevelUI.DeepCopy();
            copy.LightmapTexCoordLevelUI.Parent = copy;
            copy.Items.Add(copy.LightmapTexCoordLevelUI);
            copy.LightmapTexCoordNameUI = this.LightmapTexCoordNameUI.DeepCopy();
            copy.LightmapTexCoordNameUI.Parent = copy;
            copy.Items.Add(copy.LightmapTexCoordNameUI);
            copy.ChartAggregatorModeUI = this.ChartAggregatorModeUI.DeepCopy();
            copy.ChartAggregatorModeUI.Parent = copy;
            copy.Items.Add(copy.ChartAggregatorModeUI);
            copy.TextureWidthUI = this.TextureWidthUI.DeepCopy();
            copy.TextureWidthUI.Parent = copy;
            copy.Items.Add(copy.TextureWidthUI);
            copy.TextureHeightUI = this.TextureHeightUI.DeepCopy();
            copy.TextureHeightUI.Parent = copy;
            copy.Items.Add(copy.TextureHeightUI);
            copy.GutterSpaceUI = this.GutterSpaceUI.DeepCopy();
            copy.GutterSpaceUI.Parent = copy;
            copy.Items.Add(copy.GutterSpaceUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.GenerateLightmapTexCoord = GenerateLightmapTexCoord;
            if(serializeUIComponents)
            {
                jsonData.GenerateLightmapTexCoordUI = GenerateLightmapTexCoordUI.SaveJson();
            }

            jsonData.LightmapTexCoordLevel = LightmapTexCoordLevel;
            if(serializeUIComponents)
            {
                jsonData.LightmapTexCoordLevelUI = LightmapTexCoordLevelUI.SaveJson();
            }

            jsonData.LightmapTexCoordName = LightmapTexCoordName;
            if(serializeUIComponents)
            {
                jsonData.LightmapTexCoordNameUI = LightmapTexCoordNameUI.SaveJson();
            }

            jsonData.ChartAggregatorMode = (int)ChartAggregatorMode;
            if(serializeUIComponents)
            {
                jsonData.ChartAggregatorModeUI = ChartAggregatorModeUI.SaveJson();
            }

            jsonData.TextureWidth = TextureWidth;
            if(serializeUIComponents)
            {
                jsonData.TextureWidthUI = TextureWidthUI.SaveJson();
            }

            jsonData.TextureHeight = TextureHeight;
            if(serializeUIComponents)
            {
                jsonData.TextureHeightUI = TextureHeightUI.SaveJson();
            }

            jsonData.GutterSpace = GutterSpace;
            if(serializeUIComponents)
            {
                jsonData.GutterSpaceUI = GutterSpaceUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("GenerateLightmapTexCoord") != null)
            {
                GenerateLightmapTexCoord = (bool)jsonData.GenerateLightmapTexCoord;
            }

            if(jsonData.GetValue("LightmapTexCoordLevel") != null)
            {
                var newLightmapTexCoordLevel = (int)jsonData.LightmapTexCoordLevel;
                if (newLightmapTexCoordLevel >= LightmapTexCoordLevelUI.DefaultMinValue && newLightmapTexCoordLevel <= LightmapTexCoordLevelUI.DefaultMaxValue)
                {
                    LightmapTexCoordLevel = newLightmapTexCoordLevel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"LightmapTexCoordLevel: Invalid value {newLightmapTexCoordLevel}, using default value {LightmapTexCoordLevel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("LightmapTexCoordName") != null)
            {
                LightmapTexCoordName = (string)jsonData.LightmapTexCoordName;
            }

            if(jsonData.GetValue("ChartAggregatorMode") != null)
            {
                ChartAggregatorMode = (EChartAggregatorMode)jsonData.ChartAggregatorMode;
            }

            if(jsonData.GetValue("TextureWidth") != null)
            {
                var newTextureWidth = (int)jsonData.TextureWidth;
                if (newTextureWidth >= TextureWidthUI.DefaultMinValue && newTextureWidth <= TextureWidthUI.DefaultMaxValue)
                {
                    TextureWidth = newTextureWidth;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TextureWidth: Invalid value {newTextureWidth}, using default value {TextureWidth.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("TextureHeight") != null)
            {
                var newTextureHeight = (int)jsonData.TextureHeight;
                if (newTextureHeight >= TextureHeightUI.DefaultMinValue && newTextureHeight <= TextureHeightUI.DefaultMaxValue)
                {
                    TextureHeight = newTextureHeight;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TextureHeight: Invalid value {newTextureHeight}, using default value {TextureHeight.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("GutterSpace") != null)
            {
                var newGutterSpace = (int)jsonData.GutterSpace;
                if (newGutterSpace >= GutterSpaceUI.DefaultMinValue && newGutterSpace <= GutterSpaceUI.DefaultMaxValue)
                {
                    GutterSpace = newGutterSpace;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"GutterSpace: Invalid value {newGutterSpace}, using default value {GutterSpace.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            GenerateLightmapTexCoordUI.Reset();
            LightmapTexCoordLevelUI.Reset();
            LightmapTexCoordNameUI.Reset();
            ChartAggregatorModeUI.Reset();
            TextureWidthUI.Reset();
            TextureHeightUI.Reset();
            GutterSpaceUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            GenerateLightmapTexCoordUI.IsEditEnabled = isEditEnabled;
            LightmapTexCoordLevelUI.IsEditEnabled = isEditEnabled;
            LightmapTexCoordNameUI.IsEditEnabled = isEditEnabled;
            ChartAggregatorModeUI.IsEditEnabled = isEditEnabled;
            TextureWidthUI.IsEditEnabled = isEditEnabled;
            TextureHeightUI.IsEditEnabled = isEditEnabled;
            GutterSpaceUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            GenerateLightmapTexCoordUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            LightmapTexCoordLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            LightmapTexCoordNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ChartAggregatorModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TextureWidthUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TextureHeightUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GutterSpaceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonFoliageSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(SeparateTrunkAndFoliageUI.Visible) return true;
                if(SeparateFoliageTriangleRatioUI.Visible) return true;
                if(SeparateFoliageTriangleThresholdUI.Visible) return true;
                if(SeparateFoliageAreaThresholdUI.Visible) return true;
                if(SeparateFoliageSizeThresholdUI.Visible) return true;
                if(TrunkReductionRatioUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonBillboardCloudSettings Parent { get; set; }
        public bool SeparateTrunkAndFoliage { get { return _SeparateTrunkAndFoliage; } set { _SeparateTrunkAndFoliage = value; OnPropertyChanged(); } }
        private bool _SeparateTrunkAndFoliage;
        public SimplygonSeparateTrunkAndFoliageEx SeparateTrunkAndFoliageUI { get; set; }
        public class SimplygonSeparateTrunkAndFoliageEx : SimplygonSettingsProperty
        {
            public SimplygonFoliageSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.SeparateTrunkAndFoliage;
                }

                set
                {
                    bool needReload = Parent.SeparateTrunkAndFoliage != value;
                    Parent.SeparateTrunkAndFoliage = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonSeparateTrunkAndFoliageEx() : base("SeparateTrunkAndFoliage")
            {
                Type = "bool";
                HelpText = "Determines whether to enable separation between foliage and trunk in a vegetation scene. Use the SeparateFoliage[...] settings to determine how parts are separated.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonSeparateTrunkAndFoliageEx(dynamic jsonData) : base("SeparateTrunkAndFoliage")
            {
                Type = "bool";
                HelpText = "Determines whether to enable separation between foliage and trunk in a vegetation scene. Use the SeparateFoliage[...] settings to determine how parts are separated.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSeparateTrunkAndFoliageEx DeepCopy()
            {
                return (SimplygonSeparateTrunkAndFoliageEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.SeparateTrunkAndFoliage;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float SeparateFoliageTriangleRatio { get { return _SeparateFoliageTriangleRatio; } set { _SeparateFoliageTriangleRatio = value; OnPropertyChanged(); } }
        private float _SeparateFoliageTriangleRatio;
        public SimplygonSeparateFoliageTriangleRatioEx SeparateFoliageTriangleRatioUI { get; set; }
        public class SimplygonSeparateFoliageTriangleRatioEx : SimplygonSettingsProperty
        {
            public SimplygonFoliageSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.SeparateFoliageTriangleRatio;
                }

                set
                {
                    bool needReload = Parent.SeparateFoliageTriangleRatio != value;
                    Parent.SeparateFoliageTriangleRatio = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonSeparateFoliageTriangleRatioEx() : base("SeparateFoliageTriangleRatio")
            {
                Type = "real";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by comparing each group of connected triangles in the scene with the scene's largest group. If a group's triangle count is below SeparateFoliageTriangleRatio * largestGrouptriangleCount it is treated as foliage and processed into billboards. The trunk is optimized using triangle reduction. The range is 0.0->1.0. 0.0 means nothing will be foliage, 1.0 means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 0.01f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonSeparateFoliageTriangleRatioEx(dynamic jsonData) : base("SeparateFoliageTriangleRatio")
            {
                Type = "real";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by comparing each group of connected triangles in the scene with the scene's largest group. If a group's triangle count is below SeparateFoliageTriangleRatio * largestGrouptriangleCount it is treated as foliage and processed into billboards. The trunk is optimized using triangle reduction. The range is 0.0->1.0. 0.0 means nothing will be foliage, 1.0 means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 0.01f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageTriangleRatio: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageTriangleRatio: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSeparateFoliageTriangleRatioEx DeepCopy()
            {
                return (SimplygonSeparateFoliageTriangleRatioEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.SeparateFoliageTriangleRatio;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int SeparateFoliageTriangleThreshold { get { return _SeparateFoliageTriangleThreshold; } set { _SeparateFoliageTriangleThreshold = value; OnPropertyChanged(); } }
        private int _SeparateFoliageTriangleThreshold;
        public SimplygonSeparateFoliageTriangleThresholdEx SeparateFoliageTriangleThresholdUI { get; set; }
        public class SimplygonSeparateFoliageTriangleThresholdEx : SimplygonSettingsProperty
        {
            public SimplygonFoliageSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.SeparateFoliageTriangleThreshold;
                }

                set
                {
                    bool needReload = Parent.SeparateFoliageTriangleThreshold != value;
                    Parent.SeparateFoliageTriangleThreshold = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonSeparateFoliageTriangleThresholdEx() : base("SeparateFoliageTriangleThreshold")
            {
                Type = "uint";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the triangle count is below SeparateFoliageTriangleThreshold it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the maximum triangle count means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 10000;
                DefaultMinValue = 0;
                DefaultMaxValue = 10000;
                TicksFrequencyValue = 10;
                Visible = true;
            }

            public SimplygonSeparateFoliageTriangleThresholdEx(dynamic jsonData) : base("SeparateFoliageTriangleThreshold")
            {
                Type = "uint";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the triangle count is below SeparateFoliageTriangleThreshold it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the maximum triangle count means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageTriangleThreshold: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10000;
                DefaultMaxValue = 10000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageTriangleThreshold: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSeparateFoliageTriangleThresholdEx DeepCopy()
            {
                return (SimplygonSeparateFoliageTriangleThresholdEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.SeparateFoliageTriangleThreshold;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float SeparateFoliageAreaThreshold { get { return _SeparateFoliageAreaThreshold; } set { _SeparateFoliageAreaThreshold = value; OnPropertyChanged(); } }
        private float _SeparateFoliageAreaThreshold;
        public SimplygonSeparateFoliageAreaThresholdEx SeparateFoliageAreaThresholdUI { get; set; }
        public class SimplygonSeparateFoliageAreaThresholdEx : SimplygonSettingsProperty
        {
            public SimplygonFoliageSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.SeparateFoliageAreaThreshold;
                }

                set
                {
                    bool needReload = Parent.SeparateFoliageAreaThreshold != value;
                    Parent.SeparateFoliageAreaThreshold = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonSeparateFoliageAreaThresholdEx() : base("SeparateFoliageAreaThreshold")
            {
                Type = "real";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the surface area is below (SeparateFoliageAreaThreshold * AreaOfTheLargestGroupInTheScene) it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the maximum surface area means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 0.1f;
                MinValue = 0f;
                MaxValue = 10000f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10000f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonSeparateFoliageAreaThresholdEx(dynamic jsonData) : base("SeparateFoliageAreaThreshold")
            {
                Type = "real";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the surface area is below (SeparateFoliageAreaThreshold * AreaOfTheLargestGroupInTheScene) it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the maximum surface area means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 0.1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageAreaThreshold: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10000f;
                DefaultMaxValue = 10000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageAreaThreshold: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSeparateFoliageAreaThresholdEx DeepCopy()
            {
                return (SimplygonSeparateFoliageAreaThresholdEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.SeparateFoliageAreaThreshold;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float SeparateFoliageSizeThreshold { get { return _SeparateFoliageSizeThreshold; } set { _SeparateFoliageSizeThreshold = value; OnPropertyChanged(); } }
        private float _SeparateFoliageSizeThreshold;
        public SimplygonSeparateFoliageSizeThresholdEx SeparateFoliageSizeThresholdUI { get; set; }
        public class SimplygonSeparateFoliageSizeThresholdEx : SimplygonSettingsProperty
        {
            public SimplygonFoliageSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.SeparateFoliageSizeThreshold;
                }

                set
                {
                    bool needReload = Parent.SeparateFoliageSizeThreshold != value;
                    Parent.SeparateFoliageSizeThreshold = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonSeparateFoliageSizeThresholdEx() : base("SeparateFoliageSizeThreshold")
            {
                Type = "real";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the diameter of the group is below (SeparateFoliageSizeThreshold * SceneDiameter) it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the scene's diameter means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 0.1f;
                MinValue = 0f;
                MaxValue = 10000f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10000f;
                TicksFrequencyValue = 1f;
                Visible = true;
            }

            public SimplygonSeparateFoliageSizeThresholdEx(dynamic jsonData) : base("SeparateFoliageSizeThreshold")
            {
                Type = "real";
                HelpText = "Is used to separate the trunk from the foliage in a vegetation scene by finding each group of connected triangles in the scene and if the diameter of the group is below (SeparateFoliageSizeThreshold * SceneDiameter) it is treated as foliage and processed into billboards. The trunk is optimized using reduction. The range is 0->large value. 0 means nothing will be foliage, value larger than the scene's diameter means everything will be foliage.";
                TypeOverride = "";
                DefaultValue = 0.1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageSizeThreshold: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10000f;
                DefaultMaxValue = 10000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageSizeThreshold: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSeparateFoliageSizeThresholdEx DeepCopy()
            {
                return (SimplygonSeparateFoliageSizeThresholdEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.SeparateFoliageSizeThreshold;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float TrunkReductionRatio { get { return _TrunkReductionRatio; } set { _TrunkReductionRatio = value; OnPropertyChanged(); } }
        private float _TrunkReductionRatio;
        public SimplygonTrunkReductionRatioEx TrunkReductionRatioUI { get; set; }
        public class SimplygonTrunkReductionRatioEx : SimplygonSettingsProperty
        {
            public SimplygonFoliageSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.TrunkReductionRatio;
                }

                set
                {
                    bool needReload = Parent.TrunkReductionRatio != value;
                    Parent.TrunkReductionRatio = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonTrunkReductionRatioEx() : base("TrunkReductionRatio")
            {
                Type = "real";
                HelpText = "Determines the triangle reduction ratio for the trunk part that has been separated from the foliage part based on the 'separate foliage' settings.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonTrunkReductionRatioEx(dynamic jsonData) : base("TrunkReductionRatio")
            {
                Type = "real";
                HelpText = "Determines the triangle reduction ratio for the trunk part that has been separated from the foliage part based on the 'separate foliage' settings.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TrunkReductionRatio: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TrunkReductionRatio: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTrunkReductionRatioEx DeepCopy()
            {
                return (SimplygonTrunkReductionRatioEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.TrunkReductionRatio;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonFoliageSettings(SimplygonBillboardCloudSettings parent) : base("FoliageSettings")
        {
            Parent = parent;
            Visible = true;
            SeparateTrunkAndFoliageUI = new SimplygonSeparateTrunkAndFoliageEx();
            SeparateTrunkAndFoliageUI.Parent = this;
            SeparateTrunkAndFoliage = SeparateTrunkAndFoliageUI.DefaultValue;
            Items.Add(SeparateTrunkAndFoliageUI);
            SeparateFoliageTriangleRatioUI = new SimplygonSeparateFoliageTriangleRatioEx();
            SeparateFoliageTriangleRatioUI.Parent = this;
            SeparateFoliageTriangleRatio = SeparateFoliageTriangleRatioUI.DefaultValue;
            Items.Add(SeparateFoliageTriangleRatioUI);
            SeparateFoliageTriangleThresholdUI = new SimplygonSeparateFoliageTriangleThresholdEx();
            SeparateFoliageTriangleThresholdUI.Parent = this;
            SeparateFoliageTriangleThreshold = SeparateFoliageTriangleThresholdUI.DefaultValue;
            Items.Add(SeparateFoliageTriangleThresholdUI);
            SeparateFoliageAreaThresholdUI = new SimplygonSeparateFoliageAreaThresholdEx();
            SeparateFoliageAreaThresholdUI.Parent = this;
            SeparateFoliageAreaThreshold = SeparateFoliageAreaThresholdUI.DefaultValue;
            Items.Add(SeparateFoliageAreaThresholdUI);
            SeparateFoliageSizeThresholdUI = new SimplygonSeparateFoliageSizeThresholdEx();
            SeparateFoliageSizeThresholdUI.Parent = this;
            SeparateFoliageSizeThreshold = SeparateFoliageSizeThresholdUI.DefaultValue;
            Items.Add(SeparateFoliageSizeThresholdUI);
            TrunkReductionRatioUI = new SimplygonTrunkReductionRatioEx();
            TrunkReductionRatioUI.Parent = this;
            TrunkReductionRatio = TrunkReductionRatioUI.DefaultValue;
            Items.Add(TrunkReductionRatioUI);
        }

        public SimplygonFoliageSettings(SimplygonBillboardCloudSettings parent, dynamic jsonData) : base("FoliageSettings")
        {
            Parent = parent;
            Visible = true;
            SeparateTrunkAndFoliageUI = new SimplygonSeparateTrunkAndFoliageEx(jsonData != null && ((JObject)jsonData).GetValue("SeparateTrunkAndFoliageUI") != null ? jsonData.SeparateTrunkAndFoliageUI : null);
            SeparateTrunkAndFoliageUI.Parent = this;
            SeparateTrunkAndFoliage = SeparateTrunkAndFoliageUI.DefaultValue;
            Items.Add(SeparateTrunkAndFoliageUI);
            SeparateFoliageTriangleRatioUI = new SimplygonSeparateFoliageTriangleRatioEx(jsonData != null && ((JObject)jsonData).GetValue("SeparateFoliageTriangleRatioUI") != null ? jsonData.SeparateFoliageTriangleRatioUI : null);
            SeparateFoliageTriangleRatioUI.Parent = this;
            SeparateFoliageTriangleRatio = SeparateFoliageTriangleRatioUI.DefaultValue;
            Items.Add(SeparateFoliageTriangleRatioUI);
            SeparateFoliageTriangleThresholdUI = new SimplygonSeparateFoliageTriangleThresholdEx(jsonData != null && ((JObject)jsonData).GetValue("SeparateFoliageTriangleThresholdUI") != null ? jsonData.SeparateFoliageTriangleThresholdUI : null);
            SeparateFoliageTriangleThresholdUI.Parent = this;
            SeparateFoliageTriangleThreshold = SeparateFoliageTriangleThresholdUI.DefaultValue;
            Items.Add(SeparateFoliageTriangleThresholdUI);
            SeparateFoliageAreaThresholdUI = new SimplygonSeparateFoliageAreaThresholdEx(jsonData != null && ((JObject)jsonData).GetValue("SeparateFoliageAreaThresholdUI") != null ? jsonData.SeparateFoliageAreaThresholdUI : null);
            SeparateFoliageAreaThresholdUI.Parent = this;
            SeparateFoliageAreaThreshold = SeparateFoliageAreaThresholdUI.DefaultValue;
            Items.Add(SeparateFoliageAreaThresholdUI);
            SeparateFoliageSizeThresholdUI = new SimplygonSeparateFoliageSizeThresholdEx(jsonData != null && ((JObject)jsonData).GetValue("SeparateFoliageSizeThresholdUI") != null ? jsonData.SeparateFoliageSizeThresholdUI : null);
            SeparateFoliageSizeThresholdUI.Parent = this;
            SeparateFoliageSizeThreshold = SeparateFoliageSizeThresholdUI.DefaultValue;
            Items.Add(SeparateFoliageSizeThresholdUI);
            TrunkReductionRatioUI = new SimplygonTrunkReductionRatioEx(jsonData != null && ((JObject)jsonData).GetValue("TrunkReductionRatioUI") != null ? jsonData.TrunkReductionRatioUI : null);
            TrunkReductionRatioUI.Parent = this;
            TrunkReductionRatio = TrunkReductionRatioUI.DefaultValue;
            Items.Add(TrunkReductionRatioUI);
            LoadJson(jsonData);
        }

        public SimplygonSettings DeepCopy(SimplygonBillboardCloudSettings parent)
        {
            var copy = new SimplygonFoliageSettings(parent);
            copy.Items.Clear();
            copy.SeparateTrunkAndFoliageUI = this.SeparateTrunkAndFoliageUI.DeepCopy();
            copy.SeparateTrunkAndFoliageUI.Parent = copy;
            copy.Items.Add(copy.SeparateTrunkAndFoliageUI);
            copy.SeparateFoliageTriangleRatioUI = this.SeparateFoliageTriangleRatioUI.DeepCopy();
            copy.SeparateFoliageTriangleRatioUI.Parent = copy;
            copy.Items.Add(copy.SeparateFoliageTriangleRatioUI);
            copy.SeparateFoliageTriangleThresholdUI = this.SeparateFoliageTriangleThresholdUI.DeepCopy();
            copy.SeparateFoliageTriangleThresholdUI.Parent = copy;
            copy.Items.Add(copy.SeparateFoliageTriangleThresholdUI);
            copy.SeparateFoliageAreaThresholdUI = this.SeparateFoliageAreaThresholdUI.DeepCopy();
            copy.SeparateFoliageAreaThresholdUI.Parent = copy;
            copy.Items.Add(copy.SeparateFoliageAreaThresholdUI);
            copy.SeparateFoliageSizeThresholdUI = this.SeparateFoliageSizeThresholdUI.DeepCopy();
            copy.SeparateFoliageSizeThresholdUI.Parent = copy;
            copy.Items.Add(copy.SeparateFoliageSizeThresholdUI);
            copy.TrunkReductionRatioUI = this.TrunkReductionRatioUI.DeepCopy();
            copy.TrunkReductionRatioUI.Parent = copy;
            copy.Items.Add(copy.TrunkReductionRatioUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.SeparateTrunkAndFoliage = SeparateTrunkAndFoliage;
            if(serializeUIComponents)
            {
                jsonData.SeparateTrunkAndFoliageUI = SeparateTrunkAndFoliageUI.SaveJson();
            }

            jsonData.SeparateFoliageTriangleRatio = SeparateFoliageTriangleRatio;
            if(serializeUIComponents)
            {
                jsonData.SeparateFoliageTriangleRatioUI = SeparateFoliageTriangleRatioUI.SaveJson();
            }

            jsonData.SeparateFoliageTriangleThreshold = SeparateFoliageTriangleThreshold;
            if(serializeUIComponents)
            {
                jsonData.SeparateFoliageTriangleThresholdUI = SeparateFoliageTriangleThresholdUI.SaveJson();
            }

            jsonData.SeparateFoliageAreaThreshold = SeparateFoliageAreaThreshold;
            if(serializeUIComponents)
            {
                jsonData.SeparateFoliageAreaThresholdUI = SeparateFoliageAreaThresholdUI.SaveJson();
            }

            jsonData.SeparateFoliageSizeThreshold = SeparateFoliageSizeThreshold;
            if(serializeUIComponents)
            {
                jsonData.SeparateFoliageSizeThresholdUI = SeparateFoliageSizeThresholdUI.SaveJson();
            }

            jsonData.TrunkReductionRatio = TrunkReductionRatio;
            if(serializeUIComponents)
            {
                jsonData.TrunkReductionRatioUI = TrunkReductionRatioUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("SeparateTrunkAndFoliage") != null)
            {
                SeparateTrunkAndFoliage = (bool)jsonData.SeparateTrunkAndFoliage;
            }

            if(jsonData.GetValue("SeparateFoliageTriangleRatio") != null)
            {
                float newSeparateFoliageTriangleRatio = (float)jsonData.SeparateFoliageTriangleRatio;
                if (newSeparateFoliageTriangleRatio >= SeparateFoliageTriangleRatioUI.DefaultMinValue && newSeparateFoliageTriangleRatio <= SeparateFoliageTriangleRatioUI.DefaultMaxValue)
                {
                    SeparateFoliageTriangleRatio = newSeparateFoliageTriangleRatio;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageTriangleRatio: Invalid value {newSeparateFoliageTriangleRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {SeparateFoliageTriangleRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("SeparateFoliageTriangleThreshold") != null)
            {
                var newSeparateFoliageTriangleThreshold = (int)jsonData.SeparateFoliageTriangleThreshold;
                if (newSeparateFoliageTriangleThreshold >= SeparateFoliageTriangleThresholdUI.DefaultMinValue && newSeparateFoliageTriangleThreshold <= SeparateFoliageTriangleThresholdUI.DefaultMaxValue)
                {
                    SeparateFoliageTriangleThreshold = newSeparateFoliageTriangleThreshold;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageTriangleThreshold: Invalid value {newSeparateFoliageTriangleThreshold}, using default value {SeparateFoliageTriangleThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("SeparateFoliageAreaThreshold") != null)
            {
                float newSeparateFoliageAreaThreshold = (float)jsonData.SeparateFoliageAreaThreshold;
                if (newSeparateFoliageAreaThreshold >= SeparateFoliageAreaThresholdUI.DefaultMinValue && newSeparateFoliageAreaThreshold <= SeparateFoliageAreaThresholdUI.DefaultMaxValue)
                {
                    SeparateFoliageAreaThreshold = newSeparateFoliageAreaThreshold;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageAreaThreshold: Invalid value {newSeparateFoliageAreaThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {SeparateFoliageAreaThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("SeparateFoliageSizeThreshold") != null)
            {
                float newSeparateFoliageSizeThreshold = (float)jsonData.SeparateFoliageSizeThreshold;
                if (newSeparateFoliageSizeThreshold >= SeparateFoliageSizeThresholdUI.DefaultMinValue && newSeparateFoliageSizeThreshold <= SeparateFoliageSizeThresholdUI.DefaultMaxValue)
                {
                    SeparateFoliageSizeThreshold = newSeparateFoliageSizeThreshold;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"SeparateFoliageSizeThreshold: Invalid value {newSeparateFoliageSizeThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {SeparateFoliageSizeThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("TrunkReductionRatio") != null)
            {
                float newTrunkReductionRatio = (float)jsonData.TrunkReductionRatio;
                if (newTrunkReductionRatio >= TrunkReductionRatioUI.DefaultMinValue && newTrunkReductionRatio <= TrunkReductionRatioUI.DefaultMaxValue)
                {
                    TrunkReductionRatio = newTrunkReductionRatio;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TrunkReductionRatio: Invalid value {newTrunkReductionRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {TrunkReductionRatio.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            SeparateTrunkAndFoliageUI.Reset();
            SeparateFoliageTriangleRatioUI.Reset();
            SeparateFoliageTriangleThresholdUI.Reset();
            SeparateFoliageAreaThresholdUI.Reset();
            SeparateFoliageSizeThresholdUI.Reset();
            TrunkReductionRatioUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            SeparateTrunkAndFoliageUI.IsEditEnabled = isEditEnabled;
            SeparateFoliageTriangleRatioUI.IsEditEnabled = isEditEnabled;
            SeparateFoliageTriangleThresholdUI.IsEditEnabled = isEditEnabled;
            SeparateFoliageAreaThresholdUI.IsEditEnabled = isEditEnabled;
            SeparateFoliageSizeThresholdUI.IsEditEnabled = isEditEnabled;
            TrunkReductionRatioUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            SeparateTrunkAndFoliageUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SeparateFoliageTriangleRatioUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SeparateFoliageTriangleThresholdUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SeparateFoliageAreaThresholdUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SeparateFoliageSizeThresholdUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TrunkReductionRatioUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonBillboardCloudSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(BillboardModeUI.Visible) return true;
                if(FavorVerticalPlanesUI.Visible) return true;
                if(TwoSidedUI.Visible) return true;
                if(UseVisibilityWeightsUI.Visible) return true;
                if(BillboardDensityUI.Visible) return true;
                if(MaxPlaneCountUI.Visible) return true;
                if(GeometricComplexityUI.Visible) return true;
                if(UpVectorXUI.Visible) return true;
                if(UpVectorYUI.Visible) return true;
                if(UpVectorZUI.Visible) return true;

                if(FoliageSettings != null && FoliageSettings.Visible) return true;
                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public SimplygonFoliageSettings FoliageSettings { get; set; }
        public EBillboardMode BillboardMode { get { return _BillboardMode; } set { _BillboardMode = value; OnPropertyChanged(); } }
        private EBillboardMode _BillboardMode;
        public SimplygonBillboardModeEx BillboardModeUI { get; set; }
        public class SimplygonBillboardModeEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public EBillboardMode Value
            {
                get
                {
                    return Parent.BillboardMode;
                }

                set
                {
                    bool needReload = Parent.BillboardMode != value;
                    Parent.BillboardMode = value;
                    OnPropertyChanged();
                }

            }

            public EBillboardMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EBillboardMode)); } }

            public SimplygonBillboardModeEx() : base("BillboardMode")
            {
                Type = "enum";
                HelpText = "Specifies how the impostors should be mapped to the scene.";
                TypeOverride = "";
                DefaultValue = EBillboardMode.OuterShell;
                Visible = true;
            }

            public SimplygonBillboardModeEx(dynamic jsonData) : base("BillboardMode")
            {
                Type = "enum";
                HelpText = "Specifies how the impostors should be mapped to the scene.";
                TypeOverride = "";
                DefaultValue = EBillboardMode.OuterShell;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBillboardModeEx DeepCopy()
            {
                return (SimplygonBillboardModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.BillboardMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EBillboardMode)value;
            }

        }

        public bool FavorVerticalPlanes { get { return _FavorVerticalPlanes; } set { _FavorVerticalPlanes = value; OnPropertyChanged(); } }
        private bool _FavorVerticalPlanes;
        public SimplygonFavorVerticalPlanesEx FavorVerticalPlanesUI { get; set; }
        public class SimplygonFavorVerticalPlanesEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.FavorVerticalPlanes;
                }

                set
                {
                    bool needReload = Parent.FavorVerticalPlanes != value;
                    Parent.FavorVerticalPlanes = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonFavorVerticalPlanesEx() : base("FavorVerticalPlanes")
            {
                Type = "bool";
                HelpText = "Determines whether to prioritize generating vertical billboards which means they will be optimized to be viewed from the side. Otherwise, if the geometry in the input scene is mostly facing upwards/downwards then the generated billboards will also be facing upwards/downwards which makes them not well suited to being viewed from the side.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonFavorVerticalPlanesEx(dynamic jsonData) : base("FavorVerticalPlanes")
            {
                Type = "bool";
                HelpText = "Determines whether to prioritize generating vertical billboards which means they will be optimized to be viewed from the side. Otherwise, if the geometry in the input scene is mostly facing upwards/downwards then the generated billboards will also be facing upwards/downwards which makes them not well suited to being viewed from the side.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFavorVerticalPlanesEx DeepCopy()
            {
                return (SimplygonFavorVerticalPlanesEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.FavorVerticalPlanes;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool TwoSided { get { return _TwoSided; } set { _TwoSided = value; OnPropertyChanged(); } }
        private bool _TwoSided;
        public SimplygonTwoSidedEx TwoSidedUI { get; set; }
        public class SimplygonTwoSidedEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.TwoSided;
                }

                set
                {
                    bool needReload = Parent.TwoSided != value;
                    Parent.TwoSided = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonTwoSidedEx() : base("TwoSided")
            {
                Type = "bool";
                HelpText = "Only applicable if BillboardMode: Foliage. Determines if the scene is intended to be viewed from both sides without back face culling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonTwoSidedEx(dynamic jsonData) : base("TwoSided")
            {
                Type = "bool";
                HelpText = "Only applicable if BillboardMode: Foliage. Determines if the scene is intended to be viewed from both sides without back face culling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTwoSidedEx DeepCopy()
            {
                return (SimplygonTwoSidedEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.TwoSided;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseVisibilityWeights { get { return _UseVisibilityWeights; } set { _UseVisibilityWeights = value; OnPropertyChanged(); } }
        private bool _UseVisibilityWeights;
        public SimplygonUseVisibilityWeightsEx UseVisibilityWeightsUI { get; set; }
        public class SimplygonUseVisibilityWeightsEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseVisibilityWeights;
                }

                set
                {
                    bool needReload = Parent.UseVisibilityWeights != value;
                    Parent.UseVisibilityWeights = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseVisibilityWeightsEx() : base("UseVisibilityWeights")
            {
                Type = "bool";
                HelpText = "Determines whether to prioritize accurately mapping triangles with higher visibility to billboards.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseVisibilityWeightsEx(dynamic jsonData) : base("UseVisibilityWeights")
            {
                Type = "bool";
                HelpText = "Determines whether to prioritize accurately mapping triangles with higher visibility to billboards.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseVisibilityWeightsEx DeepCopy()
            {
                return (SimplygonUseVisibilityWeightsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseVisibilityWeights;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float BillboardDensity { get { return _BillboardDensity; } set { _BillboardDensity = value; OnPropertyChanged(); } }
        private float _BillboardDensity;
        public SimplygonBillboardDensityEx BillboardDensityUI { get; set; }
        public class SimplygonBillboardDensityEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.BillboardDensity;
                }

                set
                {
                    bool needReload = Parent.BillboardDensity != value;
                    Parent.BillboardDensity = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonBillboardDensityEx() : base("BillboardDensity")
            {
                Type = "real";
                HelpText = "Determines how many billboards to create. A large BillboardDensity means that more billboards will be created to represent spatially spread out triangles better. Having a low BillboardDensity means that fewer billboards will be created and the distances from original leaves to billboards will get larger. The range is 0->1.";
                TypeOverride = "";
                DefaultValue = 0.2f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonBillboardDensityEx(dynamic jsonData) : base("BillboardDensity")
            {
                Type = "real";
                HelpText = "Determines how many billboards to create. A large BillboardDensity means that more billboards will be created to represent spatially spread out triangles better. Having a low BillboardDensity means that fewer billboards will be created and the distances from original leaves to billboards will get larger. The range is 0->1.";
                TypeOverride = "";
                DefaultValue = 0.2f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BillboardDensity: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"BillboardDensity: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBillboardDensityEx DeepCopy()
            {
                return (SimplygonBillboardDensityEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.BillboardDensity;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int MaxPlaneCount { get { return _MaxPlaneCount; } set { _MaxPlaneCount = value; OnPropertyChanged(); } }
        private int _MaxPlaneCount;
        public SimplygonMaxPlaneCountEx MaxPlaneCountUI { get; set; }
        public class SimplygonMaxPlaneCountEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.MaxPlaneCount;
                }

                set
                {
                    bool needReload = Parent.MaxPlaneCount != value;
                    Parent.MaxPlaneCount = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonMaxPlaneCountEx() : base("MaxPlaneCount")
            {
                Type = "uint";
                HelpText = "Determines the maximum billboard count. When this criteria is met, it is not guaranteed that all triangles in the scene have been accurately mapped to a billboard yet. Triangles that have not been mapped to a billboard within the BillboardMaxDeviation distance will be mapped to an existing billboard that best represents the triangle.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 64;
                DefaultMinValue = 0;
                DefaultMaxValue = 64;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonMaxPlaneCountEx(dynamic jsonData) : base("MaxPlaneCount")
            {
                Type = "uint";
                HelpText = "Determines the maximum billboard count. When this criteria is met, it is not guaranteed that all triangles in the scene have been accurately mapped to a billboard yet. Triangles that have not been mapped to a billboard within the BillboardMaxDeviation distance will be mapped to an existing billboard that best represents the triangle.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaxPlaneCount: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 64;
                DefaultMaxValue = 64;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MaxPlaneCount: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaxPlaneCountEx DeepCopy()
            {
                return (SimplygonMaxPlaneCountEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.MaxPlaneCount;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float GeometricComplexity { get { return _GeometricComplexity; } set { _GeometricComplexity = value; OnPropertyChanged(); } }
        private float _GeometricComplexity;
        public SimplygonGeometricComplexityEx GeometricComplexityUI { get; set; }
        public class SimplygonGeometricComplexityEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.GeometricComplexity;
                }

                set
                {
                    bool needReload = Parent.GeometricComplexity != value;
                    Parent.GeometricComplexity = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonGeometricComplexityEx() : base("GeometricComplexity")
            {
                Type = "real";
                HelpText = "Determines the geometric complexity of the billboards. The value range is 0->1, where a value of Zero means that the billboards will be simple and not follow the projection closely. And a value of One means that the geometric complexity will be increased and follow the projection closely.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                MaxValue = 1f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonGeometricComplexityEx(dynamic jsonData) : base("GeometricComplexity")
            {
                Type = "real";
                HelpText = "Determines the geometric complexity of the billboards. The value range is 0->1, where a value of Zero means that the billboards will be simple and not follow the projection closely. And a value of One means that the geometric complexity will be increased and follow the projection closely.";
                TypeOverride = "";
                DefaultValue = 0.5f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometricComplexity: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometricComplexity: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGeometricComplexityEx DeepCopy()
            {
                return (SimplygonGeometricComplexityEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.GeometricComplexity;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float UpVectorX { get { return _UpVectorX; } set { _UpVectorX = value; OnPropertyChanged(); } }
        private float _UpVectorX;
        public SimplygonUpVectorXEx UpVectorXUI { get; set; }
        public class SimplygonUpVectorXEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.UpVectorX;
                }

                set
                {
                    bool needReload = Parent.UpVectorX != value;
                    Parent.UpVectorX = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonUpVectorXEx() : base("UpVectorX")
            {
                Type = "real";
                HelpText = "The UpVector used in the Billboard Cloud Processor. Set this if the input scene has an up vector other than Y+. If FavorVerticalPlanes is enabled, the UpVector determines verticality.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonUpVectorXEx(dynamic jsonData) : base("UpVectorX")
            {
                Type = "real";
                HelpText = "The UpVector used in the Billboard Cloud Processor. Set this if the input scene has an up vector other than Y+. If FavorVerticalPlanes is enabled, the UpVector determines verticality.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorX: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorX: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUpVectorXEx DeepCopy()
            {
                return (SimplygonUpVectorXEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.UpVectorX;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float UpVectorY { get { return _UpVectorY; } set { _UpVectorY = value; OnPropertyChanged(); } }
        private float _UpVectorY;
        public SimplygonUpVectorYEx UpVectorYUI { get; set; }
        public class SimplygonUpVectorYEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.UpVectorY;
                }

                set
                {
                    bool needReload = Parent.UpVectorY != value;
                    Parent.UpVectorY = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonUpVectorYEx() : base("UpVectorY")
            {
                Type = "real";
                HelpText = "The UpVector used in the Billboard Cloud Processor. Set this if the input scene has an up vector other than Y+. If FavorVerticalPlanes is enabled, the UpVector determines verticality.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonUpVectorYEx(dynamic jsonData) : base("UpVectorY")
            {
                Type = "real";
                HelpText = "The UpVector used in the Billboard Cloud Processor. Set this if the input scene has an up vector other than Y+. If FavorVerticalPlanes is enabled, the UpVector determines verticality.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorY: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorY: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUpVectorYEx DeepCopy()
            {
                return (SimplygonUpVectorYEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.UpVectorY;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float UpVectorZ { get { return _UpVectorZ; } set { _UpVectorZ = value; OnPropertyChanged(); } }
        private float _UpVectorZ;
        public SimplygonUpVectorZEx UpVectorZUI { get; set; }
        public class SimplygonUpVectorZEx : SimplygonSettingsProperty
        {
            public SimplygonBillboardCloudSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.UpVectorZ;
                }

                set
                {
                    bool needReload = Parent.UpVectorZ != value;
                    Parent.UpVectorZ = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonUpVectorZEx() : base("UpVectorZ")
            {
                Type = "real";
                HelpText = "The UpVector used in the Billboard Cloud Processor. Set this if the input scene has an up vector other than Y+. If FavorVerticalPlanes is enabled, the UpVector determines verticality.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonUpVectorZEx(dynamic jsonData) : base("UpVectorZ")
            {
                Type = "real";
                HelpText = "The UpVector used in the Billboard Cloud Processor. Set this if the input scene has an up vector other than Y+. If FavorVerticalPlanes is enabled, the UpVector determines verticality.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorZ: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorZ: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUpVectorZEx DeepCopy()
            {
                return (SimplygonUpVectorZEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.UpVectorZ;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonBillboardCloudSettings() : base("BillboardCloudSettings")
        {
            Visible = true;
            BillboardModeUI = new SimplygonBillboardModeEx();
            BillboardModeUI.Parent = this;
            BillboardMode = BillboardModeUI.DefaultValue;
            Items.Add(BillboardModeUI);
            FavorVerticalPlanesUI = new SimplygonFavorVerticalPlanesEx();
            FavorVerticalPlanesUI.Parent = this;
            FavorVerticalPlanes = FavorVerticalPlanesUI.DefaultValue;
            Items.Add(FavorVerticalPlanesUI);
            TwoSidedUI = new SimplygonTwoSidedEx();
            TwoSidedUI.Parent = this;
            TwoSided = TwoSidedUI.DefaultValue;
            Items.Add(TwoSidedUI);
            UseVisibilityWeightsUI = new SimplygonUseVisibilityWeightsEx();
            UseVisibilityWeightsUI.Parent = this;
            UseVisibilityWeights = UseVisibilityWeightsUI.DefaultValue;
            Items.Add(UseVisibilityWeightsUI);
            BillboardDensityUI = new SimplygonBillboardDensityEx();
            BillboardDensityUI.Parent = this;
            BillboardDensity = BillboardDensityUI.DefaultValue;
            Items.Add(BillboardDensityUI);
            MaxPlaneCountUI = new SimplygonMaxPlaneCountEx();
            MaxPlaneCountUI.Parent = this;
            MaxPlaneCount = MaxPlaneCountUI.DefaultValue;
            Items.Add(MaxPlaneCountUI);
            GeometricComplexityUI = new SimplygonGeometricComplexityEx();
            GeometricComplexityUI.Parent = this;
            GeometricComplexity = GeometricComplexityUI.DefaultValue;
            Items.Add(GeometricComplexityUI);
            UpVectorXUI = new SimplygonUpVectorXEx();
            UpVectorXUI.Parent = this;
            UpVectorX = UpVectorXUI.DefaultValue;
            Items.Add(UpVectorXUI);
            UpVectorYUI = new SimplygonUpVectorYEx();
            UpVectorYUI.Parent = this;
            UpVectorY = UpVectorYUI.DefaultValue;
            Items.Add(UpVectorYUI);
            UpVectorZUI = new SimplygonUpVectorZEx();
            UpVectorZUI.Parent = this;
            UpVectorZ = UpVectorZUI.DefaultValue;
            Items.Add(UpVectorZUI);
            FoliageSettings = new SimplygonFoliageSettings(this);
            Items.Add(FoliageSettings);
        }

        public SimplygonBillboardCloudSettings(dynamic jsonData) : base("BillboardCloudSettings")
        {
            Visible = true;
            BillboardModeUI = new SimplygonBillboardModeEx(jsonData != null && ((JObject)jsonData).GetValue("BillboardModeUI") != null ? jsonData.BillboardModeUI : null);
            BillboardModeUI.Parent = this;
            BillboardMode = BillboardModeUI.DefaultValue;
            Items.Add(BillboardModeUI);
            FavorVerticalPlanesUI = new SimplygonFavorVerticalPlanesEx(jsonData != null && ((JObject)jsonData).GetValue("FavorVerticalPlanesUI") != null ? jsonData.FavorVerticalPlanesUI : null);
            FavorVerticalPlanesUI.Parent = this;
            FavorVerticalPlanes = FavorVerticalPlanesUI.DefaultValue;
            Items.Add(FavorVerticalPlanesUI);
            TwoSidedUI = new SimplygonTwoSidedEx(jsonData != null && ((JObject)jsonData).GetValue("TwoSidedUI") != null ? jsonData.TwoSidedUI : null);
            TwoSidedUI.Parent = this;
            TwoSided = TwoSidedUI.DefaultValue;
            Items.Add(TwoSidedUI);
            UseVisibilityWeightsUI = new SimplygonUseVisibilityWeightsEx(jsonData != null && ((JObject)jsonData).GetValue("UseVisibilityWeightsUI") != null ? jsonData.UseVisibilityWeightsUI : null);
            UseVisibilityWeightsUI.Parent = this;
            UseVisibilityWeights = UseVisibilityWeightsUI.DefaultValue;
            Items.Add(UseVisibilityWeightsUI);
            BillboardDensityUI = new SimplygonBillboardDensityEx(jsonData != null && ((JObject)jsonData).GetValue("BillboardDensityUI") != null ? jsonData.BillboardDensityUI : null);
            BillboardDensityUI.Parent = this;
            BillboardDensity = BillboardDensityUI.DefaultValue;
            Items.Add(BillboardDensityUI);
            MaxPlaneCountUI = new SimplygonMaxPlaneCountEx(jsonData != null && ((JObject)jsonData).GetValue("MaxPlaneCountUI") != null ? jsonData.MaxPlaneCountUI : null);
            MaxPlaneCountUI.Parent = this;
            MaxPlaneCount = MaxPlaneCountUI.DefaultValue;
            Items.Add(MaxPlaneCountUI);
            GeometricComplexityUI = new SimplygonGeometricComplexityEx(jsonData != null && ((JObject)jsonData).GetValue("GeometricComplexityUI") != null ? jsonData.GeometricComplexityUI : null);
            GeometricComplexityUI.Parent = this;
            GeometricComplexity = GeometricComplexityUI.DefaultValue;
            Items.Add(GeometricComplexityUI);
            UpVectorXUI = new SimplygonUpVectorXEx(jsonData != null && ((JObject)jsonData).GetValue("UpVectorXUI") != null ? jsonData.UpVectorXUI : null);
            UpVectorXUI.Parent = this;
            UpVectorX = UpVectorXUI.DefaultValue;
            Items.Add(UpVectorXUI);
            UpVectorYUI = new SimplygonUpVectorYEx(jsonData != null && ((JObject)jsonData).GetValue("UpVectorYUI") != null ? jsonData.UpVectorYUI : null);
            UpVectorYUI.Parent = this;
            UpVectorY = UpVectorYUI.DefaultValue;
            Items.Add(UpVectorYUI);
            UpVectorZUI = new SimplygonUpVectorZEx(jsonData != null && ((JObject)jsonData).GetValue("UpVectorZUI") != null ? jsonData.UpVectorZUI : null);
            UpVectorZUI.Parent = this;
            UpVectorZ = UpVectorZUI.DefaultValue;
            Items.Add(UpVectorZUI);
            if(jsonData.GetValue("FoliageSettings") != null)
            {
                FoliageSettings = new SimplygonFoliageSettings(this, jsonData.FoliageSettings);
                Items.Add(FoliageSettings);
            }

            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonBillboardCloudSettings();
            copy.Items.Clear();
            copy.BillboardModeUI = this.BillboardModeUI.DeepCopy();
            copy.BillboardModeUI.Parent = copy;
            copy.Items.Add(copy.BillboardModeUI);
            copy.FavorVerticalPlanesUI = this.FavorVerticalPlanesUI.DeepCopy();
            copy.FavorVerticalPlanesUI.Parent = copy;
            copy.Items.Add(copy.FavorVerticalPlanesUI);
            copy.TwoSidedUI = this.TwoSidedUI.DeepCopy();
            copy.TwoSidedUI.Parent = copy;
            copy.Items.Add(copy.TwoSidedUI);
            copy.UseVisibilityWeightsUI = this.UseVisibilityWeightsUI.DeepCopy();
            copy.UseVisibilityWeightsUI.Parent = copy;
            copy.Items.Add(copy.UseVisibilityWeightsUI);
            copy.BillboardDensityUI = this.BillboardDensityUI.DeepCopy();
            copy.BillboardDensityUI.Parent = copy;
            copy.Items.Add(copy.BillboardDensityUI);
            copy.MaxPlaneCountUI = this.MaxPlaneCountUI.DeepCopy();
            copy.MaxPlaneCountUI.Parent = copy;
            copy.Items.Add(copy.MaxPlaneCountUI);
            copy.GeometricComplexityUI = this.GeometricComplexityUI.DeepCopy();
            copy.GeometricComplexityUI.Parent = copy;
            copy.Items.Add(copy.GeometricComplexityUI);
            copy.UpVectorXUI = this.UpVectorXUI.DeepCopy();
            copy.UpVectorXUI.Parent = copy;
            copy.Items.Add(copy.UpVectorXUI);
            copy.UpVectorYUI = this.UpVectorYUI.DeepCopy();
            copy.UpVectorYUI.Parent = copy;
            copy.Items.Add(copy.UpVectorYUI);
            copy.UpVectorZUI = this.UpVectorZUI.DeepCopy();
            copy.UpVectorZUI.Parent = copy;
            copy.Items.Add(copy.UpVectorZUI);
            if (FoliageSettings != null)
            {
                copy.FoliageSettings = (SimplygonFoliageSettings)this.FoliageSettings.DeepCopy(copy);
                copy.Items.Add(copy.FoliageSettings);
            }

            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.BillboardMode = (int)BillboardMode;
            if(serializeUIComponents)
            {
                jsonData.BillboardModeUI = BillboardModeUI.SaveJson();
            }

            jsonData.FavorVerticalPlanes = FavorVerticalPlanes;
            if(serializeUIComponents)
            {
                jsonData.FavorVerticalPlanesUI = FavorVerticalPlanesUI.SaveJson();
            }

            jsonData.TwoSided = TwoSided;
            if(serializeUIComponents)
            {
                jsonData.TwoSidedUI = TwoSidedUI.SaveJson();
            }

            jsonData.UseVisibilityWeights = UseVisibilityWeights;
            if(serializeUIComponents)
            {
                jsonData.UseVisibilityWeightsUI = UseVisibilityWeightsUI.SaveJson();
            }

            jsonData.BillboardDensity = BillboardDensity;
            if(serializeUIComponents)
            {
                jsonData.BillboardDensityUI = BillboardDensityUI.SaveJson();
            }

            jsonData.MaxPlaneCount = MaxPlaneCount;
            if(serializeUIComponents)
            {
                jsonData.MaxPlaneCountUI = MaxPlaneCountUI.SaveJson();
            }

            jsonData.GeometricComplexity = GeometricComplexity;
            if(serializeUIComponents)
            {
                jsonData.GeometricComplexityUI = GeometricComplexityUI.SaveJson();
            }

            jsonData.UpVectorX = UpVectorX;
            if(serializeUIComponents)
            {
                jsonData.UpVectorXUI = UpVectorXUI.SaveJson();
            }

            jsonData.UpVectorY = UpVectorY;
            if(serializeUIComponents)
            {
                jsonData.UpVectorYUI = UpVectorYUI.SaveJson();
            }

            jsonData.UpVectorZ = UpVectorZ;
            if(serializeUIComponents)
            {
                jsonData.UpVectorZUI = UpVectorZUI.SaveJson();
            }

            if (FoliageSettings != null)
            {
                jsonData.FoliageSettings = FoliageSettings.SaveJson(serializeUIComponents);
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("BillboardMode") != null)
            {
                BillboardMode = (EBillboardMode)jsonData.BillboardMode;
            }

            if(jsonData.GetValue("FavorVerticalPlanes") != null)
            {
                FavorVerticalPlanes = (bool)jsonData.FavorVerticalPlanes;
            }

            if(jsonData.GetValue("TwoSided") != null)
            {
                TwoSided = (bool)jsonData.TwoSided;
            }

            if(jsonData.GetValue("UseVisibilityWeights") != null)
            {
                UseVisibilityWeights = (bool)jsonData.UseVisibilityWeights;
            }

            if(jsonData.GetValue("BillboardDensity") != null)
            {
                float newBillboardDensity = (float)jsonData.BillboardDensity;
                if (newBillboardDensity >= BillboardDensityUI.DefaultMinValue && newBillboardDensity <= BillboardDensityUI.DefaultMaxValue)
                {
                    BillboardDensity = newBillboardDensity;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"BillboardDensity: Invalid value {newBillboardDensity.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {BillboardDensity.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MaxPlaneCount") != null)
            {
                var newMaxPlaneCount = (int)jsonData.MaxPlaneCount;
                if (newMaxPlaneCount >= MaxPlaneCountUI.DefaultMinValue && newMaxPlaneCount <= MaxPlaneCountUI.DefaultMaxValue)
                {
                    MaxPlaneCount = newMaxPlaneCount;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MaxPlaneCount: Invalid value {newMaxPlaneCount}, using default value {MaxPlaneCount.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("GeometricComplexity") != null)
            {
                float newGeometricComplexity = (float)jsonData.GeometricComplexity;
                if (newGeometricComplexity >= GeometricComplexityUI.DefaultMinValue && newGeometricComplexity <= GeometricComplexityUI.DefaultMaxValue)
                {
                    GeometricComplexity = newGeometricComplexity;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"GeometricComplexity: Invalid value {newGeometricComplexity.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {GeometricComplexity.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UpVectorX") != null)
            {
                float newUpVectorX = (float)jsonData.UpVectorX;
                if (newUpVectorX >= UpVectorXUI.DefaultMinValue && newUpVectorX <= UpVectorXUI.DefaultMaxValue)
                {
                    UpVectorX = newUpVectorX;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorX: Invalid value {newUpVectorX.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {UpVectorX.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UpVectorY") != null)
            {
                float newUpVectorY = (float)jsonData.UpVectorY;
                if (newUpVectorY >= UpVectorYUI.DefaultMinValue && newUpVectorY <= UpVectorYUI.DefaultMaxValue)
                {
                    UpVectorY = newUpVectorY;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorY: Invalid value {newUpVectorY.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {UpVectorY.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UpVectorZ") != null)
            {
                float newUpVectorZ = (float)jsonData.UpVectorZ;
                if (newUpVectorZ >= UpVectorZUI.DefaultMinValue && newUpVectorZ <= UpVectorZUI.DefaultMaxValue)
                {
                    UpVectorZ = newUpVectorZ;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorZ: Invalid value {newUpVectorZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {UpVectorZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            BillboardModeUI.Reset();
            FavorVerticalPlanesUI.Reset();
            TwoSidedUI.Reset();
            UseVisibilityWeightsUI.Reset();
            BillboardDensityUI.Reset();
            MaxPlaneCountUI.Reset();
            GeometricComplexityUI.Reset();
            UpVectorXUI.Reset();
            UpVectorYUI.Reset();
            UpVectorZUI.Reset();
            if (FoliageSettings != null)
            {
                FoliageSettings.Reset();
            }

        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            BillboardModeUI.IsEditEnabled = isEditEnabled;
            FavorVerticalPlanesUI.IsEditEnabled = isEditEnabled;
            TwoSidedUI.IsEditEnabled = isEditEnabled;
            UseVisibilityWeightsUI.IsEditEnabled = isEditEnabled;
            BillboardDensityUI.IsEditEnabled = isEditEnabled;
            MaxPlaneCountUI.IsEditEnabled = isEditEnabled;
            GeometricComplexityUI.IsEditEnabled = isEditEnabled;
            UpVectorXUI.IsEditEnabled = isEditEnabled;
            UpVectorYUI.IsEditEnabled = isEditEnabled;
            UpVectorZUI.IsEditEnabled = isEditEnabled;
            if (FoliageSettings != null)
            {
                FoliageSettings.SetEditMode(isEditEnabled);
            }

        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            BillboardModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FavorVerticalPlanesUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TwoSidedUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseVisibilityWeightsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BillboardDensityUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MaxPlaneCountUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GeometricComplexityUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UpVectorXUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UpVectorYUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UpVectorZUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (FoliageSettings != null)
            {
                FoliageSettings.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonFlipbookSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(NumberOfViewsUI.Visible) return true;
                if(ViewDirectionXUI.Visible) return true;
                if(ViewDirectionYUI.Visible) return true;
                if(ViewDirectionZUI.Visible) return true;
                if(UpVectorXUI.Visible) return true;
                if(UpVectorYUI.Visible) return true;
                if(UpVectorZUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public int NumberOfViews { get { return _NumberOfViews; } set { _NumberOfViews = value; OnPropertyChanged(); } }
        private int _NumberOfViews;
        public SimplygonNumberOfViewsEx NumberOfViewsUI { get; set; }
        public class SimplygonNumberOfViewsEx : SimplygonSettingsProperty
        {
            public SimplygonFlipbookSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.NumberOfViews;
                }

                set
                {
                    bool needReload = Parent.NumberOfViews != value;
                    Parent.NumberOfViews = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonNumberOfViewsEx() : base("NumberOfViews")
            {
                Type = "uint";
                HelpText = "Determines the number of views generated for the flip book impostor.";
                TypeOverride = "";
                DefaultValue = 9;
                MinValue = 0;
                MaxValue = 64;
                DefaultMinValue = 0;
                DefaultMaxValue = 64;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonNumberOfViewsEx(dynamic jsonData) : base("NumberOfViews")
            {
                Type = "uint";
                HelpText = "Determines the number of views generated for the flip book impostor.";
                TypeOverride = "";
                DefaultValue = 9;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"NumberOfViews: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 64;
                DefaultMaxValue = 64;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"NumberOfViews: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonNumberOfViewsEx DeepCopy()
            {
                return (SimplygonNumberOfViewsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.NumberOfViews;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float ViewDirectionX { get { return _ViewDirectionX; } set { _ViewDirectionX = value; OnPropertyChanged(); } }
        private float _ViewDirectionX;
        public SimplygonViewDirectionXEx ViewDirectionXUI { get; set; }
        public class SimplygonViewDirectionXEx : SimplygonSettingsProperty
        {
            public SimplygonFlipbookSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ViewDirectionX;
                }

                set
                {
                    bool needReload = Parent.ViewDirectionX != value;
                    Parent.ViewDirectionX = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonViewDirectionXEx() : base("ViewDirectionX")
            {
                Type = "real";
                HelpText = "The X component of the ViewDirection vector. The ViewDirection determines the direction of the first view. The rest of the views are uniformly distributed around the scene rotated around the up-vector. The resulting billboard will be oriented in the negative view direction.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonViewDirectionXEx(dynamic jsonData) : base("ViewDirectionX")
            {
                Type = "real";
                HelpText = "The X component of the ViewDirection vector. The ViewDirection determines the direction of the first view. The rest of the views are uniformly distributed around the scene rotated around the up-vector. The resulting billboard will be oriented in the negative view direction.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionX: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionX: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonViewDirectionXEx DeepCopy()
            {
                return (SimplygonViewDirectionXEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ViewDirectionX;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float ViewDirectionY { get { return _ViewDirectionY; } set { _ViewDirectionY = value; OnPropertyChanged(); } }
        private float _ViewDirectionY;
        public SimplygonViewDirectionYEx ViewDirectionYUI { get; set; }
        public class SimplygonViewDirectionYEx : SimplygonSettingsProperty
        {
            public SimplygonFlipbookSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ViewDirectionY;
                }

                set
                {
                    bool needReload = Parent.ViewDirectionY != value;
                    Parent.ViewDirectionY = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonViewDirectionYEx() : base("ViewDirectionY")
            {
                Type = "real";
                HelpText = "The Y component of the ViewDirection vector. The ViewDirection determines the direction of the first view. The rest of the views are uniformly distributed around the scene rotated around the up-vector. The resulting billboard will be oriented in the negative view direction.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonViewDirectionYEx(dynamic jsonData) : base("ViewDirectionY")
            {
                Type = "real";
                HelpText = "The Y component of the ViewDirection vector. The ViewDirection determines the direction of the first view. The rest of the views are uniformly distributed around the scene rotated around the up-vector. The resulting billboard will be oriented in the negative view direction.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionY: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionY: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonViewDirectionYEx DeepCopy()
            {
                return (SimplygonViewDirectionYEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ViewDirectionY;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float ViewDirectionZ { get { return _ViewDirectionZ; } set { _ViewDirectionZ = value; OnPropertyChanged(); } }
        private float _ViewDirectionZ;
        public SimplygonViewDirectionZEx ViewDirectionZUI { get; set; }
        public class SimplygonViewDirectionZEx : SimplygonSettingsProperty
        {
            public SimplygonFlipbookSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ViewDirectionZ;
                }

                set
                {
                    bool needReload = Parent.ViewDirectionZ != value;
                    Parent.ViewDirectionZ = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonViewDirectionZEx() : base("ViewDirectionZ")
            {
                Type = "real";
                HelpText = "The Z component of the ViewDirection vector. The ViewDirection determines the direction of the first view. The rest of the views are uniformly distributed around the scene rotated around the up-vector. The resulting billboard will be oriented in the negative view direction.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonViewDirectionZEx(dynamic jsonData) : base("ViewDirectionZ")
            {
                Type = "real";
                HelpText = "The Z component of the ViewDirection vector. The ViewDirection determines the direction of the first view. The rest of the views are uniformly distributed around the scene rotated around the up-vector. The resulting billboard will be oriented in the negative view direction.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionZ: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionZ: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonViewDirectionZEx DeepCopy()
            {
                return (SimplygonViewDirectionZEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ViewDirectionZ;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float UpVectorX { get { return _UpVectorX; } set { _UpVectorX = value; OnPropertyChanged(); } }
        private float _UpVectorX;
        public SimplygonUpVectorXEx UpVectorXUI { get; set; }
        public class SimplygonUpVectorXEx : SimplygonSettingsProperty
        {
            public SimplygonFlipbookSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.UpVectorX;
                }

                set
                {
                    bool needReload = Parent.UpVectorX != value;
                    Parent.UpVectorX = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonUpVectorXEx() : base("UpVectorX")
            {
                Type = "real";
                HelpText = "The views are rotated around the up vector and the rendered images are oriented with the up vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonUpVectorXEx(dynamic jsonData) : base("UpVectorX")
            {
                Type = "real";
                HelpText = "The views are rotated around the up vector and the rendered images are oriented with the up vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorX: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorX: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUpVectorXEx DeepCopy()
            {
                return (SimplygonUpVectorXEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.UpVectorX;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float UpVectorY { get { return _UpVectorY; } set { _UpVectorY = value; OnPropertyChanged(); } }
        private float _UpVectorY;
        public SimplygonUpVectorYEx UpVectorYUI { get; set; }
        public class SimplygonUpVectorYEx : SimplygonSettingsProperty
        {
            public SimplygonFlipbookSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.UpVectorY;
                }

                set
                {
                    bool needReload = Parent.UpVectorY != value;
                    Parent.UpVectorY = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonUpVectorYEx() : base("UpVectorY")
            {
                Type = "real";
                HelpText = "The views are rotated around the up vector and the rendered images are oriented with the up vector.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonUpVectorYEx(dynamic jsonData) : base("UpVectorY")
            {
                Type = "real";
                HelpText = "The views are rotated around the up vector and the rendered images are oriented with the up vector.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorY: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorY: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUpVectorYEx DeepCopy()
            {
                return (SimplygonUpVectorYEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.UpVectorY;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float UpVectorZ { get { return _UpVectorZ; } set { _UpVectorZ = value; OnPropertyChanged(); } }
        private float _UpVectorZ;
        public SimplygonUpVectorZEx UpVectorZUI { get; set; }
        public class SimplygonUpVectorZEx : SimplygonSettingsProperty
        {
            public SimplygonFlipbookSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.UpVectorZ;
                }

                set
                {
                    bool needReload = Parent.UpVectorZ != value;
                    Parent.UpVectorZ = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonUpVectorZEx() : base("UpVectorZ")
            {
                Type = "real";
                HelpText = "The views are rotated around the up vector and the rendered images are oriented with the up vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonUpVectorZEx(dynamic jsonData) : base("UpVectorZ")
            {
                Type = "real";
                HelpText = "The views are rotated around the up vector and the rendered images are oriented with the up vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorZ: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorZ: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUpVectorZEx DeepCopy()
            {
                return (SimplygonUpVectorZEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.UpVectorZ;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonFlipbookSettings() : base("FlipbookSettings")
        {
            Visible = true;
            NumberOfViewsUI = new SimplygonNumberOfViewsEx();
            NumberOfViewsUI.Parent = this;
            NumberOfViews = NumberOfViewsUI.DefaultValue;
            Items.Add(NumberOfViewsUI);
            ViewDirectionXUI = new SimplygonViewDirectionXEx();
            ViewDirectionXUI.Parent = this;
            ViewDirectionX = ViewDirectionXUI.DefaultValue;
            Items.Add(ViewDirectionXUI);
            ViewDirectionYUI = new SimplygonViewDirectionYEx();
            ViewDirectionYUI.Parent = this;
            ViewDirectionY = ViewDirectionYUI.DefaultValue;
            Items.Add(ViewDirectionYUI);
            ViewDirectionZUI = new SimplygonViewDirectionZEx();
            ViewDirectionZUI.Parent = this;
            ViewDirectionZ = ViewDirectionZUI.DefaultValue;
            Items.Add(ViewDirectionZUI);
            UpVectorXUI = new SimplygonUpVectorXEx();
            UpVectorXUI.Parent = this;
            UpVectorX = UpVectorXUI.DefaultValue;
            Items.Add(UpVectorXUI);
            UpVectorYUI = new SimplygonUpVectorYEx();
            UpVectorYUI.Parent = this;
            UpVectorY = UpVectorYUI.DefaultValue;
            Items.Add(UpVectorYUI);
            UpVectorZUI = new SimplygonUpVectorZEx();
            UpVectorZUI.Parent = this;
            UpVectorZ = UpVectorZUI.DefaultValue;
            Items.Add(UpVectorZUI);
        }

        public SimplygonFlipbookSettings(dynamic jsonData) : base("FlipbookSettings")
        {
            Visible = true;
            NumberOfViewsUI = new SimplygonNumberOfViewsEx(jsonData != null && ((JObject)jsonData).GetValue("NumberOfViewsUI") != null ? jsonData.NumberOfViewsUI : null);
            NumberOfViewsUI.Parent = this;
            NumberOfViews = NumberOfViewsUI.DefaultValue;
            Items.Add(NumberOfViewsUI);
            ViewDirectionXUI = new SimplygonViewDirectionXEx(jsonData != null && ((JObject)jsonData).GetValue("ViewDirectionXUI") != null ? jsonData.ViewDirectionXUI : null);
            ViewDirectionXUI.Parent = this;
            ViewDirectionX = ViewDirectionXUI.DefaultValue;
            Items.Add(ViewDirectionXUI);
            ViewDirectionYUI = new SimplygonViewDirectionYEx(jsonData != null && ((JObject)jsonData).GetValue("ViewDirectionYUI") != null ? jsonData.ViewDirectionYUI : null);
            ViewDirectionYUI.Parent = this;
            ViewDirectionY = ViewDirectionYUI.DefaultValue;
            Items.Add(ViewDirectionYUI);
            ViewDirectionZUI = new SimplygonViewDirectionZEx(jsonData != null && ((JObject)jsonData).GetValue("ViewDirectionZUI") != null ? jsonData.ViewDirectionZUI : null);
            ViewDirectionZUI.Parent = this;
            ViewDirectionZ = ViewDirectionZUI.DefaultValue;
            Items.Add(ViewDirectionZUI);
            UpVectorXUI = new SimplygonUpVectorXEx(jsonData != null && ((JObject)jsonData).GetValue("UpVectorXUI") != null ? jsonData.UpVectorXUI : null);
            UpVectorXUI.Parent = this;
            UpVectorX = UpVectorXUI.DefaultValue;
            Items.Add(UpVectorXUI);
            UpVectorYUI = new SimplygonUpVectorYEx(jsonData != null && ((JObject)jsonData).GetValue("UpVectorYUI") != null ? jsonData.UpVectorYUI : null);
            UpVectorYUI.Parent = this;
            UpVectorY = UpVectorYUI.DefaultValue;
            Items.Add(UpVectorYUI);
            UpVectorZUI = new SimplygonUpVectorZEx(jsonData != null && ((JObject)jsonData).GetValue("UpVectorZUI") != null ? jsonData.UpVectorZUI : null);
            UpVectorZUI.Parent = this;
            UpVectorZ = UpVectorZUI.DefaultValue;
            Items.Add(UpVectorZUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonFlipbookSettings();
            copy.Items.Clear();
            copy.NumberOfViewsUI = this.NumberOfViewsUI.DeepCopy();
            copy.NumberOfViewsUI.Parent = copy;
            copy.Items.Add(copy.NumberOfViewsUI);
            copy.ViewDirectionXUI = this.ViewDirectionXUI.DeepCopy();
            copy.ViewDirectionXUI.Parent = copy;
            copy.Items.Add(copy.ViewDirectionXUI);
            copy.ViewDirectionYUI = this.ViewDirectionYUI.DeepCopy();
            copy.ViewDirectionYUI.Parent = copy;
            copy.Items.Add(copy.ViewDirectionYUI);
            copy.ViewDirectionZUI = this.ViewDirectionZUI.DeepCopy();
            copy.ViewDirectionZUI.Parent = copy;
            copy.Items.Add(copy.ViewDirectionZUI);
            copy.UpVectorXUI = this.UpVectorXUI.DeepCopy();
            copy.UpVectorXUI.Parent = copy;
            copy.Items.Add(copy.UpVectorXUI);
            copy.UpVectorYUI = this.UpVectorYUI.DeepCopy();
            copy.UpVectorYUI.Parent = copy;
            copy.Items.Add(copy.UpVectorYUI);
            copy.UpVectorZUI = this.UpVectorZUI.DeepCopy();
            copy.UpVectorZUI.Parent = copy;
            copy.Items.Add(copy.UpVectorZUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.NumberOfViews = NumberOfViews;
            if(serializeUIComponents)
            {
                jsonData.NumberOfViewsUI = NumberOfViewsUI.SaveJson();
            }

            jsonData.ViewDirectionX = ViewDirectionX;
            if(serializeUIComponents)
            {
                jsonData.ViewDirectionXUI = ViewDirectionXUI.SaveJson();
            }

            jsonData.ViewDirectionY = ViewDirectionY;
            if(serializeUIComponents)
            {
                jsonData.ViewDirectionYUI = ViewDirectionYUI.SaveJson();
            }

            jsonData.ViewDirectionZ = ViewDirectionZ;
            if(serializeUIComponents)
            {
                jsonData.ViewDirectionZUI = ViewDirectionZUI.SaveJson();
            }

            jsonData.UpVectorX = UpVectorX;
            if(serializeUIComponents)
            {
                jsonData.UpVectorXUI = UpVectorXUI.SaveJson();
            }

            jsonData.UpVectorY = UpVectorY;
            if(serializeUIComponents)
            {
                jsonData.UpVectorYUI = UpVectorYUI.SaveJson();
            }

            jsonData.UpVectorZ = UpVectorZ;
            if(serializeUIComponents)
            {
                jsonData.UpVectorZUI = UpVectorZUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("NumberOfViews") != null)
            {
                var newNumberOfViews = (int)jsonData.NumberOfViews;
                if (newNumberOfViews >= NumberOfViewsUI.DefaultMinValue && newNumberOfViews <= NumberOfViewsUI.DefaultMaxValue)
                {
                    NumberOfViews = newNumberOfViews;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"NumberOfViews: Invalid value {newNumberOfViews}, using default value {NumberOfViews.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ViewDirectionX") != null)
            {
                float newViewDirectionX = (float)jsonData.ViewDirectionX;
                if (newViewDirectionX >= ViewDirectionXUI.DefaultMinValue && newViewDirectionX <= ViewDirectionXUI.DefaultMaxValue)
                {
                    ViewDirectionX = newViewDirectionX;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionX: Invalid value {newViewDirectionX.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ViewDirectionX.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ViewDirectionY") != null)
            {
                float newViewDirectionY = (float)jsonData.ViewDirectionY;
                if (newViewDirectionY >= ViewDirectionYUI.DefaultMinValue && newViewDirectionY <= ViewDirectionYUI.DefaultMaxValue)
                {
                    ViewDirectionY = newViewDirectionY;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionY: Invalid value {newViewDirectionY.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ViewDirectionY.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ViewDirectionZ") != null)
            {
                float newViewDirectionZ = (float)jsonData.ViewDirectionZ;
                if (newViewDirectionZ >= ViewDirectionZUI.DefaultMinValue && newViewDirectionZ <= ViewDirectionZUI.DefaultMaxValue)
                {
                    ViewDirectionZ = newViewDirectionZ;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionZ: Invalid value {newViewDirectionZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ViewDirectionZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UpVectorX") != null)
            {
                float newUpVectorX = (float)jsonData.UpVectorX;
                if (newUpVectorX >= UpVectorXUI.DefaultMinValue && newUpVectorX <= UpVectorXUI.DefaultMaxValue)
                {
                    UpVectorX = newUpVectorX;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorX: Invalid value {newUpVectorX.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {UpVectorX.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UpVectorY") != null)
            {
                float newUpVectorY = (float)jsonData.UpVectorY;
                if (newUpVectorY >= UpVectorYUI.DefaultMinValue && newUpVectorY <= UpVectorYUI.DefaultMaxValue)
                {
                    UpVectorY = newUpVectorY;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorY: Invalid value {newUpVectorY.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {UpVectorY.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UpVectorZ") != null)
            {
                float newUpVectorZ = (float)jsonData.UpVectorZ;
                if (newUpVectorZ >= UpVectorZUI.DefaultMinValue && newUpVectorZ <= UpVectorZUI.DefaultMaxValue)
                {
                    UpVectorZ = newUpVectorZ;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"UpVectorZ: Invalid value {newUpVectorZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {UpVectorZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            NumberOfViewsUI.Reset();
            ViewDirectionXUI.Reset();
            ViewDirectionYUI.Reset();
            ViewDirectionZUI.Reset();
            UpVectorXUI.Reset();
            UpVectorYUI.Reset();
            UpVectorZUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            NumberOfViewsUI.IsEditEnabled = isEditEnabled;
            ViewDirectionXUI.IsEditEnabled = isEditEnabled;
            ViewDirectionYUI.IsEditEnabled = isEditEnabled;
            ViewDirectionZUI.IsEditEnabled = isEditEnabled;
            UpVectorXUI.IsEditEnabled = isEditEnabled;
            UpVectorYUI.IsEditEnabled = isEditEnabled;
            UpVectorZUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            NumberOfViewsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ViewDirectionXUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ViewDirectionYUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ViewDirectionZUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UpVectorXUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UpVectorYUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UpVectorZUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonImpostorFromSingleViewSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(UseTightFittingUI.Visible) return true;
                if(TightFittingDepthOffsetUI.Visible) return true;
                if(TwoSidedUI.Visible) return true;
                if(ViewDirectionXUI.Visible) return true;
                if(ViewDirectionYUI.Visible) return true;
                if(ViewDirectionZUI.Visible) return true;
                if(TexCoordPaddingUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public bool UseTightFitting { get { return _UseTightFitting; } set { _UseTightFitting = value; OnPropertyChanged(); } }
        private bool _UseTightFitting;
        public SimplygonUseTightFittingEx UseTightFittingUI { get; set; }
        public class SimplygonUseTightFittingEx : SimplygonSettingsProperty
        {
            public SimplygonImpostorFromSingleViewSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseTightFitting;
                }

                set
                {
                    bool needReload = Parent.UseTightFitting != value;
                    Parent.UseTightFitting = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseTightFittingEx() : base("UseTightFitting")
            {
                Type = "bool";
                HelpText = "If set, the impostor will exactly conform to the bounds of the geometry. If false, its dimensions will always be diameter*diameter.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseTightFittingEx(dynamic jsonData) : base("UseTightFitting")
            {
                Type = "bool";
                HelpText = "If set, the impostor will exactly conform to the bounds of the geometry. If false, its dimensions will always be diameter*diameter.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseTightFittingEx DeepCopy()
            {
                return (SimplygonUseTightFittingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseTightFitting;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float TightFittingDepthOffset { get { return _TightFittingDepthOffset; } set { _TightFittingDepthOffset = value; OnPropertyChanged(); } }
        private float _TightFittingDepthOffset;
        public SimplygonTightFittingDepthOffsetEx TightFittingDepthOffsetUI { get; set; }
        public class SimplygonTightFittingDepthOffsetEx : SimplygonSettingsProperty
        {
            public SimplygonImpostorFromSingleViewSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.TightFittingDepthOffset;
                }

                set
                {
                    bool needReload = Parent.TightFittingDepthOffset != value;
                    Parent.TightFittingDepthOffset = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonTightFittingDepthOffsetEx() : base("TightFittingDepthOffset")
            {
                Type = "real";
                HelpText = "This determines where the impostor will end up in depth. 0 is 'center', 1 is 'front' and -1 is 'back'.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonTightFittingDepthOffsetEx(dynamic jsonData) : base("TightFittingDepthOffset")
            {
                Type = "real";
                HelpText = "This determines where the impostor will end up in depth. 0 is 'center', 1 is 'front' and -1 is 'back'.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TightFittingDepthOffset: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TightFittingDepthOffset: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTightFittingDepthOffsetEx DeepCopy()
            {
                return (SimplygonTightFittingDepthOffsetEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.TightFittingDepthOffset;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool TwoSided { get { return _TwoSided; } set { _TwoSided = value; OnPropertyChanged(); } }
        private bool _TwoSided;
        public SimplygonTwoSidedEx TwoSidedUI { get; set; }
        public class SimplygonTwoSidedEx : SimplygonSettingsProperty
        {
            public SimplygonImpostorFromSingleViewSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.TwoSided;
                }

                set
                {
                    bool needReload = Parent.TwoSided != value;
                    Parent.TwoSided = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonTwoSidedEx() : base("TwoSided")
            {
                Type = "bool";
                HelpText = "If set, the impostor will contain both front and back facing surfaces.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonTwoSidedEx(dynamic jsonData) : base("TwoSided")
            {
                Type = "bool";
                HelpText = "If set, the impostor will contain both front and back facing surfaces.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTwoSidedEx DeepCopy()
            {
                return (SimplygonTwoSidedEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.TwoSided;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float ViewDirectionX { get { return _ViewDirectionX; } set { _ViewDirectionX = value; OnPropertyChanged(); } }
        private float _ViewDirectionX;
        public SimplygonViewDirectionXEx ViewDirectionXUI { get; set; }
        public class SimplygonViewDirectionXEx : SimplygonSettingsProperty
        {
            public SimplygonImpostorFromSingleViewSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ViewDirectionX;
                }

                set
                {
                    bool needReload = Parent.ViewDirectionX != value;
                    Parent.ViewDirectionX = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonViewDirectionXEx() : base("ViewDirectionX")
            {
                Type = "real";
                HelpText = "The X component of the ViewDirection vector. The ViewDirection determines how the resulting impostor geometry will be oriented. The billboard will be perpendicular to this vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonViewDirectionXEx(dynamic jsonData) : base("ViewDirectionX")
            {
                Type = "real";
                HelpText = "The X component of the ViewDirection vector. The ViewDirection determines how the resulting impostor geometry will be oriented. The billboard will be perpendicular to this vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionX: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionX: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonViewDirectionXEx DeepCopy()
            {
                return (SimplygonViewDirectionXEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ViewDirectionX;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float ViewDirectionY { get { return _ViewDirectionY; } set { _ViewDirectionY = value; OnPropertyChanged(); } }
        private float _ViewDirectionY;
        public SimplygonViewDirectionYEx ViewDirectionYUI { get; set; }
        public class SimplygonViewDirectionYEx : SimplygonSettingsProperty
        {
            public SimplygonImpostorFromSingleViewSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ViewDirectionY;
                }

                set
                {
                    bool needReload = Parent.ViewDirectionY != value;
                    Parent.ViewDirectionY = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonViewDirectionYEx() : base("ViewDirectionY")
            {
                Type = "real";
                HelpText = "The Y component of the ViewDirection vector. The ViewDirection determines how the resulting impostor geometry will be oriented. The billboard will be perpendicular to this vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonViewDirectionYEx(dynamic jsonData) : base("ViewDirectionY")
            {
                Type = "real";
                HelpText = "The Y component of the ViewDirection vector. The ViewDirection determines how the resulting impostor geometry will be oriented. The billboard will be perpendicular to this vector.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionY: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionY: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonViewDirectionYEx DeepCopy()
            {
                return (SimplygonViewDirectionYEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ViewDirectionY;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float ViewDirectionZ { get { return _ViewDirectionZ; } set { _ViewDirectionZ = value; OnPropertyChanged(); } }
        private float _ViewDirectionZ;
        public SimplygonViewDirectionZEx ViewDirectionZUI { get; set; }
        public class SimplygonViewDirectionZEx : SimplygonSettingsProperty
        {
            public SimplygonImpostorFromSingleViewSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ViewDirectionZ;
                }

                set
                {
                    bool needReload = Parent.ViewDirectionZ != value;
                    Parent.ViewDirectionZ = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonViewDirectionZEx() : base("ViewDirectionZ")
            {
                Type = "real";
                HelpText = "The Z component of the ViewDirection vector. The ViewDirection determines how the resulting impostor geometry will be oriented. The billboard will be perpendicular to this vector.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                MaxValue = 1f;
                DefaultMinValue = -1f;
                DefaultMaxValue = 1f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonViewDirectionZEx(dynamic jsonData) : base("ViewDirectionZ")
            {
                Type = "real";
                HelpText = "The Z component of the ViewDirection vector. The ViewDirection determines how the resulting impostor geometry will be oriented. The billboard will be perpendicular to this vector.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1f;
                DefaultMinValue = -1f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionZ: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1f;
                DefaultMaxValue = 1f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionZ: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonViewDirectionZEx DeepCopy()
            {
                return (SimplygonViewDirectionZEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ViewDirectionZ;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float TexCoordPadding { get { return _TexCoordPadding; } set { _TexCoordPadding = value; OnPropertyChanged(); } }
        private float _TexCoordPadding;
        public SimplygonTexCoordPaddingEx TexCoordPaddingUI { get; set; }
        public class SimplygonTexCoordPaddingEx : SimplygonSettingsProperty
        {
            public SimplygonImpostorFromSingleViewSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.TexCoordPadding;
                }

                set
                {
                    bool needReload = Parent.TexCoordPadding != value;
                    Parent.TexCoordPadding = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonTexCoordPaddingEx() : base("TexCoordPadding")
            {
                Type = "real";
                HelpText = "Normally, the processor will generate an impostor with texcoords from 0.0 to 1.0, giving perfect UV coverage in the final texture. If your engine uses permanent tiling rendering mode, you may need to add a small padding to avoid sub-pixel wrapping artifact at the impostor edges, which this setting supplies. Ex: Setting this to 0.01 will generate texcoords in the range 0.01 to 0.99.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                MaxValue = 0.5f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 0.5f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonTexCoordPaddingEx(dynamic jsonData) : base("TexCoordPadding")
            {
                Type = "real";
                HelpText = "Normally, the processor will generate an impostor with texcoords from 0.0 to 1.0, giving perfect UV coverage in the final texture. If your engine uses permanent tiling rendering mode, you may need to add a small padding to avoid sub-pixel wrapping artifact at the impostor edges, which this setting supplies. Ex: Setting this to 0.01 will generate texcoords in the range 0.01 to 0.99.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TexCoordPadding: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 0.5f;
                DefaultMaxValue = 0.5f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"TexCoordPadding: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTexCoordPaddingEx DeepCopy()
            {
                return (SimplygonTexCoordPaddingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.TexCoordPadding;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonImpostorFromSingleViewSettings() : base("ImpostorFromSingleViewSettings")
        {
            Visible = true;
            UseTightFittingUI = new SimplygonUseTightFittingEx();
            UseTightFittingUI.Parent = this;
            UseTightFitting = UseTightFittingUI.DefaultValue;
            Items.Add(UseTightFittingUI);
            TightFittingDepthOffsetUI = new SimplygonTightFittingDepthOffsetEx();
            TightFittingDepthOffsetUI.Parent = this;
            TightFittingDepthOffset = TightFittingDepthOffsetUI.DefaultValue;
            Items.Add(TightFittingDepthOffsetUI);
            TwoSidedUI = new SimplygonTwoSidedEx();
            TwoSidedUI.Parent = this;
            TwoSided = TwoSidedUI.DefaultValue;
            Items.Add(TwoSidedUI);
            ViewDirectionXUI = new SimplygonViewDirectionXEx();
            ViewDirectionXUI.Parent = this;
            ViewDirectionX = ViewDirectionXUI.DefaultValue;
            Items.Add(ViewDirectionXUI);
            ViewDirectionYUI = new SimplygonViewDirectionYEx();
            ViewDirectionYUI.Parent = this;
            ViewDirectionY = ViewDirectionYUI.DefaultValue;
            Items.Add(ViewDirectionYUI);
            ViewDirectionZUI = new SimplygonViewDirectionZEx();
            ViewDirectionZUI.Parent = this;
            ViewDirectionZ = ViewDirectionZUI.DefaultValue;
            Items.Add(ViewDirectionZUI);
            TexCoordPaddingUI = new SimplygonTexCoordPaddingEx();
            TexCoordPaddingUI.Parent = this;
            TexCoordPadding = TexCoordPaddingUI.DefaultValue;
            Items.Add(TexCoordPaddingUI);
        }

        public SimplygonImpostorFromSingleViewSettings(dynamic jsonData) : base("ImpostorFromSingleViewSettings")
        {
            Visible = true;
            UseTightFittingUI = new SimplygonUseTightFittingEx(jsonData != null && ((JObject)jsonData).GetValue("UseTightFittingUI") != null ? jsonData.UseTightFittingUI : null);
            UseTightFittingUI.Parent = this;
            UseTightFitting = UseTightFittingUI.DefaultValue;
            Items.Add(UseTightFittingUI);
            TightFittingDepthOffsetUI = new SimplygonTightFittingDepthOffsetEx(jsonData != null && ((JObject)jsonData).GetValue("TightFittingDepthOffsetUI") != null ? jsonData.TightFittingDepthOffsetUI : null);
            TightFittingDepthOffsetUI.Parent = this;
            TightFittingDepthOffset = TightFittingDepthOffsetUI.DefaultValue;
            Items.Add(TightFittingDepthOffsetUI);
            TwoSidedUI = new SimplygonTwoSidedEx(jsonData != null && ((JObject)jsonData).GetValue("TwoSidedUI") != null ? jsonData.TwoSidedUI : null);
            TwoSidedUI.Parent = this;
            TwoSided = TwoSidedUI.DefaultValue;
            Items.Add(TwoSidedUI);
            ViewDirectionXUI = new SimplygonViewDirectionXEx(jsonData != null && ((JObject)jsonData).GetValue("ViewDirectionXUI") != null ? jsonData.ViewDirectionXUI : null);
            ViewDirectionXUI.Parent = this;
            ViewDirectionX = ViewDirectionXUI.DefaultValue;
            Items.Add(ViewDirectionXUI);
            ViewDirectionYUI = new SimplygonViewDirectionYEx(jsonData != null && ((JObject)jsonData).GetValue("ViewDirectionYUI") != null ? jsonData.ViewDirectionYUI : null);
            ViewDirectionYUI.Parent = this;
            ViewDirectionY = ViewDirectionYUI.DefaultValue;
            Items.Add(ViewDirectionYUI);
            ViewDirectionZUI = new SimplygonViewDirectionZEx(jsonData != null && ((JObject)jsonData).GetValue("ViewDirectionZUI") != null ? jsonData.ViewDirectionZUI : null);
            ViewDirectionZUI.Parent = this;
            ViewDirectionZ = ViewDirectionZUI.DefaultValue;
            Items.Add(ViewDirectionZUI);
            TexCoordPaddingUI = new SimplygonTexCoordPaddingEx(jsonData != null && ((JObject)jsonData).GetValue("TexCoordPaddingUI") != null ? jsonData.TexCoordPaddingUI : null);
            TexCoordPaddingUI.Parent = this;
            TexCoordPadding = TexCoordPaddingUI.DefaultValue;
            Items.Add(TexCoordPaddingUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonImpostorFromSingleViewSettings();
            copy.Items.Clear();
            copy.UseTightFittingUI = this.UseTightFittingUI.DeepCopy();
            copy.UseTightFittingUI.Parent = copy;
            copy.Items.Add(copy.UseTightFittingUI);
            copy.TightFittingDepthOffsetUI = this.TightFittingDepthOffsetUI.DeepCopy();
            copy.TightFittingDepthOffsetUI.Parent = copy;
            copy.Items.Add(copy.TightFittingDepthOffsetUI);
            copy.TwoSidedUI = this.TwoSidedUI.DeepCopy();
            copy.TwoSidedUI.Parent = copy;
            copy.Items.Add(copy.TwoSidedUI);
            copy.ViewDirectionXUI = this.ViewDirectionXUI.DeepCopy();
            copy.ViewDirectionXUI.Parent = copy;
            copy.Items.Add(copy.ViewDirectionXUI);
            copy.ViewDirectionYUI = this.ViewDirectionYUI.DeepCopy();
            copy.ViewDirectionYUI.Parent = copy;
            copy.Items.Add(copy.ViewDirectionYUI);
            copy.ViewDirectionZUI = this.ViewDirectionZUI.DeepCopy();
            copy.ViewDirectionZUI.Parent = copy;
            copy.Items.Add(copy.ViewDirectionZUI);
            copy.TexCoordPaddingUI = this.TexCoordPaddingUI.DeepCopy();
            copy.TexCoordPaddingUI.Parent = copy;
            copy.Items.Add(copy.TexCoordPaddingUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.UseTightFitting = UseTightFitting;
            if(serializeUIComponents)
            {
                jsonData.UseTightFittingUI = UseTightFittingUI.SaveJson();
            }

            jsonData.TightFittingDepthOffset = TightFittingDepthOffset;
            if(serializeUIComponents)
            {
                jsonData.TightFittingDepthOffsetUI = TightFittingDepthOffsetUI.SaveJson();
            }

            jsonData.TwoSided = TwoSided;
            if(serializeUIComponents)
            {
                jsonData.TwoSidedUI = TwoSidedUI.SaveJson();
            }

            jsonData.ViewDirectionX = ViewDirectionX;
            if(serializeUIComponents)
            {
                jsonData.ViewDirectionXUI = ViewDirectionXUI.SaveJson();
            }

            jsonData.ViewDirectionY = ViewDirectionY;
            if(serializeUIComponents)
            {
                jsonData.ViewDirectionYUI = ViewDirectionYUI.SaveJson();
            }

            jsonData.ViewDirectionZ = ViewDirectionZ;
            if(serializeUIComponents)
            {
                jsonData.ViewDirectionZUI = ViewDirectionZUI.SaveJson();
            }

            jsonData.TexCoordPadding = TexCoordPadding;
            if(serializeUIComponents)
            {
                jsonData.TexCoordPaddingUI = TexCoordPaddingUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("UseTightFitting") != null)
            {
                UseTightFitting = (bool)jsonData.UseTightFitting;
            }

            if(jsonData.GetValue("TightFittingDepthOffset") != null)
            {
                float newTightFittingDepthOffset = (float)jsonData.TightFittingDepthOffset;
                if (newTightFittingDepthOffset >= TightFittingDepthOffsetUI.DefaultMinValue && newTightFittingDepthOffset <= TightFittingDepthOffsetUI.DefaultMaxValue)
                {
                    TightFittingDepthOffset = newTightFittingDepthOffset;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TightFittingDepthOffset: Invalid value {newTightFittingDepthOffset.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {TightFittingDepthOffset.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("TwoSided") != null)
            {
                TwoSided = (bool)jsonData.TwoSided;
            }

            if(jsonData.GetValue("ViewDirectionX") != null)
            {
                float newViewDirectionX = (float)jsonData.ViewDirectionX;
                if (newViewDirectionX >= ViewDirectionXUI.DefaultMinValue && newViewDirectionX <= ViewDirectionXUI.DefaultMaxValue)
                {
                    ViewDirectionX = newViewDirectionX;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionX: Invalid value {newViewDirectionX.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ViewDirectionX.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ViewDirectionY") != null)
            {
                float newViewDirectionY = (float)jsonData.ViewDirectionY;
                if (newViewDirectionY >= ViewDirectionYUI.DefaultMinValue && newViewDirectionY <= ViewDirectionYUI.DefaultMaxValue)
                {
                    ViewDirectionY = newViewDirectionY;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionY: Invalid value {newViewDirectionY.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ViewDirectionY.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("ViewDirectionZ") != null)
            {
                float newViewDirectionZ = (float)jsonData.ViewDirectionZ;
                if (newViewDirectionZ >= ViewDirectionZUI.DefaultMinValue && newViewDirectionZ <= ViewDirectionZUI.DefaultMaxValue)
                {
                    ViewDirectionZ = newViewDirectionZ;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ViewDirectionZ: Invalid value {newViewDirectionZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ViewDirectionZ.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("TexCoordPadding") != null)
            {
                float newTexCoordPadding = (float)jsonData.TexCoordPadding;
                if (newTexCoordPadding >= TexCoordPaddingUI.DefaultMinValue && newTexCoordPadding <= TexCoordPaddingUI.DefaultMaxValue)
                {
                    TexCoordPadding = newTexCoordPadding;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"TexCoordPadding: Invalid value {newTexCoordPadding.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {TexCoordPadding.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            UseTightFittingUI.Reset();
            TightFittingDepthOffsetUI.Reset();
            TwoSidedUI.Reset();
            ViewDirectionXUI.Reset();
            ViewDirectionYUI.Reset();
            ViewDirectionZUI.Reset();
            TexCoordPaddingUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            UseTightFittingUI.IsEditEnabled = isEditEnabled;
            TightFittingDepthOffsetUI.IsEditEnabled = isEditEnabled;
            TwoSidedUI.IsEditEnabled = isEditEnabled;
            ViewDirectionXUI.IsEditEnabled = isEditEnabled;
            ViewDirectionYUI.IsEditEnabled = isEditEnabled;
            ViewDirectionZUI.IsEditEnabled = isEditEnabled;
            TexCoordPaddingUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            UseTightFittingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TightFittingDepthOffsetUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TwoSidedUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ViewDirectionXUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ViewDirectionYUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ViewDirectionZUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TexCoordPaddingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonOcclusionMeshSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(OnScreenSizeUI.Visible) return true;
                if(OnScreenErrorToleranceUI.Visible) return true;
                if(InvertOutputMeshUI.Visible) return true;
                if(TransferSkinningUI.Visible) return true;
                if(UseCamerasUI.Visible) return true;
                if(CameraSelectionSetNameUI.Visible) return true;
                if(OcclusionModeUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public int OnScreenSize { get { return _OnScreenSize; } set { _OnScreenSize = value; OnPropertyChanged(); } }
        private int _OnScreenSize;
        public SimplygonOnScreenSizeEx OnScreenSizeUI { get; set; }
        public class SimplygonOnScreenSizeEx : SimplygonSettingsProperty
        {
            public SimplygonOcclusionMeshSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.OnScreenSize;
                }

                set
                {
                    bool needReload = Parent.OnScreenSize != value;
                    Parent.OnScreenSize = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonOnScreenSizeEx() : base("OnScreenSize")
            {
                Type = "uint";
                HelpText = "The onscreen size (px) of the output utility mesh. This will determine triangle count and quality.";
                TypeOverride = "";
                DefaultValue = 100;
                MinValue = 20;
                MaxValue = 10000;
                DefaultMinValue = 20;
                DefaultMaxValue = 10000;
                TicksFrequencyValue = 10;
                Visible = true;
            }

            public SimplygonOnScreenSizeEx(dynamic jsonData) : base("OnScreenSize")
            {
                Type = "uint";
                HelpText = "The onscreen size (px) of the output utility mesh. This will determine triangle count and quality.";
                TypeOverride = "";
                DefaultValue = 100;
                MinValue = 20;
                DefaultMinValue = 20;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenSize: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10000;
                DefaultMaxValue = 10000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenSize: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 10;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOnScreenSizeEx DeepCopy()
            {
                return (SimplygonOnScreenSizeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.OnScreenSize;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int OnScreenErrorTolerance { get { return _OnScreenErrorTolerance; } set { _OnScreenErrorTolerance = value; OnPropertyChanged(); } }
        private int _OnScreenErrorTolerance;
        public SimplygonOnScreenErrorToleranceEx OnScreenErrorToleranceUI { get; set; }
        public class SimplygonOnScreenErrorToleranceEx : SimplygonSettingsProperty
        {
            public SimplygonOcclusionMeshSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.OnScreenErrorTolerance;
                }

                set
                {
                    bool needReload = Parent.OnScreenErrorTolerance != value;
                    Parent.OnScreenErrorTolerance = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonOnScreenErrorToleranceEx() : base("OnScreenErrorTolerance")
            {
                Type = "uint";
                HelpText = "The OnScreenErrorTolerance determines how large of an error that is tolerated, in pixels. Valid range is 1-50. Since this setting is based around the absolute worst-case scenario, you can usually get good results at relatively high tolerances.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 1;
                MaxValue = 50;
                DefaultMinValue = 1;
                DefaultMaxValue = 50;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonOnScreenErrorToleranceEx(dynamic jsonData) : base("OnScreenErrorTolerance")
            {
                Type = "uint";
                HelpText = "The OnScreenErrorTolerance determines how large of an error that is tolerated, in pixels. Valid range is 1-50. Since this setting is based around the absolute worst-case scenario, you can usually get good results at relatively high tolerances.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 1;
                DefaultMinValue = 1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenErrorTolerance: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 50;
                DefaultMaxValue = 50;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenErrorTolerance: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOnScreenErrorToleranceEx DeepCopy()
            {
                return (SimplygonOnScreenErrorToleranceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.OnScreenErrorTolerance;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool InvertOutputMesh { get { return _InvertOutputMesh; } set { _InvertOutputMesh = value; OnPropertyChanged(); } }
        private bool _InvertOutputMesh;
        public SimplygonInvertOutputMeshEx InvertOutputMeshUI { get; set; }
        public class SimplygonInvertOutputMeshEx : SimplygonSettingsProperty
        {
            public SimplygonOcclusionMeshSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.InvertOutputMesh;
                }

                set
                {
                    bool needReload = Parent.InvertOutputMesh != value;
                    Parent.InvertOutputMesh = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonInvertOutputMeshEx() : base("InvertOutputMesh")
            {
                Type = "bool";
                HelpText = "Flips the winding of the triangles of the output, making frontfaces backfaces and vice versa. Good for conservative z testing.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonInvertOutputMeshEx(dynamic jsonData) : base("InvertOutputMesh")
            {
                Type = "bool";
                HelpText = "Flips the winding of the triangles of the output, making frontfaces backfaces and vice versa. Good for conservative z testing.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonInvertOutputMeshEx DeepCopy()
            {
                return (SimplygonInvertOutputMeshEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.InvertOutputMesh;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool TransferSkinning { get { return _TransferSkinning; } set { _TransferSkinning = value; OnPropertyChanged(); } }
        private bool _TransferSkinning;
        public SimplygonTransferSkinningEx TransferSkinningUI { get; set; }
        public class SimplygonTransferSkinningEx : SimplygonSettingsProperty
        {
            public SimplygonOcclusionMeshSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.TransferSkinning;
                }

                set
                {
                    bool needReload = Parent.TransferSkinning != value;
                    Parent.TransferSkinning = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonTransferSkinningEx() : base("TransferSkinning")
            {
                Type = "bool";
                HelpText = "Sets whether to transfer the bone weights and bone ids to the new geometry.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonTransferSkinningEx(dynamic jsonData) : base("TransferSkinning")
            {
                Type = "bool";
                HelpText = "Sets whether to transfer the bone weights and bone ids to the new geometry.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonTransferSkinningEx DeepCopy()
            {
                return (SimplygonTransferSkinningEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.TransferSkinning;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseCameras { get { return _UseCameras; } set { _UseCameras = value; OnPropertyChanged(); } }
        private bool _UseCameras;
        public SimplygonUseCamerasEx UseCamerasUI { get; set; }
        public class SimplygonUseCamerasEx : SimplygonSettingsProperty
        {
            public SimplygonOcclusionMeshSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseCameras;
                }

                set
                {
                    bool needReload = Parent.UseCameras != value;
                    Parent.UseCameras = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseCamerasEx() : base("UseCameras")
            {
                Type = "bool";
                HelpText = "If set, cameras from the input scene will be used to define what angles the occlusion mesh can be visible from, and optimize the output mesh accordingly. Otherwise, the occlusion mesh will be assumed to be viewable from all directions.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseCamerasEx(dynamic jsonData) : base("UseCameras")
            {
                Type = "bool";
                HelpText = "If set, cameras from the input scene will be used to define what angles the occlusion mesh can be visible from, and optimize the output mesh accordingly. Otherwise, the occlusion mesh will be assumed to be viewable from all directions.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseCamerasEx DeepCopy()
            {
                return (SimplygonUseCamerasEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseCameras;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public string CameraSelectionSetName { get { return _CameraSelectionSetName; } set { _CameraSelectionSetName = value; OnPropertyChanged(); } }
        private string _CameraSelectionSetName;
        public SimplygonCameraSelectionSetNameEx CameraSelectionSetNameUI { get; set; }
        public class SimplygonCameraSelectionSetNameEx : SimplygonSettingsProperty
        {
            public SimplygonOcclusionMeshSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.CameraSelectionSetName;
                }

                set
                {
                    bool needReload = Parent.CameraSelectionSetName != value;
                    Parent.CameraSelectionSetName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonCameraSelectionSetNameEx() : base("CameraSelectionSetName")
            {
                Type = "string";
                HelpText = "The camera selection set name. This determines the selection set used for the cameras for when UseCameras is on. If set to null, all cameras in the scene will be used. If both selection set name and ID are set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonCameraSelectionSetNameEx(dynamic jsonData) : base("CameraSelectionSetName")
            {
                Type = "string";
                HelpText = "The camera selection set name. This determines the selection set used for the cameras for when UseCameras is on. If set to null, all cameras in the scene will be used. If both selection set name and ID are set, the name will be used.";
                TypeOverride = "SelectionSet";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonCameraSelectionSetNameEx DeepCopy()
            {
                return (SimplygonCameraSelectionSetNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.CameraSelectionSetName;
                int selectedIndex = 0;
                string[] sets = Simplygon.Unity.EditorPlugin.SimplygonUtils.GetCameraObjectNamesInScene();
                List<GUIContent> selectionSets = new List<GUIContent>();
                selectionSets.Add(new GUIContent("Not used"));
                for(int i = 0; i < sets.Length; ++i)
                {
                    if(value == sets[i]) selectedIndex = i+1;
                    selectionSets.Add(new GUIContent(sets[i]));
                }

                selectedIndex = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), selectedIndex, selectionSets.ToArray());
                Parent.CameraSelectionSetName = selectedIndex == 0 ? "" : selectionSets[selectedIndex].text;
            }

        }

        public EOcclusionMode OcclusionMode { get { return _OcclusionMode; } set { _OcclusionMode = value; OnPropertyChanged(); } }
        private EOcclusionMode _OcclusionMode;
        public SimplygonOcclusionModeEx OcclusionModeUI { get; set; }
        public class SimplygonOcclusionModeEx : SimplygonSettingsProperty
        {
            public SimplygonOcclusionMeshSettings Parent { get; set; }
            public EOcclusionMode Value
            {
                get
                {
                    return Parent.OcclusionMode;
                }

                set
                {
                    bool needReload = Parent.OcclusionMode != value;
                    Parent.OcclusionMode = value;
                    OnPropertyChanged();
                }

            }

            public EOcclusionMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EOcclusionMode)); } }

            public SimplygonOcclusionModeEx() : base("OcclusionMode")
            {
                Type = "enum";
                HelpText = "The occlusion mode. This decides if the processor generates an occluder (which is smaller than the original mesh), an occludee (which is larger), or an output that just tries to match the input.";
                TypeOverride = "";
                DefaultValue = EOcclusionMode.Occluder;
                Visible = true;
            }

            public SimplygonOcclusionModeEx(dynamic jsonData) : base("OcclusionMode")
            {
                Type = "enum";
                HelpText = "The occlusion mode. This decides if the processor generates an occluder (which is smaller than the original mesh), an occludee (which is larger), or an output that just tries to match the input.";
                TypeOverride = "";
                DefaultValue = EOcclusionMode.Occluder;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOcclusionModeEx DeepCopy()
            {
                return (SimplygonOcclusionModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OcclusionMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EOcclusionMode)value;
            }

        }


        public SimplygonOcclusionMeshSettings() : base("OcclusionMeshSettings")
        {
            Visible = true;
            OnScreenSizeUI = new SimplygonOnScreenSizeEx();
            OnScreenSizeUI.Parent = this;
            OnScreenSize = OnScreenSizeUI.DefaultValue;
            Items.Add(OnScreenSizeUI);
            OnScreenErrorToleranceUI = new SimplygonOnScreenErrorToleranceEx();
            OnScreenErrorToleranceUI.Parent = this;
            OnScreenErrorTolerance = OnScreenErrorToleranceUI.DefaultValue;
            Items.Add(OnScreenErrorToleranceUI);
            InvertOutputMeshUI = new SimplygonInvertOutputMeshEx();
            InvertOutputMeshUI.Parent = this;
            InvertOutputMesh = InvertOutputMeshUI.DefaultValue;
            Items.Add(InvertOutputMeshUI);
            TransferSkinningUI = new SimplygonTransferSkinningEx();
            TransferSkinningUI.Parent = this;
            TransferSkinning = TransferSkinningUI.DefaultValue;
            Items.Add(TransferSkinningUI);
            UseCamerasUI = new SimplygonUseCamerasEx();
            UseCamerasUI.Parent = this;
            UseCameras = UseCamerasUI.DefaultValue;
            Items.Add(UseCamerasUI);
            CameraSelectionSetNameUI = new SimplygonCameraSelectionSetNameEx();
            CameraSelectionSetNameUI.Parent = this;
            CameraSelectionSetName = CameraSelectionSetNameUI.DefaultValue;
            Items.Add(CameraSelectionSetNameUI);
            OcclusionModeUI = new SimplygonOcclusionModeEx();
            OcclusionModeUI.Parent = this;
            OcclusionMode = OcclusionModeUI.DefaultValue;
            Items.Add(OcclusionModeUI);
        }

        public SimplygonOcclusionMeshSettings(dynamic jsonData) : base("OcclusionMeshSettings")
        {
            Visible = true;
            OnScreenSizeUI = new SimplygonOnScreenSizeEx(jsonData != null && ((JObject)jsonData).GetValue("OnScreenSizeUI") != null ? jsonData.OnScreenSizeUI : null);
            OnScreenSizeUI.Parent = this;
            OnScreenSize = OnScreenSizeUI.DefaultValue;
            Items.Add(OnScreenSizeUI);
            OnScreenErrorToleranceUI = new SimplygonOnScreenErrorToleranceEx(jsonData != null && ((JObject)jsonData).GetValue("OnScreenErrorToleranceUI") != null ? jsonData.OnScreenErrorToleranceUI : null);
            OnScreenErrorToleranceUI.Parent = this;
            OnScreenErrorTolerance = OnScreenErrorToleranceUI.DefaultValue;
            Items.Add(OnScreenErrorToleranceUI);
            InvertOutputMeshUI = new SimplygonInvertOutputMeshEx(jsonData != null && ((JObject)jsonData).GetValue("InvertOutputMeshUI") != null ? jsonData.InvertOutputMeshUI : null);
            InvertOutputMeshUI.Parent = this;
            InvertOutputMesh = InvertOutputMeshUI.DefaultValue;
            Items.Add(InvertOutputMeshUI);
            TransferSkinningUI = new SimplygonTransferSkinningEx(jsonData != null && ((JObject)jsonData).GetValue("TransferSkinningUI") != null ? jsonData.TransferSkinningUI : null);
            TransferSkinningUI.Parent = this;
            TransferSkinning = TransferSkinningUI.DefaultValue;
            Items.Add(TransferSkinningUI);
            UseCamerasUI = new SimplygonUseCamerasEx(jsonData != null && ((JObject)jsonData).GetValue("UseCamerasUI") != null ? jsonData.UseCamerasUI : null);
            UseCamerasUI.Parent = this;
            UseCameras = UseCamerasUI.DefaultValue;
            Items.Add(UseCamerasUI);
            CameraSelectionSetNameUI = new SimplygonCameraSelectionSetNameEx(jsonData != null && ((JObject)jsonData).GetValue("CameraSelectionSetNameUI") != null ? jsonData.CameraSelectionSetNameUI : null);
            CameraSelectionSetNameUI.Parent = this;
            CameraSelectionSetName = CameraSelectionSetNameUI.DefaultValue;
            Items.Add(CameraSelectionSetNameUI);
            OcclusionModeUI = new SimplygonOcclusionModeEx(jsonData != null && ((JObject)jsonData).GetValue("OcclusionModeUI") != null ? jsonData.OcclusionModeUI : null);
            OcclusionModeUI.Parent = this;
            OcclusionMode = OcclusionModeUI.DefaultValue;
            Items.Add(OcclusionModeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonOcclusionMeshSettings();
            copy.Items.Clear();
            copy.OnScreenSizeUI = this.OnScreenSizeUI.DeepCopy();
            copy.OnScreenSizeUI.Parent = copy;
            copy.Items.Add(copy.OnScreenSizeUI);
            copy.OnScreenErrorToleranceUI = this.OnScreenErrorToleranceUI.DeepCopy();
            copy.OnScreenErrorToleranceUI.Parent = copy;
            copy.Items.Add(copy.OnScreenErrorToleranceUI);
            copy.InvertOutputMeshUI = this.InvertOutputMeshUI.DeepCopy();
            copy.InvertOutputMeshUI.Parent = copy;
            copy.Items.Add(copy.InvertOutputMeshUI);
            copy.TransferSkinningUI = this.TransferSkinningUI.DeepCopy();
            copy.TransferSkinningUI.Parent = copy;
            copy.Items.Add(copy.TransferSkinningUI);
            copy.UseCamerasUI = this.UseCamerasUI.DeepCopy();
            copy.UseCamerasUI.Parent = copy;
            copy.Items.Add(copy.UseCamerasUI);
            copy.CameraSelectionSetNameUI = this.CameraSelectionSetNameUI.DeepCopy();
            copy.CameraSelectionSetNameUI.Parent = copy;
            copy.Items.Add(copy.CameraSelectionSetNameUI);
            copy.OcclusionModeUI = this.OcclusionModeUI.DeepCopy();
            copy.OcclusionModeUI.Parent = copy;
            copy.Items.Add(copy.OcclusionModeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.OnScreenSize = OnScreenSize;
            if(serializeUIComponents)
            {
                jsonData.OnScreenSizeUI = OnScreenSizeUI.SaveJson();
            }

            jsonData.OnScreenErrorTolerance = OnScreenErrorTolerance;
            if(serializeUIComponents)
            {
                jsonData.OnScreenErrorToleranceUI = OnScreenErrorToleranceUI.SaveJson();
            }

            jsonData.InvertOutputMesh = InvertOutputMesh;
            if(serializeUIComponents)
            {
                jsonData.InvertOutputMeshUI = InvertOutputMeshUI.SaveJson();
            }

            jsonData.TransferSkinning = TransferSkinning;
            if(serializeUIComponents)
            {
                jsonData.TransferSkinningUI = TransferSkinningUI.SaveJson();
            }

            jsonData.UseCameras = UseCameras;
            if(serializeUIComponents)
            {
                jsonData.UseCamerasUI = UseCamerasUI.SaveJson();
            }

            jsonData.CameraSelectionSetName = CameraSelectionSetName;
            if(serializeUIComponents)
            {
                jsonData.CameraSelectionSetNameUI = CameraSelectionSetNameUI.SaveJson();
            }

            jsonData.OcclusionMode = (int)OcclusionMode;
            if(serializeUIComponents)
            {
                jsonData.OcclusionModeUI = OcclusionModeUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("OnScreenSize") != null)
            {
                var newOnScreenSize = (int)jsonData.OnScreenSize;
                if (newOnScreenSize >= OnScreenSizeUI.DefaultMinValue && newOnScreenSize <= OnScreenSizeUI.DefaultMaxValue)
                {
                    OnScreenSize = newOnScreenSize;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenSize: Invalid value {newOnScreenSize}, using default value {OnScreenSize.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OnScreenErrorTolerance") != null)
            {
                var newOnScreenErrorTolerance = (int)jsonData.OnScreenErrorTolerance;
                if (newOnScreenErrorTolerance >= OnScreenErrorToleranceUI.DefaultMinValue && newOnScreenErrorTolerance <= OnScreenErrorToleranceUI.DefaultMaxValue)
                {
                    OnScreenErrorTolerance = newOnScreenErrorTolerance;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OnScreenErrorTolerance: Invalid value {newOnScreenErrorTolerance}, using default value {OnScreenErrorTolerance.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("InvertOutputMesh") != null)
            {
                InvertOutputMesh = (bool)jsonData.InvertOutputMesh;
            }

            if(jsonData.GetValue("TransferSkinning") != null)
            {
                TransferSkinning = (bool)jsonData.TransferSkinning;
            }

            if(jsonData.GetValue("UseCameras") != null)
            {
                UseCameras = (bool)jsonData.UseCameras;
            }

            if(jsonData.GetValue("CameraSelectionSetName") != null)
            {
                CameraSelectionSetName = (string)jsonData.CameraSelectionSetName;
            }

            if(jsonData.GetValue("OcclusionMode") != null)
            {
                OcclusionMode = (EOcclusionMode)jsonData.OcclusionMode;
            }

        }

        public override void Reset()
        {
            OnScreenSizeUI.Reset();
            OnScreenErrorToleranceUI.Reset();
            InvertOutputMeshUI.Reset();
            TransferSkinningUI.Reset();
            UseCamerasUI.Reset();
            CameraSelectionSetNameUI.Reset();
            OcclusionModeUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            OnScreenSizeUI.IsEditEnabled = isEditEnabled;
            OnScreenErrorToleranceUI.IsEditEnabled = isEditEnabled;
            InvertOutputMeshUI.IsEditEnabled = isEditEnabled;
            TransferSkinningUI.IsEditEnabled = isEditEnabled;
            UseCamerasUI.IsEditEnabled = isEditEnabled;
            CameraSelectionSetNameUI.IsEditEnabled = isEditEnabled;
            OcclusionModeUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            OnScreenSizeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OnScreenErrorToleranceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            InvertOutputMeshUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            TransferSkinningUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseCamerasUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            CameraSelectionSetNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OcclusionModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonColorCasterSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialChannelUI.Visible) return true;
                if(OpacityChannelComponentUI.Visible) return true;
                if(DitherTypeUI.Visible) return true;
                if(FillModeUI.Visible) return true;
                if(OpacityChannelUI.Visible) return true;
                if(UseMultisamplingUI.Visible) return true;
                if(BakeOpacityInAlphaUI.Visible) return true;
                if(OutputImageFileFormatUI.Visible) return true;
                if(OutputDDSCompressionTypeUI.Visible) return true;
                if(DilationUI.Visible) return true;
                if(OutputOpacityTypeUI.Visible) return true;
                if(OutputPixelFormatUI.Visible) return true;
                if(SkipCastingIfNoInputChannelUI.Visible) return true;
                if(OutputSRGBUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string MaterialChannel { get { return _MaterialChannel; } set { _MaterialChannel = value; OnPropertyChanged(); } }
        private string _MaterialChannel;
        public SimplygonMaterialChannelEx MaterialChannelUI { get; set; }
        public class SimplygonMaterialChannelEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.MaterialChannel;
                }

                set
                {
                    bool needReload = Parent.MaterialChannel != value;
                    Parent.MaterialChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonMaterialChannelEx() : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonMaterialChannelEx(dynamic jsonData) : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialChannelEx DeepCopy()
            {
                return (SimplygonMaterialChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string[] options = { "diffuseColor", "specularColor", "emissiveColor", "metallic", "roughness" };
                GUIContent[] optionContents = { new GUIContent("Albedo", ""), new GUIContent("Specular", ""), new GUIContent("Emission", ""), new GUIContent("Metallic", ""), new GUIContent("Smoothness", "") };
                int index = Array.IndexOf(options, Parent.MaterialChannel);
                index = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), index < 0 ? 0 : index, optionContents, EditorStyles.popup);
                Value = options[index];
                Parent.Parent.displayName = ObjectNames.NicifyVariableName("ColorCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(Parent.MaterialChannel);
            }

        }

        public EColorComponent OpacityChannelComponent { get { return _OpacityChannelComponent; } set { _OpacityChannelComponent = value; OnPropertyChanged(); } }
        private EColorComponent _OpacityChannelComponent;
        public SimplygonOpacityChannelComponentEx OpacityChannelComponentUI { get; set; }
        public class SimplygonOpacityChannelComponentEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.OpacityChannelComponent;
                }

                set
                {
                    bool needReload = Parent.OpacityChannelComponent != value;
                    Parent.OpacityChannelComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonOpacityChannelComponentEx() : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonOpacityChannelComponentEx(dynamic jsonData) : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelComponentEx DeepCopy()
            {
                return (SimplygonOpacityChannelComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OpacityChannelComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public EDitherPatterns DitherType { get { return _DitherType; } set { _DitherType = value; OnPropertyChanged(); } }
        private EDitherPatterns _DitherType;
        public SimplygonDitherTypeEx DitherTypeUI { get; set; }
        public class SimplygonDitherTypeEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public EDitherPatterns Value
            {
                get
                {
                    return Parent.DitherType;
                }

                set
                {
                    bool needReload = Parent.DitherType != value;
                    Parent.DitherType = value;
                    OnPropertyChanged();
                }

            }

            public EDitherPatterns DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDitherPatterns)); } }

            public SimplygonDitherTypeEx() : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                Visible = true;
            }

            public SimplygonDitherTypeEx(dynamic jsonData) : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDitherTypeEx DeepCopy()
            {
                return (SimplygonDitherTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DitherType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDitherPatterns)value;
            }

        }

        public EAtlasFillMode FillMode { get { return _FillMode; } set { _FillMode = value; OnPropertyChanged(); } }
        private EAtlasFillMode _FillMode;
        public SimplygonFillModeEx FillModeUI { get; set; }
        public class SimplygonFillModeEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public EAtlasFillMode Value
            {
                get
                {
                    return Parent.FillMode;
                }

                set
                {
                    bool needReload = Parent.FillMode != value;
                    Parent.FillMode = value;
                    OnPropertyChanged();
                }

            }

            public EAtlasFillMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EAtlasFillMode)); } }

            public SimplygonFillModeEx() : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                Visible = true;
            }

            public SimplygonFillModeEx(dynamic jsonData) : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillModeEx DeepCopy()
            {
                return (SimplygonFillModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.FillMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EAtlasFillMode)value;
            }

        }

        public string OpacityChannel { get { return _OpacityChannel; } set { _OpacityChannel = value; OnPropertyChanged(); } }
        private string _OpacityChannel;
        public SimplygonOpacityChannelEx OpacityChannelUI { get; set; }
        public class SimplygonOpacityChannelEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OpacityChannel;
                }

                set
                {
                    bool needReload = Parent.OpacityChannel != value;
                    Parent.OpacityChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOpacityChannelEx() : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                Visible = true;
            }

            public SimplygonOpacityChannelEx(dynamic jsonData) : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelEx DeepCopy()
            {
                return (SimplygonOpacityChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OpacityChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseMultisampling { get { return _UseMultisampling; } set { _UseMultisampling = value; OnPropertyChanged(); } }
        private bool _UseMultisampling;
        public SimplygonUseMultisamplingEx UseMultisamplingUI { get; set; }
        public class SimplygonUseMultisamplingEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseMultisampling;
                }

                set
                {
                    bool needReload = Parent.UseMultisampling != value;
                    Parent.UseMultisampling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseMultisamplingEx() : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseMultisamplingEx(dynamic jsonData) : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseMultisamplingEx DeepCopy()
            {
                return (SimplygonUseMultisamplingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseMultisampling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool BakeOpacityInAlpha { get { return _BakeOpacityInAlpha; } set { _BakeOpacityInAlpha = value; OnPropertyChanged(); } }
        private bool _BakeOpacityInAlpha;
        public SimplygonBakeOpacityInAlphaEx BakeOpacityInAlphaUI { get; set; }
        public class SimplygonBakeOpacityInAlphaEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.BakeOpacityInAlpha;
                }

                set
                {
                    bool needReload = Parent.BakeOpacityInAlpha != value;
                    Parent.BakeOpacityInAlpha = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonBakeOpacityInAlphaEx() : base("BakeOpacityInAlpha")
            {
                Type = "bool";
                HelpText = "If set, the total opacity of the baked layers replaces the alpha value in the output texture.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonBakeOpacityInAlphaEx(dynamic jsonData) : base("BakeOpacityInAlpha")
            {
                Type = "bool";
                HelpText = "If set, the total opacity of the baked layers replaces the alpha value in the output texture.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonBakeOpacityInAlphaEx DeepCopy()
            {
                return (SimplygonBakeOpacityInAlphaEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.BakeOpacityInAlpha;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EImageOutputFormat OutputImageFileFormat { get { return _OutputImageFileFormat; } set { _OutputImageFileFormat = value; OnPropertyChanged(); } }
        private EImageOutputFormat _OutputImageFileFormat;
        public SimplygonOutputImageFileFormatEx OutputImageFileFormatUI { get; set; }
        public class SimplygonOutputImageFileFormatEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public EImageOutputFormat Value
            {
                get
                {
                    return Parent.OutputImageFileFormat;
                }

                set
                {
                    bool needReload = Parent.OutputImageFileFormat != value;
                    Parent.OutputImageFileFormat = value;
                    Parent.OutputDDSCompressionTypeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public EImageOutputFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EImageOutputFormat)); } }

            public SimplygonOutputImageFileFormatEx() : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                Visible = true;
            }

            public SimplygonOutputImageFileFormatEx(dynamic jsonData) : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputImageFileFormatEx DeepCopy()
            {
                return (SimplygonOutputImageFileFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputImageFileFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EImageOutputFormat)value;
            }

        }

        public EDDSCompressionType OutputDDSCompressionType { get { return _OutputDDSCompressionType; } set { _OutputDDSCompressionType = value; OnPropertyChanged(); } }
        private EDDSCompressionType _OutputDDSCompressionType;
        public SimplygonOutputDDSCompressionTypeEx OutputDDSCompressionTypeUI { get; set; }
        public class SimplygonOutputDDSCompressionTypeEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public EDDSCompressionType Value
            {
                get
                {
                    return Parent.OutputDDSCompressionType;
                }

                set
                {
                    bool needReload = Parent.OutputDDSCompressionType != value;
                    Parent.OutputDDSCompressionType = value;
                    OnPropertyChanged();
                }

            }

            public EDDSCompressionType DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.OutputImageFileFormatUI != null ) { return Parent.OutputImageFileFormat == EImageOutputFormat.DDS && Parent.OutputImageFileFormatUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDDSCompressionType)); } }

            public SimplygonOutputDDSCompressionTypeEx() : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                Visible = true;
            }

            public SimplygonOutputDDSCompressionTypeEx(dynamic jsonData) : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputDDSCompressionTypeEx DeepCopy()
            {
                return (SimplygonOutputDDSCompressionTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.OutputImageFileFormatUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputDDSCompressionType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDDSCompressionType)value;
            }

        }

        public int Dilation { get { return _Dilation; } set { _Dilation = value; OnPropertyChanged(); } }
        private int _Dilation;
        public SimplygonDilationEx DilationUI { get; set; }
        public class SimplygonDilationEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.Dilation;
                }

                set
                {
                    bool needReload = Parent.Dilation != value;
                    Parent.Dilation = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonDilationEx() : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 1000;
                DefaultMinValue = 0;
                DefaultMaxValue = 1000;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonDilationEx(dynamic jsonData) : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000;
                DefaultMaxValue = 1000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDilationEx DeepCopy()
            {
                return (SimplygonDilationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.Dilation;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EOpacityType OutputOpacityType { get { return _OutputOpacityType; } set { _OutputOpacityType = value; OnPropertyChanged(); } }
        private EOpacityType _OutputOpacityType;
        public SimplygonOutputOpacityTypeEx OutputOpacityTypeUI { get; set; }
        public class SimplygonOutputOpacityTypeEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public EOpacityType Value
            {
                get
                {
                    return Parent.OutputOpacityType;
                }

                set
                {
                    bool needReload = Parent.OutputOpacityType != value;
                    Parent.OutputOpacityType = value;
                    OnPropertyChanged();
                }

            }

            public EOpacityType DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EOpacityType)); } }

            public SimplygonOutputOpacityTypeEx() : base("OutputOpacityType")
            {
                Type = "enum";
                HelpText = "The opacity type determines how the opacity channel of this material should be saved. To make (0.0->1.0) map to (transparent-opaque), use 'Opacity'. To make (0.0->1.0) map to (opaque-transparent), use 'Transparency'";
                TypeOverride = "";
                DefaultValue = EOpacityType.Opacity;
                Visible = true;
            }

            public SimplygonOutputOpacityTypeEx(dynamic jsonData) : base("OutputOpacityType")
            {
                Type = "enum";
                HelpText = "The opacity type determines how the opacity channel of this material should be saved. To make (0.0->1.0) map to (transparent-opaque), use 'Opacity'. To make (0.0->1.0) map to (opaque-transparent), use 'Transparency'";
                TypeOverride = "";
                DefaultValue = EOpacityType.Opacity;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputOpacityTypeEx DeepCopy()
            {
                return (SimplygonOutputOpacityTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputOpacityType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EOpacityType)value;
            }

        }

        public EPixelFormat OutputPixelFormat { get { return _OutputPixelFormat; } set { _OutputPixelFormat = value; OnPropertyChanged(); } }
        private EPixelFormat _OutputPixelFormat;
        public SimplygonOutputPixelFormatEx OutputPixelFormatUI { get; set; }
        public class SimplygonOutputPixelFormatEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public EPixelFormat Value
            {
                get
                {
                    return Parent.OutputPixelFormat;
                }

                set
                {
                    bool needReload = Parent.OutputPixelFormat != value;
                    Parent.OutputPixelFormat = value;
                    OnPropertyChanged();
                }

            }

            public EPixelFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPixelFormat)); } }

            public SimplygonOutputPixelFormatEx() : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                Visible = true;
            }

            public SimplygonOutputPixelFormatEx(dynamic jsonData) : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputPixelFormatEx DeepCopy()
            {
                return (SimplygonOutputPixelFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputPixelFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPixelFormat)value;
            }

        }

        public bool SkipCastingIfNoInputChannel { get { return _SkipCastingIfNoInputChannel; } set { _SkipCastingIfNoInputChannel = value; OnPropertyChanged(); } }
        private bool _SkipCastingIfNoInputChannel;
        public SimplygonSkipCastingIfNoInputChannelEx SkipCastingIfNoInputChannelUI { get; set; }
        public class SimplygonSkipCastingIfNoInputChannelEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.SkipCastingIfNoInputChannel;
                }

                set
                {
                    bool needReload = Parent.SkipCastingIfNoInputChannel != value;
                    Parent.SkipCastingIfNoInputChannel = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonSkipCastingIfNoInputChannelEx() : base("SkipCastingIfNoInputChannel")
            {
                Type = "bool";
                HelpText = "If this flag is set, the caster will only run if there is at least one input material that has the main input channel which is to be cast. If the flag is not set, the caster will always produce an output, even if it is totally empty/unset.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonSkipCastingIfNoInputChannelEx(dynamic jsonData) : base("SkipCastingIfNoInputChannel")
            {
                Type = "bool";
                HelpText = "If this flag is set, the caster will only run if there is at least one input material that has the main input channel which is to be cast. If the flag is not set, the caster will always produce an output, even if it is totally empty/unset.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonSkipCastingIfNoInputChannelEx DeepCopy()
            {
                return (SimplygonSkipCastingIfNoInputChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.SkipCastingIfNoInputChannel;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool OutputSRGB { get { return _OutputSRGB; } set { _OutputSRGB = value; OnPropertyChanged(); } }
        private bool _OutputSRGB;
        public SimplygonOutputSRGBEx OutputSRGBUI { get; set; }
        public class SimplygonOutputSRGBEx : SimplygonSettingsProperty
        {
            public SimplygonColorCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.OutputSRGB;
                }

                set
                {
                    bool needReload = Parent.OutputSRGB != value;
                    Parent.OutputSRGB = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonOutputSRGBEx() : base("OutputSRGB")
            {
                Type = "bool";
                HelpText = "If set, output textures are exported in sRGB format. Input texture format is determined by the flag in the corresponding texture node in the material definition.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonOutputSRGBEx(dynamic jsonData) : base("OutputSRGB")
            {
                Type = "bool";
                HelpText = "If set, output textures are exported in sRGB format. Input texture format is determined by the flag in the corresponding texture node in the material definition.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputSRGBEx DeepCopy()
            {
                return (SimplygonOutputSRGBEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.OutputSRGB;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonColorCasterSettings() : base("ColorCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx();
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx();
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx();
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx();
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx();
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx();
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx();
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx();
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputSRGBUI = new SimplygonOutputSRGBEx();
            OutputSRGBUI.Parent = this;
            OutputSRGB = OutputSRGBUI.DefaultValue;
            Items.Add(OutputSRGBUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx();
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx();
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            BakeOpacityInAlphaUI = new SimplygonBakeOpacityInAlphaEx();
            BakeOpacityInAlphaUI.Parent = this;
            BakeOpacityInAlpha = BakeOpacityInAlphaUI.DefaultValue;
            Items.Add(BakeOpacityInAlphaUI);
            SkipCastingIfNoInputChannelUI = new SimplygonSkipCastingIfNoInputChannelEx();
            SkipCastingIfNoInputChannelUI.Parent = this;
            SkipCastingIfNoInputChannel = SkipCastingIfNoInputChannelUI.DefaultValue;
            Items.Add(SkipCastingIfNoInputChannelUI);
            OutputOpacityTypeUI = new SimplygonOutputOpacityTypeEx();
            OutputOpacityTypeUI.Parent = this;
            OutputOpacityType = OutputOpacityTypeUI.DefaultValue;
            Items.Add(OutputOpacityTypeUI);
        }

        public SimplygonColorCasterSettings(dynamic jsonData) : base("ColorCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialChannelUI") != null ? jsonData.MaterialChannelUI : null);
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelComponentUI") != null ? jsonData.OpacityChannelComponentUI : null);
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelUI") != null ? jsonData.OpacityChannelUI : null);
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DitherTypeUI") != null ? jsonData.DitherTypeUI : null);
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx(jsonData != null && ((JObject)jsonData).GetValue("FillModeUI") != null ? jsonData.FillModeUI : null);
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx(jsonData != null && ((JObject)jsonData).GetValue("DilationUI") != null ? jsonData.DilationUI : null);
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx(jsonData != null && ((JObject)jsonData).GetValue("UseMultisamplingUI") != null ? jsonData.UseMultisamplingUI : null);
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputPixelFormatUI") != null ? jsonData.OutputPixelFormatUI : null);
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputSRGBUI = new SimplygonOutputSRGBEx(jsonData != null && ((JObject)jsonData).GetValue("OutputSRGBUI") != null ? jsonData.OutputSRGBUI : null);
            OutputSRGBUI.Parent = this;
            OutputSRGB = OutputSRGBUI.DefaultValue;
            Items.Add(OutputSRGBUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputImageFileFormatUI") != null ? jsonData.OutputImageFileFormatUI : null);
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputDDSCompressionTypeUI") != null ? jsonData.OutputDDSCompressionTypeUI : null);
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            BakeOpacityInAlphaUI = new SimplygonBakeOpacityInAlphaEx(jsonData != null && ((JObject)jsonData).GetValue("BakeOpacityInAlphaUI") != null ? jsonData.BakeOpacityInAlphaUI : null);
            BakeOpacityInAlphaUI.Parent = this;
            BakeOpacityInAlpha = BakeOpacityInAlphaUI.DefaultValue;
            Items.Add(BakeOpacityInAlphaUI);
            SkipCastingIfNoInputChannelUI = new SimplygonSkipCastingIfNoInputChannelEx(jsonData != null && ((JObject)jsonData).GetValue("SkipCastingIfNoInputChannelUI") != null ? jsonData.SkipCastingIfNoInputChannelUI : null);
            SkipCastingIfNoInputChannelUI.Parent = this;
            SkipCastingIfNoInputChannel = SkipCastingIfNoInputChannelUI.DefaultValue;
            Items.Add(SkipCastingIfNoInputChannelUI);
            OutputOpacityTypeUI = new SimplygonOutputOpacityTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputOpacityTypeUI") != null ? jsonData.OutputOpacityTypeUI : null);
            OutputOpacityTypeUI.Parent = this;
            OutputOpacityType = OutputOpacityTypeUI.DefaultValue;
            Items.Add(OutputOpacityTypeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonColorCasterSettings();
            copy.Items.Clear();
            copy.MaterialChannelUI = this.MaterialChannelUI.DeepCopy();
            copy.MaterialChannelUI.Parent = copy;
            copy.Items.Add(copy.MaterialChannelUI);
            copy.OpacityChannelComponentUI = this.OpacityChannelComponentUI.DeepCopy();
            copy.OpacityChannelComponentUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelComponentUI);
            copy.OpacityChannelUI = this.OpacityChannelUI.DeepCopy();
            copy.OpacityChannelUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelUI);
            copy.DitherTypeUI = this.DitherTypeUI.DeepCopy();
            copy.DitherTypeUI.Parent = copy;
            copy.Items.Add(copy.DitherTypeUI);
            copy.FillModeUI = this.FillModeUI.DeepCopy();
            copy.FillModeUI.Parent = copy;
            copy.Items.Add(copy.FillModeUI);
            copy.DilationUI = this.DilationUI.DeepCopy();
            copy.DilationUI.Parent = copy;
            copy.Items.Add(copy.DilationUI);
            copy.UseMultisamplingUI = this.UseMultisamplingUI.DeepCopy();
            copy.UseMultisamplingUI.Parent = copy;
            copy.Items.Add(copy.UseMultisamplingUI);
            copy.OutputPixelFormatUI = this.OutputPixelFormatUI.DeepCopy();
            copy.OutputPixelFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputPixelFormatUI);
            copy.OutputSRGBUI = this.OutputSRGBUI.DeepCopy();
            copy.OutputSRGBUI.Parent = copy;
            copy.Items.Add(copy.OutputSRGBUI);
            copy.OutputImageFileFormatUI = this.OutputImageFileFormatUI.DeepCopy();
            copy.OutputImageFileFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputImageFileFormatUI);
            copy.OutputDDSCompressionTypeUI = this.OutputDDSCompressionTypeUI.DeepCopy();
            copy.OutputDDSCompressionTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputDDSCompressionTypeUI);
            copy.BakeOpacityInAlphaUI = this.BakeOpacityInAlphaUI.DeepCopy();
            copy.BakeOpacityInAlphaUI.Parent = copy;
            copy.Items.Add(copy.BakeOpacityInAlphaUI);
            copy.SkipCastingIfNoInputChannelUI = this.SkipCastingIfNoInputChannelUI.DeepCopy();
            copy.SkipCastingIfNoInputChannelUI.Parent = copy;
            copy.Items.Add(copy.SkipCastingIfNoInputChannelUI);
            copy.OutputOpacityTypeUI = this.OutputOpacityTypeUI.DeepCopy();
            copy.OutputOpacityTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputOpacityTypeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialChannel = MaterialChannel;
            if(serializeUIComponents)
            {
                jsonData.MaterialChannelUI = MaterialChannelUI.SaveJson();
            }

            jsonData.OpacityChannelComponent = (int)OpacityChannelComponent;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelComponentUI = OpacityChannelComponentUI.SaveJson();
            }

            jsonData.DitherType = (int)DitherType;
            if(serializeUIComponents)
            {
                jsonData.DitherTypeUI = DitherTypeUI.SaveJson();
            }

            jsonData.FillMode = (int)FillMode;
            if(serializeUIComponents)
            {
                jsonData.FillModeUI = FillModeUI.SaveJson();
            }

            jsonData.OpacityChannel = OpacityChannel;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelUI = OpacityChannelUI.SaveJson();
            }

            jsonData.UseMultisampling = UseMultisampling;
            if(serializeUIComponents)
            {
                jsonData.UseMultisamplingUI = UseMultisamplingUI.SaveJson();
            }

            jsonData.BakeOpacityInAlpha = BakeOpacityInAlpha;
            if(serializeUIComponents)
            {
                jsonData.BakeOpacityInAlphaUI = BakeOpacityInAlphaUI.SaveJson();
            }

            jsonData.OutputImageFileFormat = (int)OutputImageFileFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputImageFileFormatUI = OutputImageFileFormatUI.SaveJson();
            }

            jsonData.OutputDDSCompressionType = (int)OutputDDSCompressionType;
            if(serializeUIComponents)
            {
                jsonData.OutputDDSCompressionTypeUI = OutputDDSCompressionTypeUI.SaveJson();
            }

            jsonData.Dilation = Dilation;
            if(serializeUIComponents)
            {
                jsonData.DilationUI = DilationUI.SaveJson();
            }

            jsonData.OutputOpacityType = (int)OutputOpacityType;
            if(serializeUIComponents)
            {
                jsonData.OutputOpacityTypeUI = OutputOpacityTypeUI.SaveJson();
            }

            jsonData.OutputPixelFormat = (int)OutputPixelFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputPixelFormatUI = OutputPixelFormatUI.SaveJson();
            }

            jsonData.SkipCastingIfNoInputChannel = SkipCastingIfNoInputChannel;
            if(serializeUIComponents)
            {
                jsonData.SkipCastingIfNoInputChannelUI = SkipCastingIfNoInputChannelUI.SaveJson();
            }

            jsonData.OutputSRGB = OutputSRGB;
            if(serializeUIComponents)
            {
                jsonData.OutputSRGBUI = OutputSRGBUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialChannel") != null)
            {
                MaterialChannel = (string)jsonData.MaterialChannel;
            }

            if(jsonData.GetValue("OpacityChannelComponent") != null)
            {
                OpacityChannelComponent = (EColorComponent)jsonData.OpacityChannelComponent;
            }

            if(jsonData.GetValue("DitherType") != null)
            {
                DitherType = (EDitherPatterns)jsonData.DitherType;
            }

            if(jsonData.GetValue("FillMode") != null)
            {
                FillMode = (EAtlasFillMode)jsonData.FillMode;
            }

            if(jsonData.GetValue("OpacityChannel") != null)
            {
                OpacityChannel = (string)jsonData.OpacityChannel;
            }

            if(jsonData.GetValue("UseMultisampling") != null)
            {
                UseMultisampling = (bool)jsonData.UseMultisampling;
            }

            if(jsonData.GetValue("BakeOpacityInAlpha") != null)
            {
                BakeOpacityInAlpha = (bool)jsonData.BakeOpacityInAlpha;
            }

            if(jsonData.GetValue("OutputImageFileFormat") != null)
            {
                OutputImageFileFormat = (EImageOutputFormat)jsonData.OutputImageFileFormat;
            }

            if(jsonData.GetValue("OutputDDSCompressionType") != null)
            {
                OutputDDSCompressionType = (EDDSCompressionType)jsonData.OutputDDSCompressionType;
            }

            if(jsonData.GetValue("Dilation") != null)
            {
                var newDilation = (int)jsonData.Dilation;
                if (newDilation >= DilationUI.DefaultMinValue && newDilation <= DilationUI.DefaultMaxValue)
                {
                    Dilation = newDilation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid value {newDilation}, using default value {Dilation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputOpacityType") != null)
            {
                OutputOpacityType = (EOpacityType)jsonData.OutputOpacityType;
            }

            if(jsonData.GetValue("OutputPixelFormat") != null)
            {
                OutputPixelFormat = (EPixelFormat)jsonData.OutputPixelFormat;
            }

            if(jsonData.GetValue("SkipCastingIfNoInputChannel") != null)
            {
                SkipCastingIfNoInputChannel = (bool)jsonData.SkipCastingIfNoInputChannel;
            }

            if(jsonData.GetValue("OutputSRGB") != null)
            {
                OutputSRGB = (bool)jsonData.OutputSRGB;
            }

        }

        public override void Reset()
        {
            MaterialChannelUI.Reset();
            OpacityChannelComponentUI.Reset();
            DitherTypeUI.Reset();
            FillModeUI.Reset();
            OpacityChannelUI.Reset();
            UseMultisamplingUI.Reset();
            BakeOpacityInAlphaUI.Reset();
            OutputImageFileFormatUI.Reset();
            OutputDDSCompressionTypeUI.Reset();
            DilationUI.Reset();
            OutputOpacityTypeUI.Reset();
            OutputPixelFormatUI.Reset();
            SkipCastingIfNoInputChannelUI.Reset();
            OutputSRGBUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialChannelUI.IsEditEnabled = isEditEnabled;
            OpacityChannelComponentUI.IsEditEnabled = isEditEnabled;
            DitherTypeUI.IsEditEnabled = isEditEnabled;
            FillModeUI.IsEditEnabled = isEditEnabled;
            OpacityChannelUI.IsEditEnabled = isEditEnabled;
            UseMultisamplingUI.IsEditEnabled = isEditEnabled;
            BakeOpacityInAlphaUI.IsEditEnabled = isEditEnabled;
            OutputImageFileFormatUI.IsEditEnabled = isEditEnabled;
            OutputDDSCompressionTypeUI.IsEditEnabled = isEditEnabled;
            DilationUI.IsEditEnabled = isEditEnabled;
            OutputOpacityTypeUI.IsEditEnabled = isEditEnabled;
            OutputPixelFormatUI.IsEditEnabled = isEditEnabled;
            SkipCastingIfNoInputChannelUI.IsEditEnabled = isEditEnabled;
            OutputSRGBUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputSRGBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            BakeOpacityInAlphaUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            SkipCastingIfNoInputChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputOpacityTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonOpacityCasterSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialChannelUI.Visible) return true;
                if(OpacityChannelComponentUI.Visible) return true;
                if(DitherTypeUI.Visible) return true;
                if(FillModeUI.Visible) return true;
                if(OpacityChannelUI.Visible) return true;
                if(UseMultisamplingUI.Visible) return true;
                if(OutputSRGBUI.Visible) return true;
                if(OutputImageFileFormatUI.Visible) return true;
                if(OutputDDSCompressionTypeUI.Visible) return true;
                if(DilationUI.Visible) return true;
                if(OutputOpacityTypeUI.Visible) return true;
                if(OutputPixelFormatUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string MaterialChannel { get { return _MaterialChannel; } set { _MaterialChannel = value; OnPropertyChanged(); } }
        private string _MaterialChannel;
        public SimplygonMaterialChannelEx MaterialChannelUI { get; set; }
        public class SimplygonMaterialChannelEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.MaterialChannel;
                }

                set
                {
                    bool needReload = Parent.MaterialChannel != value;
                    Parent.MaterialChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonMaterialChannelEx() : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonMaterialChannelEx(dynamic jsonData) : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialChannelEx DeepCopy()
            {
                return (SimplygonMaterialChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.MaterialChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
                Parent.Parent.displayName = ObjectNames.NicifyVariableName("OpacityCaster") + " - " + value;
            }

        }

        public EColorComponent OpacityChannelComponent { get { return _OpacityChannelComponent; } set { _OpacityChannelComponent = value; OnPropertyChanged(); } }
        private EColorComponent _OpacityChannelComponent;
        public SimplygonOpacityChannelComponentEx OpacityChannelComponentUI { get; set; }
        public class SimplygonOpacityChannelComponentEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.OpacityChannelComponent;
                }

                set
                {
                    bool needReload = Parent.OpacityChannelComponent != value;
                    Parent.OpacityChannelComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonOpacityChannelComponentEx() : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonOpacityChannelComponentEx(dynamic jsonData) : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelComponentEx DeepCopy()
            {
                return (SimplygonOpacityChannelComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OpacityChannelComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public EDitherPatterns DitherType { get { return _DitherType; } set { _DitherType = value; OnPropertyChanged(); } }
        private EDitherPatterns _DitherType;
        public SimplygonDitherTypeEx DitherTypeUI { get; set; }
        public class SimplygonDitherTypeEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public EDitherPatterns Value
            {
                get
                {
                    return Parent.DitherType;
                }

                set
                {
                    bool needReload = Parent.DitherType != value;
                    Parent.DitherType = value;
                    OnPropertyChanged();
                }

            }

            public EDitherPatterns DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDitherPatterns)); } }

            public SimplygonDitherTypeEx() : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                Visible = true;
            }

            public SimplygonDitherTypeEx(dynamic jsonData) : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDitherTypeEx DeepCopy()
            {
                return (SimplygonDitherTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DitherType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDitherPatterns)value;
            }

        }

        public EAtlasFillMode FillMode { get { return _FillMode; } set { _FillMode = value; OnPropertyChanged(); } }
        private EAtlasFillMode _FillMode;
        public SimplygonFillModeEx FillModeUI { get; set; }
        public class SimplygonFillModeEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public EAtlasFillMode Value
            {
                get
                {
                    return Parent.FillMode;
                }

                set
                {
                    bool needReload = Parent.FillMode != value;
                    Parent.FillMode = value;
                    OnPropertyChanged();
                }

            }

            public EAtlasFillMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EAtlasFillMode)); } }

            public SimplygonFillModeEx() : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                Visible = true;
            }

            public SimplygonFillModeEx(dynamic jsonData) : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillModeEx DeepCopy()
            {
                return (SimplygonFillModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.FillMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EAtlasFillMode)value;
            }

        }

        public string OpacityChannel { get { return _OpacityChannel; } set { _OpacityChannel = value; OnPropertyChanged(); } }
        private string _OpacityChannel;
        public SimplygonOpacityChannelEx OpacityChannelUI { get; set; }
        public class SimplygonOpacityChannelEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OpacityChannel;
                }

                set
                {
                    bool needReload = Parent.OpacityChannel != value;
                    Parent.OpacityChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOpacityChannelEx() : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                Visible = true;
            }

            public SimplygonOpacityChannelEx(dynamic jsonData) : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelEx DeepCopy()
            {
                return (SimplygonOpacityChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OpacityChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseMultisampling { get { return _UseMultisampling; } set { _UseMultisampling = value; OnPropertyChanged(); } }
        private bool _UseMultisampling;
        public SimplygonUseMultisamplingEx UseMultisamplingUI { get; set; }
        public class SimplygonUseMultisamplingEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseMultisampling;
                }

                set
                {
                    bool needReload = Parent.UseMultisampling != value;
                    Parent.UseMultisampling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseMultisamplingEx() : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseMultisamplingEx(dynamic jsonData) : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseMultisamplingEx DeepCopy()
            {
                return (SimplygonUseMultisamplingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseMultisampling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool OutputSRGB { get { return _OutputSRGB; } set { _OutputSRGB = value; OnPropertyChanged(); } }
        private bool _OutputSRGB;
        public SimplygonOutputSRGBEx OutputSRGBUI { get; set; }
        public class SimplygonOutputSRGBEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.OutputSRGB;
                }

                set
                {
                    bool needReload = Parent.OutputSRGB != value;
                    Parent.OutputSRGB = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonOutputSRGBEx() : base("OutputSRGB")
            {
                Type = "bool";
                HelpText = "If set, output textures are exported in sRGB format. Input texture format is determined by the flag in the corresponding texture node in the material definition.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonOutputSRGBEx(dynamic jsonData) : base("OutputSRGB")
            {
                Type = "bool";
                HelpText = "If set, output textures are exported in sRGB format. Input texture format is determined by the flag in the corresponding texture node in the material definition.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputSRGBEx DeepCopy()
            {
                return (SimplygonOutputSRGBEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.OutputSRGB;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EImageOutputFormat OutputImageFileFormat { get { return _OutputImageFileFormat; } set { _OutputImageFileFormat = value; OnPropertyChanged(); } }
        private EImageOutputFormat _OutputImageFileFormat;
        public SimplygonOutputImageFileFormatEx OutputImageFileFormatUI { get; set; }
        public class SimplygonOutputImageFileFormatEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public EImageOutputFormat Value
            {
                get
                {
                    return Parent.OutputImageFileFormat;
                }

                set
                {
                    bool needReload = Parent.OutputImageFileFormat != value;
                    Parent.OutputImageFileFormat = value;
                    Parent.OutputDDSCompressionTypeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public EImageOutputFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EImageOutputFormat)); } }

            public SimplygonOutputImageFileFormatEx() : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                Visible = true;
            }

            public SimplygonOutputImageFileFormatEx(dynamic jsonData) : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputImageFileFormatEx DeepCopy()
            {
                return (SimplygonOutputImageFileFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputImageFileFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EImageOutputFormat)value;
            }

        }

        public EDDSCompressionType OutputDDSCompressionType { get { return _OutputDDSCompressionType; } set { _OutputDDSCompressionType = value; OnPropertyChanged(); } }
        private EDDSCompressionType _OutputDDSCompressionType;
        public SimplygonOutputDDSCompressionTypeEx OutputDDSCompressionTypeUI { get; set; }
        public class SimplygonOutputDDSCompressionTypeEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public EDDSCompressionType Value
            {
                get
                {
                    return Parent.OutputDDSCompressionType;
                }

                set
                {
                    bool needReload = Parent.OutputDDSCompressionType != value;
                    Parent.OutputDDSCompressionType = value;
                    OnPropertyChanged();
                }

            }

            public EDDSCompressionType DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.OutputImageFileFormatUI != null ) { return Parent.OutputImageFileFormat == EImageOutputFormat.DDS && Parent.OutputImageFileFormatUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDDSCompressionType)); } }

            public SimplygonOutputDDSCompressionTypeEx() : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                Visible = true;
            }

            public SimplygonOutputDDSCompressionTypeEx(dynamic jsonData) : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputDDSCompressionTypeEx DeepCopy()
            {
                return (SimplygonOutputDDSCompressionTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.OutputImageFileFormatUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputDDSCompressionType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDDSCompressionType)value;
            }

        }

        public int Dilation { get { return _Dilation; } set { _Dilation = value; OnPropertyChanged(); } }
        private int _Dilation;
        public SimplygonDilationEx DilationUI { get; set; }
        public class SimplygonDilationEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.Dilation;
                }

                set
                {
                    bool needReload = Parent.Dilation != value;
                    Parent.Dilation = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonDilationEx() : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 1000;
                DefaultMinValue = 0;
                DefaultMaxValue = 1000;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonDilationEx(dynamic jsonData) : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000;
                DefaultMaxValue = 1000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDilationEx DeepCopy()
            {
                return (SimplygonDilationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.Dilation;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EOpacityType OutputOpacityType { get { return _OutputOpacityType; } set { _OutputOpacityType = value; OnPropertyChanged(); } }
        private EOpacityType _OutputOpacityType;
        public SimplygonOutputOpacityTypeEx OutputOpacityTypeUI { get; set; }
        public class SimplygonOutputOpacityTypeEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public EOpacityType Value
            {
                get
                {
                    return Parent.OutputOpacityType;
                }

                set
                {
                    bool needReload = Parent.OutputOpacityType != value;
                    Parent.OutputOpacityType = value;
                    OnPropertyChanged();
                }

            }

            public EOpacityType DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EOpacityType)); } }

            public SimplygonOutputOpacityTypeEx() : base("OutputOpacityType")
            {
                Type = "enum";
                HelpText = "The opacity type determines how the opacity channel of this material should be saved. To make (0.0->1.0) map to (transparent-opaque), use 'Opacity'. To make (0.0->1.0) map to (opaque-transparent), use 'Transparency'";
                TypeOverride = "";
                DefaultValue = EOpacityType.Opacity;
                Visible = true;
            }

            public SimplygonOutputOpacityTypeEx(dynamic jsonData) : base("OutputOpacityType")
            {
                Type = "enum";
                HelpText = "The opacity type determines how the opacity channel of this material should be saved. To make (0.0->1.0) map to (transparent-opaque), use 'Opacity'. To make (0.0->1.0) map to (opaque-transparent), use 'Transparency'";
                TypeOverride = "";
                DefaultValue = EOpacityType.Opacity;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputOpacityTypeEx DeepCopy()
            {
                return (SimplygonOutputOpacityTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputOpacityType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EOpacityType)value;
            }

        }

        public EPixelFormat OutputPixelFormat { get { return _OutputPixelFormat; } set { _OutputPixelFormat = value; OnPropertyChanged(); } }
        private EPixelFormat _OutputPixelFormat;
        public SimplygonOutputPixelFormatEx OutputPixelFormatUI { get; set; }
        public class SimplygonOutputPixelFormatEx : SimplygonSettingsProperty
        {
            public SimplygonOpacityCasterSettings Parent { get; set; }
            public EPixelFormat Value
            {
                get
                {
                    return Parent.OutputPixelFormat;
                }

                set
                {
                    bool needReload = Parent.OutputPixelFormat != value;
                    Parent.OutputPixelFormat = value;
                    OnPropertyChanged();
                }

            }

            public EPixelFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPixelFormat)); } }

            public SimplygonOutputPixelFormatEx() : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                Visible = true;
            }

            public SimplygonOutputPixelFormatEx(dynamic jsonData) : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputPixelFormatEx DeepCopy()
            {
                return (SimplygonOutputPixelFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputPixelFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPixelFormat)value;
            }

        }


        public SimplygonOpacityCasterSettings() : base("OpacityCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx();
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx();
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx();
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx();
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx();
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx();
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx();
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputSRGBUI = new SimplygonOutputSRGBEx();
            OutputSRGBUI.Parent = this;
            OutputSRGB = OutputSRGBUI.DefaultValue;
            Items.Add(OutputSRGBUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx();
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx();
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx();
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            OutputOpacityTypeUI = new SimplygonOutputOpacityTypeEx();
            OutputOpacityTypeUI.Parent = this;
            OutputOpacityType = OutputOpacityTypeUI.DefaultValue;
            Items.Add(OutputOpacityTypeUI);
        }

        public SimplygonOpacityCasterSettings(dynamic jsonData) : base("OpacityCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialChannelUI") != null ? jsonData.MaterialChannelUI : null);
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelComponentUI") != null ? jsonData.OpacityChannelComponentUI : null);
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelUI") != null ? jsonData.OpacityChannelUI : null);
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DitherTypeUI") != null ? jsonData.DitherTypeUI : null);
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx(jsonData != null && ((JObject)jsonData).GetValue("FillModeUI") != null ? jsonData.FillModeUI : null);
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx(jsonData != null && ((JObject)jsonData).GetValue("DilationUI") != null ? jsonData.DilationUI : null);
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx(jsonData != null && ((JObject)jsonData).GetValue("UseMultisamplingUI") != null ? jsonData.UseMultisamplingUI : null);
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputSRGBUI = new SimplygonOutputSRGBEx(jsonData != null && ((JObject)jsonData).GetValue("OutputSRGBUI") != null ? jsonData.OutputSRGBUI : null);
            OutputSRGBUI.Parent = this;
            OutputSRGB = OutputSRGBUI.DefaultValue;
            Items.Add(OutputSRGBUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputPixelFormatUI") != null ? jsonData.OutputPixelFormatUI : null);
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputImageFileFormatUI") != null ? jsonData.OutputImageFileFormatUI : null);
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputDDSCompressionTypeUI") != null ? jsonData.OutputDDSCompressionTypeUI : null);
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            OutputOpacityTypeUI = new SimplygonOutputOpacityTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputOpacityTypeUI") != null ? jsonData.OutputOpacityTypeUI : null);
            OutputOpacityTypeUI.Parent = this;
            OutputOpacityType = OutputOpacityTypeUI.DefaultValue;
            Items.Add(OutputOpacityTypeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonOpacityCasterSettings();
            copy.Items.Clear();
            copy.MaterialChannelUI = this.MaterialChannelUI.DeepCopy();
            copy.MaterialChannelUI.Parent = copy;
            copy.Items.Add(copy.MaterialChannelUI);
            copy.OpacityChannelComponentUI = this.OpacityChannelComponentUI.DeepCopy();
            copy.OpacityChannelComponentUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelComponentUI);
            copy.OpacityChannelUI = this.OpacityChannelUI.DeepCopy();
            copy.OpacityChannelUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelUI);
            copy.DitherTypeUI = this.DitherTypeUI.DeepCopy();
            copy.DitherTypeUI.Parent = copy;
            copy.Items.Add(copy.DitherTypeUI);
            copy.FillModeUI = this.FillModeUI.DeepCopy();
            copy.FillModeUI.Parent = copy;
            copy.Items.Add(copy.FillModeUI);
            copy.DilationUI = this.DilationUI.DeepCopy();
            copy.DilationUI.Parent = copy;
            copy.Items.Add(copy.DilationUI);
            copy.UseMultisamplingUI = this.UseMultisamplingUI.DeepCopy();
            copy.UseMultisamplingUI.Parent = copy;
            copy.Items.Add(copy.UseMultisamplingUI);
            copy.OutputSRGBUI = this.OutputSRGBUI.DeepCopy();
            copy.OutputSRGBUI.Parent = copy;
            copy.Items.Add(copy.OutputSRGBUI);
            copy.OutputPixelFormatUI = this.OutputPixelFormatUI.DeepCopy();
            copy.OutputPixelFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputPixelFormatUI);
            copy.OutputImageFileFormatUI = this.OutputImageFileFormatUI.DeepCopy();
            copy.OutputImageFileFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputImageFileFormatUI);
            copy.OutputDDSCompressionTypeUI = this.OutputDDSCompressionTypeUI.DeepCopy();
            copy.OutputDDSCompressionTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputDDSCompressionTypeUI);
            copy.OutputOpacityTypeUI = this.OutputOpacityTypeUI.DeepCopy();
            copy.OutputOpacityTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputOpacityTypeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialChannel = MaterialChannel;
            if(serializeUIComponents)
            {
                jsonData.MaterialChannelUI = MaterialChannelUI.SaveJson();
            }

            jsonData.OpacityChannelComponent = (int)OpacityChannelComponent;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelComponentUI = OpacityChannelComponentUI.SaveJson();
            }

            jsonData.DitherType = (int)DitherType;
            if(serializeUIComponents)
            {
                jsonData.DitherTypeUI = DitherTypeUI.SaveJson();
            }

            jsonData.FillMode = (int)FillMode;
            if(serializeUIComponents)
            {
                jsonData.FillModeUI = FillModeUI.SaveJson();
            }

            jsonData.OpacityChannel = OpacityChannel;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelUI = OpacityChannelUI.SaveJson();
            }

            jsonData.UseMultisampling = UseMultisampling;
            if(serializeUIComponents)
            {
                jsonData.UseMultisamplingUI = UseMultisamplingUI.SaveJson();
            }

            jsonData.OutputSRGB = OutputSRGB;
            if(serializeUIComponents)
            {
                jsonData.OutputSRGBUI = OutputSRGBUI.SaveJson();
            }

            jsonData.OutputImageFileFormat = (int)OutputImageFileFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputImageFileFormatUI = OutputImageFileFormatUI.SaveJson();
            }

            jsonData.OutputDDSCompressionType = (int)OutputDDSCompressionType;
            if(serializeUIComponents)
            {
                jsonData.OutputDDSCompressionTypeUI = OutputDDSCompressionTypeUI.SaveJson();
            }

            jsonData.Dilation = Dilation;
            if(serializeUIComponents)
            {
                jsonData.DilationUI = DilationUI.SaveJson();
            }

            jsonData.OutputOpacityType = (int)OutputOpacityType;
            if(serializeUIComponents)
            {
                jsonData.OutputOpacityTypeUI = OutputOpacityTypeUI.SaveJson();
            }

            jsonData.OutputPixelFormat = (int)OutputPixelFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputPixelFormatUI = OutputPixelFormatUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialChannel") != null)
            {
                MaterialChannel = (string)jsonData.MaterialChannel;
            }

            if(jsonData.GetValue("OpacityChannelComponent") != null)
            {
                OpacityChannelComponent = (EColorComponent)jsonData.OpacityChannelComponent;
            }

            if(jsonData.GetValue("DitherType") != null)
            {
                DitherType = (EDitherPatterns)jsonData.DitherType;
            }

            if(jsonData.GetValue("FillMode") != null)
            {
                FillMode = (EAtlasFillMode)jsonData.FillMode;
            }

            if(jsonData.GetValue("OpacityChannel") != null)
            {
                OpacityChannel = (string)jsonData.OpacityChannel;
            }

            if(jsonData.GetValue("UseMultisampling") != null)
            {
                UseMultisampling = (bool)jsonData.UseMultisampling;
            }

            if(jsonData.GetValue("OutputSRGB") != null)
            {
                OutputSRGB = (bool)jsonData.OutputSRGB;
            }

            if(jsonData.GetValue("OutputImageFileFormat") != null)
            {
                OutputImageFileFormat = (EImageOutputFormat)jsonData.OutputImageFileFormat;
            }

            if(jsonData.GetValue("OutputDDSCompressionType") != null)
            {
                OutputDDSCompressionType = (EDDSCompressionType)jsonData.OutputDDSCompressionType;
            }

            if(jsonData.GetValue("Dilation") != null)
            {
                var newDilation = (int)jsonData.Dilation;
                if (newDilation >= DilationUI.DefaultMinValue && newDilation <= DilationUI.DefaultMaxValue)
                {
                    Dilation = newDilation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid value {newDilation}, using default value {Dilation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputOpacityType") != null)
            {
                OutputOpacityType = (EOpacityType)jsonData.OutputOpacityType;
            }

            if(jsonData.GetValue("OutputPixelFormat") != null)
            {
                OutputPixelFormat = (EPixelFormat)jsonData.OutputPixelFormat;
            }

        }

        public override void Reset()
        {
            MaterialChannelUI.Reset();
            OpacityChannelComponentUI.Reset();
            DitherTypeUI.Reset();
            FillModeUI.Reset();
            OpacityChannelUI.Reset();
            UseMultisamplingUI.Reset();
            OutputSRGBUI.Reset();
            OutputImageFileFormatUI.Reset();
            OutputDDSCompressionTypeUI.Reset();
            DilationUI.Reset();
            OutputOpacityTypeUI.Reset();
            OutputPixelFormatUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialChannelUI.IsEditEnabled = isEditEnabled;
            OpacityChannelComponentUI.IsEditEnabled = isEditEnabled;
            DitherTypeUI.IsEditEnabled = isEditEnabled;
            FillModeUI.IsEditEnabled = isEditEnabled;
            OpacityChannelUI.IsEditEnabled = isEditEnabled;
            UseMultisamplingUI.IsEditEnabled = isEditEnabled;
            OutputSRGBUI.IsEditEnabled = isEditEnabled;
            OutputImageFileFormatUI.IsEditEnabled = isEditEnabled;
            OutputDDSCompressionTypeUI.IsEditEnabled = isEditEnabled;
            DilationUI.IsEditEnabled = isEditEnabled;
            OutputOpacityTypeUI.IsEditEnabled = isEditEnabled;
            OutputPixelFormatUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputSRGBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputOpacityTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonNormalCasterSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialChannelUI.Visible) return true;
                if(OpacityChannelComponentUI.Visible) return true;
                if(DitherTypeUI.Visible) return true;
                if(FillModeUI.Visible) return true;
                if(OpacityChannelUI.Visible) return true;
                if(UseMultisamplingUI.Visible) return true;
                if(FlipBackfacingNormalsUI.Visible) return true;
                if(OutputImageFileFormatUI.Visible) return true;
                if(OutputDDSCompressionTypeUI.Visible) return true;
                if(DilationUI.Visible) return true;
                if(GenerateTangentSpaceNormalsUI.Visible) return true;
                if(OutputPixelFormatUI.Visible) return true;
                if(FlipGreenUI.Visible) return true;
                if(CalculateBitangentPerFragmentUI.Visible) return true;
                if(NormalizeInterpolatedTangentSpaceUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string MaterialChannel { get { return _MaterialChannel; } set { _MaterialChannel = value; OnPropertyChanged(); } }
        private string _MaterialChannel;
        public SimplygonMaterialChannelEx MaterialChannelUI { get; set; }
        public class SimplygonMaterialChannelEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.MaterialChannel;
                }

                set
                {
                    bool needReload = Parent.MaterialChannel != value;
                    Parent.MaterialChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonMaterialChannelEx() : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonMaterialChannelEx(dynamic jsonData) : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialChannelEx DeepCopy()
            {
                return (SimplygonMaterialChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.MaterialChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
                Parent.Parent.displayName = ObjectNames.NicifyVariableName("NormalCaster") + " - " + value;
            }

        }

        public EColorComponent OpacityChannelComponent { get { return _OpacityChannelComponent; } set { _OpacityChannelComponent = value; OnPropertyChanged(); } }
        private EColorComponent _OpacityChannelComponent;
        public SimplygonOpacityChannelComponentEx OpacityChannelComponentUI { get; set; }
        public class SimplygonOpacityChannelComponentEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.OpacityChannelComponent;
                }

                set
                {
                    bool needReload = Parent.OpacityChannelComponent != value;
                    Parent.OpacityChannelComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonOpacityChannelComponentEx() : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonOpacityChannelComponentEx(dynamic jsonData) : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelComponentEx DeepCopy()
            {
                return (SimplygonOpacityChannelComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OpacityChannelComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public EDitherPatterns DitherType { get { return _DitherType; } set { _DitherType = value; OnPropertyChanged(); } }
        private EDitherPatterns _DitherType;
        public SimplygonDitherTypeEx DitherTypeUI { get; set; }
        public class SimplygonDitherTypeEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public EDitherPatterns Value
            {
                get
                {
                    return Parent.DitherType;
                }

                set
                {
                    bool needReload = Parent.DitherType != value;
                    Parent.DitherType = value;
                    OnPropertyChanged();
                }

            }

            public EDitherPatterns DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDitherPatterns)); } }

            public SimplygonDitherTypeEx() : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                Visible = true;
            }

            public SimplygonDitherTypeEx(dynamic jsonData) : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDitherTypeEx DeepCopy()
            {
                return (SimplygonDitherTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DitherType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDitherPatterns)value;
            }

        }

        public EAtlasFillMode FillMode { get { return _FillMode; } set { _FillMode = value; OnPropertyChanged(); } }
        private EAtlasFillMode _FillMode;
        public SimplygonFillModeEx FillModeUI { get; set; }
        public class SimplygonFillModeEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public EAtlasFillMode Value
            {
                get
                {
                    return Parent.FillMode;
                }

                set
                {
                    bool needReload = Parent.FillMode != value;
                    Parent.FillMode = value;
                    OnPropertyChanged();
                }

            }

            public EAtlasFillMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EAtlasFillMode)); } }

            public SimplygonFillModeEx() : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                Visible = true;
            }

            public SimplygonFillModeEx(dynamic jsonData) : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillModeEx DeepCopy()
            {
                return (SimplygonFillModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.FillMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EAtlasFillMode)value;
            }

        }

        public string OpacityChannel { get { return _OpacityChannel; } set { _OpacityChannel = value; OnPropertyChanged(); } }
        private string _OpacityChannel;
        public SimplygonOpacityChannelEx OpacityChannelUI { get; set; }
        public class SimplygonOpacityChannelEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OpacityChannel;
                }

                set
                {
                    bool needReload = Parent.OpacityChannel != value;
                    Parent.OpacityChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOpacityChannelEx() : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                Visible = true;
            }

            public SimplygonOpacityChannelEx(dynamic jsonData) : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelEx DeepCopy()
            {
                return (SimplygonOpacityChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OpacityChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseMultisampling { get { return _UseMultisampling; } set { _UseMultisampling = value; OnPropertyChanged(); } }
        private bool _UseMultisampling;
        public SimplygonUseMultisamplingEx UseMultisamplingUI { get; set; }
        public class SimplygonUseMultisamplingEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseMultisampling;
                }

                set
                {
                    bool needReload = Parent.UseMultisampling != value;
                    Parent.UseMultisampling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseMultisamplingEx() : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseMultisamplingEx(dynamic jsonData) : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseMultisamplingEx DeepCopy()
            {
                return (SimplygonUseMultisamplingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseMultisampling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool FlipBackfacingNormals { get { return _FlipBackfacingNormals; } set { _FlipBackfacingNormals = value; OnPropertyChanged(); } }
        private bool _FlipBackfacingNormals;
        public SimplygonFlipBackfacingNormalsEx FlipBackfacingNormalsUI { get; set; }
        public class SimplygonFlipBackfacingNormalsEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.FlipBackfacingNormals;
                }

                set
                {
                    bool needReload = Parent.FlipBackfacingNormals != value;
                    Parent.FlipBackfacingNormals = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonFlipBackfacingNormalsEx() : base("FlipBackfacingNormals")
            {
                Type = "bool";
                HelpText = "If set, then normals will be flipped if they are back facing, i.e. pointing into the surface. This may introduce artifacts on geometries that have correctly facing normals, so only use for geometries with known back-facing normals.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonFlipBackfacingNormalsEx(dynamic jsonData) : base("FlipBackfacingNormals")
            {
                Type = "bool";
                HelpText = "If set, then normals will be flipped if they are back facing, i.e. pointing into the surface. This may introduce artifacts on geometries that have correctly facing normals, so only use for geometries with known back-facing normals.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFlipBackfacingNormalsEx DeepCopy()
            {
                return (SimplygonFlipBackfacingNormalsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.FlipBackfacingNormals;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EImageOutputFormat OutputImageFileFormat { get { return _OutputImageFileFormat; } set { _OutputImageFileFormat = value; OnPropertyChanged(); } }
        private EImageOutputFormat _OutputImageFileFormat;
        public SimplygonOutputImageFileFormatEx OutputImageFileFormatUI { get; set; }
        public class SimplygonOutputImageFileFormatEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public EImageOutputFormat Value
            {
                get
                {
                    return Parent.OutputImageFileFormat;
                }

                set
                {
                    bool needReload = Parent.OutputImageFileFormat != value;
                    Parent.OutputImageFileFormat = value;
                    Parent.OutputDDSCompressionTypeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public EImageOutputFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EImageOutputFormat)); } }

            public SimplygonOutputImageFileFormatEx() : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                Visible = true;
            }

            public SimplygonOutputImageFileFormatEx(dynamic jsonData) : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputImageFileFormatEx DeepCopy()
            {
                return (SimplygonOutputImageFileFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputImageFileFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EImageOutputFormat)value;
            }

        }

        public EDDSCompressionType OutputDDSCompressionType { get { return _OutputDDSCompressionType; } set { _OutputDDSCompressionType = value; OnPropertyChanged(); } }
        private EDDSCompressionType _OutputDDSCompressionType;
        public SimplygonOutputDDSCompressionTypeEx OutputDDSCompressionTypeUI { get; set; }
        public class SimplygonOutputDDSCompressionTypeEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public EDDSCompressionType Value
            {
                get
                {
                    return Parent.OutputDDSCompressionType;
                }

                set
                {
                    bool needReload = Parent.OutputDDSCompressionType != value;
                    Parent.OutputDDSCompressionType = value;
                    OnPropertyChanged();
                }

            }

            public EDDSCompressionType DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.OutputImageFileFormatUI != null ) { return Parent.OutputImageFileFormat == EImageOutputFormat.DDS && Parent.OutputImageFileFormatUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDDSCompressionType)); } }

            public SimplygonOutputDDSCompressionTypeEx() : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                Visible = true;
            }

            public SimplygonOutputDDSCompressionTypeEx(dynamic jsonData) : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputDDSCompressionTypeEx DeepCopy()
            {
                return (SimplygonOutputDDSCompressionTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.OutputImageFileFormatUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputDDSCompressionType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDDSCompressionType)value;
            }

        }

        public int Dilation { get { return _Dilation; } set { _Dilation = value; OnPropertyChanged(); } }
        private int _Dilation;
        public SimplygonDilationEx DilationUI { get; set; }
        public class SimplygonDilationEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.Dilation;
                }

                set
                {
                    bool needReload = Parent.Dilation != value;
                    Parent.Dilation = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonDilationEx() : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 1000;
                DefaultMinValue = 0;
                DefaultMaxValue = 1000;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonDilationEx(dynamic jsonData) : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000;
                DefaultMaxValue = 1000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDilationEx DeepCopy()
            {
                return (SimplygonDilationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.Dilation;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool GenerateTangentSpaceNormals { get { return _GenerateTangentSpaceNormals; } set { _GenerateTangentSpaceNormals = value; OnPropertyChanged(); } }
        private bool _GenerateTangentSpaceNormals;
        public SimplygonGenerateTangentSpaceNormalsEx GenerateTangentSpaceNormalsUI { get; set; }
        public class SimplygonGenerateTangentSpaceNormalsEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.GenerateTangentSpaceNormals;
                }

                set
                {
                    bool needReload = Parent.GenerateTangentSpaceNormals != value;
                    Parent.GenerateTangentSpaceNormals = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonGenerateTangentSpaceNormalsEx() : base("GenerateTangentSpaceNormals")
            {
                Type = "bool";
                HelpText = "If set, then the generated normal map will be in tangent space. Please note that the geometry casted to must contain tangent space fields.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonGenerateTangentSpaceNormalsEx(dynamic jsonData) : base("GenerateTangentSpaceNormals")
            {
                Type = "bool";
                HelpText = "If set, then the generated normal map will be in tangent space. Please note that the geometry casted to must contain tangent space fields.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGenerateTangentSpaceNormalsEx DeepCopy()
            {
                return (SimplygonGenerateTangentSpaceNormalsEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.GenerateTangentSpaceNormals;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EPixelFormat OutputPixelFormat { get { return _OutputPixelFormat; } set { _OutputPixelFormat = value; OnPropertyChanged(); } }
        private EPixelFormat _OutputPixelFormat;
        public SimplygonOutputPixelFormatEx OutputPixelFormatUI { get; set; }
        public class SimplygonOutputPixelFormatEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public EPixelFormat Value
            {
                get
                {
                    return Parent.OutputPixelFormat;
                }

                set
                {
                    bool needReload = Parent.OutputPixelFormat != value;
                    Parent.OutputPixelFormat = value;
                    OnPropertyChanged();
                }

            }

            public EPixelFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPixelFormat)); } }

            public SimplygonOutputPixelFormatEx() : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                Visible = true;
            }

            public SimplygonOutputPixelFormatEx(dynamic jsonData) : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputPixelFormatEx DeepCopy()
            {
                return (SimplygonOutputPixelFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputPixelFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPixelFormat)value;
            }

        }

        public bool FlipGreen { get { return _FlipGreen; } set { _FlipGreen = value; OnPropertyChanged(); } }
        private bool _FlipGreen;
        public SimplygonFlipGreenEx FlipGreenUI { get; set; }
        public class SimplygonFlipGreenEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.FlipGreen;
                }

                set
                {
                    bool needReload = Parent.FlipGreen != value;
                    Parent.FlipGreen = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonFlipGreenEx() : base("FlipGreen")
            {
                Type = "bool";
                HelpText = "If set, the green channel is assumed to point along the negative bitangent instead of the positive. This is roughly equivalent to switching between left- and righthanded, but some rounding may differ.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonFlipGreenEx(dynamic jsonData) : base("FlipGreen")
            {
                Type = "bool";
                HelpText = "If set, the green channel is assumed to point along the negative bitangent instead of the positive. This is roughly equivalent to switching between left- and righthanded, but some rounding may differ.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFlipGreenEx DeepCopy()
            {
                return (SimplygonFlipGreenEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.FlipGreen;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool CalculateBitangentPerFragment { get { return _CalculateBitangentPerFragment; } set { _CalculateBitangentPerFragment = value; OnPropertyChanged(); } }
        private bool _CalculateBitangentPerFragment;
        public SimplygonCalculateBitangentPerFragmentEx CalculateBitangentPerFragmentUI { get; set; }
        public class SimplygonCalculateBitangentPerFragmentEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.CalculateBitangentPerFragment;
                }

                set
                {
                    bool needReload = Parent.CalculateBitangentPerFragment != value;
                    Parent.CalculateBitangentPerFragment = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonCalculateBitangentPerFragmentEx() : base("CalculateBitangentPerFragment")
            {
                Type = "bool";
                HelpText = "If set, the normal caster calculates the bitangent used for encoding per-fragment using the normal, tangent and bitangent sign instead of interpolating the actual bitangent vertex data. This needs to match the behavior of the renderer to not produce rendering artifacts.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonCalculateBitangentPerFragmentEx(dynamic jsonData) : base("CalculateBitangentPerFragment")
            {
                Type = "bool";
                HelpText = "If set, the normal caster calculates the bitangent used for encoding per-fragment using the normal, tangent and bitangent sign instead of interpolating the actual bitangent vertex data. This needs to match the behavior of the renderer to not produce rendering artifacts.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonCalculateBitangentPerFragmentEx DeepCopy()
            {
                return (SimplygonCalculateBitangentPerFragmentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.CalculateBitangentPerFragment;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool NormalizeInterpolatedTangentSpace { get { return _NormalizeInterpolatedTangentSpace; } set { _NormalizeInterpolatedTangentSpace = value; OnPropertyChanged(); } }
        private bool _NormalizeInterpolatedTangentSpace;
        public SimplygonNormalizeInterpolatedTangentSpaceEx NormalizeInterpolatedTangentSpaceUI { get; set; }
        public class SimplygonNormalizeInterpolatedTangentSpaceEx : SimplygonSettingsProperty
        {
            public SimplygonNormalCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.NormalizeInterpolatedTangentSpace;
                }

                set
                {
                    bool needReload = Parent.NormalizeInterpolatedTangentSpace != value;
                    Parent.NormalizeInterpolatedTangentSpace = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonNormalizeInterpolatedTangentSpaceEx() : base("NormalizeInterpolatedTangentSpace")
            {
                Type = "bool";
                HelpText = "If set, the normal caster normalizes the normal and tangent data used for encoding after interpolation. This needs to match the behavior of the renderer to not produce rendering artifacts.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonNormalizeInterpolatedTangentSpaceEx(dynamic jsonData) : base("NormalizeInterpolatedTangentSpace")
            {
                Type = "bool";
                HelpText = "If set, the normal caster normalizes the normal and tangent data used for encoding after interpolation. This needs to match the behavior of the renderer to not produce rendering artifacts.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonNormalizeInterpolatedTangentSpaceEx DeepCopy()
            {
                return (SimplygonNormalizeInterpolatedTangentSpaceEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.NormalizeInterpolatedTangentSpace;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonNormalCasterSettings() : base("NormalCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx();
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx();
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx();
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx();
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx();
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx();
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx();
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx();
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx();
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx();
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            FlipBackfacingNormalsUI = new SimplygonFlipBackfacingNormalsEx();
            FlipBackfacingNormalsUI.Parent = this;
            FlipBackfacingNormals = FlipBackfacingNormalsUI.DefaultValue;
            Items.Add(FlipBackfacingNormalsUI);
            GenerateTangentSpaceNormalsUI = new SimplygonGenerateTangentSpaceNormalsEx();
            GenerateTangentSpaceNormalsUI.Parent = this;
            GenerateTangentSpaceNormals = GenerateTangentSpaceNormalsUI.DefaultValue;
            Items.Add(GenerateTangentSpaceNormalsUI);
            FlipGreenUI = new SimplygonFlipGreenEx();
            FlipGreenUI.Parent = this;
            FlipGreen = FlipGreenUI.DefaultValue;
            Items.Add(FlipGreenUI);
            CalculateBitangentPerFragmentUI = new SimplygonCalculateBitangentPerFragmentEx();
            CalculateBitangentPerFragmentUI.Parent = this;
            CalculateBitangentPerFragment = CalculateBitangentPerFragmentUI.DefaultValue;
            Items.Add(CalculateBitangentPerFragmentUI);
            NormalizeInterpolatedTangentSpaceUI = new SimplygonNormalizeInterpolatedTangentSpaceEx();
            NormalizeInterpolatedTangentSpaceUI.Parent = this;
            NormalizeInterpolatedTangentSpace = NormalizeInterpolatedTangentSpaceUI.DefaultValue;
            Items.Add(NormalizeInterpolatedTangentSpaceUI);
        }

        public SimplygonNormalCasterSettings(dynamic jsonData) : base("NormalCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialChannelUI") != null ? jsonData.MaterialChannelUI : null);
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelComponentUI") != null ? jsonData.OpacityChannelComponentUI : null);
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelUI") != null ? jsonData.OpacityChannelUI : null);
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DitherTypeUI") != null ? jsonData.DitherTypeUI : null);
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx(jsonData != null && ((JObject)jsonData).GetValue("FillModeUI") != null ? jsonData.FillModeUI : null);
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx(jsonData != null && ((JObject)jsonData).GetValue("DilationUI") != null ? jsonData.DilationUI : null);
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx(jsonData != null && ((JObject)jsonData).GetValue("UseMultisamplingUI") != null ? jsonData.UseMultisamplingUI : null);
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputPixelFormatUI") != null ? jsonData.OutputPixelFormatUI : null);
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputImageFileFormatUI") != null ? jsonData.OutputImageFileFormatUI : null);
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputDDSCompressionTypeUI") != null ? jsonData.OutputDDSCompressionTypeUI : null);
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            FlipBackfacingNormalsUI = new SimplygonFlipBackfacingNormalsEx(jsonData != null && ((JObject)jsonData).GetValue("FlipBackfacingNormalsUI") != null ? jsonData.FlipBackfacingNormalsUI : null);
            FlipBackfacingNormalsUI.Parent = this;
            FlipBackfacingNormals = FlipBackfacingNormalsUI.DefaultValue;
            Items.Add(FlipBackfacingNormalsUI);
            GenerateTangentSpaceNormalsUI = new SimplygonGenerateTangentSpaceNormalsEx(jsonData != null && ((JObject)jsonData).GetValue("GenerateTangentSpaceNormalsUI") != null ? jsonData.GenerateTangentSpaceNormalsUI : null);
            GenerateTangentSpaceNormalsUI.Parent = this;
            GenerateTangentSpaceNormals = GenerateTangentSpaceNormalsUI.DefaultValue;
            Items.Add(GenerateTangentSpaceNormalsUI);
            FlipGreenUI = new SimplygonFlipGreenEx(jsonData != null && ((JObject)jsonData).GetValue("FlipGreenUI") != null ? jsonData.FlipGreenUI : null);
            FlipGreenUI.Parent = this;
            FlipGreen = FlipGreenUI.DefaultValue;
            Items.Add(FlipGreenUI);
            CalculateBitangentPerFragmentUI = new SimplygonCalculateBitangentPerFragmentEx(jsonData != null && ((JObject)jsonData).GetValue("CalculateBitangentPerFragmentUI") != null ? jsonData.CalculateBitangentPerFragmentUI : null);
            CalculateBitangentPerFragmentUI.Parent = this;
            CalculateBitangentPerFragment = CalculateBitangentPerFragmentUI.DefaultValue;
            Items.Add(CalculateBitangentPerFragmentUI);
            NormalizeInterpolatedTangentSpaceUI = new SimplygonNormalizeInterpolatedTangentSpaceEx(jsonData != null && ((JObject)jsonData).GetValue("NormalizeInterpolatedTangentSpaceUI") != null ? jsonData.NormalizeInterpolatedTangentSpaceUI : null);
            NormalizeInterpolatedTangentSpaceUI.Parent = this;
            NormalizeInterpolatedTangentSpace = NormalizeInterpolatedTangentSpaceUI.DefaultValue;
            Items.Add(NormalizeInterpolatedTangentSpaceUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonNormalCasterSettings();
            copy.Items.Clear();
            copy.MaterialChannelUI = this.MaterialChannelUI.DeepCopy();
            copy.MaterialChannelUI.Parent = copy;
            copy.Items.Add(copy.MaterialChannelUI);
            copy.OpacityChannelComponentUI = this.OpacityChannelComponentUI.DeepCopy();
            copy.OpacityChannelComponentUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelComponentUI);
            copy.OpacityChannelUI = this.OpacityChannelUI.DeepCopy();
            copy.OpacityChannelUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelUI);
            copy.DitherTypeUI = this.DitherTypeUI.DeepCopy();
            copy.DitherTypeUI.Parent = copy;
            copy.Items.Add(copy.DitherTypeUI);
            copy.FillModeUI = this.FillModeUI.DeepCopy();
            copy.FillModeUI.Parent = copy;
            copy.Items.Add(copy.FillModeUI);
            copy.DilationUI = this.DilationUI.DeepCopy();
            copy.DilationUI.Parent = copy;
            copy.Items.Add(copy.DilationUI);
            copy.UseMultisamplingUI = this.UseMultisamplingUI.DeepCopy();
            copy.UseMultisamplingUI.Parent = copy;
            copy.Items.Add(copy.UseMultisamplingUI);
            copy.OutputPixelFormatUI = this.OutputPixelFormatUI.DeepCopy();
            copy.OutputPixelFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputPixelFormatUI);
            copy.OutputImageFileFormatUI = this.OutputImageFileFormatUI.DeepCopy();
            copy.OutputImageFileFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputImageFileFormatUI);
            copy.OutputDDSCompressionTypeUI = this.OutputDDSCompressionTypeUI.DeepCopy();
            copy.OutputDDSCompressionTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputDDSCompressionTypeUI);
            copy.FlipBackfacingNormalsUI = this.FlipBackfacingNormalsUI.DeepCopy();
            copy.FlipBackfacingNormalsUI.Parent = copy;
            copy.Items.Add(copy.FlipBackfacingNormalsUI);
            copy.GenerateTangentSpaceNormalsUI = this.GenerateTangentSpaceNormalsUI.DeepCopy();
            copy.GenerateTangentSpaceNormalsUI.Parent = copy;
            copy.Items.Add(copy.GenerateTangentSpaceNormalsUI);
            copy.FlipGreenUI = this.FlipGreenUI.DeepCopy();
            copy.FlipGreenUI.Parent = copy;
            copy.Items.Add(copy.FlipGreenUI);
            copy.CalculateBitangentPerFragmentUI = this.CalculateBitangentPerFragmentUI.DeepCopy();
            copy.CalculateBitangentPerFragmentUI.Parent = copy;
            copy.Items.Add(copy.CalculateBitangentPerFragmentUI);
            copy.NormalizeInterpolatedTangentSpaceUI = this.NormalizeInterpolatedTangentSpaceUI.DeepCopy();
            copy.NormalizeInterpolatedTangentSpaceUI.Parent = copy;
            copy.Items.Add(copy.NormalizeInterpolatedTangentSpaceUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialChannel = MaterialChannel;
            if(serializeUIComponents)
            {
                jsonData.MaterialChannelUI = MaterialChannelUI.SaveJson();
            }

            jsonData.OpacityChannelComponent = (int)OpacityChannelComponent;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelComponentUI = OpacityChannelComponentUI.SaveJson();
            }

            jsonData.DitherType = (int)DitherType;
            if(serializeUIComponents)
            {
                jsonData.DitherTypeUI = DitherTypeUI.SaveJson();
            }

            jsonData.FillMode = (int)FillMode;
            if(serializeUIComponents)
            {
                jsonData.FillModeUI = FillModeUI.SaveJson();
            }

            jsonData.OpacityChannel = OpacityChannel;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelUI = OpacityChannelUI.SaveJson();
            }

            jsonData.UseMultisampling = UseMultisampling;
            if(serializeUIComponents)
            {
                jsonData.UseMultisamplingUI = UseMultisamplingUI.SaveJson();
            }

            jsonData.FlipBackfacingNormals = FlipBackfacingNormals;
            if(serializeUIComponents)
            {
                jsonData.FlipBackfacingNormalsUI = FlipBackfacingNormalsUI.SaveJson();
            }

            jsonData.OutputImageFileFormat = (int)OutputImageFileFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputImageFileFormatUI = OutputImageFileFormatUI.SaveJson();
            }

            jsonData.OutputDDSCompressionType = (int)OutputDDSCompressionType;
            if(serializeUIComponents)
            {
                jsonData.OutputDDSCompressionTypeUI = OutputDDSCompressionTypeUI.SaveJson();
            }

            jsonData.Dilation = Dilation;
            if(serializeUIComponents)
            {
                jsonData.DilationUI = DilationUI.SaveJson();
            }

            jsonData.GenerateTangentSpaceNormals = GenerateTangentSpaceNormals;
            if(serializeUIComponents)
            {
                jsonData.GenerateTangentSpaceNormalsUI = GenerateTangentSpaceNormalsUI.SaveJson();
            }

            jsonData.OutputPixelFormat = (int)OutputPixelFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputPixelFormatUI = OutputPixelFormatUI.SaveJson();
            }

            jsonData.FlipGreen = FlipGreen;
            if(serializeUIComponents)
            {
                jsonData.FlipGreenUI = FlipGreenUI.SaveJson();
            }

            jsonData.CalculateBitangentPerFragment = CalculateBitangentPerFragment;
            if(serializeUIComponents)
            {
                jsonData.CalculateBitangentPerFragmentUI = CalculateBitangentPerFragmentUI.SaveJson();
            }

            jsonData.NormalizeInterpolatedTangentSpace = NormalizeInterpolatedTangentSpace;
            if(serializeUIComponents)
            {
                jsonData.NormalizeInterpolatedTangentSpaceUI = NormalizeInterpolatedTangentSpaceUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialChannel") != null)
            {
                MaterialChannel = (string)jsonData.MaterialChannel;
            }

            if(jsonData.GetValue("OpacityChannelComponent") != null)
            {
                OpacityChannelComponent = (EColorComponent)jsonData.OpacityChannelComponent;
            }

            if(jsonData.GetValue("DitherType") != null)
            {
                DitherType = (EDitherPatterns)jsonData.DitherType;
            }

            if(jsonData.GetValue("FillMode") != null)
            {
                FillMode = (EAtlasFillMode)jsonData.FillMode;
            }

            if(jsonData.GetValue("OpacityChannel") != null)
            {
                OpacityChannel = (string)jsonData.OpacityChannel;
            }

            if(jsonData.GetValue("UseMultisampling") != null)
            {
                UseMultisampling = (bool)jsonData.UseMultisampling;
            }

            if(jsonData.GetValue("FlipBackfacingNormals") != null)
            {
                FlipBackfacingNormals = (bool)jsonData.FlipBackfacingNormals;
            }

            if(jsonData.GetValue("OutputImageFileFormat") != null)
            {
                OutputImageFileFormat = (EImageOutputFormat)jsonData.OutputImageFileFormat;
            }

            if(jsonData.GetValue("OutputDDSCompressionType") != null)
            {
                OutputDDSCompressionType = (EDDSCompressionType)jsonData.OutputDDSCompressionType;
            }

            if(jsonData.GetValue("Dilation") != null)
            {
                var newDilation = (int)jsonData.Dilation;
                if (newDilation >= DilationUI.DefaultMinValue && newDilation <= DilationUI.DefaultMaxValue)
                {
                    Dilation = newDilation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid value {newDilation}, using default value {Dilation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("GenerateTangentSpaceNormals") != null)
            {
                GenerateTangentSpaceNormals = (bool)jsonData.GenerateTangentSpaceNormals;
            }

            if(jsonData.GetValue("OutputPixelFormat") != null)
            {
                OutputPixelFormat = (EPixelFormat)jsonData.OutputPixelFormat;
            }

            if(jsonData.GetValue("FlipGreen") != null)
            {
                FlipGreen = (bool)jsonData.FlipGreen;
            }

            if(jsonData.GetValue("CalculateBitangentPerFragment") != null)
            {
                CalculateBitangentPerFragment = (bool)jsonData.CalculateBitangentPerFragment;
            }

            if(jsonData.GetValue("NormalizeInterpolatedTangentSpace") != null)
            {
                NormalizeInterpolatedTangentSpace = (bool)jsonData.NormalizeInterpolatedTangentSpace;
            }

        }

        public override void Reset()
        {
            MaterialChannelUI.Reset();
            OpacityChannelComponentUI.Reset();
            DitherTypeUI.Reset();
            FillModeUI.Reset();
            OpacityChannelUI.Reset();
            UseMultisamplingUI.Reset();
            FlipBackfacingNormalsUI.Reset();
            OutputImageFileFormatUI.Reset();
            OutputDDSCompressionTypeUI.Reset();
            DilationUI.Reset();
            GenerateTangentSpaceNormalsUI.Reset();
            OutputPixelFormatUI.Reset();
            FlipGreenUI.Reset();
            CalculateBitangentPerFragmentUI.Reset();
            NormalizeInterpolatedTangentSpaceUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialChannelUI.IsEditEnabled = isEditEnabled;
            OpacityChannelComponentUI.IsEditEnabled = isEditEnabled;
            DitherTypeUI.IsEditEnabled = isEditEnabled;
            FillModeUI.IsEditEnabled = isEditEnabled;
            OpacityChannelUI.IsEditEnabled = isEditEnabled;
            UseMultisamplingUI.IsEditEnabled = isEditEnabled;
            FlipBackfacingNormalsUI.IsEditEnabled = isEditEnabled;
            OutputImageFileFormatUI.IsEditEnabled = isEditEnabled;
            OutputDDSCompressionTypeUI.IsEditEnabled = isEditEnabled;
            DilationUI.IsEditEnabled = isEditEnabled;
            GenerateTangentSpaceNormalsUI.IsEditEnabled = isEditEnabled;
            OutputPixelFormatUI.IsEditEnabled = isEditEnabled;
            FlipGreenUI.IsEditEnabled = isEditEnabled;
            CalculateBitangentPerFragmentUI.IsEditEnabled = isEditEnabled;
            NormalizeInterpolatedTangentSpaceUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FlipBackfacingNormalsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GenerateTangentSpaceNormalsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FlipGreenUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            CalculateBitangentPerFragmentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            NormalizeInterpolatedTangentSpaceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonDisplacementCasterSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialChannelUI.Visible) return true;
                if(OpacityChannelComponentUI.Visible) return true;
                if(DitherTypeUI.Visible) return true;
                if(FillModeUI.Visible) return true;
                if(OpacityChannelUI.Visible) return true;
                if(UseMultisamplingUI.Visible) return true;
                if(DistanceScalingUI.Visible) return true;
                if(OutputImageFileFormatUI.Visible) return true;
                if(OutputDDSCompressionTypeUI.Visible) return true;
                if(DilationUI.Visible) return true;
                if(GenerateScalarDisplacementUI.Visible) return true;
                if(OutputPixelFormatUI.Visible) return true;
                if(GenerateTangentSpaceDisplacementUI.Visible) return true;
                if(NormalMapTexCoordLevelUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string MaterialChannel { get { return _MaterialChannel; } set { _MaterialChannel = value; OnPropertyChanged(); } }
        private string _MaterialChannel;
        public SimplygonMaterialChannelEx MaterialChannelUI { get; set; }
        public class SimplygonMaterialChannelEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.MaterialChannel;
                }

                set
                {
                    bool needReload = Parent.MaterialChannel != value;
                    Parent.MaterialChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonMaterialChannelEx() : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonMaterialChannelEx(dynamic jsonData) : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialChannelEx DeepCopy()
            {
                return (SimplygonMaterialChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.MaterialChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
                Parent.Parent.displayName = ObjectNames.NicifyVariableName("DisplacementCaster") + " - " + value;
            }

        }

        public EColorComponent OpacityChannelComponent { get { return _OpacityChannelComponent; } set { _OpacityChannelComponent = value; OnPropertyChanged(); } }
        private EColorComponent _OpacityChannelComponent;
        public SimplygonOpacityChannelComponentEx OpacityChannelComponentUI { get; set; }
        public class SimplygonOpacityChannelComponentEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.OpacityChannelComponent;
                }

                set
                {
                    bool needReload = Parent.OpacityChannelComponent != value;
                    Parent.OpacityChannelComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonOpacityChannelComponentEx() : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonOpacityChannelComponentEx(dynamic jsonData) : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelComponentEx DeepCopy()
            {
                return (SimplygonOpacityChannelComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OpacityChannelComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public EDitherPatterns DitherType { get { return _DitherType; } set { _DitherType = value; OnPropertyChanged(); } }
        private EDitherPatterns _DitherType;
        public SimplygonDitherTypeEx DitherTypeUI { get; set; }
        public class SimplygonDitherTypeEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public EDitherPatterns Value
            {
                get
                {
                    return Parent.DitherType;
                }

                set
                {
                    bool needReload = Parent.DitherType != value;
                    Parent.DitherType = value;
                    OnPropertyChanged();
                }

            }

            public EDitherPatterns DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDitherPatterns)); } }

            public SimplygonDitherTypeEx() : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                Visible = true;
            }

            public SimplygonDitherTypeEx(dynamic jsonData) : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDitherTypeEx DeepCopy()
            {
                return (SimplygonDitherTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DitherType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDitherPatterns)value;
            }

        }

        public EAtlasFillMode FillMode { get { return _FillMode; } set { _FillMode = value; OnPropertyChanged(); } }
        private EAtlasFillMode _FillMode;
        public SimplygonFillModeEx FillModeUI { get; set; }
        public class SimplygonFillModeEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public EAtlasFillMode Value
            {
                get
                {
                    return Parent.FillMode;
                }

                set
                {
                    bool needReload = Parent.FillMode != value;
                    Parent.FillMode = value;
                    OnPropertyChanged();
                }

            }

            public EAtlasFillMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EAtlasFillMode)); } }

            public SimplygonFillModeEx() : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                Visible = true;
            }

            public SimplygonFillModeEx(dynamic jsonData) : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillModeEx DeepCopy()
            {
                return (SimplygonFillModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.FillMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EAtlasFillMode)value;
            }

        }

        public string OpacityChannel { get { return _OpacityChannel; } set { _OpacityChannel = value; OnPropertyChanged(); } }
        private string _OpacityChannel;
        public SimplygonOpacityChannelEx OpacityChannelUI { get; set; }
        public class SimplygonOpacityChannelEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OpacityChannel;
                }

                set
                {
                    bool needReload = Parent.OpacityChannel != value;
                    Parent.OpacityChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOpacityChannelEx() : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                Visible = true;
            }

            public SimplygonOpacityChannelEx(dynamic jsonData) : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelEx DeepCopy()
            {
                return (SimplygonOpacityChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OpacityChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseMultisampling { get { return _UseMultisampling; } set { _UseMultisampling = value; OnPropertyChanged(); } }
        private bool _UseMultisampling;
        public SimplygonUseMultisamplingEx UseMultisamplingUI { get; set; }
        public class SimplygonUseMultisamplingEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseMultisampling;
                }

                set
                {
                    bool needReload = Parent.UseMultisampling != value;
                    Parent.UseMultisampling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseMultisamplingEx() : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseMultisamplingEx(dynamic jsonData) : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseMultisamplingEx DeepCopy()
            {
                return (SimplygonUseMultisamplingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseMultisampling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public float DistanceScaling { get { return _DistanceScaling; } set { _DistanceScaling = value; OnPropertyChanged(); } }
        private float _DistanceScaling;
        public SimplygonDistanceScalingEx DistanceScalingUI { get; set; }
        public class SimplygonDistanceScalingEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.DistanceScaling;
                }

                set
                {
                    bool needReload = Parent.DistanceScaling != value;
                    Parent.DistanceScaling = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonDistanceScalingEx() : base("DistanceScaling")
            {
                Type = "real";
                HelpText = "All the delta values are divided by this value before storing them into an image.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                MaxValue = 10f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonDistanceScalingEx(dynamic jsonData) : base("DistanceScaling")
            {
                Type = "real";
                HelpText = "All the delta values are divided by this value before storing them into an image.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"DistanceScaling: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"DistanceScaling: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDistanceScalingEx DeepCopy()
            {
                return (SimplygonDistanceScalingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.DistanceScaling;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EImageOutputFormat OutputImageFileFormat { get { return _OutputImageFileFormat; } set { _OutputImageFileFormat = value; OnPropertyChanged(); } }
        private EImageOutputFormat _OutputImageFileFormat;
        public SimplygonOutputImageFileFormatEx OutputImageFileFormatUI { get; set; }
        public class SimplygonOutputImageFileFormatEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public EImageOutputFormat Value
            {
                get
                {
                    return Parent.OutputImageFileFormat;
                }

                set
                {
                    bool needReload = Parent.OutputImageFileFormat != value;
                    Parent.OutputImageFileFormat = value;
                    Parent.OutputDDSCompressionTypeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public EImageOutputFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EImageOutputFormat)); } }

            public SimplygonOutputImageFileFormatEx() : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                Visible = true;
            }

            public SimplygonOutputImageFileFormatEx(dynamic jsonData) : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputImageFileFormatEx DeepCopy()
            {
                return (SimplygonOutputImageFileFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputImageFileFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EImageOutputFormat)value;
            }

        }

        public EDDSCompressionType OutputDDSCompressionType { get { return _OutputDDSCompressionType; } set { _OutputDDSCompressionType = value; OnPropertyChanged(); } }
        private EDDSCompressionType _OutputDDSCompressionType;
        public SimplygonOutputDDSCompressionTypeEx OutputDDSCompressionTypeUI { get; set; }
        public class SimplygonOutputDDSCompressionTypeEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public EDDSCompressionType Value
            {
                get
                {
                    return Parent.OutputDDSCompressionType;
                }

                set
                {
                    bool needReload = Parent.OutputDDSCompressionType != value;
                    Parent.OutputDDSCompressionType = value;
                    OnPropertyChanged();
                }

            }

            public EDDSCompressionType DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.OutputImageFileFormatUI != null ) { return Parent.OutputImageFileFormat == EImageOutputFormat.DDS && Parent.OutputImageFileFormatUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDDSCompressionType)); } }

            public SimplygonOutputDDSCompressionTypeEx() : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                Visible = true;
            }

            public SimplygonOutputDDSCompressionTypeEx(dynamic jsonData) : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputDDSCompressionTypeEx DeepCopy()
            {
                return (SimplygonOutputDDSCompressionTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.OutputImageFileFormatUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputDDSCompressionType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDDSCompressionType)value;
            }

        }

        public int Dilation { get { return _Dilation; } set { _Dilation = value; OnPropertyChanged(); } }
        private int _Dilation;
        public SimplygonDilationEx DilationUI { get; set; }
        public class SimplygonDilationEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.Dilation;
                }

                set
                {
                    bool needReload = Parent.Dilation != value;
                    Parent.Dilation = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonDilationEx() : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 1000;
                DefaultMinValue = 0;
                DefaultMaxValue = 1000;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonDilationEx(dynamic jsonData) : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000;
                DefaultMaxValue = 1000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDilationEx DeepCopy()
            {
                return (SimplygonDilationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.Dilation;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool GenerateScalarDisplacement { get { return _GenerateScalarDisplacement; } set { _GenerateScalarDisplacement = value; OnPropertyChanged(); } }
        private bool _GenerateScalarDisplacement;
        public SimplygonGenerateScalarDisplacementEx GenerateScalarDisplacementUI { get; set; }
        public class SimplygonGenerateScalarDisplacementEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.GenerateScalarDisplacement;
                }

                set
                {
                    bool needReload = Parent.GenerateScalarDisplacement != value;
                    Parent.GenerateScalarDisplacement = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonGenerateScalarDisplacementEx() : base("GenerateScalarDisplacement")
            {
                Type = "bool";
                HelpText = "If set to true, the size of the displacement vector components in the direction of the interpolated normal are stored in the displacement map, instead of the displacement vectors.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonGenerateScalarDisplacementEx(dynamic jsonData) : base("GenerateScalarDisplacement")
            {
                Type = "bool";
                HelpText = "If set to true, the size of the displacement vector components in the direction of the interpolated normal are stored in the displacement map, instead of the displacement vectors.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGenerateScalarDisplacementEx DeepCopy()
            {
                return (SimplygonGenerateScalarDisplacementEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.GenerateScalarDisplacement;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EPixelFormat OutputPixelFormat { get { return _OutputPixelFormat; } set { _OutputPixelFormat = value; OnPropertyChanged(); } }
        private EPixelFormat _OutputPixelFormat;
        public SimplygonOutputPixelFormatEx OutputPixelFormatUI { get; set; }
        public class SimplygonOutputPixelFormatEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public EPixelFormat Value
            {
                get
                {
                    return Parent.OutputPixelFormat;
                }

                set
                {
                    bool needReload = Parent.OutputPixelFormat != value;
                    Parent.OutputPixelFormat = value;
                    OnPropertyChanged();
                }

            }

            public EPixelFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPixelFormat)); } }

            public SimplygonOutputPixelFormatEx() : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                Visible = true;
            }

            public SimplygonOutputPixelFormatEx(dynamic jsonData) : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputPixelFormatEx DeepCopy()
            {
                return (SimplygonOutputPixelFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputPixelFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPixelFormat)value;
            }

        }

        public bool GenerateTangentSpaceDisplacement { get { return _GenerateTangentSpaceDisplacement; } set { _GenerateTangentSpaceDisplacement = value; OnPropertyChanged(); } }
        private bool _GenerateTangentSpaceDisplacement;
        public SimplygonGenerateTangentSpaceDisplacementEx GenerateTangentSpaceDisplacementUI { get; set; }
        public class SimplygonGenerateTangentSpaceDisplacementEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.GenerateTangentSpaceDisplacement;
                }

                set
                {
                    bool needReload = Parent.GenerateTangentSpaceDisplacement != value;
                    Parent.GenerateTangentSpaceDisplacement = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonGenerateTangentSpaceDisplacementEx() : base("GenerateTangentSpaceDisplacement")
            {
                Type = "bool";
                HelpText = "If set, the displacement vectors are transformed into the destination object tangent space.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonGenerateTangentSpaceDisplacementEx(dynamic jsonData) : base("GenerateTangentSpaceDisplacement")
            {
                Type = "bool";
                HelpText = "If set, the displacement vectors are transformed into the destination object tangent space.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGenerateTangentSpaceDisplacementEx DeepCopy()
            {
                return (SimplygonGenerateTangentSpaceDisplacementEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.GenerateTangentSpaceDisplacement;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int NormalMapTexCoordLevel { get { return _NormalMapTexCoordLevel; } set { _NormalMapTexCoordLevel = value; OnPropertyChanged(); } }
        private int _NormalMapTexCoordLevel;
        public SimplygonNormalMapTexCoordLevelEx NormalMapTexCoordLevelUI { get; set; }
        public class SimplygonNormalMapTexCoordLevelEx : SimplygonSettingsProperty
        {
            public SimplygonDisplacementCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.NormalMapTexCoordLevel;
                }

                set
                {
                    bool needReload = Parent.NormalMapTexCoordLevel != value;
                    Parent.NormalMapTexCoordLevel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonNormalMapTexCoordLevelEx() : base("NormalMapTexCoordLevel")
            {
                Type = "rid";
                HelpText = "The texture coordinate level to use for the tangent space displacement vectors.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                MaxValue = 10;
                DefaultMinValue = -1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonNormalMapTexCoordLevelEx(dynamic jsonData) : base("NormalMapTexCoordLevel")
            {
                Type = "rid";
                HelpText = "The texture coordinate level to use for the tangent space displacement vectors.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                DefaultMinValue = -1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"NormalMapTexCoordLevel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"NormalMapTexCoordLevel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonNormalMapTexCoordLevelEx DeepCopy()
            {
                return (SimplygonNormalMapTexCoordLevelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.NormalMapTexCoordLevel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonDisplacementCasterSettings() : base("DisplacementCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx();
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx();
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx();
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx();
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx();
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx();
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx();
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx();
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx();
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx();
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            DistanceScalingUI = new SimplygonDistanceScalingEx();
            DistanceScalingUI.Parent = this;
            DistanceScaling = DistanceScalingUI.DefaultValue;
            Items.Add(DistanceScalingUI);
            GenerateScalarDisplacementUI = new SimplygonGenerateScalarDisplacementEx();
            GenerateScalarDisplacementUI.Parent = this;
            GenerateScalarDisplacement = GenerateScalarDisplacementUI.DefaultValue;
            Items.Add(GenerateScalarDisplacementUI);
            GenerateTangentSpaceDisplacementUI = new SimplygonGenerateTangentSpaceDisplacementEx();
            GenerateTangentSpaceDisplacementUI.Parent = this;
            GenerateTangentSpaceDisplacement = GenerateTangentSpaceDisplacementUI.DefaultValue;
            Items.Add(GenerateTangentSpaceDisplacementUI);
            NormalMapTexCoordLevelUI = new SimplygonNormalMapTexCoordLevelEx();
            NormalMapTexCoordLevelUI.Parent = this;
            NormalMapTexCoordLevel = NormalMapTexCoordLevelUI.DefaultValue;
            Items.Add(NormalMapTexCoordLevelUI);
        }

        public SimplygonDisplacementCasterSettings(dynamic jsonData) : base("DisplacementCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialChannelUI") != null ? jsonData.MaterialChannelUI : null);
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelComponentUI") != null ? jsonData.OpacityChannelComponentUI : null);
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelUI") != null ? jsonData.OpacityChannelUI : null);
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DitherTypeUI") != null ? jsonData.DitherTypeUI : null);
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx(jsonData != null && ((JObject)jsonData).GetValue("FillModeUI") != null ? jsonData.FillModeUI : null);
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx(jsonData != null && ((JObject)jsonData).GetValue("DilationUI") != null ? jsonData.DilationUI : null);
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx(jsonData != null && ((JObject)jsonData).GetValue("UseMultisamplingUI") != null ? jsonData.UseMultisamplingUI : null);
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputPixelFormatUI") != null ? jsonData.OutputPixelFormatUI : null);
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputImageFileFormatUI") != null ? jsonData.OutputImageFileFormatUI : null);
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputDDSCompressionTypeUI") != null ? jsonData.OutputDDSCompressionTypeUI : null);
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            DistanceScalingUI = new SimplygonDistanceScalingEx(jsonData != null && ((JObject)jsonData).GetValue("DistanceScalingUI") != null ? jsonData.DistanceScalingUI : null);
            DistanceScalingUI.Parent = this;
            DistanceScaling = DistanceScalingUI.DefaultValue;
            Items.Add(DistanceScalingUI);
            GenerateScalarDisplacementUI = new SimplygonGenerateScalarDisplacementEx(jsonData != null && ((JObject)jsonData).GetValue("GenerateScalarDisplacementUI") != null ? jsonData.GenerateScalarDisplacementUI : null);
            GenerateScalarDisplacementUI.Parent = this;
            GenerateScalarDisplacement = GenerateScalarDisplacementUI.DefaultValue;
            Items.Add(GenerateScalarDisplacementUI);
            GenerateTangentSpaceDisplacementUI = new SimplygonGenerateTangentSpaceDisplacementEx(jsonData != null && ((JObject)jsonData).GetValue("GenerateTangentSpaceDisplacementUI") != null ? jsonData.GenerateTangentSpaceDisplacementUI : null);
            GenerateTangentSpaceDisplacementUI.Parent = this;
            GenerateTangentSpaceDisplacement = GenerateTangentSpaceDisplacementUI.DefaultValue;
            Items.Add(GenerateTangentSpaceDisplacementUI);
            NormalMapTexCoordLevelUI = new SimplygonNormalMapTexCoordLevelEx(jsonData != null && ((JObject)jsonData).GetValue("NormalMapTexCoordLevelUI") != null ? jsonData.NormalMapTexCoordLevelUI : null);
            NormalMapTexCoordLevelUI.Parent = this;
            NormalMapTexCoordLevel = NormalMapTexCoordLevelUI.DefaultValue;
            Items.Add(NormalMapTexCoordLevelUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonDisplacementCasterSettings();
            copy.Items.Clear();
            copy.MaterialChannelUI = this.MaterialChannelUI.DeepCopy();
            copy.MaterialChannelUI.Parent = copy;
            copy.Items.Add(copy.MaterialChannelUI);
            copy.OpacityChannelComponentUI = this.OpacityChannelComponentUI.DeepCopy();
            copy.OpacityChannelComponentUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelComponentUI);
            copy.OpacityChannelUI = this.OpacityChannelUI.DeepCopy();
            copy.OpacityChannelUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelUI);
            copy.DitherTypeUI = this.DitherTypeUI.DeepCopy();
            copy.DitherTypeUI.Parent = copy;
            copy.Items.Add(copy.DitherTypeUI);
            copy.FillModeUI = this.FillModeUI.DeepCopy();
            copy.FillModeUI.Parent = copy;
            copy.Items.Add(copy.FillModeUI);
            copy.DilationUI = this.DilationUI.DeepCopy();
            copy.DilationUI.Parent = copy;
            copy.Items.Add(copy.DilationUI);
            copy.UseMultisamplingUI = this.UseMultisamplingUI.DeepCopy();
            copy.UseMultisamplingUI.Parent = copy;
            copy.Items.Add(copy.UseMultisamplingUI);
            copy.OutputPixelFormatUI = this.OutputPixelFormatUI.DeepCopy();
            copy.OutputPixelFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputPixelFormatUI);
            copy.OutputImageFileFormatUI = this.OutputImageFileFormatUI.DeepCopy();
            copy.OutputImageFileFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputImageFileFormatUI);
            copy.OutputDDSCompressionTypeUI = this.OutputDDSCompressionTypeUI.DeepCopy();
            copy.OutputDDSCompressionTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputDDSCompressionTypeUI);
            copy.DistanceScalingUI = this.DistanceScalingUI.DeepCopy();
            copy.DistanceScalingUI.Parent = copy;
            copy.Items.Add(copy.DistanceScalingUI);
            copy.GenerateScalarDisplacementUI = this.GenerateScalarDisplacementUI.DeepCopy();
            copy.GenerateScalarDisplacementUI.Parent = copy;
            copy.Items.Add(copy.GenerateScalarDisplacementUI);
            copy.GenerateTangentSpaceDisplacementUI = this.GenerateTangentSpaceDisplacementUI.DeepCopy();
            copy.GenerateTangentSpaceDisplacementUI.Parent = copy;
            copy.Items.Add(copy.GenerateTangentSpaceDisplacementUI);
            copy.NormalMapTexCoordLevelUI = this.NormalMapTexCoordLevelUI.DeepCopy();
            copy.NormalMapTexCoordLevelUI.Parent = copy;
            copy.Items.Add(copy.NormalMapTexCoordLevelUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialChannel = MaterialChannel;
            if(serializeUIComponents)
            {
                jsonData.MaterialChannelUI = MaterialChannelUI.SaveJson();
            }

            jsonData.OpacityChannelComponent = (int)OpacityChannelComponent;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelComponentUI = OpacityChannelComponentUI.SaveJson();
            }

            jsonData.DitherType = (int)DitherType;
            if(serializeUIComponents)
            {
                jsonData.DitherTypeUI = DitherTypeUI.SaveJson();
            }

            jsonData.FillMode = (int)FillMode;
            if(serializeUIComponents)
            {
                jsonData.FillModeUI = FillModeUI.SaveJson();
            }

            jsonData.OpacityChannel = OpacityChannel;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelUI = OpacityChannelUI.SaveJson();
            }

            jsonData.UseMultisampling = UseMultisampling;
            if(serializeUIComponents)
            {
                jsonData.UseMultisamplingUI = UseMultisamplingUI.SaveJson();
            }

            jsonData.DistanceScaling = DistanceScaling;
            if(serializeUIComponents)
            {
                jsonData.DistanceScalingUI = DistanceScalingUI.SaveJson();
            }

            jsonData.OutputImageFileFormat = (int)OutputImageFileFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputImageFileFormatUI = OutputImageFileFormatUI.SaveJson();
            }

            jsonData.OutputDDSCompressionType = (int)OutputDDSCompressionType;
            if(serializeUIComponents)
            {
                jsonData.OutputDDSCompressionTypeUI = OutputDDSCompressionTypeUI.SaveJson();
            }

            jsonData.Dilation = Dilation;
            if(serializeUIComponents)
            {
                jsonData.DilationUI = DilationUI.SaveJson();
            }

            jsonData.GenerateScalarDisplacement = GenerateScalarDisplacement;
            if(serializeUIComponents)
            {
                jsonData.GenerateScalarDisplacementUI = GenerateScalarDisplacementUI.SaveJson();
            }

            jsonData.OutputPixelFormat = (int)OutputPixelFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputPixelFormatUI = OutputPixelFormatUI.SaveJson();
            }

            jsonData.GenerateTangentSpaceDisplacement = GenerateTangentSpaceDisplacement;
            if(serializeUIComponents)
            {
                jsonData.GenerateTangentSpaceDisplacementUI = GenerateTangentSpaceDisplacementUI.SaveJson();
            }

            jsonData.NormalMapTexCoordLevel = NormalMapTexCoordLevel;
            if(serializeUIComponents)
            {
                jsonData.NormalMapTexCoordLevelUI = NormalMapTexCoordLevelUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialChannel") != null)
            {
                MaterialChannel = (string)jsonData.MaterialChannel;
            }

            if(jsonData.GetValue("OpacityChannelComponent") != null)
            {
                OpacityChannelComponent = (EColorComponent)jsonData.OpacityChannelComponent;
            }

            if(jsonData.GetValue("DitherType") != null)
            {
                DitherType = (EDitherPatterns)jsonData.DitherType;
            }

            if(jsonData.GetValue("FillMode") != null)
            {
                FillMode = (EAtlasFillMode)jsonData.FillMode;
            }

            if(jsonData.GetValue("OpacityChannel") != null)
            {
                OpacityChannel = (string)jsonData.OpacityChannel;
            }

            if(jsonData.GetValue("UseMultisampling") != null)
            {
                UseMultisampling = (bool)jsonData.UseMultisampling;
            }

            if(jsonData.GetValue("DistanceScaling") != null)
            {
                float newDistanceScaling = (float)jsonData.DistanceScaling;
                if (newDistanceScaling >= DistanceScalingUI.DefaultMinValue && newDistanceScaling <= DistanceScalingUI.DefaultMaxValue)
                {
                    DistanceScaling = newDistanceScaling;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"DistanceScaling: Invalid value {newDistanceScaling.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DistanceScaling.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputImageFileFormat") != null)
            {
                OutputImageFileFormat = (EImageOutputFormat)jsonData.OutputImageFileFormat;
            }

            if(jsonData.GetValue("OutputDDSCompressionType") != null)
            {
                OutputDDSCompressionType = (EDDSCompressionType)jsonData.OutputDDSCompressionType;
            }

            if(jsonData.GetValue("Dilation") != null)
            {
                var newDilation = (int)jsonData.Dilation;
                if (newDilation >= DilationUI.DefaultMinValue && newDilation <= DilationUI.DefaultMaxValue)
                {
                    Dilation = newDilation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid value {newDilation}, using default value {Dilation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("GenerateScalarDisplacement") != null)
            {
                GenerateScalarDisplacement = (bool)jsonData.GenerateScalarDisplacement;
            }

            if(jsonData.GetValue("OutputPixelFormat") != null)
            {
                OutputPixelFormat = (EPixelFormat)jsonData.OutputPixelFormat;
            }

            if(jsonData.GetValue("GenerateTangentSpaceDisplacement") != null)
            {
                GenerateTangentSpaceDisplacement = (bool)jsonData.GenerateTangentSpaceDisplacement;
            }

            if(jsonData.GetValue("NormalMapTexCoordLevel") != null)
            {
                var newNormalMapTexCoordLevel = (int)jsonData.NormalMapTexCoordLevel;
                if (newNormalMapTexCoordLevel >= NormalMapTexCoordLevelUI.DefaultMinValue && newNormalMapTexCoordLevel <= NormalMapTexCoordLevelUI.DefaultMaxValue)
                {
                    NormalMapTexCoordLevel = newNormalMapTexCoordLevel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"NormalMapTexCoordLevel: Invalid value {newNormalMapTexCoordLevel}, using default value {NormalMapTexCoordLevel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            MaterialChannelUI.Reset();
            OpacityChannelComponentUI.Reset();
            DitherTypeUI.Reset();
            FillModeUI.Reset();
            OpacityChannelUI.Reset();
            UseMultisamplingUI.Reset();
            DistanceScalingUI.Reset();
            OutputImageFileFormatUI.Reset();
            OutputDDSCompressionTypeUI.Reset();
            DilationUI.Reset();
            GenerateScalarDisplacementUI.Reset();
            OutputPixelFormatUI.Reset();
            GenerateTangentSpaceDisplacementUI.Reset();
            NormalMapTexCoordLevelUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialChannelUI.IsEditEnabled = isEditEnabled;
            OpacityChannelComponentUI.IsEditEnabled = isEditEnabled;
            DitherTypeUI.IsEditEnabled = isEditEnabled;
            FillModeUI.IsEditEnabled = isEditEnabled;
            OpacityChannelUI.IsEditEnabled = isEditEnabled;
            UseMultisamplingUI.IsEditEnabled = isEditEnabled;
            DistanceScalingUI.IsEditEnabled = isEditEnabled;
            OutputImageFileFormatUI.IsEditEnabled = isEditEnabled;
            OutputDDSCompressionTypeUI.IsEditEnabled = isEditEnabled;
            DilationUI.IsEditEnabled = isEditEnabled;
            GenerateScalarDisplacementUI.IsEditEnabled = isEditEnabled;
            OutputPixelFormatUI.IsEditEnabled = isEditEnabled;
            GenerateTangentSpaceDisplacementUI.IsEditEnabled = isEditEnabled;
            NormalMapTexCoordLevelUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DistanceScalingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GenerateScalarDisplacementUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GenerateTangentSpaceDisplacementUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            NormalMapTexCoordLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonAmbientOcclusionCasterSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialChannelUI.Visible) return true;
                if(OpacityChannelComponentUI.Visible) return true;
                if(DitherTypeUI.Visible) return true;
                if(FillModeUI.Visible) return true;
                if(OpacityChannelUI.Visible) return true;
                if(UseMultisamplingUI.Visible) return true;
                if(RaysPerPixelUI.Visible) return true;
                if(OutputImageFileFormatUI.Visible) return true;
                if(OutputDDSCompressionTypeUI.Visible) return true;
                if(DilationUI.Visible) return true;
                if(OcclusionFalloffUI.Visible) return true;
                if(OutputPixelFormatUI.Visible) return true;
                if(OcclusionMultiplierUI.Visible) return true;
                if(UseSimpleOcclusionModeUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string MaterialChannel { get { return _MaterialChannel; } set { _MaterialChannel = value; OnPropertyChanged(); } }
        private string _MaterialChannel;
        public SimplygonMaterialChannelEx MaterialChannelUI { get; set; }
        public class SimplygonMaterialChannelEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.MaterialChannel;
                }

                set
                {
                    bool needReload = Parent.MaterialChannel != value;
                    Parent.MaterialChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonMaterialChannelEx() : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonMaterialChannelEx(dynamic jsonData) : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialChannelEx DeepCopy()
            {
                return (SimplygonMaterialChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.MaterialChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
                Parent.Parent.displayName = ObjectNames.NicifyVariableName("AmbientOcclusionCaster") + " - " + value;
            }

        }

        public EColorComponent OpacityChannelComponent { get { return _OpacityChannelComponent; } set { _OpacityChannelComponent = value; OnPropertyChanged(); } }
        private EColorComponent _OpacityChannelComponent;
        public SimplygonOpacityChannelComponentEx OpacityChannelComponentUI { get; set; }
        public class SimplygonOpacityChannelComponentEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.OpacityChannelComponent;
                }

                set
                {
                    bool needReload = Parent.OpacityChannelComponent != value;
                    Parent.OpacityChannelComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonOpacityChannelComponentEx() : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonOpacityChannelComponentEx(dynamic jsonData) : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelComponentEx DeepCopy()
            {
                return (SimplygonOpacityChannelComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OpacityChannelComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public EDitherPatterns DitherType { get { return _DitherType; } set { _DitherType = value; OnPropertyChanged(); } }
        private EDitherPatterns _DitherType;
        public SimplygonDitherTypeEx DitherTypeUI { get; set; }
        public class SimplygonDitherTypeEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public EDitherPatterns Value
            {
                get
                {
                    return Parent.DitherType;
                }

                set
                {
                    bool needReload = Parent.DitherType != value;
                    Parent.DitherType = value;
                    OnPropertyChanged();
                }

            }

            public EDitherPatterns DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDitherPatterns)); } }

            public SimplygonDitherTypeEx() : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                Visible = true;
            }

            public SimplygonDitherTypeEx(dynamic jsonData) : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDitherTypeEx DeepCopy()
            {
                return (SimplygonDitherTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DitherType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDitherPatterns)value;
            }

        }

        public EAtlasFillMode FillMode { get { return _FillMode; } set { _FillMode = value; OnPropertyChanged(); } }
        private EAtlasFillMode _FillMode;
        public SimplygonFillModeEx FillModeUI { get; set; }
        public class SimplygonFillModeEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public EAtlasFillMode Value
            {
                get
                {
                    return Parent.FillMode;
                }

                set
                {
                    bool needReload = Parent.FillMode != value;
                    Parent.FillMode = value;
                    OnPropertyChanged();
                }

            }

            public EAtlasFillMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EAtlasFillMode)); } }

            public SimplygonFillModeEx() : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                Visible = true;
            }

            public SimplygonFillModeEx(dynamic jsonData) : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillModeEx DeepCopy()
            {
                return (SimplygonFillModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.FillMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EAtlasFillMode)value;
            }

        }

        public string OpacityChannel { get { return _OpacityChannel; } set { _OpacityChannel = value; OnPropertyChanged(); } }
        private string _OpacityChannel;
        public SimplygonOpacityChannelEx OpacityChannelUI { get; set; }
        public class SimplygonOpacityChannelEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OpacityChannel;
                }

                set
                {
                    bool needReload = Parent.OpacityChannel != value;
                    Parent.OpacityChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOpacityChannelEx() : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                Visible = true;
            }

            public SimplygonOpacityChannelEx(dynamic jsonData) : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelEx DeepCopy()
            {
                return (SimplygonOpacityChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OpacityChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseMultisampling { get { return _UseMultisampling; } set { _UseMultisampling = value; OnPropertyChanged(); } }
        private bool _UseMultisampling;
        public SimplygonUseMultisamplingEx UseMultisamplingUI { get; set; }
        public class SimplygonUseMultisamplingEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseMultisampling;
                }

                set
                {
                    bool needReload = Parent.UseMultisampling != value;
                    Parent.UseMultisampling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseMultisamplingEx() : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseMultisamplingEx(dynamic jsonData) : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseMultisamplingEx DeepCopy()
            {
                return (SimplygonUseMultisamplingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseMultisampling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int RaysPerPixel { get { return _RaysPerPixel; } set { _RaysPerPixel = value; OnPropertyChanged(); } }
        private int _RaysPerPixel;
        public SimplygonRaysPerPixelEx RaysPerPixelUI { get; set; }
        public class SimplygonRaysPerPixelEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.RaysPerPixel;
                }

                set
                {
                    bool needReload = Parent.RaysPerPixel != value;
                    Parent.RaysPerPixel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonRaysPerPixelEx() : base("RaysPerPixel")
            {
                Type = "uint";
                HelpText = "This determines how many rays are traced per pixel (or subpixel) to evaluate the occlusion.";
                TypeOverride = "";
                DefaultValue = 64;
                MinValue = 0;
                MaxValue = 256;
                DefaultMinValue = 0;
                DefaultMaxValue = 256;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonRaysPerPixelEx(dynamic jsonData) : base("RaysPerPixel")
            {
                Type = "uint";
                HelpText = "This determines how many rays are traced per pixel (or subpixel) to evaluate the occlusion.";
                TypeOverride = "";
                DefaultValue = 64;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RaysPerPixel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 256;
                DefaultMaxValue = 256;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"RaysPerPixel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonRaysPerPixelEx DeepCopy()
            {
                return (SimplygonRaysPerPixelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.RaysPerPixel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EImageOutputFormat OutputImageFileFormat { get { return _OutputImageFileFormat; } set { _OutputImageFileFormat = value; OnPropertyChanged(); } }
        private EImageOutputFormat _OutputImageFileFormat;
        public SimplygonOutputImageFileFormatEx OutputImageFileFormatUI { get; set; }
        public class SimplygonOutputImageFileFormatEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public EImageOutputFormat Value
            {
                get
                {
                    return Parent.OutputImageFileFormat;
                }

                set
                {
                    bool needReload = Parent.OutputImageFileFormat != value;
                    Parent.OutputImageFileFormat = value;
                    Parent.OutputDDSCompressionTypeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public EImageOutputFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EImageOutputFormat)); } }

            public SimplygonOutputImageFileFormatEx() : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                Visible = true;
            }

            public SimplygonOutputImageFileFormatEx(dynamic jsonData) : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputImageFileFormatEx DeepCopy()
            {
                return (SimplygonOutputImageFileFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputImageFileFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EImageOutputFormat)value;
            }

        }

        public EDDSCompressionType OutputDDSCompressionType { get { return _OutputDDSCompressionType; } set { _OutputDDSCompressionType = value; OnPropertyChanged(); } }
        private EDDSCompressionType _OutputDDSCompressionType;
        public SimplygonOutputDDSCompressionTypeEx OutputDDSCompressionTypeUI { get; set; }
        public class SimplygonOutputDDSCompressionTypeEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public EDDSCompressionType Value
            {
                get
                {
                    return Parent.OutputDDSCompressionType;
                }

                set
                {
                    bool needReload = Parent.OutputDDSCompressionType != value;
                    Parent.OutputDDSCompressionType = value;
                    OnPropertyChanged();
                }

            }

            public EDDSCompressionType DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.OutputImageFileFormatUI != null ) { return Parent.OutputImageFileFormat == EImageOutputFormat.DDS && Parent.OutputImageFileFormatUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDDSCompressionType)); } }

            public SimplygonOutputDDSCompressionTypeEx() : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                Visible = true;
            }

            public SimplygonOutputDDSCompressionTypeEx(dynamic jsonData) : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputDDSCompressionTypeEx DeepCopy()
            {
                return (SimplygonOutputDDSCompressionTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.OutputImageFileFormatUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputDDSCompressionType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDDSCompressionType)value;
            }

        }

        public int Dilation { get { return _Dilation; } set { _Dilation = value; OnPropertyChanged(); } }
        private int _Dilation;
        public SimplygonDilationEx DilationUI { get; set; }
        public class SimplygonDilationEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.Dilation;
                }

                set
                {
                    bool needReload = Parent.Dilation != value;
                    Parent.Dilation = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonDilationEx() : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 1000;
                DefaultMinValue = 0;
                DefaultMaxValue = 1000;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonDilationEx(dynamic jsonData) : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000;
                DefaultMaxValue = 1000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDilationEx DeepCopy()
            {
                return (SimplygonDilationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.Dilation;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float OcclusionFalloff { get { return _OcclusionFalloff; } set { _OcclusionFalloff = value; OnPropertyChanged(); } }
        private float _OcclusionFalloff;
        public SimplygonOcclusionFalloffEx OcclusionFalloffUI { get; set; }
        public class SimplygonOcclusionFalloffEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.OcclusionFalloff;
                }

                set
                {
                    bool needReload = Parent.OcclusionFalloff != value;
                    Parent.OcclusionFalloff = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonOcclusionFalloffEx() : base("OcclusionFalloff")
            {
                Type = "real";
                HelpText = "How far away a surface has to be from another surface to generate no occlusion. Only applicable if SimpleOcclusionMode is off.";
                TypeOverride = "";
                DefaultValue = -1f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonOcclusionFalloffEx(dynamic jsonData) : base("OcclusionFalloff")
            {
                Type = "real";
                HelpText = "How far away a surface has to be from another surface to generate no occlusion. Only applicable if SimpleOcclusionMode is off.";
                TypeOverride = "";
                DefaultValue = -1f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OcclusionFalloff: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OcclusionFalloff: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOcclusionFalloffEx DeepCopy()
            {
                return (SimplygonOcclusionFalloffEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.OcclusionFalloff;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EPixelFormat OutputPixelFormat { get { return _OutputPixelFormat; } set { _OutputPixelFormat = value; OnPropertyChanged(); } }
        private EPixelFormat _OutputPixelFormat;
        public SimplygonOutputPixelFormatEx OutputPixelFormatUI { get; set; }
        public class SimplygonOutputPixelFormatEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public EPixelFormat Value
            {
                get
                {
                    return Parent.OutputPixelFormat;
                }

                set
                {
                    bool needReload = Parent.OutputPixelFormat != value;
                    Parent.OutputPixelFormat = value;
                    OnPropertyChanged();
                }

            }

            public EPixelFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPixelFormat)); } }

            public SimplygonOutputPixelFormatEx() : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                Visible = true;
            }

            public SimplygonOutputPixelFormatEx(dynamic jsonData) : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputPixelFormatEx DeepCopy()
            {
                return (SimplygonOutputPixelFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputPixelFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPixelFormat)value;
            }

        }

        public float OcclusionMultiplier { get { return _OcclusionMultiplier; } set { _OcclusionMultiplier = value; OnPropertyChanged(); } }
        private float _OcclusionMultiplier;
        public SimplygonOcclusionMultiplierEx OcclusionMultiplierUI { get; set; }
        public class SimplygonOcclusionMultiplierEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.OcclusionMultiplier;
                }

                set
                {
                    bool needReload = Parent.OcclusionMultiplier != value;
                    Parent.OcclusionMultiplier = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonOcclusionMultiplierEx() : base("OcclusionMultiplier")
            {
                Type = "real";
                HelpText = "This is just a basic intensity scaler. Higher is 'darker'.";
                TypeOverride = "";
                DefaultValue = -1f;
                MinValue = -10f;
                MaxValue = 10f;
                DefaultMinValue = -10f;
                DefaultMaxValue = 10f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonOcclusionMultiplierEx(dynamic jsonData) : base("OcclusionMultiplier")
            {
                Type = "real";
                HelpText = "This is just a basic intensity scaler. Higher is 'darker'.";
                TypeOverride = "";
                DefaultValue = -1f;
                MinValue = -10f;
                DefaultMinValue = -10f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OcclusionMultiplier: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10f;
                DefaultMaxValue = 10f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OcclusionMultiplier: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOcclusionMultiplierEx DeepCopy()
            {
                return (SimplygonOcclusionMultiplierEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.OcclusionMultiplier;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public bool UseSimpleOcclusionMode { get { return _UseSimpleOcclusionMode; } set { _UseSimpleOcclusionMode = value; OnPropertyChanged(); } }
        private bool _UseSimpleOcclusionMode;
        public SimplygonUseSimpleOcclusionModeEx UseSimpleOcclusionModeUI { get; set; }
        public class SimplygonUseSimpleOcclusionModeEx : SimplygonSettingsProperty
        {
            public SimplygonAmbientOcclusionCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseSimpleOcclusionMode;
                }

                set
                {
                    bool needReload = Parent.UseSimpleOcclusionMode != value;
                    Parent.UseSimpleOcclusionMode = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseSimpleOcclusionModeEx() : base("UseSimpleOcclusionMode")
            {
                Type = "bool";
                HelpText = "If set, occlusion will not scale with distance, each ray will only be either fully occluded or not at all. Speeds up processing time.";
                TypeOverride = "";
                DefaultValue = false;
                Visible = true;
            }

            public SimplygonUseSimpleOcclusionModeEx(dynamic jsonData) : base("UseSimpleOcclusionMode")
            {
                Type = "bool";
                HelpText = "If set, occlusion will not scale with distance, each ray will only be either fully occluded or not at all. Speeds up processing time.";
                TypeOverride = "";
                DefaultValue = false;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseSimpleOcclusionModeEx DeepCopy()
            {
                return (SimplygonUseSimpleOcclusionModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseSimpleOcclusionMode;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }


        public SimplygonAmbientOcclusionCasterSettings() : base("AmbientOcclusionCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx();
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx();
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx();
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx();
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx();
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx();
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx();
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx();
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx();
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx();
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            RaysPerPixelUI = new SimplygonRaysPerPixelEx();
            RaysPerPixelUI.Parent = this;
            RaysPerPixel = RaysPerPixelUI.DefaultValue;
            Items.Add(RaysPerPixelUI);
            OcclusionFalloffUI = new SimplygonOcclusionFalloffEx();
            OcclusionFalloffUI.Parent = this;
            OcclusionFalloff = OcclusionFalloffUI.DefaultValue;
            Items.Add(OcclusionFalloffUI);
            OcclusionMultiplierUI = new SimplygonOcclusionMultiplierEx();
            OcclusionMultiplierUI.Parent = this;
            OcclusionMultiplier = OcclusionMultiplierUI.DefaultValue;
            Items.Add(OcclusionMultiplierUI);
            UseSimpleOcclusionModeUI = new SimplygonUseSimpleOcclusionModeEx();
            UseSimpleOcclusionModeUI.Parent = this;
            UseSimpleOcclusionMode = UseSimpleOcclusionModeUI.DefaultValue;
            Items.Add(UseSimpleOcclusionModeUI);
        }

        public SimplygonAmbientOcclusionCasterSettings(dynamic jsonData) : base("AmbientOcclusionCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialChannelUI") != null ? jsonData.MaterialChannelUI : null);
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelComponentUI") != null ? jsonData.OpacityChannelComponentUI : null);
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelUI") != null ? jsonData.OpacityChannelUI : null);
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DitherTypeUI") != null ? jsonData.DitherTypeUI : null);
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx(jsonData != null && ((JObject)jsonData).GetValue("FillModeUI") != null ? jsonData.FillModeUI : null);
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx(jsonData != null && ((JObject)jsonData).GetValue("DilationUI") != null ? jsonData.DilationUI : null);
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx(jsonData != null && ((JObject)jsonData).GetValue("UseMultisamplingUI") != null ? jsonData.UseMultisamplingUI : null);
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputPixelFormatUI") != null ? jsonData.OutputPixelFormatUI : null);
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputImageFileFormatUI") != null ? jsonData.OutputImageFileFormatUI : null);
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputDDSCompressionTypeUI") != null ? jsonData.OutputDDSCompressionTypeUI : null);
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            RaysPerPixelUI = new SimplygonRaysPerPixelEx(jsonData != null && ((JObject)jsonData).GetValue("RaysPerPixelUI") != null ? jsonData.RaysPerPixelUI : null);
            RaysPerPixelUI.Parent = this;
            RaysPerPixel = RaysPerPixelUI.DefaultValue;
            Items.Add(RaysPerPixelUI);
            OcclusionFalloffUI = new SimplygonOcclusionFalloffEx(jsonData != null && ((JObject)jsonData).GetValue("OcclusionFalloffUI") != null ? jsonData.OcclusionFalloffUI : null);
            OcclusionFalloffUI.Parent = this;
            OcclusionFalloff = OcclusionFalloffUI.DefaultValue;
            Items.Add(OcclusionFalloffUI);
            OcclusionMultiplierUI = new SimplygonOcclusionMultiplierEx(jsonData != null && ((JObject)jsonData).GetValue("OcclusionMultiplierUI") != null ? jsonData.OcclusionMultiplierUI : null);
            OcclusionMultiplierUI.Parent = this;
            OcclusionMultiplier = OcclusionMultiplierUI.DefaultValue;
            Items.Add(OcclusionMultiplierUI);
            UseSimpleOcclusionModeUI = new SimplygonUseSimpleOcclusionModeEx(jsonData != null && ((JObject)jsonData).GetValue("UseSimpleOcclusionModeUI") != null ? jsonData.UseSimpleOcclusionModeUI : null);
            UseSimpleOcclusionModeUI.Parent = this;
            UseSimpleOcclusionMode = UseSimpleOcclusionModeUI.DefaultValue;
            Items.Add(UseSimpleOcclusionModeUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonAmbientOcclusionCasterSettings();
            copy.Items.Clear();
            copy.MaterialChannelUI = this.MaterialChannelUI.DeepCopy();
            copy.MaterialChannelUI.Parent = copy;
            copy.Items.Add(copy.MaterialChannelUI);
            copy.OpacityChannelComponentUI = this.OpacityChannelComponentUI.DeepCopy();
            copy.OpacityChannelComponentUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelComponentUI);
            copy.OpacityChannelUI = this.OpacityChannelUI.DeepCopy();
            copy.OpacityChannelUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelUI);
            copy.DitherTypeUI = this.DitherTypeUI.DeepCopy();
            copy.DitherTypeUI.Parent = copy;
            copy.Items.Add(copy.DitherTypeUI);
            copy.FillModeUI = this.FillModeUI.DeepCopy();
            copy.FillModeUI.Parent = copy;
            copy.Items.Add(copy.FillModeUI);
            copy.DilationUI = this.DilationUI.DeepCopy();
            copy.DilationUI.Parent = copy;
            copy.Items.Add(copy.DilationUI);
            copy.UseMultisamplingUI = this.UseMultisamplingUI.DeepCopy();
            copy.UseMultisamplingUI.Parent = copy;
            copy.Items.Add(copy.UseMultisamplingUI);
            copy.OutputPixelFormatUI = this.OutputPixelFormatUI.DeepCopy();
            copy.OutputPixelFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputPixelFormatUI);
            copy.OutputImageFileFormatUI = this.OutputImageFileFormatUI.DeepCopy();
            copy.OutputImageFileFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputImageFileFormatUI);
            copy.OutputDDSCompressionTypeUI = this.OutputDDSCompressionTypeUI.DeepCopy();
            copy.OutputDDSCompressionTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputDDSCompressionTypeUI);
            copy.RaysPerPixelUI = this.RaysPerPixelUI.DeepCopy();
            copy.RaysPerPixelUI.Parent = copy;
            copy.Items.Add(copy.RaysPerPixelUI);
            copy.OcclusionFalloffUI = this.OcclusionFalloffUI.DeepCopy();
            copy.OcclusionFalloffUI.Parent = copy;
            copy.Items.Add(copy.OcclusionFalloffUI);
            copy.OcclusionMultiplierUI = this.OcclusionMultiplierUI.DeepCopy();
            copy.OcclusionMultiplierUI.Parent = copy;
            copy.Items.Add(copy.OcclusionMultiplierUI);
            copy.UseSimpleOcclusionModeUI = this.UseSimpleOcclusionModeUI.DeepCopy();
            copy.UseSimpleOcclusionModeUI.Parent = copy;
            copy.Items.Add(copy.UseSimpleOcclusionModeUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialChannel = MaterialChannel;
            if(serializeUIComponents)
            {
                jsonData.MaterialChannelUI = MaterialChannelUI.SaveJson();
            }

            jsonData.OpacityChannelComponent = (int)OpacityChannelComponent;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelComponentUI = OpacityChannelComponentUI.SaveJson();
            }

            jsonData.DitherType = (int)DitherType;
            if(serializeUIComponents)
            {
                jsonData.DitherTypeUI = DitherTypeUI.SaveJson();
            }

            jsonData.FillMode = (int)FillMode;
            if(serializeUIComponents)
            {
                jsonData.FillModeUI = FillModeUI.SaveJson();
            }

            jsonData.OpacityChannel = OpacityChannel;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelUI = OpacityChannelUI.SaveJson();
            }

            jsonData.UseMultisampling = UseMultisampling;
            if(serializeUIComponents)
            {
                jsonData.UseMultisamplingUI = UseMultisamplingUI.SaveJson();
            }

            jsonData.RaysPerPixel = RaysPerPixel;
            if(serializeUIComponents)
            {
                jsonData.RaysPerPixelUI = RaysPerPixelUI.SaveJson();
            }

            jsonData.OutputImageFileFormat = (int)OutputImageFileFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputImageFileFormatUI = OutputImageFileFormatUI.SaveJson();
            }

            jsonData.OutputDDSCompressionType = (int)OutputDDSCompressionType;
            if(serializeUIComponents)
            {
                jsonData.OutputDDSCompressionTypeUI = OutputDDSCompressionTypeUI.SaveJson();
            }

            jsonData.Dilation = Dilation;
            if(serializeUIComponents)
            {
                jsonData.DilationUI = DilationUI.SaveJson();
            }

            jsonData.OcclusionFalloff = OcclusionFalloff;
            if(serializeUIComponents)
            {
                jsonData.OcclusionFalloffUI = OcclusionFalloffUI.SaveJson();
            }

            jsonData.OutputPixelFormat = (int)OutputPixelFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputPixelFormatUI = OutputPixelFormatUI.SaveJson();
            }

            jsonData.OcclusionMultiplier = OcclusionMultiplier;
            if(serializeUIComponents)
            {
                jsonData.OcclusionMultiplierUI = OcclusionMultiplierUI.SaveJson();
            }

            jsonData.UseSimpleOcclusionMode = UseSimpleOcclusionMode;
            if(serializeUIComponents)
            {
                jsonData.UseSimpleOcclusionModeUI = UseSimpleOcclusionModeUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialChannel") != null)
            {
                MaterialChannel = (string)jsonData.MaterialChannel;
            }

            if(jsonData.GetValue("OpacityChannelComponent") != null)
            {
                OpacityChannelComponent = (EColorComponent)jsonData.OpacityChannelComponent;
            }

            if(jsonData.GetValue("DitherType") != null)
            {
                DitherType = (EDitherPatterns)jsonData.DitherType;
            }

            if(jsonData.GetValue("FillMode") != null)
            {
                FillMode = (EAtlasFillMode)jsonData.FillMode;
            }

            if(jsonData.GetValue("OpacityChannel") != null)
            {
                OpacityChannel = (string)jsonData.OpacityChannel;
            }

            if(jsonData.GetValue("UseMultisampling") != null)
            {
                UseMultisampling = (bool)jsonData.UseMultisampling;
            }

            if(jsonData.GetValue("RaysPerPixel") != null)
            {
                var newRaysPerPixel = (int)jsonData.RaysPerPixel;
                if (newRaysPerPixel >= RaysPerPixelUI.DefaultMinValue && newRaysPerPixel <= RaysPerPixelUI.DefaultMaxValue)
                {
                    RaysPerPixel = newRaysPerPixel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"RaysPerPixel: Invalid value {newRaysPerPixel}, using default value {RaysPerPixel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputImageFileFormat") != null)
            {
                OutputImageFileFormat = (EImageOutputFormat)jsonData.OutputImageFileFormat;
            }

            if(jsonData.GetValue("OutputDDSCompressionType") != null)
            {
                OutputDDSCompressionType = (EDDSCompressionType)jsonData.OutputDDSCompressionType;
            }

            if(jsonData.GetValue("Dilation") != null)
            {
                var newDilation = (int)jsonData.Dilation;
                if (newDilation >= DilationUI.DefaultMinValue && newDilation <= DilationUI.DefaultMaxValue)
                {
                    Dilation = newDilation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid value {newDilation}, using default value {Dilation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OcclusionFalloff") != null)
            {
                float newOcclusionFalloff = (float)jsonData.OcclusionFalloff;
                if (newOcclusionFalloff >= OcclusionFalloffUI.DefaultMinValue && newOcclusionFalloff <= OcclusionFalloffUI.DefaultMaxValue)
                {
                    OcclusionFalloff = newOcclusionFalloff;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OcclusionFalloff: Invalid value {newOcclusionFalloff.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {OcclusionFalloff.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputPixelFormat") != null)
            {
                OutputPixelFormat = (EPixelFormat)jsonData.OutputPixelFormat;
            }

            if(jsonData.GetValue("OcclusionMultiplier") != null)
            {
                float newOcclusionMultiplier = (float)jsonData.OcclusionMultiplier;
                if (newOcclusionMultiplier >= OcclusionMultiplierUI.DefaultMinValue && newOcclusionMultiplier <= OcclusionMultiplierUI.DefaultMaxValue)
                {
                    OcclusionMultiplier = newOcclusionMultiplier;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OcclusionMultiplier: Invalid value {newOcclusionMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {OcclusionMultiplier.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("UseSimpleOcclusionMode") != null)
            {
                UseSimpleOcclusionMode = (bool)jsonData.UseSimpleOcclusionMode;
            }

        }

        public override void Reset()
        {
            MaterialChannelUI.Reset();
            OpacityChannelComponentUI.Reset();
            DitherTypeUI.Reset();
            FillModeUI.Reset();
            OpacityChannelUI.Reset();
            UseMultisamplingUI.Reset();
            RaysPerPixelUI.Reset();
            OutputImageFileFormatUI.Reset();
            OutputDDSCompressionTypeUI.Reset();
            DilationUI.Reset();
            OcclusionFalloffUI.Reset();
            OutputPixelFormatUI.Reset();
            OcclusionMultiplierUI.Reset();
            UseSimpleOcclusionModeUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialChannelUI.IsEditEnabled = isEditEnabled;
            OpacityChannelComponentUI.IsEditEnabled = isEditEnabled;
            DitherTypeUI.IsEditEnabled = isEditEnabled;
            FillModeUI.IsEditEnabled = isEditEnabled;
            OpacityChannelUI.IsEditEnabled = isEditEnabled;
            UseMultisamplingUI.IsEditEnabled = isEditEnabled;
            RaysPerPixelUI.IsEditEnabled = isEditEnabled;
            OutputImageFileFormatUI.IsEditEnabled = isEditEnabled;
            OutputDDSCompressionTypeUI.IsEditEnabled = isEditEnabled;
            DilationUI.IsEditEnabled = isEditEnabled;
            OcclusionFalloffUI.IsEditEnabled = isEditEnabled;
            OutputPixelFormatUI.IsEditEnabled = isEditEnabled;
            OcclusionMultiplierUI.IsEditEnabled = isEditEnabled;
            UseSimpleOcclusionModeUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            RaysPerPixelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OcclusionFalloffUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OcclusionMultiplierUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseSimpleOcclusionModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonGeometryDataCasterSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialChannelUI.Visible) return true;
                if(OpacityChannelComponentUI.Visible) return true;
                if(DitherTypeUI.Visible) return true;
                if(FillModeUI.Visible) return true;
                if(OpacityChannelUI.Visible) return true;
                if(UseMultisamplingUI.Visible) return true;
                if(GeometryDataFieldTypeUI.Visible) return true;
                if(OutputImageFileFormatUI.Visible) return true;
                if(OutputDDSCompressionTypeUI.Visible) return true;
                if(DilationUI.Visible) return true;
                if(GeometryDataFieldIndexUI.Visible) return true;
                if(OutputPixelFormatUI.Visible) return true;
                if(MappingInfRUI.Visible) return true;
                if(MappingSupRUI.Visible) return true;
                if(MappingInfGUI.Visible) return true;
                if(MappingSupGUI.Visible) return true;
                if(MappingInfBUI.Visible) return true;
                if(MappingSupBUI.Visible) return true;
                if(MappingInfAUI.Visible) return true;
                if(MappingSupAUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string MaterialChannel { get { return _MaterialChannel; } set { _MaterialChannel = value; OnPropertyChanged(); } }
        private string _MaterialChannel;
        public SimplygonMaterialChannelEx MaterialChannelUI { get; set; }
        public class SimplygonMaterialChannelEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.MaterialChannel;
                }

                set
                {
                    bool needReload = Parent.MaterialChannel != value;
                    Parent.MaterialChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonMaterialChannelEx() : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonMaterialChannelEx(dynamic jsonData) : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialChannelEx DeepCopy()
            {
                return (SimplygonMaterialChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.MaterialChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
                Parent.Parent.displayName = ObjectNames.NicifyVariableName("GeometryDataCaster") + " - " + value;
            }

        }

        public EColorComponent OpacityChannelComponent { get { return _OpacityChannelComponent; } set { _OpacityChannelComponent = value; OnPropertyChanged(); } }
        private EColorComponent _OpacityChannelComponent;
        public SimplygonOpacityChannelComponentEx OpacityChannelComponentUI { get; set; }
        public class SimplygonOpacityChannelComponentEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.OpacityChannelComponent;
                }

                set
                {
                    bool needReload = Parent.OpacityChannelComponent != value;
                    Parent.OpacityChannelComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonOpacityChannelComponentEx() : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonOpacityChannelComponentEx(dynamic jsonData) : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelComponentEx DeepCopy()
            {
                return (SimplygonOpacityChannelComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OpacityChannelComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public EDitherPatterns DitherType { get { return _DitherType; } set { _DitherType = value; OnPropertyChanged(); } }
        private EDitherPatterns _DitherType;
        public SimplygonDitherTypeEx DitherTypeUI { get; set; }
        public class SimplygonDitherTypeEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public EDitherPatterns Value
            {
                get
                {
                    return Parent.DitherType;
                }

                set
                {
                    bool needReload = Parent.DitherType != value;
                    Parent.DitherType = value;
                    OnPropertyChanged();
                }

            }

            public EDitherPatterns DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDitherPatterns)); } }

            public SimplygonDitherTypeEx() : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                Visible = true;
            }

            public SimplygonDitherTypeEx(dynamic jsonData) : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDitherTypeEx DeepCopy()
            {
                return (SimplygonDitherTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DitherType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDitherPatterns)value;
            }

        }

        public EAtlasFillMode FillMode { get { return _FillMode; } set { _FillMode = value; OnPropertyChanged(); } }
        private EAtlasFillMode _FillMode;
        public SimplygonFillModeEx FillModeUI { get; set; }
        public class SimplygonFillModeEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public EAtlasFillMode Value
            {
                get
                {
                    return Parent.FillMode;
                }

                set
                {
                    bool needReload = Parent.FillMode != value;
                    Parent.FillMode = value;
                    OnPropertyChanged();
                }

            }

            public EAtlasFillMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EAtlasFillMode)); } }

            public SimplygonFillModeEx() : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                Visible = true;
            }

            public SimplygonFillModeEx(dynamic jsonData) : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillModeEx DeepCopy()
            {
                return (SimplygonFillModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.FillMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EAtlasFillMode)value;
            }

        }

        public string OpacityChannel { get { return _OpacityChannel; } set { _OpacityChannel = value; OnPropertyChanged(); } }
        private string _OpacityChannel;
        public SimplygonOpacityChannelEx OpacityChannelUI { get; set; }
        public class SimplygonOpacityChannelEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OpacityChannel;
                }

                set
                {
                    bool needReload = Parent.OpacityChannel != value;
                    Parent.OpacityChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOpacityChannelEx() : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                Visible = true;
            }

            public SimplygonOpacityChannelEx(dynamic jsonData) : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelEx DeepCopy()
            {
                return (SimplygonOpacityChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OpacityChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseMultisampling { get { return _UseMultisampling; } set { _UseMultisampling = value; OnPropertyChanged(); } }
        private bool _UseMultisampling;
        public SimplygonUseMultisamplingEx UseMultisamplingUI { get; set; }
        public class SimplygonUseMultisamplingEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseMultisampling;
                }

                set
                {
                    bool needReload = Parent.UseMultisampling != value;
                    Parent.UseMultisampling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseMultisamplingEx() : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseMultisamplingEx(dynamic jsonData) : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseMultisamplingEx DeepCopy()
            {
                return (SimplygonUseMultisamplingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseMultisampling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EGeometryDataFieldType GeometryDataFieldType { get { return _GeometryDataFieldType; } set { _GeometryDataFieldType = value; OnPropertyChanged(); } }
        private EGeometryDataFieldType _GeometryDataFieldType;
        public SimplygonGeometryDataFieldTypeEx GeometryDataFieldTypeUI { get; set; }
        public class SimplygonGeometryDataFieldTypeEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public EGeometryDataFieldType Value
            {
                get
                {
                    return Parent.GeometryDataFieldType;
                }

                set
                {
                    bool needReload = Parent.GeometryDataFieldType != value;
                    Parent.GeometryDataFieldType = value;
                    OnPropertyChanged();
                }

            }

            public EGeometryDataFieldType DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EGeometryDataFieldType)); } }

            public SimplygonGeometryDataFieldTypeEx() : base("GeometryDataFieldType")
            {
                Type = "enum";
                HelpText = "The GeometryDataFieldType setting, which specifies what field type to cast in the GeometryDataCaster.";
                TypeOverride = "";
                DefaultValue = EGeometryDataFieldType.Coords;
                Visible = true;
            }

            public SimplygonGeometryDataFieldTypeEx(dynamic jsonData) : base("GeometryDataFieldType")
            {
                Type = "enum";
                HelpText = "The GeometryDataFieldType setting, which specifies what field type to cast in the GeometryDataCaster.";
                TypeOverride = "";
                DefaultValue = EGeometryDataFieldType.Coords;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGeometryDataFieldTypeEx DeepCopy()
            {
                return (SimplygonGeometryDataFieldTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.GeometryDataFieldType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EGeometryDataFieldType)value;
            }

        }

        public EImageOutputFormat OutputImageFileFormat { get { return _OutputImageFileFormat; } set { _OutputImageFileFormat = value; OnPropertyChanged(); } }
        private EImageOutputFormat _OutputImageFileFormat;
        public SimplygonOutputImageFileFormatEx OutputImageFileFormatUI { get; set; }
        public class SimplygonOutputImageFileFormatEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public EImageOutputFormat Value
            {
                get
                {
                    return Parent.OutputImageFileFormat;
                }

                set
                {
                    bool needReload = Parent.OutputImageFileFormat != value;
                    Parent.OutputImageFileFormat = value;
                    Parent.OutputDDSCompressionTypeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public EImageOutputFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EImageOutputFormat)); } }

            public SimplygonOutputImageFileFormatEx() : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                Visible = true;
            }

            public SimplygonOutputImageFileFormatEx(dynamic jsonData) : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputImageFileFormatEx DeepCopy()
            {
                return (SimplygonOutputImageFileFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputImageFileFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EImageOutputFormat)value;
            }

        }

        public EDDSCompressionType OutputDDSCompressionType { get { return _OutputDDSCompressionType; } set { _OutputDDSCompressionType = value; OnPropertyChanged(); } }
        private EDDSCompressionType _OutputDDSCompressionType;
        public SimplygonOutputDDSCompressionTypeEx OutputDDSCompressionTypeUI { get; set; }
        public class SimplygonOutputDDSCompressionTypeEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public EDDSCompressionType Value
            {
                get
                {
                    return Parent.OutputDDSCompressionType;
                }

                set
                {
                    bool needReload = Parent.OutputDDSCompressionType != value;
                    Parent.OutputDDSCompressionType = value;
                    OnPropertyChanged();
                }

            }

            public EDDSCompressionType DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.OutputImageFileFormatUI != null ) { return Parent.OutputImageFileFormat == EImageOutputFormat.DDS && Parent.OutputImageFileFormatUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDDSCompressionType)); } }

            public SimplygonOutputDDSCompressionTypeEx() : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                Visible = true;
            }

            public SimplygonOutputDDSCompressionTypeEx(dynamic jsonData) : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputDDSCompressionTypeEx DeepCopy()
            {
                return (SimplygonOutputDDSCompressionTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.OutputImageFileFormatUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputDDSCompressionType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDDSCompressionType)value;
            }

        }

        public int Dilation { get { return _Dilation; } set { _Dilation = value; OnPropertyChanged(); } }
        private int _Dilation;
        public SimplygonDilationEx DilationUI { get; set; }
        public class SimplygonDilationEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.Dilation;
                }

                set
                {
                    bool needReload = Parent.Dilation != value;
                    Parent.Dilation = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonDilationEx() : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 1000;
                DefaultMinValue = 0;
                DefaultMaxValue = 1000;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonDilationEx(dynamic jsonData) : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000;
                DefaultMaxValue = 1000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDilationEx DeepCopy()
            {
                return (SimplygonDilationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.Dilation;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public int GeometryDataFieldIndex { get { return _GeometryDataFieldIndex; } set { _GeometryDataFieldIndex = value; OnPropertyChanged(); } }
        private int _GeometryDataFieldIndex;
        public SimplygonGeometryDataFieldIndexEx GeometryDataFieldIndexUI { get; set; }
        public class SimplygonGeometryDataFieldIndexEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.GeometryDataFieldIndex;
                }

                set
                {
                    bool needReload = Parent.GeometryDataFieldIndex != value;
                    Parent.GeometryDataFieldIndex = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonGeometryDataFieldIndexEx() : base("GeometryDataFieldIndex")
            {
                Type = "uint";
                HelpText = "The GeometryDataFieldIndex setting, which specifies what field index to cast in the GeometryDataCaster, for fields where it is applicable (TexCoords, Tangents, Bitangents and Colors). The setting is ignored for other field types.";
                TypeOverride = "";
                DefaultValue = 0;
                MinValue = 0;
                MaxValue = 10;
                DefaultMinValue = 0;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonGeometryDataFieldIndexEx(dynamic jsonData) : base("GeometryDataFieldIndex")
            {
                Type = "uint";
                HelpText = "The GeometryDataFieldIndex setting, which specifies what field index to cast in the GeometryDataCaster, for fields where it is applicable (TexCoords, Tangents, Bitangents and Colors). The setting is ignored for other field types.";
                TypeOverride = "";
                DefaultValue = 0;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometryDataFieldIndex: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"GeometryDataFieldIndex: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonGeometryDataFieldIndexEx DeepCopy()
            {
                return (SimplygonGeometryDataFieldIndexEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.GeometryDataFieldIndex;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EPixelFormat OutputPixelFormat { get { return _OutputPixelFormat; } set { _OutputPixelFormat = value; OnPropertyChanged(); } }
        private EPixelFormat _OutputPixelFormat;
        public SimplygonOutputPixelFormatEx OutputPixelFormatUI { get; set; }
        public class SimplygonOutputPixelFormatEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public EPixelFormat Value
            {
                get
                {
                    return Parent.OutputPixelFormat;
                }

                set
                {
                    bool needReload = Parent.OutputPixelFormat != value;
                    Parent.OutputPixelFormat = value;
                    OnPropertyChanged();
                }

            }

            public EPixelFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPixelFormat)); } }

            public SimplygonOutputPixelFormatEx() : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                Visible = true;
            }

            public SimplygonOutputPixelFormatEx(dynamic jsonData) : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputPixelFormatEx DeepCopy()
            {
                return (SimplygonOutputPixelFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputPixelFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPixelFormat)value;
            }

        }

        public float MappingInfR { get { return _MappingInfR; } set { _MappingInfR = value; OnPropertyChanged(); } }
        private float _MappingInfR;
        public SimplygonMappingInfREx MappingInfRUI { get; set; }
        public class SimplygonMappingInfREx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingInfR;
                }

                set
                {
                    bool needReload = Parent.MappingInfR != value;
                    Parent.MappingInfR = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingInfREx() : base("MappingInfR")
            {
                Type = "real";
                HelpText = "The inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingInfREx(dynamic jsonData) : base("MappingInfR")
            {
                Type = "real";
                HelpText = "The inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfR: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfR: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingInfREx DeepCopy()
            {
                return (SimplygonMappingInfREx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingInfR;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MappingSupR { get { return _MappingSupR; } set { _MappingSupR = value; OnPropertyChanged(); } }
        private float _MappingSupR;
        public SimplygonMappingSupREx MappingSupRUI { get; set; }
        public class SimplygonMappingSupREx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingSupR;
                }

                set
                {
                    bool needReload = Parent.MappingSupR != value;
                    Parent.MappingSupR = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingSupREx() : base("MappingSupR")
            {
                Type = "real";
                HelpText = "The Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingSupREx(dynamic jsonData) : base("MappingSupR")
            {
                Type = "real";
                HelpText = "The Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupR: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupR: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingSupREx DeepCopy()
            {
                return (SimplygonMappingSupREx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingSupR;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MappingInfG { get { return _MappingInfG; } set { _MappingInfG = value; OnPropertyChanged(); } }
        private float _MappingInfG;
        public SimplygonMappingInfGEx MappingInfGUI { get; set; }
        public class SimplygonMappingInfGEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingInfG;
                }

                set
                {
                    bool needReload = Parent.MappingInfG != value;
                    Parent.MappingInfG = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingInfGEx() : base("MappingInfG")
            {
                Type = "real";
                HelpText = "The inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingInfGEx(dynamic jsonData) : base("MappingInfG")
            {
                Type = "real";
                HelpText = "The inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfG: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfG: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingInfGEx DeepCopy()
            {
                return (SimplygonMappingInfGEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingInfG;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MappingSupG { get { return _MappingSupG; } set { _MappingSupG = value; OnPropertyChanged(); } }
        private float _MappingSupG;
        public SimplygonMappingSupGEx MappingSupGUI { get; set; }
        public class SimplygonMappingSupGEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingSupG;
                }

                set
                {
                    bool needReload = Parent.MappingSupG != value;
                    Parent.MappingSupG = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingSupGEx() : base("MappingSupG")
            {
                Type = "real";
                HelpText = "The Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingSupGEx(dynamic jsonData) : base("MappingSupG")
            {
                Type = "real";
                HelpText = "The Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupG: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupG: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingSupGEx DeepCopy()
            {
                return (SimplygonMappingSupGEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingSupG;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MappingInfB { get { return _MappingInfB; } set { _MappingInfB = value; OnPropertyChanged(); } }
        private float _MappingInfB;
        public SimplygonMappingInfBEx MappingInfBUI { get; set; }
        public class SimplygonMappingInfBEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingInfB;
                }

                set
                {
                    bool needReload = Parent.MappingInfB != value;
                    Parent.MappingInfB = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingInfBEx() : base("MappingInfB")
            {
                Type = "real";
                HelpText = "The inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingInfBEx(dynamic jsonData) : base("MappingInfB")
            {
                Type = "real";
                HelpText = "The inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfB: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfB: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingInfBEx DeepCopy()
            {
                return (SimplygonMappingInfBEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingInfB;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MappingSupB { get { return _MappingSupB; } set { _MappingSupB = value; OnPropertyChanged(); } }
        private float _MappingSupB;
        public SimplygonMappingSupBEx MappingSupBUI { get; set; }
        public class SimplygonMappingSupBEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingSupB;
                }

                set
                {
                    bool needReload = Parent.MappingSupB != value;
                    Parent.MappingSupB = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingSupBEx() : base("MappingSupB")
            {
                Type = "real";
                HelpText = "The Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingSupBEx(dynamic jsonData) : base("MappingSupB")
            {
                Type = "real";
                HelpText = "The Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupB: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupB: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingSupBEx DeepCopy()
            {
                return (SimplygonMappingSupBEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingSupB;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MappingInfA { get { return _MappingInfA; } set { _MappingInfA = value; OnPropertyChanged(); } }
        private float _MappingInfA;
        public SimplygonMappingInfAEx MappingInfAUI { get; set; }
        public class SimplygonMappingInfAEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingInfA;
                }

                set
                {
                    bool needReload = Parent.MappingInfA != value;
                    Parent.MappingInfA = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingInfAEx() : base("MappingInfA")
            {
                Type = "real";
                HelpText = "Property the inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingInfAEx(dynamic jsonData) : base("MappingInfA")
            {
                Type = "real";
                HelpText = "Property the inferior/minimum value of field values to map onto the image data range (0->1). The minimum value will be represented by 0 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 0f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfA: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfA: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingInfAEx DeepCopy()
            {
                return (SimplygonMappingInfAEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingInfA;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public float MappingSupA { get { return _MappingSupA; } set { _MappingSupA = value; OnPropertyChanged(); } }
        private float _MappingSupA;
        public SimplygonMappingSupAEx MappingSupAUI { get; set; }
        public class SimplygonMappingSupAEx : SimplygonSettingsProperty
        {
            public SimplygonGeometryDataCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.MappingSupA;
                }

                set
                {
                    bool needReload = Parent.MappingSupA != value;
                    Parent.MappingSupA = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonMappingSupAEx() : base("MappingSupA")
            {
                Type = "real";
                HelpText = "Property the Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                MaxValue = 1000f;
                DefaultMinValue = -1000f;
                DefaultMaxValue = 1000f;
                TicksFrequencyValue = 0.1f;
                Visible = true;
            }

            public SimplygonMappingSupAEx(dynamic jsonData) : base("MappingSupA")
            {
                Type = "real";
                HelpText = "Property the Superior/maximum value of field values to map onto the image data range (0->1). The maximum value will be represented by 1 in the image. Note that the mapping is only used for real value fields, not id-based fields, which cannot be scaled accurately.";
                TypeOverride = "";
                DefaultValue = 1f;
                MinValue = -1000f;
                DefaultMinValue = -1000f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupA: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000f;
                DefaultMaxValue = 1000f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupA: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.1f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMappingSupAEx DeepCopy()
            {
                return (SimplygonMappingSupAEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.MappingSupA;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonGeometryDataCasterSettings() : base("GeometryDataCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx();
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx();
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx();
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx();
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx();
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx();
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx();
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx();
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx();
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx();
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            GeometryDataFieldTypeUI = new SimplygonGeometryDataFieldTypeEx();
            GeometryDataFieldTypeUI.Parent = this;
            GeometryDataFieldType = GeometryDataFieldTypeUI.DefaultValue;
            Items.Add(GeometryDataFieldTypeUI);
            GeometryDataFieldIndexUI = new SimplygonGeometryDataFieldIndexEx();
            GeometryDataFieldIndexUI.Parent = this;
            GeometryDataFieldIndex = GeometryDataFieldIndexUI.DefaultValue;
            Items.Add(GeometryDataFieldIndexUI);
            MappingInfRUI = new SimplygonMappingInfREx();
            MappingInfRUI.Parent = this;
            MappingInfR = MappingInfRUI.DefaultValue;
            Items.Add(MappingInfRUI);
            MappingSupRUI = new SimplygonMappingSupREx();
            MappingSupRUI.Parent = this;
            MappingSupR = MappingSupRUI.DefaultValue;
            Items.Add(MappingSupRUI);
            MappingInfGUI = new SimplygonMappingInfGEx();
            MappingInfGUI.Parent = this;
            MappingInfG = MappingInfGUI.DefaultValue;
            Items.Add(MappingInfGUI);
            MappingSupGUI = new SimplygonMappingSupGEx();
            MappingSupGUI.Parent = this;
            MappingSupG = MappingSupGUI.DefaultValue;
            Items.Add(MappingSupGUI);
            MappingInfBUI = new SimplygonMappingInfBEx();
            MappingInfBUI.Parent = this;
            MappingInfB = MappingInfBUI.DefaultValue;
            Items.Add(MappingInfBUI);
            MappingSupBUI = new SimplygonMappingSupBEx();
            MappingSupBUI.Parent = this;
            MappingSupB = MappingSupBUI.DefaultValue;
            Items.Add(MappingSupBUI);
            MappingInfAUI = new SimplygonMappingInfAEx();
            MappingInfAUI.Parent = this;
            MappingInfA = MappingInfAUI.DefaultValue;
            Items.Add(MappingInfAUI);
            MappingSupAUI = new SimplygonMappingSupAEx();
            MappingSupAUI.Parent = this;
            MappingSupA = MappingSupAUI.DefaultValue;
            Items.Add(MappingSupAUI);
        }

        public SimplygonGeometryDataCasterSettings(dynamic jsonData) : base("GeometryDataCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialChannelUI") != null ? jsonData.MaterialChannelUI : null);
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelComponentUI") != null ? jsonData.OpacityChannelComponentUI : null);
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelUI") != null ? jsonData.OpacityChannelUI : null);
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DitherTypeUI") != null ? jsonData.DitherTypeUI : null);
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx(jsonData != null && ((JObject)jsonData).GetValue("FillModeUI") != null ? jsonData.FillModeUI : null);
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx(jsonData != null && ((JObject)jsonData).GetValue("DilationUI") != null ? jsonData.DilationUI : null);
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx(jsonData != null && ((JObject)jsonData).GetValue("UseMultisamplingUI") != null ? jsonData.UseMultisamplingUI : null);
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputPixelFormatUI") != null ? jsonData.OutputPixelFormatUI : null);
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputImageFileFormatUI") != null ? jsonData.OutputImageFileFormatUI : null);
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputDDSCompressionTypeUI") != null ? jsonData.OutputDDSCompressionTypeUI : null);
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            GeometryDataFieldTypeUI = new SimplygonGeometryDataFieldTypeEx(jsonData != null && ((JObject)jsonData).GetValue("GeometryDataFieldTypeUI") != null ? jsonData.GeometryDataFieldTypeUI : null);
            GeometryDataFieldTypeUI.Parent = this;
            GeometryDataFieldType = GeometryDataFieldTypeUI.DefaultValue;
            Items.Add(GeometryDataFieldTypeUI);
            GeometryDataFieldIndexUI = new SimplygonGeometryDataFieldIndexEx(jsonData != null && ((JObject)jsonData).GetValue("GeometryDataFieldIndexUI") != null ? jsonData.GeometryDataFieldIndexUI : null);
            GeometryDataFieldIndexUI.Parent = this;
            GeometryDataFieldIndex = GeometryDataFieldIndexUI.DefaultValue;
            Items.Add(GeometryDataFieldIndexUI);
            MappingInfRUI = new SimplygonMappingInfREx(jsonData != null && ((JObject)jsonData).GetValue("MappingInfRUI") != null ? jsonData.MappingInfRUI : null);
            MappingInfRUI.Parent = this;
            MappingInfR = MappingInfRUI.DefaultValue;
            Items.Add(MappingInfRUI);
            MappingSupRUI = new SimplygonMappingSupREx(jsonData != null && ((JObject)jsonData).GetValue("MappingSupRUI") != null ? jsonData.MappingSupRUI : null);
            MappingSupRUI.Parent = this;
            MappingSupR = MappingSupRUI.DefaultValue;
            Items.Add(MappingSupRUI);
            MappingInfGUI = new SimplygonMappingInfGEx(jsonData != null && ((JObject)jsonData).GetValue("MappingInfGUI") != null ? jsonData.MappingInfGUI : null);
            MappingInfGUI.Parent = this;
            MappingInfG = MappingInfGUI.DefaultValue;
            Items.Add(MappingInfGUI);
            MappingSupGUI = new SimplygonMappingSupGEx(jsonData != null && ((JObject)jsonData).GetValue("MappingSupGUI") != null ? jsonData.MappingSupGUI : null);
            MappingSupGUI.Parent = this;
            MappingSupG = MappingSupGUI.DefaultValue;
            Items.Add(MappingSupGUI);
            MappingInfBUI = new SimplygonMappingInfBEx(jsonData != null && ((JObject)jsonData).GetValue("MappingInfBUI") != null ? jsonData.MappingInfBUI : null);
            MappingInfBUI.Parent = this;
            MappingInfB = MappingInfBUI.DefaultValue;
            Items.Add(MappingInfBUI);
            MappingSupBUI = new SimplygonMappingSupBEx(jsonData != null && ((JObject)jsonData).GetValue("MappingSupBUI") != null ? jsonData.MappingSupBUI : null);
            MappingSupBUI.Parent = this;
            MappingSupB = MappingSupBUI.DefaultValue;
            Items.Add(MappingSupBUI);
            MappingInfAUI = new SimplygonMappingInfAEx(jsonData != null && ((JObject)jsonData).GetValue("MappingInfAUI") != null ? jsonData.MappingInfAUI : null);
            MappingInfAUI.Parent = this;
            MappingInfA = MappingInfAUI.DefaultValue;
            Items.Add(MappingInfAUI);
            MappingSupAUI = new SimplygonMappingSupAEx(jsonData != null && ((JObject)jsonData).GetValue("MappingSupAUI") != null ? jsonData.MappingSupAUI : null);
            MappingSupAUI.Parent = this;
            MappingSupA = MappingSupAUI.DefaultValue;
            Items.Add(MappingSupAUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonGeometryDataCasterSettings();
            copy.Items.Clear();
            copy.MaterialChannelUI = this.MaterialChannelUI.DeepCopy();
            copy.MaterialChannelUI.Parent = copy;
            copy.Items.Add(copy.MaterialChannelUI);
            copy.OpacityChannelComponentUI = this.OpacityChannelComponentUI.DeepCopy();
            copy.OpacityChannelComponentUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelComponentUI);
            copy.OpacityChannelUI = this.OpacityChannelUI.DeepCopy();
            copy.OpacityChannelUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelUI);
            copy.DitherTypeUI = this.DitherTypeUI.DeepCopy();
            copy.DitherTypeUI.Parent = copy;
            copy.Items.Add(copy.DitherTypeUI);
            copy.FillModeUI = this.FillModeUI.DeepCopy();
            copy.FillModeUI.Parent = copy;
            copy.Items.Add(copy.FillModeUI);
            copy.DilationUI = this.DilationUI.DeepCopy();
            copy.DilationUI.Parent = copy;
            copy.Items.Add(copy.DilationUI);
            copy.UseMultisamplingUI = this.UseMultisamplingUI.DeepCopy();
            copy.UseMultisamplingUI.Parent = copy;
            copy.Items.Add(copy.UseMultisamplingUI);
            copy.OutputPixelFormatUI = this.OutputPixelFormatUI.DeepCopy();
            copy.OutputPixelFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputPixelFormatUI);
            copy.OutputImageFileFormatUI = this.OutputImageFileFormatUI.DeepCopy();
            copy.OutputImageFileFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputImageFileFormatUI);
            copy.OutputDDSCompressionTypeUI = this.OutputDDSCompressionTypeUI.DeepCopy();
            copy.OutputDDSCompressionTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputDDSCompressionTypeUI);
            copy.GeometryDataFieldTypeUI = this.GeometryDataFieldTypeUI.DeepCopy();
            copy.GeometryDataFieldTypeUI.Parent = copy;
            copy.Items.Add(copy.GeometryDataFieldTypeUI);
            copy.GeometryDataFieldIndexUI = this.GeometryDataFieldIndexUI.DeepCopy();
            copy.GeometryDataFieldIndexUI.Parent = copy;
            copy.Items.Add(copy.GeometryDataFieldIndexUI);
            copy.MappingInfRUI = this.MappingInfRUI.DeepCopy();
            copy.MappingInfRUI.Parent = copy;
            copy.Items.Add(copy.MappingInfRUI);
            copy.MappingSupRUI = this.MappingSupRUI.DeepCopy();
            copy.MappingSupRUI.Parent = copy;
            copy.Items.Add(copy.MappingSupRUI);
            copy.MappingInfGUI = this.MappingInfGUI.DeepCopy();
            copy.MappingInfGUI.Parent = copy;
            copy.Items.Add(copy.MappingInfGUI);
            copy.MappingSupGUI = this.MappingSupGUI.DeepCopy();
            copy.MappingSupGUI.Parent = copy;
            copy.Items.Add(copy.MappingSupGUI);
            copy.MappingInfBUI = this.MappingInfBUI.DeepCopy();
            copy.MappingInfBUI.Parent = copy;
            copy.Items.Add(copy.MappingInfBUI);
            copy.MappingSupBUI = this.MappingSupBUI.DeepCopy();
            copy.MappingSupBUI.Parent = copy;
            copy.Items.Add(copy.MappingSupBUI);
            copy.MappingInfAUI = this.MappingInfAUI.DeepCopy();
            copy.MappingInfAUI.Parent = copy;
            copy.Items.Add(copy.MappingInfAUI);
            copy.MappingSupAUI = this.MappingSupAUI.DeepCopy();
            copy.MappingSupAUI.Parent = copy;
            copy.Items.Add(copy.MappingSupAUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialChannel = MaterialChannel;
            if(serializeUIComponents)
            {
                jsonData.MaterialChannelUI = MaterialChannelUI.SaveJson();
            }

            jsonData.OpacityChannelComponent = (int)OpacityChannelComponent;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelComponentUI = OpacityChannelComponentUI.SaveJson();
            }

            jsonData.DitherType = (int)DitherType;
            if(serializeUIComponents)
            {
                jsonData.DitherTypeUI = DitherTypeUI.SaveJson();
            }

            jsonData.FillMode = (int)FillMode;
            if(serializeUIComponents)
            {
                jsonData.FillModeUI = FillModeUI.SaveJson();
            }

            jsonData.OpacityChannel = OpacityChannel;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelUI = OpacityChannelUI.SaveJson();
            }

            jsonData.UseMultisampling = UseMultisampling;
            if(serializeUIComponents)
            {
                jsonData.UseMultisamplingUI = UseMultisamplingUI.SaveJson();
            }

            jsonData.GeometryDataFieldType = (int)GeometryDataFieldType;
            if(serializeUIComponents)
            {
                jsonData.GeometryDataFieldTypeUI = GeometryDataFieldTypeUI.SaveJson();
            }

            jsonData.OutputImageFileFormat = (int)OutputImageFileFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputImageFileFormatUI = OutputImageFileFormatUI.SaveJson();
            }

            jsonData.OutputDDSCompressionType = (int)OutputDDSCompressionType;
            if(serializeUIComponents)
            {
                jsonData.OutputDDSCompressionTypeUI = OutputDDSCompressionTypeUI.SaveJson();
            }

            jsonData.Dilation = Dilation;
            if(serializeUIComponents)
            {
                jsonData.DilationUI = DilationUI.SaveJson();
            }

            jsonData.GeometryDataFieldIndex = GeometryDataFieldIndex;
            if(serializeUIComponents)
            {
                jsonData.GeometryDataFieldIndexUI = GeometryDataFieldIndexUI.SaveJson();
            }

            jsonData.OutputPixelFormat = (int)OutputPixelFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputPixelFormatUI = OutputPixelFormatUI.SaveJson();
            }

            jsonData.MappingInfR = MappingInfR;
            if(serializeUIComponents)
            {
                jsonData.MappingInfRUI = MappingInfRUI.SaveJson();
            }

            jsonData.MappingSupR = MappingSupR;
            if(serializeUIComponents)
            {
                jsonData.MappingSupRUI = MappingSupRUI.SaveJson();
            }

            jsonData.MappingInfG = MappingInfG;
            if(serializeUIComponents)
            {
                jsonData.MappingInfGUI = MappingInfGUI.SaveJson();
            }

            jsonData.MappingSupG = MappingSupG;
            if(serializeUIComponents)
            {
                jsonData.MappingSupGUI = MappingSupGUI.SaveJson();
            }

            jsonData.MappingInfB = MappingInfB;
            if(serializeUIComponents)
            {
                jsonData.MappingInfBUI = MappingInfBUI.SaveJson();
            }

            jsonData.MappingSupB = MappingSupB;
            if(serializeUIComponents)
            {
                jsonData.MappingSupBUI = MappingSupBUI.SaveJson();
            }

            jsonData.MappingInfA = MappingInfA;
            if(serializeUIComponents)
            {
                jsonData.MappingInfAUI = MappingInfAUI.SaveJson();
            }

            jsonData.MappingSupA = MappingSupA;
            if(serializeUIComponents)
            {
                jsonData.MappingSupAUI = MappingSupAUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialChannel") != null)
            {
                MaterialChannel = (string)jsonData.MaterialChannel;
            }

            if(jsonData.GetValue("OpacityChannelComponent") != null)
            {
                OpacityChannelComponent = (EColorComponent)jsonData.OpacityChannelComponent;
            }

            if(jsonData.GetValue("DitherType") != null)
            {
                DitherType = (EDitherPatterns)jsonData.DitherType;
            }

            if(jsonData.GetValue("FillMode") != null)
            {
                FillMode = (EAtlasFillMode)jsonData.FillMode;
            }

            if(jsonData.GetValue("OpacityChannel") != null)
            {
                OpacityChannel = (string)jsonData.OpacityChannel;
            }

            if(jsonData.GetValue("UseMultisampling") != null)
            {
                UseMultisampling = (bool)jsonData.UseMultisampling;
            }

            if(jsonData.GetValue("GeometryDataFieldType") != null)
            {
                GeometryDataFieldType = (EGeometryDataFieldType)jsonData.GeometryDataFieldType;
            }

            if(jsonData.GetValue("OutputImageFileFormat") != null)
            {
                OutputImageFileFormat = (EImageOutputFormat)jsonData.OutputImageFileFormat;
            }

            if(jsonData.GetValue("OutputDDSCompressionType") != null)
            {
                OutputDDSCompressionType = (EDDSCompressionType)jsonData.OutputDDSCompressionType;
            }

            if(jsonData.GetValue("Dilation") != null)
            {
                var newDilation = (int)jsonData.Dilation;
                if (newDilation >= DilationUI.DefaultMinValue && newDilation <= DilationUI.DefaultMaxValue)
                {
                    Dilation = newDilation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid value {newDilation}, using default value {Dilation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("GeometryDataFieldIndex") != null)
            {
                var newGeometryDataFieldIndex = (int)jsonData.GeometryDataFieldIndex;
                if (newGeometryDataFieldIndex >= GeometryDataFieldIndexUI.DefaultMinValue && newGeometryDataFieldIndex <= GeometryDataFieldIndexUI.DefaultMaxValue)
                {
                    GeometryDataFieldIndex = newGeometryDataFieldIndex;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"GeometryDataFieldIndex: Invalid value {newGeometryDataFieldIndex}, using default value {GeometryDataFieldIndex.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputPixelFormat") != null)
            {
                OutputPixelFormat = (EPixelFormat)jsonData.OutputPixelFormat;
            }

            if(jsonData.GetValue("MappingInfR") != null)
            {
                float newMappingInfR = (float)jsonData.MappingInfR;
                if (newMappingInfR >= MappingInfRUI.DefaultMinValue && newMappingInfR <= MappingInfRUI.DefaultMaxValue)
                {
                    MappingInfR = newMappingInfR;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfR: Invalid value {newMappingInfR.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingInfR.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MappingSupR") != null)
            {
                float newMappingSupR = (float)jsonData.MappingSupR;
                if (newMappingSupR >= MappingSupRUI.DefaultMinValue && newMappingSupR <= MappingSupRUI.DefaultMaxValue)
                {
                    MappingSupR = newMappingSupR;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupR: Invalid value {newMappingSupR.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingSupR.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MappingInfG") != null)
            {
                float newMappingInfG = (float)jsonData.MappingInfG;
                if (newMappingInfG >= MappingInfGUI.DefaultMinValue && newMappingInfG <= MappingInfGUI.DefaultMaxValue)
                {
                    MappingInfG = newMappingInfG;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfG: Invalid value {newMappingInfG.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingInfG.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MappingSupG") != null)
            {
                float newMappingSupG = (float)jsonData.MappingSupG;
                if (newMappingSupG >= MappingSupGUI.DefaultMinValue && newMappingSupG <= MappingSupGUI.DefaultMaxValue)
                {
                    MappingSupG = newMappingSupG;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupG: Invalid value {newMappingSupG.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingSupG.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MappingInfB") != null)
            {
                float newMappingInfB = (float)jsonData.MappingInfB;
                if (newMappingInfB >= MappingInfBUI.DefaultMinValue && newMappingInfB <= MappingInfBUI.DefaultMaxValue)
                {
                    MappingInfB = newMappingInfB;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfB: Invalid value {newMappingInfB.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingInfB.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MappingSupB") != null)
            {
                float newMappingSupB = (float)jsonData.MappingSupB;
                if (newMappingSupB >= MappingSupBUI.DefaultMinValue && newMappingSupB <= MappingSupBUI.DefaultMaxValue)
                {
                    MappingSupB = newMappingSupB;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupB: Invalid value {newMappingSupB.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingSupB.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MappingInfA") != null)
            {
                float newMappingInfA = (float)jsonData.MappingInfA;
                if (newMappingInfA >= MappingInfAUI.DefaultMinValue && newMappingInfA <= MappingInfAUI.DefaultMaxValue)
                {
                    MappingInfA = newMappingInfA;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingInfA: Invalid value {newMappingInfA.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingInfA.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("MappingSupA") != null)
            {
                float newMappingSupA = (float)jsonData.MappingSupA;
                if (newMappingSupA >= MappingSupAUI.DefaultMinValue && newMappingSupA <= MappingSupAUI.DefaultMaxValue)
                {
                    MappingSupA = newMappingSupA;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"MappingSupA: Invalid value {newMappingSupA.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {MappingSupA.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            MaterialChannelUI.Reset();
            OpacityChannelComponentUI.Reset();
            DitherTypeUI.Reset();
            FillModeUI.Reset();
            OpacityChannelUI.Reset();
            UseMultisamplingUI.Reset();
            GeometryDataFieldTypeUI.Reset();
            OutputImageFileFormatUI.Reset();
            OutputDDSCompressionTypeUI.Reset();
            DilationUI.Reset();
            GeometryDataFieldIndexUI.Reset();
            OutputPixelFormatUI.Reset();
            MappingInfRUI.Reset();
            MappingSupRUI.Reset();
            MappingInfGUI.Reset();
            MappingSupGUI.Reset();
            MappingInfBUI.Reset();
            MappingSupBUI.Reset();
            MappingInfAUI.Reset();
            MappingSupAUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialChannelUI.IsEditEnabled = isEditEnabled;
            OpacityChannelComponentUI.IsEditEnabled = isEditEnabled;
            DitherTypeUI.IsEditEnabled = isEditEnabled;
            FillModeUI.IsEditEnabled = isEditEnabled;
            OpacityChannelUI.IsEditEnabled = isEditEnabled;
            UseMultisamplingUI.IsEditEnabled = isEditEnabled;
            GeometryDataFieldTypeUI.IsEditEnabled = isEditEnabled;
            OutputImageFileFormatUI.IsEditEnabled = isEditEnabled;
            OutputDDSCompressionTypeUI.IsEditEnabled = isEditEnabled;
            DilationUI.IsEditEnabled = isEditEnabled;
            GeometryDataFieldIndexUI.IsEditEnabled = isEditEnabled;
            OutputPixelFormatUI.IsEditEnabled = isEditEnabled;
            MappingInfRUI.IsEditEnabled = isEditEnabled;
            MappingSupRUI.IsEditEnabled = isEditEnabled;
            MappingInfGUI.IsEditEnabled = isEditEnabled;
            MappingSupGUI.IsEditEnabled = isEditEnabled;
            MappingInfBUI.IsEditEnabled = isEditEnabled;
            MappingSupBUI.IsEditEnabled = isEditEnabled;
            MappingInfAUI.IsEditEnabled = isEditEnabled;
            MappingSupAUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GeometryDataFieldTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            GeometryDataFieldIndexUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingInfRUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingSupRUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingInfGUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingSupGUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingInfBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingSupBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingInfAUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            MappingSupAUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public class SimplygonVertexColorCasterSettings : SimplygonSettings
    {
        public override bool Visible
        {
            get
            {
                if (!VisibleOverride) return false;
                if (Name == "InputMaterialSettings") return false;
                if(MaterialChannelUI.Visible) return true;
                if(OpacityChannelComponentUI.Visible) return true;
                if(DitherTypeUI.Visible) return true;
                if(FillModeUI.Visible) return true;
                if(OpacityChannelUI.Visible) return true;
                if(UseMultisamplingUI.Visible) return true;
                if(OutputColorLevelUI.Visible) return true;
                if(OutputImageFileFormatUI.Visible) return true;
                if(OutputDDSCompressionTypeUI.Visible) return true;
                if(DilationUI.Visible) return true;
                if(OutputColorNameUI.Visible) return true;
                if(OutputPixelFormatUI.Visible) return true;
                if(ColorSpaceEdgeThresholdUI.Visible) return true;

                return false;
            }

            set
            {
                OnPropertyChanged();
            }

        }

        public SimplygonTreeViewItem Parent { get; set; }
        public string MaterialChannel { get { return _MaterialChannel; } set { _MaterialChannel = value; OnPropertyChanged(); } }
        private string _MaterialChannel;
        public SimplygonMaterialChannelEx MaterialChannelUI { get; set; }
        public class SimplygonMaterialChannelEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.MaterialChannel;
                }

                set
                {
                    bool needReload = Parent.MaterialChannel != value;
                    Parent.MaterialChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonMaterialChannelEx() : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonMaterialChannelEx(dynamic jsonData) : base("MaterialChannel")
            {
                Type = "string";
                HelpText = "The name of the input material channel to cast. Existing user channels of any arbitrary name in the input materials can be cast.";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonMaterialChannelEx DeepCopy()
            {
                return (SimplygonMaterialChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string[] options = { "diffuseColor", "specularColor", "emissiveColor", "metallic", "roughness" };
                GUIContent[] optionContents = { new GUIContent("Albedo", ""), new GUIContent("Specular", ""), new GUIContent("Emission", ""), new GUIContent("Metallic", ""), new GUIContent("Smoothness", "") };
                int index = Array.IndexOf(options, Parent.MaterialChannel);
                index = EditorGUI.Popup(rect, new GUIContent(nameUI, HelpText), index < 0 ? 0 : index, optionContents, EditorStyles.popup);
                Value = options[index];
                Parent.Parent.displayName = ObjectNames.NicifyVariableName("VertexColorCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(Parent.MaterialChannel);
            }

        }

        public EColorComponent OpacityChannelComponent { get { return _OpacityChannelComponent; } set { _OpacityChannelComponent = value; OnPropertyChanged(); } }
        private EColorComponent _OpacityChannelComponent;
        public SimplygonOpacityChannelComponentEx OpacityChannelComponentUI { get; set; }
        public class SimplygonOpacityChannelComponentEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public EColorComponent Value
            {
                get
                {
                    return Parent.OpacityChannelComponent;
                }

                set
                {
                    bool needReload = Parent.OpacityChannelComponent != value;
                    Parent.OpacityChannelComponent = value;
                    OnPropertyChanged();
                }

            }

            public EColorComponent DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EColorComponent)); } }

            public SimplygonOpacityChannelComponentEx() : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                Visible = true;
            }

            public SimplygonOpacityChannelComponentEx(dynamic jsonData) : base("OpacityChannelComponent")
            {
                Type = "enum";
                HelpText = "The component in the opacity channel to use as opacity value.";
                TypeOverride = "";
                DefaultValue = EColorComponent.Red;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelComponentEx DeepCopy()
            {
                return (SimplygonOpacityChannelComponentEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OpacityChannelComponent;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EColorComponent)value;
            }

        }

        public EDitherPatterns DitherType { get { return _DitherType; } set { _DitherType = value; OnPropertyChanged(); } }
        private EDitherPatterns _DitherType;
        public SimplygonDitherTypeEx DitherTypeUI { get; set; }
        public class SimplygonDitherTypeEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public EDitherPatterns Value
            {
                get
                {
                    return Parent.DitherType;
                }

                set
                {
                    bool needReload = Parent.DitherType != value;
                    Parent.DitherType = value;
                    OnPropertyChanged();
                }

            }

            public EDitherPatterns DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDitherPatterns)); } }

            public SimplygonDitherTypeEx() : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                Visible = true;
            }

            public SimplygonDitherTypeEx(dynamic jsonData) : base("DitherType")
            {
                Type = "enum";
                HelpText = "The type of dithering to use when creating the output object.";
                TypeOverride = "";
                DefaultValue = EDitherPatterns.FloydSteinberg;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDitherTypeEx DeepCopy()
            {
                return (SimplygonDitherTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.DitherType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDitherPatterns)value;
            }

        }

        public EAtlasFillMode FillMode { get { return _FillMode; } set { _FillMode = value; OnPropertyChanged(); } }
        private EAtlasFillMode _FillMode;
        public SimplygonFillModeEx FillModeUI { get; set; }
        public class SimplygonFillModeEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public EAtlasFillMode Value
            {
                get
                {
                    return Parent.FillMode;
                }

                set
                {
                    bool needReload = Parent.FillMode != value;
                    Parent.FillMode = value;
                    OnPropertyChanged();
                }

            }

            public EAtlasFillMode DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EAtlasFillMode)); } }

            public SimplygonFillModeEx() : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                Visible = true;
            }

            public SimplygonFillModeEx(dynamic jsonData) : base("FillMode")
            {
                Type = "enum";
                HelpText = "The fill mode determines what to do with the pixels that remain unfilled after both the casting and dilation has been performed. Options are:  None = Do not fill remaining pixels  Interpolate = linearly interpolate the closest samples  NearestNeighbor = use the closest available pixel value without interpolation.";
                TypeOverride = "";
                DefaultValue = EAtlasFillMode.Interpolate;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonFillModeEx DeepCopy()
            {
                return (SimplygonFillModeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.FillMode;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EAtlasFillMode)value;
            }

        }

        public string OpacityChannel { get { return _OpacityChannel; } set { _OpacityChannel = value; OnPropertyChanged(); } }
        private string _OpacityChannel;
        public SimplygonOpacityChannelEx OpacityChannelUI { get; set; }
        public class SimplygonOpacityChannelEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OpacityChannel;
                }

                set
                {
                    bool needReload = Parent.OpacityChannel != value;
                    Parent.OpacityChannel = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOpacityChannelEx() : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                Visible = true;
            }

            public SimplygonOpacityChannelEx(dynamic jsonData) : base("OpacityChannel")
            {
                Type = "string";
                HelpText = "The name of the input opacity channel to use for combining layers in most casters and casting opacity in the opacitycaster. User channels of any arbitrary name can be used. If the caster is run through a Pipeline object, the OpacityChannel set here will also be set as the output materials OpacityChannel property.";
                TypeOverride = "";
                DefaultValue = "Opacity";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOpacityChannelEx DeepCopy()
            {
                return (SimplygonOpacityChannelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OpacityChannel;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public bool UseMultisampling { get { return _UseMultisampling; } set { _UseMultisampling = value; OnPropertyChanged(); } }
        private bool _UseMultisampling;
        public SimplygonUseMultisamplingEx UseMultisamplingUI { get; set; }
        public class SimplygonUseMultisamplingEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public bool Value
            {
                get
                {
                    return Parent.UseMultisampling;
                }

                set
                {
                    bool needReload = Parent.UseMultisampling != value;
                    Parent.UseMultisampling = value;
                    OnPropertyChanged();
                }

            }

            public bool DefaultValue { get; set; }

            public SimplygonUseMultisamplingEx() : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                Visible = true;
            }

            public SimplygonUseMultisamplingEx(dynamic jsonData) : base("UseMultisampling")
            {
                Type = "bool";
                HelpText = "Enable or disable multisampling.";
                TypeOverride = "";
                DefaultValue = true;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonUseMultisamplingEx DeepCopy()
            {
                return (SimplygonUseMultisamplingEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                bool value = Parent.UseMultisampling;
                value = EditorGUI.Toggle(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public int OutputColorLevel { get { return _OutputColorLevel; } set { _OutputColorLevel = value; OnPropertyChanged(); } }
        private int _OutputColorLevel;
        public SimplygonOutputColorLevelEx OutputColorLevelUI { get; set; }
        public class SimplygonOutputColorLevelEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.OutputColorLevel;
                }

                set
                {
                    bool needReload = Parent.OutputColorLevel != value;
                    Parent.OutputColorLevel = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonOutputColorLevelEx() : base("OutputColorLevel")
            {
                Type = "rid";
                HelpText = "The OutputColorLevel index.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                MaxValue = 10;
                DefaultMinValue = -1;
                DefaultMaxValue = 10;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonOutputColorLevelEx(dynamic jsonData) : base("OutputColorLevel")
            {
                Type = "rid";
                HelpText = "The OutputColorLevel index.";
                TypeOverride = "";
                DefaultValue = -1;
                MinValue = -1;
                DefaultMinValue = -1;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OutputColorLevel: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 10;
                DefaultMaxValue = 10;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"OutputColorLevel: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputColorLevelEx DeepCopy()
            {
                return (SimplygonOutputColorLevelEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.OutputColorLevel;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public EImageOutputFormat OutputImageFileFormat { get { return _OutputImageFileFormat; } set { _OutputImageFileFormat = value; OnPropertyChanged(); } }
        private EImageOutputFormat _OutputImageFileFormat;
        public SimplygonOutputImageFileFormatEx OutputImageFileFormatUI { get; set; }
        public class SimplygonOutputImageFileFormatEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public EImageOutputFormat Value
            {
                get
                {
                    return Parent.OutputImageFileFormat;
                }

                set
                {
                    bool needReload = Parent.OutputImageFileFormat != value;
                    Parent.OutputImageFileFormat = value;
                    Parent.OutputDDSCompressionTypeUI.Visible = Visible;
                    OnPropertyChanged();
                    if (TreeView != null && needReload)
                    {
                        TreeView.Reload();
                    }

                }

            }

            public EImageOutputFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EImageOutputFormat)); } }

            public SimplygonOutputImageFileFormatEx() : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                Visible = true;
            }

            public SimplygonOutputImageFileFormatEx(dynamic jsonData) : base("OutputImageFileFormat")
            {
                Type = "enum";
                HelpText = "File format for output texture.";
                TypeOverride = "";
                DefaultValue = EImageOutputFormat.PNG;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputImageFileFormatEx DeepCopy()
            {
                return (SimplygonOutputImageFileFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputImageFileFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EImageOutputFormat)value;
            }

        }

        public EDDSCompressionType OutputDDSCompressionType { get { return _OutputDDSCompressionType; } set { _OutputDDSCompressionType = value; OnPropertyChanged(); } }
        private EDDSCompressionType _OutputDDSCompressionType;
        public SimplygonOutputDDSCompressionTypeEx OutputDDSCompressionTypeUI { get; set; }
        public class SimplygonOutputDDSCompressionTypeEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public EDDSCompressionType Value
            {
                get
                {
                    return Parent.OutputDDSCompressionType;
                }

                set
                {
                    bool needReload = Parent.OutputDDSCompressionType != value;
                    Parent.OutputDDSCompressionType = value;
                    OnPropertyChanged();
                }

            }

            public EDDSCompressionType DefaultValue { get; set; }
            public override bool Visible { get { if( Parent.OutputImageFileFormatUI != null ) { return Parent.OutputImageFileFormat == EImageOutputFormat.DDS && Parent.OutputImageFileFormatUI.Visible; } else { return visible; } } set { OnPropertyChanged(); } }
            public Array EnumValues { get { return Enum.GetValues(typeof(EDDSCompressionType)); } }

            public SimplygonOutputDDSCompressionTypeEx() : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                Visible = true;
            }

            public SimplygonOutputDDSCompressionTypeEx(dynamic jsonData) : base("OutputDDSCompressionType")
            {
                Type = "enum";
                HelpText = "DDS compression if output format is DDS.";
                TypeOverride = "";
                DefaultValue = EDDSCompressionType.NoCompression;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputDDSCompressionTypeEx DeepCopy()
            {
                return (SimplygonOutputDDSCompressionTypeEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if(treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if(!treeViewParentItem.children.Contains(this))
                    {
                        int dependencyIndex = treeViewParentItem.children.IndexOf(Parent.OutputImageFileFormatUI);
                        if(treeViewParentItem.children.Count < dependencyIndex || dependencyIndex == -1)
                        {
                            treeViewParentItem.AddChild(this);
                        }

                        else
                        {
                            treeViewParentItem.children.Insert(dependencyIndex+1, this);
                        }

                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputDDSCompressionType;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EDDSCompressionType)value;
            }

        }

        public int Dilation { get { return _Dilation; } set { _Dilation = value; OnPropertyChanged(); } }
        private int _Dilation;
        public SimplygonDilationEx DilationUI { get; set; }
        public class SimplygonDilationEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public int Value
            {
                get
                {
                    return Parent.Dilation;
                }

                set
                {
                    bool needReload = Parent.Dilation != value;
                    Parent.Dilation = value;
                    OnPropertyChanged();
                }

            }

            public int DefaultValue { get; set; }
            public int MinValue { get; set; }
            public int MaxValue { get; set; }
            public int DefaultMinValue { get; set; }
            public int DefaultMaxValue { get; set; }
            public int TicksFrequencyValue { get; set; }

            public SimplygonDilationEx() : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                MaxValue = 1000;
                DefaultMinValue = 0;
                DefaultMaxValue = 1000;
                TicksFrequencyValue = 1;
                Visible = true;
            }

            public SimplygonDilationEx(dynamic jsonData) : base("Dilation")
            {
                Type = "uint";
                HelpText = "The Dilation value. Where applicable, such as colors and normals, the caster will fill empty pixels surrounding filled pixels with values mixed from the filled ones. This setting sets how many pixels to fill outside the original filled pixels.";
                TypeOverride = "";
                DefaultValue = 10;
                MinValue = 0;
                DefaultMinValue = 0;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (int)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 1000;
                DefaultMaxValue = 1000;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (int)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (int)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 1;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonDilationEx DeepCopy()
            {
                return (SimplygonDilationEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                int value = Parent.Dilation;
                value = EditorGUI.IntSlider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }

        public string OutputColorName { get { return _OutputColorName; } set { _OutputColorName = value; OnPropertyChanged(); } }
        private string _OutputColorName;
        public SimplygonOutputColorNameEx OutputColorNameUI { get; set; }
        public class SimplygonOutputColorNameEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public string Value
            {
                get
                {
                    return Parent.OutputColorName;
                }

                set
                {
                    bool needReload = Parent.OutputColorName != value;
                    Parent.OutputColorName = value;
                    OnPropertyChanged();
                }

            }

            public string DefaultValue { get; set; }

            public SimplygonOutputColorNameEx() : base("OutputColorName")
            {
                Type = "string";
                HelpText = "The OutputColorName string .";
                TypeOverride = "";
                DefaultValue = "";
                Visible = true;
            }

            public SimplygonOutputColorNameEx(dynamic jsonData) : base("OutputColorName")
            {
                Type = "string";
                HelpText = "The OutputColorName string .";
                TypeOverride = "";
                DefaultValue = "";
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputColorNameEx DeepCopy()
            {
                return (SimplygonOutputColorNameEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                string value = Parent.OutputColorName;
                value = EditorGUI.TextField(rect, new GUIContent(nameUI, HelpText), value);
                Value = value;
            }

        }

        public EPixelFormat OutputPixelFormat { get { return _OutputPixelFormat; } set { _OutputPixelFormat = value; OnPropertyChanged(); } }
        private EPixelFormat _OutputPixelFormat;
        public SimplygonOutputPixelFormatEx OutputPixelFormatUI { get; set; }
        public class SimplygonOutputPixelFormatEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public EPixelFormat Value
            {
                get
                {
                    return Parent.OutputPixelFormat;
                }

                set
                {
                    bool needReload = Parent.OutputPixelFormat != value;
                    Parent.OutputPixelFormat = value;
                    OnPropertyChanged();
                }

            }

            public EPixelFormat DefaultValue { get; set; }
            public Array EnumValues { get { return Enum.GetValues(typeof(EPixelFormat)); } }

            public SimplygonOutputPixelFormatEx() : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                Visible = true;
            }

            public SimplygonOutputPixelFormatEx(dynamic jsonData) : base("OutputPixelFormat")
            {
                Type = "enum";
                HelpText = "The output pixel format";
                TypeOverride = "";
                DefaultValue = EPixelFormat.R8G8B8A8;
                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonOutputPixelFormatEx DeepCopy()
            {
                return (SimplygonOutputPixelFormatEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                Enum value = Parent.OutputPixelFormat;
                value = EditorGUI.EnumPopup(rect, new GUIContent(nameUI, HelpText), value);
                Value = (EPixelFormat)value;
            }

        }

        public float ColorSpaceEdgeThreshold { get { return _ColorSpaceEdgeThreshold; } set { _ColorSpaceEdgeThreshold = value; OnPropertyChanged(); } }
        private float _ColorSpaceEdgeThreshold;
        public SimplygonColorSpaceEdgeThresholdEx ColorSpaceEdgeThresholdUI { get; set; }
        public class SimplygonColorSpaceEdgeThresholdEx : SimplygonSettingsProperty
        {
            public SimplygonVertexColorCasterSettings Parent { get; set; }
            public float Value
            {
                get
                {
                    return Parent.ColorSpaceEdgeThreshold;
                }

                set
                {
                    bool needReload = Parent.ColorSpaceEdgeThreshold != value;
                    Parent.ColorSpaceEdgeThreshold = value;
                    OnPropertyChanged();
                }

            }

            public float DefaultValue { get; set; }
            public float MinValue { get; set; }
            public float MaxValue { get; set; }
            public float DefaultMinValue { get; set; }
            public float DefaultMaxValue { get; set; }
            public float TicksFrequencyValue { get; set; }

            public SimplygonColorSpaceEdgeThresholdEx() : base("ColorSpaceEdgeThreshold")
            {
                Type = "real";
                HelpText = "The color space edge threshold, which will define how many hard color borders there will be. Corners more similar than the threshold will be merged. This works similarly to HardEdgeAngle for normals; lower values leads more hard borders between neighboring corner colors, and higher values will give you more shared, smoother, colors. This also impacts data usage when using packed geometry since (more unique colors) == (more vertices). The distance is measured in RGBA space.";
                TypeOverride = "";
                DefaultValue = 2f;
                MinValue = 0f;
                MaxValue = 2f;
                DefaultMinValue = 0f;
                DefaultMaxValue = 2f;
                TicksFrequencyValue = 0.01f;
                Visible = true;
            }

            public SimplygonColorSpaceEdgeThresholdEx(dynamic jsonData) : base("ColorSpaceEdgeThreshold")
            {
                Type = "real";
                HelpText = "The color space edge threshold, which will define how many hard color borders there will be. Corners more similar than the threshold will be merged. This works similarly to HardEdgeAngle for normals; lower values leads more hard borders between neighboring corner colors, and higher values will give you more shared, smoother, colors. This also impacts data usage when using packed geometry since (more unique colors) == (more vertices). The distance is measured in RGBA space.";
                TypeOverride = "";
                DefaultValue = 2f;
                MinValue = 0f;
                DefaultMinValue = 0f;
                if (jsonData != null && jsonData.GetValue("MinValue") != null)
                {
                    var newMinValue = (float)jsonData.MinValue;
                    if (newMinValue >= MinValue)
                    {
                        MinValue = newMinValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ColorSpaceEdgeThreshold: Invalid MinValue {newMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMinValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                MaxValue = 2f;
                DefaultMaxValue = 2f;
                if (jsonData != null && jsonData.GetValue("MaxValue") != null)
                {
                    var newMaxValue = (float)jsonData.MaxValue;
                    if (newMaxValue <= MaxValue)
                    {
                        MaxValue = newMaxValue;
                    }

                    else
                    {
                        SimplygonLogger.Instance.Log(Category.Warning, $"ColorSpaceEdgeThreshold: Invalid MaxValue {newMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {DefaultMaxValue.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                    }

                }

                if (jsonData != null && jsonData.GetValue("TicksFrequencyValue") != null)
                {
                    TicksFrequencyValue = (float)jsonData.TicksFrequencyValue;
                }

                else
                {
                    TicksFrequencyValue = 0.01f;
                }

                if (jsonData != null && jsonData.GetValue("Visible") != null)
                {
                    Visible = Convert.ToBoolean(jsonData.Visible);
                }

                else
                {
                    Visible = true;
                }

            }

            public override void Reset()
            {
                Value = DefaultValue;
            }

            public SimplygonColorSpaceEdgeThresholdEx DeepCopy()
            {
                return (SimplygonColorSpaceEdgeThresholdEx)this.MemberwiseClone();
            }

            public JObject SaveJson()
            {
                dynamic jsonData = new JObject();
                jsonData.Visible = Visible;
                jsonData.MinValue = MinValue;
                jsonData.MaxValue = MaxValue;
                jsonData.TicksFrequencyValue = TicksFrequencyValue;
                return jsonData;
            }

            public TreeView TreeView { get; set; }
            public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
            {
                TreeView = treeView;
                if (!createInvisibleTreeViewItems && !Visible)
                {
                    if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.children.Remove(this);
                    }

                }

                else
                {
                    if (treeViewParentItem.children == null)
                    {
                        treeViewParentItem.AddChild(this);
                    }

                    if (!treeViewParentItem.children.Contains(this))
                    {
                        treeViewParentItem.AddChild(this);
                    }

                }

            }

            public override void ShowUI(Rect rect)
            {
                string nameUI = ObjectNames.NicifyVariableName(Name);
                float value = Parent.ColorSpaceEdgeThreshold;
                value = EditorGUI.Slider(rect, new GUIContent(nameUI, HelpText), value, MinValue, MaxValue);
                Value = value;
            }

        }


        public SimplygonVertexColorCasterSettings() : base("VertexColorCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx();
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx();
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx();
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx();
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx();
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx();
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx();
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx();
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx();
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx();
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            OutputColorLevelUI = new SimplygonOutputColorLevelEx();
            OutputColorLevelUI.Parent = this;
            OutputColorLevel = OutputColorLevelUI.DefaultValue;
            Items.Add(OutputColorLevelUI);
            OutputColorNameUI = new SimplygonOutputColorNameEx();
            OutputColorNameUI.Parent = this;
            OutputColorName = OutputColorNameUI.DefaultValue;
            Items.Add(OutputColorNameUI);
            ColorSpaceEdgeThresholdUI = new SimplygonColorSpaceEdgeThresholdEx();
            ColorSpaceEdgeThresholdUI.Parent = this;
            ColorSpaceEdgeThreshold = ColorSpaceEdgeThresholdUI.DefaultValue;
            Items.Add(ColorSpaceEdgeThresholdUI);
        }

        public SimplygonVertexColorCasterSettings(dynamic jsonData) : base("VertexColorCasterSettings")
        {
            Visible = true;
            MaterialChannelUI = new SimplygonMaterialChannelEx(jsonData != null && ((JObject)jsonData).GetValue("MaterialChannelUI") != null ? jsonData.MaterialChannelUI : null);
            MaterialChannelUI.Parent = this;
            MaterialChannel = MaterialChannelUI.DefaultValue;
            Items.Add(MaterialChannelUI);
            OpacityChannelComponentUI = new SimplygonOpacityChannelComponentEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelComponentUI") != null ? jsonData.OpacityChannelComponentUI : null);
            OpacityChannelComponentUI.Parent = this;
            OpacityChannelComponent = OpacityChannelComponentUI.DefaultValue;
            Items.Add(OpacityChannelComponentUI);
            OpacityChannelUI = new SimplygonOpacityChannelEx(jsonData != null && ((JObject)jsonData).GetValue("OpacityChannelUI") != null ? jsonData.OpacityChannelUI : null);
            OpacityChannelUI.Parent = this;
            OpacityChannel = OpacityChannelUI.DefaultValue;
            Items.Add(OpacityChannelUI);
            DitherTypeUI = new SimplygonDitherTypeEx(jsonData != null && ((JObject)jsonData).GetValue("DitherTypeUI") != null ? jsonData.DitherTypeUI : null);
            DitherTypeUI.Parent = this;
            DitherType = DitherTypeUI.DefaultValue;
            Items.Add(DitherTypeUI);
            FillModeUI = new SimplygonFillModeEx(jsonData != null && ((JObject)jsonData).GetValue("FillModeUI") != null ? jsonData.FillModeUI : null);
            FillModeUI.Parent = this;
            FillMode = FillModeUI.DefaultValue;
            Items.Add(FillModeUI);
            DilationUI = new SimplygonDilationEx(jsonData != null && ((JObject)jsonData).GetValue("DilationUI") != null ? jsonData.DilationUI : null);
            DilationUI.Parent = this;
            Dilation = DilationUI.DefaultValue;
            Items.Add(DilationUI);
            UseMultisamplingUI = new SimplygonUseMultisamplingEx(jsonData != null && ((JObject)jsonData).GetValue("UseMultisamplingUI") != null ? jsonData.UseMultisamplingUI : null);
            UseMultisamplingUI.Parent = this;
            UseMultisampling = UseMultisamplingUI.DefaultValue;
            Items.Add(UseMultisamplingUI);
            OutputPixelFormatUI = new SimplygonOutputPixelFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputPixelFormatUI") != null ? jsonData.OutputPixelFormatUI : null);
            OutputPixelFormatUI.Parent = this;
            OutputPixelFormat = OutputPixelFormatUI.DefaultValue;
            Items.Add(OutputPixelFormatUI);
            OutputImageFileFormatUI = new SimplygonOutputImageFileFormatEx(jsonData != null && ((JObject)jsonData).GetValue("OutputImageFileFormatUI") != null ? jsonData.OutputImageFileFormatUI : null);
            OutputImageFileFormatUI.Parent = this;
            OutputImageFileFormat = OutputImageFileFormatUI.DefaultValue;
            Items.Add(OutputImageFileFormatUI);
            OutputDDSCompressionTypeUI = new SimplygonOutputDDSCompressionTypeEx(jsonData != null && ((JObject)jsonData).GetValue("OutputDDSCompressionTypeUI") != null ? jsonData.OutputDDSCompressionTypeUI : null);
            OutputDDSCompressionTypeUI.Parent = this;
            OutputDDSCompressionType = OutputDDSCompressionTypeUI.DefaultValue;
            Items.Add(OutputDDSCompressionTypeUI);
            OutputColorLevelUI = new SimplygonOutputColorLevelEx(jsonData != null && ((JObject)jsonData).GetValue("OutputColorLevelUI") != null ? jsonData.OutputColorLevelUI : null);
            OutputColorLevelUI.Parent = this;
            OutputColorLevel = OutputColorLevelUI.DefaultValue;
            Items.Add(OutputColorLevelUI);
            OutputColorNameUI = new SimplygonOutputColorNameEx(jsonData != null && ((JObject)jsonData).GetValue("OutputColorNameUI") != null ? jsonData.OutputColorNameUI : null);
            OutputColorNameUI.Parent = this;
            OutputColorName = OutputColorNameUI.DefaultValue;
            Items.Add(OutputColorNameUI);
            ColorSpaceEdgeThresholdUI = new SimplygonColorSpaceEdgeThresholdEx(jsonData != null && ((JObject)jsonData).GetValue("ColorSpaceEdgeThresholdUI") != null ? jsonData.ColorSpaceEdgeThresholdUI : null);
            ColorSpaceEdgeThresholdUI.Parent = this;
            ColorSpaceEdgeThreshold = ColorSpaceEdgeThresholdUI.DefaultValue;
            Items.Add(ColorSpaceEdgeThresholdUI);
            LoadJson(jsonData);
        }

        public override SimplygonSettings DeepCopy()
        {
            var copy = new SimplygonVertexColorCasterSettings();
            copy.Items.Clear();
            copy.MaterialChannelUI = this.MaterialChannelUI.DeepCopy();
            copy.MaterialChannelUI.Parent = copy;
            copy.Items.Add(copy.MaterialChannelUI);
            copy.OpacityChannelComponentUI = this.OpacityChannelComponentUI.DeepCopy();
            copy.OpacityChannelComponentUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelComponentUI);
            copy.OpacityChannelUI = this.OpacityChannelUI.DeepCopy();
            copy.OpacityChannelUI.Parent = copy;
            copy.Items.Add(copy.OpacityChannelUI);
            copy.DitherTypeUI = this.DitherTypeUI.DeepCopy();
            copy.DitherTypeUI.Parent = copy;
            copy.Items.Add(copy.DitherTypeUI);
            copy.FillModeUI = this.FillModeUI.DeepCopy();
            copy.FillModeUI.Parent = copy;
            copy.Items.Add(copy.FillModeUI);
            copy.DilationUI = this.DilationUI.DeepCopy();
            copy.DilationUI.Parent = copy;
            copy.Items.Add(copy.DilationUI);
            copy.UseMultisamplingUI = this.UseMultisamplingUI.DeepCopy();
            copy.UseMultisamplingUI.Parent = copy;
            copy.Items.Add(copy.UseMultisamplingUI);
            copy.OutputPixelFormatUI = this.OutputPixelFormatUI.DeepCopy();
            copy.OutputPixelFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputPixelFormatUI);
            copy.OutputImageFileFormatUI = this.OutputImageFileFormatUI.DeepCopy();
            copy.OutputImageFileFormatUI.Parent = copy;
            copy.Items.Add(copy.OutputImageFileFormatUI);
            copy.OutputDDSCompressionTypeUI = this.OutputDDSCompressionTypeUI.DeepCopy();
            copy.OutputDDSCompressionTypeUI.Parent = copy;
            copy.Items.Add(copy.OutputDDSCompressionTypeUI);
            copy.OutputColorLevelUI = this.OutputColorLevelUI.DeepCopy();
            copy.OutputColorLevelUI.Parent = copy;
            copy.Items.Add(copy.OutputColorLevelUI);
            copy.OutputColorNameUI = this.OutputColorNameUI.DeepCopy();
            copy.OutputColorNameUI.Parent = copy;
            copy.Items.Add(copy.OutputColorNameUI);
            copy.ColorSpaceEdgeThresholdUI = this.ColorSpaceEdgeThresholdUI.DeepCopy();
            copy.ColorSpaceEdgeThresholdUI.Parent = copy;
            copy.Items.Add(copy.ColorSpaceEdgeThresholdUI);
            return copy;
        }

        public override JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.MaterialChannel = MaterialChannel;
            if(serializeUIComponents)
            {
                jsonData.MaterialChannelUI = MaterialChannelUI.SaveJson();
            }

            jsonData.OpacityChannelComponent = (int)OpacityChannelComponent;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelComponentUI = OpacityChannelComponentUI.SaveJson();
            }

            jsonData.DitherType = (int)DitherType;
            if(serializeUIComponents)
            {
                jsonData.DitherTypeUI = DitherTypeUI.SaveJson();
            }

            jsonData.FillMode = (int)FillMode;
            if(serializeUIComponents)
            {
                jsonData.FillModeUI = FillModeUI.SaveJson();
            }

            jsonData.OpacityChannel = OpacityChannel;
            if(serializeUIComponents)
            {
                jsonData.OpacityChannelUI = OpacityChannelUI.SaveJson();
            }

            jsonData.UseMultisampling = UseMultisampling;
            if(serializeUIComponents)
            {
                jsonData.UseMultisamplingUI = UseMultisamplingUI.SaveJson();
            }

            jsonData.OutputColorLevel = OutputColorLevel;
            if(serializeUIComponents)
            {
                jsonData.OutputColorLevelUI = OutputColorLevelUI.SaveJson();
            }

            jsonData.OutputImageFileFormat = (int)OutputImageFileFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputImageFileFormatUI = OutputImageFileFormatUI.SaveJson();
            }

            jsonData.OutputDDSCompressionType = (int)OutputDDSCompressionType;
            if(serializeUIComponents)
            {
                jsonData.OutputDDSCompressionTypeUI = OutputDDSCompressionTypeUI.SaveJson();
            }

            jsonData.Dilation = Dilation;
            if(serializeUIComponents)
            {
                jsonData.DilationUI = DilationUI.SaveJson();
            }

            jsonData.OutputColorName = OutputColorName;
            if(serializeUIComponents)
            {
                jsonData.OutputColorNameUI = OutputColorNameUI.SaveJson();
            }

            jsonData.OutputPixelFormat = (int)OutputPixelFormat;
            if(serializeUIComponents)
            {
                jsonData.OutputPixelFormatUI = OutputPixelFormatUI.SaveJson();
            }

            jsonData.ColorSpaceEdgeThreshold = ColorSpaceEdgeThreshold;
            if(serializeUIComponents)
            {
                jsonData.ColorSpaceEdgeThresholdUI = ColorSpaceEdgeThresholdUI.SaveJson();
            }

            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("MaterialChannel") != null)
            {
                MaterialChannel = (string)jsonData.MaterialChannel;
            }

            if(jsonData.GetValue("OpacityChannelComponent") != null)
            {
                OpacityChannelComponent = (EColorComponent)jsonData.OpacityChannelComponent;
            }

            if(jsonData.GetValue("DitherType") != null)
            {
                DitherType = (EDitherPatterns)jsonData.DitherType;
            }

            if(jsonData.GetValue("FillMode") != null)
            {
                FillMode = (EAtlasFillMode)jsonData.FillMode;
            }

            if(jsonData.GetValue("OpacityChannel") != null)
            {
                OpacityChannel = (string)jsonData.OpacityChannel;
            }

            if(jsonData.GetValue("UseMultisampling") != null)
            {
                UseMultisampling = (bool)jsonData.UseMultisampling;
            }

            if(jsonData.GetValue("OutputColorLevel") != null)
            {
                var newOutputColorLevel = (int)jsonData.OutputColorLevel;
                if (newOutputColorLevel >= OutputColorLevelUI.DefaultMinValue && newOutputColorLevel <= OutputColorLevelUI.DefaultMaxValue)
                {
                    OutputColorLevel = newOutputColorLevel;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"OutputColorLevel: Invalid value {newOutputColorLevel}, using default value {OutputColorLevel.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputImageFileFormat") != null)
            {
                OutputImageFileFormat = (EImageOutputFormat)jsonData.OutputImageFileFormat;
            }

            if(jsonData.GetValue("OutputDDSCompressionType") != null)
            {
                OutputDDSCompressionType = (EDDSCompressionType)jsonData.OutputDDSCompressionType;
            }

            if(jsonData.GetValue("Dilation") != null)
            {
                var newDilation = (int)jsonData.Dilation;
                if (newDilation >= DilationUI.DefaultMinValue && newDilation <= DilationUI.DefaultMaxValue)
                {
                    Dilation = newDilation;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"Dilation: Invalid value {newDilation}, using default value {Dilation.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

            if(jsonData.GetValue("OutputColorName") != null)
            {
                OutputColorName = (string)jsonData.OutputColorName;
            }

            if(jsonData.GetValue("OutputPixelFormat") != null)
            {
                OutputPixelFormat = (EPixelFormat)jsonData.OutputPixelFormat;
            }

            if(jsonData.GetValue("ColorSpaceEdgeThreshold") != null)
            {
                float newColorSpaceEdgeThreshold = (float)jsonData.ColorSpaceEdgeThreshold;
                if (newColorSpaceEdgeThreshold >= ColorSpaceEdgeThresholdUI.DefaultMinValue && newColorSpaceEdgeThreshold <= ColorSpaceEdgeThresholdUI.DefaultMaxValue)
                {
                    ColorSpaceEdgeThreshold = newColorSpaceEdgeThreshold;
                }

                else
                {
                    SimplygonLogger.Instance.Log(Category.Warning, $"ColorSpaceEdgeThreshold: Invalid value {newColorSpaceEdgeThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}, using default value {ColorSpaceEdgeThreshold.ToString(System.Globalization.CultureInfo.InvariantCulture)}");
                }

            }

        }

        public override void Reset()
        {
            MaterialChannelUI.Reset();
            OpacityChannelComponentUI.Reset();
            DitherTypeUI.Reset();
            FillModeUI.Reset();
            OpacityChannelUI.Reset();
            UseMultisamplingUI.Reset();
            OutputColorLevelUI.Reset();
            OutputImageFileFormatUI.Reset();
            OutputDDSCompressionTypeUI.Reset();
            DilationUI.Reset();
            OutputColorNameUI.Reset();
            OutputPixelFormatUI.Reset();
            ColorSpaceEdgeThresholdUI.Reset();
        }

        public override void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            MaterialChannelUI.IsEditEnabled = isEditEnabled;
            OpacityChannelComponentUI.IsEditEnabled = isEditEnabled;
            DitherTypeUI.IsEditEnabled = isEditEnabled;
            FillModeUI.IsEditEnabled = isEditEnabled;
            OpacityChannelUI.IsEditEnabled = isEditEnabled;
            UseMultisamplingUI.IsEditEnabled = isEditEnabled;
            OutputColorLevelUI.IsEditEnabled = isEditEnabled;
            OutputImageFileFormatUI.IsEditEnabled = isEditEnabled;
            OutputDDSCompressionTypeUI.IsEditEnabled = isEditEnabled;
            DilationUI.IsEditEnabled = isEditEnabled;
            OutputColorNameUI.IsEditEnabled = isEditEnabled;
            OutputPixelFormatUI.IsEditEnabled = isEditEnabled;
            ColorSpaceEdgeThresholdUI.IsEditEnabled = isEditEnabled;
        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputColorLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            OutputColorNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            ColorSpaceEdgeThresholdUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            if (this.hasChildren && (createInvisibleTreeViewItems || Visible))
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public enum ESimplygonMaterialCaster
    {
        ColorCaster,
        OpacityCaster,
        NormalCaster,
        DisplacementCaster,
        AmbientOcclusionCaster,
        GeometryDataCaster,
        VertexColorCaster,
    }

    public partial class SimplygonMaterialCaster : SimplygonSettings
    {
        public ESimplygonPipeline PipelineType { get; set; }
        public ESimplygonMaterialCaster MaterialCasterType { get; set; }
        public string MenuPath { get; set; }
        public string FilePath { get; set; }
        public SimplygonSettings Settings { get; set; }
        public string MaterialCasterName { get { return MaterialCasterType.ToString(); } }
        public string MaterialChannelName
        {
            get
            {
                if (MaterialCasterType == ESimplygonMaterialCaster.ColorCaster)
                {
                    return ColorCasterSettings.MaterialChannel;
                }

                if (MaterialCasterType == ESimplygonMaterialCaster.OpacityCaster)
                {
                    return OpacityCasterSettings.MaterialChannel;
                }

                if (MaterialCasterType == ESimplygonMaterialCaster.NormalCaster)
                {
                    return NormalCasterSettings.MaterialChannel;
                }

                if (MaterialCasterType == ESimplygonMaterialCaster.DisplacementCaster)
                {
                    return DisplacementCasterSettings.MaterialChannel;
                }

                if (MaterialCasterType == ESimplygonMaterialCaster.AmbientOcclusionCaster)
                {
                    return AmbientOcclusionCasterSettings.MaterialChannel;
                }

                if (MaterialCasterType == ESimplygonMaterialCaster.GeometryDataCaster)
                {
                    return GeometryDataCasterSettings.MaterialChannel;
                }

                if (MaterialCasterType == ESimplygonMaterialCaster.VertexColorCaster)
                {
                    return VertexColorCasterSettings.MaterialChannel;
                }

                return string.Empty;
            }

        }

        public SimplygonColorCasterSettings ColorCasterSettings { get; set; }
        public SimplygonOpacityCasterSettings OpacityCasterSettings { get; set; }
        public SimplygonNormalCasterSettings NormalCasterSettings { get; set; }
        public SimplygonDisplacementCasterSettings DisplacementCasterSettings { get; set; }
        public SimplygonAmbientOcclusionCasterSettings AmbientOcclusionCasterSettings { get; set; }
        public SimplygonGeometryDataCasterSettings GeometryDataCasterSettings { get; set; }
        public SimplygonVertexColorCasterSettings VertexColorCasterSettings { get; set; }

        public SimplygonMaterialCaster(ESimplygonPipeline pipelineType, ESimplygonMaterialCaster materialCasterType, string materialChannelName, string menuPath, bool allowMaterialChannelOverride = true) : base("")
        {
            PipelineType = pipelineType;
            MenuPath = menuPath;
            Visible = true;
            MaterialCasterType = materialCasterType;

            if (MaterialCasterType == ESimplygonMaterialCaster.ColorCaster)
            {
                ColorCasterSettings = new SimplygonColorCasterSettings();
                ColorCasterSettings.MaterialChannel = materialChannelName;
                ColorCasterSettings.Parent = this;
                Settings = ColorCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("ColorCaster") + " - " +  SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(ColorCasterSettings.MaterialChannel);;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.OpacityCaster)
            {
                OpacityCasterSettings = new SimplygonOpacityCasterSettings();
                OpacityCasterSettings.MaterialChannel = materialChannelName;
                OpacityCasterSettings.Parent = this;
                Settings = OpacityCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("OpacityCaster") + " - " +  SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(OpacityCasterSettings.MaterialChannel);;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.NormalCaster)
            {
                NormalCasterSettings = new SimplygonNormalCasterSettings();
                NormalCasterSettings.MaterialChannel = materialChannelName;
                NormalCasterSettings.Parent = this;
                Settings = NormalCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("NormalCaster") + " - " +  SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(NormalCasterSettings.MaterialChannel);;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.DisplacementCaster)
            {
                DisplacementCasterSettings = new SimplygonDisplacementCasterSettings();
                DisplacementCasterSettings.MaterialChannel = materialChannelName;
                DisplacementCasterSettings.Parent = this;
                Settings = DisplacementCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("DisplacementCaster") + " - " +  SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(DisplacementCasterSettings.MaterialChannel);;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.AmbientOcclusionCaster)
            {
                AmbientOcclusionCasterSettings = new SimplygonAmbientOcclusionCasterSettings();
                AmbientOcclusionCasterSettings.MaterialChannel = materialChannelName;
                AmbientOcclusionCasterSettings.Parent = this;
                Settings = AmbientOcclusionCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("AmbientOcclusionCaster") + " - " +  SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(AmbientOcclusionCasterSettings.MaterialChannel);;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.GeometryDataCaster)
            {
                GeometryDataCasterSettings = new SimplygonGeometryDataCasterSettings();
                GeometryDataCasterSettings.MaterialChannel = materialChannelName;
                GeometryDataCasterSettings.Parent = this;
                Settings = GeometryDataCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("GeometryDataCaster") + " - " +  SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(GeometryDataCasterSettings.MaterialChannel);;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.VertexColorCaster)
            {
                VertexColorCasterSettings = new SimplygonVertexColorCasterSettings();
                VertexColorCasterSettings.MaterialChannel = materialChannelName;
                VertexColorCasterSettings.Parent = this;
                Settings = VertexColorCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("VertexColorCaster") + " - " +  SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(VertexColorCasterSettings.MaterialChannel);;
            }

            SetTemplateOverrides(allowMaterialChannelOverride);
        }

        public SimplygonMaterialCaster(ESimplygonPipeline pipelineType, dynamic jsonData) : base("")
        {
            PipelineType = pipelineType;
            Visible = true;

            LoadJson(jsonData);

            if (MaterialCasterType == ESimplygonMaterialCaster.ColorCaster)
            {
                ColorCasterSettings = new SimplygonColorCasterSettings(jsonData.ColorCasterSettings);
                ColorCasterSettings.Parent = this;
                Settings = ColorCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("ColorCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(ColorCasterSettings.MaterialChannel);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.OpacityCaster)
            {
                OpacityCasterSettings = new SimplygonOpacityCasterSettings(jsonData.OpacityCasterSettings);
                OpacityCasterSettings.Parent = this;
                Settings = OpacityCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("OpacityCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(OpacityCasterSettings.MaterialChannel);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.NormalCaster)
            {
                NormalCasterSettings = new SimplygonNormalCasterSettings(jsonData.NormalCasterSettings);
                NormalCasterSettings.Parent = this;
                Settings = NormalCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("NormalCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(NormalCasterSettings.MaterialChannel);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.DisplacementCaster)
            {
                DisplacementCasterSettings = new SimplygonDisplacementCasterSettings(jsonData.DisplacementCasterSettings);
                DisplacementCasterSettings.Parent = this;
                Settings = DisplacementCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("DisplacementCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(DisplacementCasterSettings.MaterialChannel);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.AmbientOcclusionCaster)
            {
                AmbientOcclusionCasterSettings = new SimplygonAmbientOcclusionCasterSettings(jsonData.AmbientOcclusionCasterSettings);
                AmbientOcclusionCasterSettings.Parent = this;
                Settings = AmbientOcclusionCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("AmbientOcclusionCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(AmbientOcclusionCasterSettings.MaterialChannel);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.GeometryDataCaster)
            {
                GeometryDataCasterSettings = new SimplygonGeometryDataCasterSettings(jsonData.GeometryDataCasterSettings);
                GeometryDataCasterSettings.Parent = this;
                Settings = GeometryDataCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("GeometryDataCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(GeometryDataCasterSettings.MaterialChannel);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.VertexColorCaster)
            {
                VertexColorCasterSettings = new SimplygonVertexColorCasterSettings(jsonData.VertexColorCasterSettings);
                VertexColorCasterSettings.Parent = this;
                Settings = VertexColorCasterSettings;
                Items.Add(Settings);
                displayName = ObjectNames.NicifyVariableName("VertexColorCaster") + " - " + SimplygonMaterialChannelMapping.GetMappedMaterialChannelName(VertexColorCasterSettings.MaterialChannel);
            }

        }

        public SimplygonMaterialCaster DeepCopy(ESimplygonPipeline pipelineType)
        {
            return new SimplygonMaterialCaster(pipelineType, this.MaterialCasterType, this.MaterialChannelName, this.MenuPath);
        }

        public new JObject SaveJson(bool serializeUIComponents)
        {
            if (MaterialCasterType == ESimplygonMaterialCaster.ColorCaster)
            {
                return SaveJsonColorCaster(serializeUIComponents);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.OpacityCaster)
            {
                return SaveJsonOpacityCaster(serializeUIComponents);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.NormalCaster)
            {
                return SaveJsonNormalCaster(serializeUIComponents);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.DisplacementCaster)
            {
                return SaveJsonDisplacementCaster(serializeUIComponents);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.AmbientOcclusionCaster)
            {
                return SaveJsonAmbientOcclusionCaster(serializeUIComponents);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.GeometryDataCaster)
            {
                return SaveJsonGeometryDataCaster(serializeUIComponents);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.VertexColorCaster)
            {
                return SaveJsonVertexColorCaster(serializeUIComponents);
            }

            return new JObject();
        }

        protected JObject SaveJsonColorCaster(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ColorCasterSettings = ColorCasterSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected JObject SaveJsonOpacityCaster(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.OpacityCasterSettings = OpacityCasterSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected JObject SaveJsonNormalCaster(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.NormalCasterSettings = NormalCasterSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected JObject SaveJsonDisplacementCaster(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.DisplacementCasterSettings = DisplacementCasterSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected JObject SaveJsonAmbientOcclusionCaster(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.AmbientOcclusionCasterSettings = AmbientOcclusionCasterSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected JObject SaveJsonGeometryDataCaster(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.GeometryDataCasterSettings = GeometryDataCasterSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected JObject SaveJsonVertexColorCaster(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.VertexColorCasterSettings = VertexColorCasterSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            if(jsonData.GetValue("ColorCasterSettings") != null)
            {
                MaterialCasterType = ESimplygonMaterialCaster.ColorCaster;
                ColorCasterSettings = new SimplygonColorCasterSettings(jsonData.ColorCasterSettings);
            }

            if(jsonData.GetValue("OpacityCasterSettings") != null)
            {
                MaterialCasterType = ESimplygonMaterialCaster.OpacityCaster;
                OpacityCasterSettings = new SimplygonOpacityCasterSettings(jsonData.OpacityCasterSettings);
            }

            if(jsonData.GetValue("NormalCasterSettings") != null)
            {
                MaterialCasterType = ESimplygonMaterialCaster.NormalCaster;
                NormalCasterSettings = new SimplygonNormalCasterSettings(jsonData.NormalCasterSettings);
            }

            if(jsonData.GetValue("DisplacementCasterSettings") != null)
            {
                MaterialCasterType = ESimplygonMaterialCaster.DisplacementCaster;
                DisplacementCasterSettings = new SimplygonDisplacementCasterSettings(jsonData.DisplacementCasterSettings);
            }

            if(jsonData.GetValue("AmbientOcclusionCasterSettings") != null)
            {
                MaterialCasterType = ESimplygonMaterialCaster.AmbientOcclusionCaster;
                AmbientOcclusionCasterSettings = new SimplygonAmbientOcclusionCasterSettings(jsonData.AmbientOcclusionCasterSettings);
            }

            if(jsonData.GetValue("GeometryDataCasterSettings") != null)
            {
                MaterialCasterType = ESimplygonMaterialCaster.GeometryDataCaster;
                GeometryDataCasterSettings = new SimplygonGeometryDataCasterSettings(jsonData.GeometryDataCasterSettings);
            }

            if(jsonData.GetValue("VertexColorCasterSettings") != null)
            {
                MaterialCasterType = ESimplygonMaterialCaster.VertexColorCaster;
                VertexColorCasterSettings = new SimplygonVertexColorCasterSettings(jsonData.VertexColorCasterSettings);
            }

        }

        public new void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            if (MaterialCasterType == ESimplygonMaterialCaster.ColorCaster)
            {
                ColorCasterSettings.SetEditMode(isEditEnabled);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.OpacityCaster)
            {
                OpacityCasterSettings.SetEditMode(isEditEnabled);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.NormalCaster)
            {
                NormalCasterSettings.SetEditMode(isEditEnabled);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.DisplacementCaster)
            {
                DisplacementCasterSettings.SetEditMode(isEditEnabled);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.AmbientOcclusionCaster)
            {
                AmbientOcclusionCasterSettings.SetEditMode(isEditEnabled);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.GeometryDataCaster)
            {
                GeometryDataCasterSettings.SetEditMode(isEditEnabled);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.VertexColorCaster)
            {
                VertexColorCasterSettings.SetEditMode(isEditEnabled);
            }

        }

        public new void Reset()
        {
            Settings.Reset();
        }

        public void SetTemplateOverrides(bool allowMaterialChannelOverride = true)
        {
            if (!string.IsNullOrEmpty(FilePath))
            {
                return;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.ColorCaster)
            {
                ColorCasterSettings.MaterialChannelUI.VisibleOverride = false;
                if (allowMaterialChannelOverride)
                {
                    ColorCasterSettings.MaterialChannel = "diffuseColor";
                }

                ColorCasterSettings.MaterialChannelUI.VisibleOverride = true;
                if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
                {
                    ColorCasterSettings.OutputPixelFormat = EPixelFormat.R8G8B8A8;
                }

                if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
                {
                    ColorCasterSettings.OutputPixelFormat = EPixelFormat.R8G8B8A8;
                }

                if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
                {
                    ColorCasterSettings.OutputPixelFormat = EPixelFormat.R8G8B8A8;
                }

                if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
                {
                    ColorCasterSettings.OutputPixelFormat = EPixelFormat.R8G8B8A8;
                }

                ColorCasterSettings.OpacityChannel = "diffuseColor";
                ColorCasterSettings.OpacityChannelUI.Visible = false;
                ColorCasterSettings.OpacityChannelComponent = EColorComponent.Alpha;
                ColorCasterSettings.OpacityChannelComponentUI.Visible = false;
                ColorCasterSettings.OpacityChannelUI.Visible = true;
                ColorCasterSettings.OpacityChannelComponentUI.Visible = true;
                if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
                {
                    ColorCasterSettings.BakeOpacityInAlpha = true;
                }

                if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
                {
                    ColorCasterSettings.BakeOpacityInAlpha = true;
                }

                if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
                {
                    ColorCasterSettings.BakeOpacityInAlpha = true;
                }

                if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
                {
                    ColorCasterSettings.BakeOpacityInAlpha = true;
                }

            }

            if (MaterialCasterType == ESimplygonMaterialCaster.NormalCaster)
            {
                NormalCasterSettings.MaterialChannelUI.VisibleOverride = false;
                if (allowMaterialChannelOverride)
                {
                    NormalCasterSettings.MaterialChannel = "normal";
                }

                NormalCasterSettings.OutputPixelFormat = EPixelFormat.R8G8B8;
                NormalCasterSettings.OpacityChannel = "diffuseColor";
                NormalCasterSettings.OpacityChannelUI.Visible = false;
                NormalCasterSettings.OpacityChannelComponent = EColorComponent.Alpha;
                NormalCasterSettings.OpacityChannelComponentUI.Visible = false;
                NormalCasterSettings.FlipGreen = true;
                NormalCasterSettings.CalculateBitangentPerFragment = false;
                NormalCasterSettings.NormalizeInterpolatedTangentSpace = false;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.DisplacementCaster)
            {
                DisplacementCasterSettings.MaterialChannelUI.VisibleOverride = false;
                if (allowMaterialChannelOverride)
                {
                    DisplacementCasterSettings.MaterialChannel = "displacement";
                }

                DisplacementCasterSettings.OpacityChannel = "diffuseColor";
                DisplacementCasterSettings.OpacityChannelUI.Visible = false;
                DisplacementCasterSettings.OpacityChannelComponent = EColorComponent.Alpha;
                DisplacementCasterSettings.OpacityChannelComponentUI.Visible = false;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.AmbientOcclusionCaster)
            {
                AmbientOcclusionCasterSettings.MaterialChannelUI.VisibleOverride = false;
                if (allowMaterialChannelOverride)
                {
                    AmbientOcclusionCasterSettings.MaterialChannel = "occlusion";
                }

                AmbientOcclusionCasterSettings.OpacityChannel = "diffuseColor";
                AmbientOcclusionCasterSettings.OpacityChannelUI.Visible = false;
                AmbientOcclusionCasterSettings.OpacityChannelComponent = EColorComponent.Alpha;
                AmbientOcclusionCasterSettings.OpacityChannelComponentUI.Visible = false;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.GeometryDataCaster)
            {
                GeometryDataCasterSettings.MaterialChannelUI.VisibleOverride = false;
                if (allowMaterialChannelOverride)
                {
                    GeometryDataCasterSettings.MaterialChannel = "geometry";
                }

                GeometryDataCasterSettings.OpacityChannel = "diffuseColor";
                GeometryDataCasterSettings.OpacityChannelUI.Visible = false;
                GeometryDataCasterSettings.OpacityChannelComponent = EColorComponent.Alpha;
                GeometryDataCasterSettings.OpacityChannelComponentUI.Visible = false;
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.VertexColorCaster)
            {
                VertexColorCasterSettings.MaterialChannelUI.VisibleOverride = false;
                if (allowMaterialChannelOverride)
                {
                    VertexColorCasterSettings.MaterialChannel = "diffuseColor";
                }

                VertexColorCasterSettings.OpacityChannel = "diffuseColor";
                VertexColorCasterSettings.OpacityChannelUI.Visible = false;
                VertexColorCasterSettings.OpacityChannelComponent = EColorComponent.Alpha;
                VertexColorCasterSettings.OpacityChannelComponentUI.Visible = false;
                VertexColorCasterSettings.OpacityChannelUI.Visible = true;
                VertexColorCasterSettings.OpacityChannelComponentUI.Visible = true;
                VertexColorCasterSettings.OutputColorName = "color";
            }

        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            if (MaterialCasterType == ESimplygonMaterialCaster.ColorCaster)
            {
                ColorCasterSettings.MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.OutputSRGBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.BakeOpacityInAlphaUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.SkipCastingIfNoInputChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                ColorCasterSettings.OutputOpacityTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.OpacityCaster)
            {
                OpacityCasterSettings.MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.OutputSRGBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                OpacityCasterSettings.OutputOpacityTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.NormalCaster)
            {
                NormalCasterSettings.MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.FlipBackfacingNormalsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.GenerateTangentSpaceNormalsUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.FlipGreenUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.CalculateBitangentPerFragmentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                NormalCasterSettings.NormalizeInterpolatedTangentSpaceUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.DisplacementCaster)
            {
                DisplacementCasterSettings.MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.DistanceScalingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.GenerateScalarDisplacementUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.GenerateTangentSpaceDisplacementUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                DisplacementCasterSettings.NormalMapTexCoordLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.AmbientOcclusionCaster)
            {
                AmbientOcclusionCasterSettings.MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.RaysPerPixelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.OcclusionFalloffUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.OcclusionMultiplierUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                AmbientOcclusionCasterSettings.UseSimpleOcclusionModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.GeometryDataCaster)
            {
                GeometryDataCasterSettings.MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.GeometryDataFieldTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.GeometryDataFieldIndexUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingInfRUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingSupRUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingInfGUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingSupGUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingInfBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingSupBUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingInfAUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                GeometryDataCasterSettings.MappingSupAUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (MaterialCasterType == ESimplygonMaterialCaster.VertexColorCaster)
            {
                VertexColorCasterSettings.MaterialChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.OpacityChannelComponentUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.OpacityChannelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.DitherTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.FillModeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.DilationUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.UseMultisamplingUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.OutputPixelFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.OutputImageFileFormatUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.OutputDDSCompressionTypeUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.OutputColorLevelUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.OutputColorNameUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
                VertexColorCasterSettings.ColorSpaceEdgeThresholdUI.CreateUI(treeView, this, createInvisibleTreeViewItems);
            }

            if (this.hasChildren)
            {
                if (treeViewParentItem.children == null)
                {
                    treeViewParentItem.AddChild(this);
                }

                if (!treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.AddChild(this);
                }

            }

            else
            {
                if (treeViewParentItem.children != null && treeViewParentItem.children.Contains(this))
                {
                    treeViewParentItem.children.Remove(this);
                }

            }

        }

    }

    public enum ESimplygonPipeline
    {
        ReductionPipeline,
        RemeshingPipeline,
        AggregationPipeline,
        BillboardCloudPipeline,
        BillboardCloudVegetationPipeline,
        FlipbookPipeline,
        ImpostorFromSingleViewPipeline,
        OcclusionMeshPipeline,
        Passthrough
    }

    public partial class SimplygonPipeline : SimplygonTreeViewItem, ISimplygonPipelineDropdownCallback
    {
        public bool VisibleMaterialCasters { get; set; }
        public bool VisibleCascadedPipelines { get; set; }
        public ESimplygonPipeline PipelineType { get; set; }
        public string MenuPath { get; set; }
        public string FilePath { get; set; }
        public bool AutomaticMaterialCastersFromSelection { get; set; }
        public string PipelineName { get { return PipelineType.ToString(); } }
        public List<SimplygonPipeline> CascadedPipelines { get; set; }
        public List<SimplygonMaterialCaster> MaterialCasters { get; set; }
        public List<SimplygonSettings> Settings { get; set; }
        public SimplygonGlobalSettings GlobalSettings { get; set; }
        public SimplygonPipelineSettings PipelineSettings { get; set; }
        public SimplygonReductionSettings ReductionSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    return (SimplygonReductionSettings)Settings[0];
                }

                return null;
            }

        }

        public SimplygonRepairSettings RepairSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    return (SimplygonRepairSettings)Settings[1];
                }

                return null;
            }

        }

        public SimplygonNormalCalculationSettings NormalCalculationSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    return (SimplygonNormalCalculationSettings)Settings[2];
                }

                return null;
            }

        }

        public SimplygonVisibilitySettings VisibilitySettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    return (SimplygonVisibilitySettings)Settings[3];
                }

                if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
                {
                    return (SimplygonVisibilitySettings)Settings[3];
                }

                if (PipelineType == ESimplygonPipeline.AggregationPipeline)
                {
                    return (SimplygonVisibilitySettings)Settings[1];
                }

                return null;
            }

        }

        public SimplygonBoneSettings BoneSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    return (SimplygonBoneSettings)Settings[4];
                }

                if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
                {
                    return (SimplygonBoneSettings)Settings[1];
                }

                return null;
            }

        }

        public SimplygonVertexWeightSettings VertexWeightSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    return (SimplygonVertexWeightSettings)Settings[5];
                }

                if (PipelineType == ESimplygonPipeline.AggregationPipeline)
                {
                    return (SimplygonVertexWeightSettings)Settings[3];
                }

                return null;
            }

        }

        public SimplygonMappingImageInputMaterialSettings MappingImageInputMaterialSettings
        {
            get
            {
                return null;
            }

        }

        public SimplygonMappingImageOutputMaterialSettings MappingImageOutputMaterialSettings
        {
            get
            {
                return null;
            }

        }

        public SimplygonChartAggregatorSettings ChartAggregatorSettings
        {
            get
            {
                return null;
            }

        }

        public SimplygonParameterizerSettings ParameterizerSettings
        {
            get
            {
                return null;
            }

        }

        public SimplygonMappingImageSettings MappingImageSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    return (SimplygonMappingImageSettings)Settings[6];
                }

                if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
                {
                    return (SimplygonMappingImageSettings)Settings[4];
                }

                if (PipelineType == ESimplygonPipeline.AggregationPipeline)
                {
                    return (SimplygonMappingImageSettings)Settings[4];
                }

                if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
                {
                    return (SimplygonMappingImageSettings)Settings[1];
                }

                if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
                {
                    return (SimplygonMappingImageSettings)Settings[1];
                }

                if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
                {
                    return (SimplygonMappingImageSettings)Settings[1];
                }

                if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
                {
                    return (SimplygonMappingImageSettings)Settings[1];
                }

                return null;
            }

        }

        public SimplygonRemeshingSettings RemeshingSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
                {
                    return (SimplygonRemeshingSettings)Settings[0];
                }

                return null;
            }

        }

        public SimplygonGeometryCullingSettings GeometryCullingSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
                {
                    return (SimplygonGeometryCullingSettings)Settings[2];
                }

                if (PipelineType == ESimplygonPipeline.AggregationPipeline)
                {
                    return (SimplygonGeometryCullingSettings)Settings[2];
                }

                return null;
            }

        }

        public SimplygonAggregationSettings AggregationSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.AggregationPipeline)
                {
                    return (SimplygonAggregationSettings)Settings[0];
                }

                return null;
            }

        }

        public SimplygonGenerateLightmapTexCoordSettings GenerateLightmapTexCoordSettings
        {
            get
            {
                return null;
            }

        }

        public SimplygonFoliageSettings FoliageSettings
        {
            get
            {
                return null;
            }

        }

        public SimplygonBillboardCloudSettings BillboardCloudSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
                {
                    return (SimplygonBillboardCloudSettings)Settings[0];
                }

                if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
                {
                    return (SimplygonBillboardCloudSettings)Settings[0];
                }

                return null;
            }

        }

        public SimplygonFlipbookSettings FlipbookSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
                {
                    return (SimplygonFlipbookSettings)Settings[0];
                }

                return null;
            }

        }

        public SimplygonImpostorFromSingleViewSettings ImpostorFromSingleViewSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
                {
                    return (SimplygonImpostorFromSingleViewSettings)Settings[0];
                }

                return null;
            }

        }

        public SimplygonOcclusionMeshSettings OcclusionMeshSettings
        {
            get
            {
                if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
                {
                    return (SimplygonOcclusionMeshSettings)Settings[0];
                }

                return null;
            }

        }


        public SimplygonPipeline(ESimplygonPipeline pipelineType, string menuPath, bool automaticMaterialCastersFromSelection) : base(pipelineType.ToString())
        {
            PipelineType = pipelineType;
            MenuPath = menuPath;
            AutomaticMaterialCastersFromSelection = automaticMaterialCastersFromSelection;
            GlobalSettings = new SimplygonGlobalSettings();
            PipelineSettings = new SimplygonPipelineSettings();
            CascadedPipelines = new List<SimplygonPipeline>();
            MaterialCasters = new List<SimplygonMaterialCaster>();
            Settings = new List<SimplygonSettings>();
            if (PipelineType == ESimplygonPipeline.Passthrough)
            {
                PipelineSettings.IntermediateStep = true;
            }

            if (PipelineType == ESimplygonPipeline.ReductionPipeline)
            {
                Settings.Add(new SimplygonReductionSettings());
                Settings.Add(new SimplygonRepairSettings());
                Settings.Add(new SimplygonNormalCalculationSettings());
                Settings.Add(new SimplygonVisibilitySettings());
                Settings.Add(new SimplygonBoneSettings());
                Settings.Add(new SimplygonVertexWeightSettings());
                Settings.Add(new SimplygonMappingImageSettings());
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
            {
                Settings.Add(new SimplygonRemeshingSettings());
                Settings.Add(new SimplygonBoneSettings());
                Settings.Add(new SimplygonGeometryCullingSettings());
                Settings.Add(new SimplygonVisibilitySettings());
                Settings.Add(new SimplygonMappingImageSettings());
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline)
            {
                Settings.Add(new SimplygonAggregationSettings());
                Settings.Add(new SimplygonVisibilitySettings());
                Settings.Add(new SimplygonGeometryCullingSettings());
                Settings.Add(new SimplygonVertexWeightSettings());
                Settings.Add(new SimplygonMappingImageSettings());
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
            {
                Settings.Add(new SimplygonBillboardCloudSettings());
                Settings.Add(new SimplygonMappingImageSettings());
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
            {
                Settings.Add(new SimplygonBillboardCloudSettings());
                Settings.Add(new SimplygonMappingImageSettings());
            }

            if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
            {
                Settings.Add(new SimplygonFlipbookSettings());
                Settings.Add(new SimplygonMappingImageSettings());
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
            {
                Settings.Add(new SimplygonImpostorFromSingleViewSettings());
                Settings.Add(new SimplygonMappingImageSettings());
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
            {
                Settings.Add(new SimplygonOcclusionMeshSettings());
            }


            foreach(var settings in Settings)
            {
                settings.Pipeline = this;
            }

            SetTemplateOverrides();
        }

        public SimplygonPipeline(string filePath, dynamic jsonData) : base("")
        {
            FilePath = filePath;
            GlobalSettings = new SimplygonGlobalSettings();
            PipelineSettings = new SimplygonPipelineSettings();
            CascadedPipelines = new List<SimplygonPipeline>();
            MaterialCasters = new List<SimplygonMaterialCaster>();
            Settings = new List<SimplygonSettings>();
            LoadJson(jsonData);
            foreach(var settings in Settings)
            {
                settings.Pipeline = this;
            }

            if(PipelineType != ESimplygonPipeline.Passthrough && Settings.Count == 0)
            {
                throw new Exception("Invalid pipeline");
            }

        }

        public SimplygonPipeline DeepCopy()
        {
            var copy = new SimplygonPipeline(this.PipelineType, this.MenuPath, this.AutomaticMaterialCastersFromSelection);
            copy.Settings = this.Settings.ConvertAll(i => i.DeepCopy()).ToList();
            copy.CascadedPipelines = this.CascadedPipelines.ConvertAll(i => i.DeepCopy()).ToList();
            copy.MaterialCasters = this.MaterialCasters.ConvertAll(i => i.DeepCopy(PipelineType)).ToList();
            foreach(var settings in copy.Settings)
            {
                settings.Pipeline = copy;
            }

            copy.SetTemplateOverrides();

            return copy;
        }

        public JObject SaveJson(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.Settings = new JObject();
            if (PipelineType == ESimplygonPipeline.Passthrough)
            {
                jsonData.Pipeline = "Passthrough";
            }

            if (PipelineType == ESimplygonPipeline.ReductionPipeline)
            {
                jsonData.Pipeline = "Reduction";
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
            {
                jsonData.Pipeline = "Remeshing";
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline)
            {
                jsonData.Pipeline = "Aggregation";
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
            {
                jsonData.Pipeline = "BillboardCloud";
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
            {
                jsonData.Pipeline = "BillboardCloudVegetation";
            }

            if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
            {
                jsonData.Pipeline = "Flipbook";
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
            {
                jsonData.Pipeline = "ImpostorFromSingleView";
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
            {
                jsonData.Pipeline = "OcclusionMesh";
            }

            jsonData.Version = "9.2";
            jsonData.Build = "9.2.1400.0";
            jsonData.Commit = "c47d3175d00ec884bd836442df285bc06f7754eb";
            jsonData.Settings.GlobalSettings = GlobalSettings.SaveJson(serializeUIComponents);
            jsonData.Settings.PipelineSettings = PipelineSettings.SaveJson(serializeUIComponents);

            if (PipelineType == ESimplygonPipeline.ReductionPipeline)
            {
                jsonData.Settings.ReductionProcessor = SaveJsonReductionPipeline(serializeUIComponents);
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
            {
                jsonData.Settings.RemeshingProcessor = SaveJsonRemeshingPipeline(serializeUIComponents);
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline)
            {
                jsonData.Settings.AggregationProcessor = SaveJsonAggregationPipeline(serializeUIComponents);
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
            {
                jsonData.Settings.ImpostorProcessor = SaveJsonBillboardCloudPipeline(serializeUIComponents);
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
            {
                jsonData.Settings.ImpostorProcessor = SaveJsonBillboardCloudVegetationPipeline(serializeUIComponents);
            }

            if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
            {
                jsonData.Settings.ImpostorProcessor = SaveJsonFlipbookPipeline(serializeUIComponents);
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
            {
                jsonData.Settings.ImpostorProcessor = SaveJsonImpostorFromSingleViewPipeline(serializeUIComponents);
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
            {
                jsonData.Settings.OcclusionMeshProcessor = SaveJsonOcclusionMeshPipeline(serializeUIComponents);
            }

            jsonData.Settings.MaterialCaster = new JArray();
            foreach(var item in MaterialCasters)
            {
                jsonData.Settings.MaterialCaster.Add(item.SaveJson(serializeUIComponents));
            }

            jsonData.Cascaded = new JArray();
            foreach(var item in CascadedPipelines)
            {
                jsonData.Cascaded.Add(item.SaveJson(serializeUIComponents));
            }

            return jsonData;
        }

        public JObject SaveJsonReductionPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ReductionSettings = ReductionSettings.SaveJson(serializeUIComponents);
            jsonData.RepairSettings = RepairSettings.SaveJson(serializeUIComponents);
            jsonData.NormalCalculationSettings = NormalCalculationSettings.SaveJson(serializeUIComponents);
            jsonData.VisibilitySettings = VisibilitySettings.SaveJson(serializeUIComponents);
            jsonData.BoneSettings = BoneSettings.SaveJson(serializeUIComponents);
            jsonData.VertexWeightSettings = VertexWeightSettings.SaveJson(serializeUIComponents);
            jsonData.MappingImageSettings = MappingImageSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        public JObject SaveJsonRemeshingPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.RemeshingSettings = RemeshingSettings.SaveJson(serializeUIComponents);
            jsonData.BoneSettings = BoneSettings.SaveJson(serializeUIComponents);
            jsonData.GeometryCullingSettings = GeometryCullingSettings.SaveJson(serializeUIComponents);
            jsonData.VisibilitySettings = VisibilitySettings.SaveJson(serializeUIComponents);
            jsonData.MappingImageSettings = MappingImageSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        public JObject SaveJsonAggregationPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.AggregationSettings = AggregationSettings.SaveJson(serializeUIComponents);
            jsonData.VisibilitySettings = VisibilitySettings.SaveJson(serializeUIComponents);
            jsonData.GeometryCullingSettings = GeometryCullingSettings.SaveJson(serializeUIComponents);
            jsonData.VertexWeightSettings = VertexWeightSettings.SaveJson(serializeUIComponents);
            jsonData.MappingImageSettings = MappingImageSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        public JObject SaveJsonBillboardCloudPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ImpostorSettings = new JObject();
            jsonData.ImpostorSettings.BillboardCloudSettings = BillboardCloudSettings.SaveJson(serializeUIComponents);
            jsonData.ImpostorSettings.ImpostorType = EImpostorType.BillboardCloud;
            jsonData.MappingImageSettings = MappingImageSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        public JObject SaveJsonBillboardCloudVegetationPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ImpostorSettings = new JObject();
            jsonData.ImpostorSettings.BillboardCloudSettings = BillboardCloudSettings.SaveJson(serializeUIComponents);
            jsonData.ImpostorSettings.ImpostorType = EImpostorType.BillboardCloud;
            jsonData.MappingImageSettings = MappingImageSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        public JObject SaveJsonFlipbookPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ImpostorSettings = new JObject();
            jsonData.ImpostorSettings.FlipbookSettings = FlipbookSettings.SaveJson(serializeUIComponents);
            jsonData.ImpostorSettings.ImpostorType = EImpostorType.Flipbook;
            jsonData.MappingImageSettings = MappingImageSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        public JObject SaveJsonImpostorFromSingleViewPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.ImpostorSettings = new JObject();
            jsonData.ImpostorSettings.ImpostorFromSingleViewSettings = ImpostorFromSingleViewSettings.SaveJson(serializeUIComponents);
            jsonData.ImpostorSettings.ImpostorType = EImpostorType.FromSingleView;
            jsonData.MappingImageSettings = MappingImageSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        public JObject SaveJsonOcclusionMeshPipeline(bool serializeUIComponents)
        {
            dynamic jsonData = new JObject();
            jsonData.OcclusionMeshSettings = OcclusionMeshSettings.SaveJson(serializeUIComponents);
            return jsonData;
        }

        protected void LoadJson(dynamic jsonData)
        {
            if(jsonData == null)
            {
                throw new Exception("Invalid pipeline - content is empty.");
            }

            else if((string)jsonData.Pipeline == null)
            {
                throw new Exception("Invalid pipeline - pipeline type could not be resolved.");
            }

            else if((string)jsonData.Version == null)
            {
                throw new Exception("Invalid pipeline - pipeline version could not be resolved.");
            }

            if ((string)jsonData.Pipeline == "Passthrough")
            {
                PipelineType = ESimplygonPipeline.Passthrough;
            }

            if ((string)jsonData.Version != "9.2")
            {
                SimplygonLogger.Instance.Log(Category.Warning, $"Pipeline '{FilePath}' updated to version 9.2. Please save the updated pipeline so it can be used with the Simplygon 9.2 API.");
            }

            if ((string)jsonData.Pipeline == "Reduction")
            {
                PipelineType = ESimplygonPipeline.ReductionPipeline;
            }

            if ((string)jsonData.Pipeline == "Remeshing")
            {
                PipelineType = ESimplygonPipeline.RemeshingPipeline;
            }

            if ((string)jsonData.Pipeline == "Aggregation")
            {
                PipelineType = ESimplygonPipeline.AggregationPipeline;
            }

            if ((string)jsonData.Pipeline == "BillboardCloud")
            {
                PipelineType = ESimplygonPipeline.BillboardCloudPipeline;
            }

            if ((string)jsonData.Pipeline == "BillboardCloudVegetation")
            {
                PipelineType = ESimplygonPipeline.BillboardCloudVegetationPipeline;
            }

            if ((string)jsonData.Pipeline == "Flipbook")
            {
                PipelineType = ESimplygonPipeline.FlipbookPipeline;
            }

            if ((string)jsonData.Pipeline == "ImpostorFromSingleView")
            {
                PipelineType = ESimplygonPipeline.ImpostorFromSingleViewPipeline;
            }

            if ((string)jsonData.Pipeline == "OcclusionMesh")
            {
                PipelineType = ESimplygonPipeline.OcclusionMeshPipeline;
            }

            if (jsonData.Settings != null)
            {
                GlobalSettings = new SimplygonGlobalSettings(jsonData.Settings.GlobalSettings);
                PipelineSettings = new SimplygonPipelineSettings(jsonData.Settings.PipelineSettings);
            }

            else
            {
                GlobalSettings = new SimplygonGlobalSettings();
                PipelineSettings = new SimplygonPipelineSettings();
            }

            if (PipelineType == ESimplygonPipeline.ReductionPipeline)
            {
                LoadJsonReductionPipeline(jsonData.Settings.ReductionProcessor);
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
            {
                LoadJsonRemeshingPipeline(jsonData.Settings.RemeshingProcessor);
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline)
            {
                LoadJsonAggregationPipeline(jsonData.Settings.AggregationProcessor);
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
            {
                LoadJsonBillboardCloudPipeline(jsonData.Settings.ImpostorProcessor);
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
            {
                LoadJsonBillboardCloudVegetationPipeline(jsonData.Settings.ImpostorProcessor);
            }

            if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
            {
                LoadJsonFlipbookPipeline(jsonData.Settings.ImpostorProcessor);
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
            {
                LoadJsonImpostorFromSingleViewPipeline(jsonData.Settings.ImpostorProcessor);
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
            {
                LoadJsonOcclusionMeshPipeline(jsonData.Settings.OcclusionMeshProcessor);
            }

            if(jsonData.GetValue("Cascaded") != null)
            {
                for(int i = 0; i < jsonData.Cascaded.Count; ++i)
                {
                    var cascadedPipeline = new SimplygonPipeline(FilePath, jsonData.Cascaded[i]);
                    CascadedPipelines.Add(cascadedPipeline);
                }

            }

            if (jsonData.Settings != null)
            {
                if(jsonData.Settings.GetValue("MaterialCaster") != null)
                {
                    for(int i = 0; i < jsonData.Settings.MaterialCaster.Count; ++i)
                    {
                        var materialCaster = new SimplygonMaterialCaster(this.PipelineType, jsonData.Settings.MaterialCaster[i]);
                        MaterialCasters.Add(materialCaster);
                    }

                }

            }

        }


        protected void LoadJsonReductionPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonReductionSettings(jsonData.ReductionSettings));
            Settings.Add(new SimplygonRepairSettings(jsonData.RepairSettings));
            Settings.Add(new SimplygonNormalCalculationSettings(jsonData.NormalCalculationSettings));
            Settings.Add(new SimplygonVisibilitySettings(jsonData.VisibilitySettings));
            Settings.Add(new SimplygonBoneSettings(jsonData.BoneSettings));
            Settings.Add(new SimplygonVertexWeightSettings(jsonData.VertexWeightSettings));
            Settings.Add(new SimplygonMappingImageSettings(jsonData.MappingImageSettings));
        }

        protected void LoadJsonRemeshingPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonRemeshingSettings(jsonData.RemeshingSettings));
            Settings.Add(new SimplygonBoneSettings(jsonData.BoneSettings));
            Settings.Add(new SimplygonGeometryCullingSettings(jsonData.GeometryCullingSettings));
            Settings.Add(new SimplygonVisibilitySettings(jsonData.VisibilitySettings));
            Settings.Add(new SimplygonMappingImageSettings(jsonData.MappingImageSettings));
        }

        protected void LoadJsonAggregationPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonAggregationSettings(jsonData.AggregationSettings));
            Settings.Add(new SimplygonVisibilitySettings(jsonData.VisibilitySettings));
            Settings.Add(new SimplygonGeometryCullingSettings(jsonData.GeometryCullingSettings));
            Settings.Add(new SimplygonVertexWeightSettings(jsonData.VertexWeightSettings));
            Settings.Add(new SimplygonMappingImageSettings(jsonData.MappingImageSettings));
        }

        protected void LoadJsonBillboardCloudPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonBillboardCloudSettings(jsonData.ImpostorSettings.BillboardCloudSettings));
            Settings.Add(new SimplygonMappingImageSettings(jsonData.MappingImageSettings));
        }

        protected void LoadJsonBillboardCloudVegetationPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonBillboardCloudSettings(jsonData.ImpostorSettings.BillboardCloudSettings));
            Settings.Add(new SimplygonMappingImageSettings(jsonData.MappingImageSettings));
        }

        protected void LoadJsonFlipbookPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonFlipbookSettings(jsonData.ImpostorSettings.FlipbookSettings));
            Settings.Add(new SimplygonMappingImageSettings(jsonData.MappingImageSettings));
        }

        protected void LoadJsonImpostorFromSingleViewPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonImpostorFromSingleViewSettings(jsonData.ImpostorSettings.ImpostorFromSingleViewSettings));
            Settings.Add(new SimplygonMappingImageSettings(jsonData.MappingImageSettings));
        }

        protected void LoadJsonOcclusionMeshPipeline(dynamic jsonData)
        {
            if(jsonData == null)
            {
                return;
            }

            Settings.Add(new SimplygonOcclusionMeshSettings(jsonData.OcclusionMeshSettings));
        }

        public SimplygonMaterialCaster AddMaterialCaster(ESimplygonMaterialCaster materialCasterType, string materialChannelName, bool allowMaterialChannelOverride = true)
        {
            var materialCaster = MaterialCasters.Where(i => i.MaterialChannelName == materialChannelName).FirstOrDefault();
            if(materialCaster == null)
            {
                materialCaster = new SimplygonMaterialCaster(this.PipelineType, materialCasterType, materialChannelName, "Template/Advanced/" + materialCasterType, allowMaterialChannelOverride);
                materialCaster.Pipeline = this;
                MaterialCasters.Add(materialCaster);
                if (PipelineType == ESimplygonPipeline.ReductionPipeline)
                {
                    MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
                }

                if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
                {
                    MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
                }

                if (PipelineType == ESimplygonPipeline.AggregationPipeline)
                {
                    MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
                }

                if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
                {
                    MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
                }

                if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
                {
                    MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
                }

                if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
                {
                    MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
                }

                if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
                {
                    MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                    MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
                }

                if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
                {
                }

            }

            return materialCaster;
        }

        public void AddMaterialCaster(SimplygonMaterialCaster materialCaster)
        {
            materialCaster.Pipeline = this;
            MaterialCasters.Add( materialCaster );
            if (PipelineType == ESimplygonPipeline.ReductionPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
            {
            }

        }

        public void RemoveMaterialCaster(SimplygonMaterialCaster materialCaster)
        {
            MaterialCasters.Remove(materialCaster);
            if (PipelineType == ESimplygonPipeline.ReductionPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
            {
                MappingImageSettings.GenerateMappingImageUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.UseFullRetexturingUI.Value = MaterialCasters.Count > 0;
                MappingImageSettings.ApplyNewMaterialIdsUI.Value = MaterialCasters.Count > 0;
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
            {
            }

        }

        public SimplygonPipeline AddCascadedPipeline(ESimplygonPipeline pipelineType)
        {
            var cascadedPipeline = new SimplygonPipeline(pipelineType, string.Empty, false);
            CascadedPipelines.Add( cascadedPipeline );
            return cascadedPipeline;
        }

        public void AddCascadedPipeline(SimplygonPipeline pipeline)
        {
            CascadedPipelines.Add( pipeline );
        }

        public void RemoveCascadedPipeline(SimplygonPipeline pipeline)
        {
            CascadedPipelines.Remove(pipeline);
        }

        public void SetEditMode(bool isEditEnabled)
        {
            IsEditEnabled = isEditEnabled;
            foreach(var settings in Settings)
            {
                settings.SetEditMode(isEditEnabled);
            }

            foreach(var materialCaster in MaterialCasters)
            {
                materialCaster.SetEditMode(isEditEnabled);
            }

            foreach(var cascadedPipeline in CascadedPipelines)
            {
                cascadedPipeline.SetEditMode(isEditEnabled);
            }

            ToggleEdit();
        }

        protected void SetTemplateOverrides()
        {
            if (!string.IsNullOrEmpty(FilePath))
            {
                return;
            }

            if (PipelineType == ESimplygonPipeline.ReductionPipeline && MenuPath == "Template/Advanced/Reduction")
            {
                VertexWeightSettings.WeightsFromColorLevel = 0;
                VertexWeightSettings.WeightsFromColorNameUI.VisibleOverride = false;
                VertexWeightSettings.WeightsFromColorLevelUI.VisibleOverride = false;
                MappingImageSettings.TexCoordGeneratorType = ETexcoordGeneratorType.ChartAggregator;
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline && MenuPath == "Template/Advanced/Remeshing")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline && MenuPath == "Template/Advanced/Aggregation")
            {
                VertexWeightSettings.WeightsFromColorLevel = 0;
                VertexWeightSettings.WeightsFromColorNameUI.VisibleOverride = false;
                VertexWeightSettings.WeightsFromColorLevelUI.VisibleOverride = false;
                AggregationSettings.EnableGeometryCulling = true;
                MappingImageSettings.TexCoordGeneratorType = ETexcoordGeneratorType.ChartAggregator;
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline && MenuPath == "Template/Advanced/Billboard cloud")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                BillboardCloudSettings.BillboardModeUI.VisibleOverride = false;
                BillboardCloudSettings.FoliageSettings.VisibleOverride = false;
                BillboardCloudSettings.BillboardMode = EBillboardMode.OuterShell;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline && MenuPath == "Template/Advanced/Billboard cloud for vegetation")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                BillboardCloudSettings.BillboardModeUI.VisibleOverride = false;
                BillboardCloudSettings.BillboardMode = EBillboardMode.Foliage;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline && MenuPath == "Template/Advanced/Impostor from single view")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                ImpostorFromSingleViewSettings.ViewDirectionX = 0;
                ImpostorFromSingleViewSettings.ViewDirectionY = 0;
                ImpostorFromSingleViewSettings.ViewDirectionZ = 1;
                ImpostorFromSingleViewSettings.TwoSidedUI.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline && MenuPath == "Template/Advanced/Occlusion mesh")
            {
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.ReductionPipeline && MenuPath == "Template/Basic/Reduction")
            {
                MappingImageSettings.TexCoordGeneratorType = ETexcoordGeneratorType.ChartAggregator;
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                ReductionSettings.ReductionTargetTriangleCountUI.VisibleOverride = false;
                ReductionSettings.ReductionTargetMaxDeviationUI.VisibleOverride = false;
                ReductionSettings.ReductionTargetOnScreenSizeUI.VisibleOverride = false;
                ReductionSettings.ReductionTargetStopConditionUI.VisibleOverride = false;
                ReductionSettings.ReductionHeuristicsUI.VisibleOverride = false;
                ReductionSettings.GeometryImportanceUI.VisibleOverride = false;
                ReductionSettings.MaterialImportanceUI.VisibleOverride = false;
                ReductionSettings.TextureImportanceUI.VisibleOverride = false;
                ReductionSettings.ShadingImportanceUI.VisibleOverride = false;
                ReductionSettings.GroupImportanceUI.VisibleOverride = false;
                ReductionSettings.VertexColorImportanceUI.VisibleOverride = false;
                ReductionSettings.EdgeSetImportanceUI.VisibleOverride = false;
                ReductionSettings.SkinningImportanceUI.VisibleOverride = false;
                ReductionSettings.CurvatureImportanceUI.VisibleOverride = false;
                ReductionSettings.OutwardMoveMultiplierUI.VisibleOverride = false;
                ReductionSettings.InwardMoveMultiplierUI.VisibleOverride = false;
                ReductionSettings.KeepSymmetryUI.VisibleOverride = false;
                ReductionSettings.CreateGeomorphGeometryUI.VisibleOverride = false;
                ReductionSettings.DataCreationPreferencesUI.VisibleOverride = false;
                ReductionSettings.UseHighQualityNormalCalculationUI.VisibleOverride = false;
                ReductionSettings.LockGeometricBorderUI.VisibleOverride = false;
                ReductionSettings.MergeGeometriesUI.VisibleOverride = false;
                ReductionSettings.AllowDegenerateTexCoordsUI.VisibleOverride = false;
                ReductionSettings.KeepUnprocessedSceneMeshesUI.VisibleOverride = false;
                RepairSettings.VisibleOverride = false;
                NormalCalculationSettings.VisibleOverride = false;
                VisibilitySettings.VisibleOverride = false;
                BoneSettings.VisibleOverride = false;
                MappingImageSettings.VisibleOverride = false;
                VertexWeightSettings.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.ReductionPipeline && MenuPath == "Template/Basic/Reduction with material baking")
            {
                MappingImageSettings.TexCoordGeneratorType = ETexcoordGeneratorType.ChartAggregator;
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                ReductionSettings.ReductionTargetTriangleCountUI.VisibleOverride = false;
                ReductionSettings.ReductionTargetMaxDeviationUI.VisibleOverride = false;
                ReductionSettings.ReductionTargetOnScreenSizeUI.VisibleOverride = false;
                ReductionSettings.ReductionTargetStopConditionUI.VisibleOverride = false;
                ReductionSettings.ReductionHeuristicsUI.VisibleOverride = false;
                ReductionSettings.GeometryImportanceUI.VisibleOverride = false;
                ReductionSettings.MaterialImportanceUI.VisibleOverride = false;
                ReductionSettings.TextureImportanceUI.VisibleOverride = false;
                ReductionSettings.ShadingImportanceUI.VisibleOverride = false;
                ReductionSettings.GroupImportanceUI.VisibleOverride = false;
                ReductionSettings.VertexColorImportanceUI.VisibleOverride = false;
                ReductionSettings.EdgeSetImportanceUI.VisibleOverride = false;
                ReductionSettings.SkinningImportanceUI.VisibleOverride = false;
                ReductionSettings.CurvatureImportanceUI.VisibleOverride = false;
                ReductionSettings.OutwardMoveMultiplierUI.VisibleOverride = false;
                ReductionSettings.InwardMoveMultiplierUI.VisibleOverride = false;
                ReductionSettings.KeepSymmetryUI.VisibleOverride = false;
                ReductionSettings.CreateGeomorphGeometryUI.VisibleOverride = false;
                ReductionSettings.DataCreationPreferencesUI.VisibleOverride = false;
                ReductionSettings.UseHighQualityNormalCalculationUI.VisibleOverride = false;
                ReductionSettings.LockGeometricBorderUI.VisibleOverride = false;
                ReductionSettings.MergeGeometriesUI.VisibleOverride = false;
                ReductionSettings.AllowDegenerateTexCoordsUI.VisibleOverride = false;
                ReductionSettings.KeepUnprocessedSceneMeshesUI.VisibleOverride = false;
                RepairSettings.VisibleOverride = false;
                NormalCalculationSettings.VisibleOverride = false;
                VisibilitySettings.VisibleOverride = false;
                BoneSettings.VisibleOverride = false;
                VertexWeightSettings.VisibleOverride = false;
                MappingImageSettings.GenerateMappingImageUI.VisibleOverride = false;
                MappingImageSettings.GenerateTexCoordsUI.VisibleOverride = false;
                MappingImageSettings.GenerateTangentsUI.VisibleOverride = false;
                MappingImageSettings.UseFullRetexturingUI.VisibleOverride = false;
                MappingImageSettings.ApplyNewMaterialIdsUI.VisibleOverride = false;
                MappingImageSettings.UseAutomaticTextureSizeUI.VisibleOverride = false;
                MappingImageSettings.AutomaticTextureSizeMultiplierUI.VisibleOverride = false;
                MappingImageSettings.ForcePower2TextureUI.VisibleOverride = false;
                MappingImageSettings.OnlyParameterizeInvalidUVsUI.VisibleOverride = false;
                MappingImageSettings.AllowTransparencyMappingUI.VisibleOverride = false;
                MappingImageSettings.MaximumLayersUI.VisibleOverride = false;
                MappingImageSettings.TexCoordLevelUI.VisibleOverride = false;
                MappingImageSettings.TexCoordNameUI.VisibleOverride = false;
                MappingImageSettings.TexCoordGeneratorTypeUI.VisibleOverride = false;
                MappingImageSettings.ParameterizerSettings.VisibleOverride = false;
                MappingImageSettings.ChartAggregatorSettings.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.MultisamplingLevelUI.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.GutterSpaceUI.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline && MenuPath == "Template/Basic/Remeshing with material baking")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                RemeshingSettings.RemeshingModeManualPositionXUI.VisibleOverride = false;
                RemeshingSettings.RemeshingModeManualPositionYUI.VisibleOverride = false;
                RemeshingSettings.RemeshingModeManualPositionZUI.VisibleOverride = false;
                RemeshingSettings.ForceSoftEdgesWithinTextureChartsUI.VisibleOverride = false;
                RemeshingSettings.HoleFillingUI.VisibleOverride = false;
                RemeshingSettings.RemeshingModeUI.VisibleOverride = false;
                RemeshingSettings.SurfaceTransferModeUI.VisibleOverride = false;
                RemeshingSettings.HardEdgeAngleUI.VisibleOverride = false;
                RemeshingSettings.TransferNormalsUI.VisibleOverride = false;
                RemeshingSettings.TransferColorsUI.VisibleOverride = false;
                RemeshingSettings.KeepUnprocessedSceneMeshesUI.VisibleOverride = false;
                BoneSettings.VisibleOverride = false;
                GeometryCullingSettings.VisibleOverride = false;
                VisibilitySettings.VisibleOverride = false;
                MappingImageSettings.GenerateMappingImageUI.VisibleOverride = false;
                MappingImageSettings.GenerateTexCoordsUI.VisibleOverride = false;
                MappingImageSettings.GenerateTangentsUI.VisibleOverride = false;
                MappingImageSettings.UseFullRetexturingUI.VisibleOverride = false;
                MappingImageSettings.ApplyNewMaterialIdsUI.VisibleOverride = false;
                MappingImageSettings.UseAutomaticTextureSizeUI.VisibleOverride = false;
                MappingImageSettings.AutomaticTextureSizeMultiplierUI.VisibleOverride = false;
                MappingImageSettings.ForcePower2TextureUI.VisibleOverride = false;
                MappingImageSettings.OnlyParameterizeInvalidUVsUI.VisibleOverride = false;
                MappingImageSettings.AllowTransparencyMappingUI.VisibleOverride = false;
                MappingImageSettings.MaximumLayersUI.VisibleOverride = false;
                MappingImageSettings.TexCoordLevelUI.VisibleOverride = false;
                MappingImageSettings.TexCoordNameUI.VisibleOverride = false;
                MappingImageSettings.TexCoordGeneratorTypeUI.VisibleOverride = false;
                MappingImageSettings.ParameterizerSettings.VisibleOverride = false;
                MappingImageSettings.ChartAggregatorSettings.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.MultisamplingLevelUI.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.GutterSpaceUI.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline && MenuPath == "Template/Basic/Aggregation")
            {
                AggregationSettings.EnableGeometryCulling = true;
                MappingImageSettings.TexCoordGeneratorType = ETexcoordGeneratorType.ChartAggregator;
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                AggregationSettings.SubdivideGeometryBasedOnUVTilesUI.VisibleOverride = false;
                AggregationSettings.KeepUnprocessedSceneMeshesUI.VisibleOverride = false;
                VisibilitySettings.VisibleOverride = false;
                VertexWeightSettings.VisibleOverride = false;
                MappingImageSettings.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline && MenuPath == "Template/Basic/Aggregation with material baking")
            {
                AggregationSettings.EnableGeometryCulling = true;
                MappingImageSettings.TexCoordGeneratorType = ETexcoordGeneratorType.ChartAggregator;
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                AggregationSettings.SubdivideGeometryBasedOnUVTilesUI.VisibleOverride = false;
                AggregationSettings.KeepUnprocessedSceneMeshesUI.VisibleOverride = false;
                MappingImageSettings.GenerateMappingImageUI.VisibleOverride = false;
                MappingImageSettings.GenerateTexCoordsUI.VisibleOverride = false;
                MappingImageSettings.GenerateTangentsUI.VisibleOverride = false;
                MappingImageSettings.UseFullRetexturingUI.VisibleOverride = false;
                MappingImageSettings.ApplyNewMaterialIdsUI.VisibleOverride = false;
                MappingImageSettings.UseAutomaticTextureSizeUI.VisibleOverride = false;
                MappingImageSettings.AutomaticTextureSizeMultiplierUI.VisibleOverride = false;
                MappingImageSettings.ForcePower2TextureUI.VisibleOverride = false;
                MappingImageSettings.OnlyParameterizeInvalidUVsUI.VisibleOverride = false;
                MappingImageSettings.AllowTransparencyMappingUI.VisibleOverride = false;
                MappingImageSettings.MaximumLayersUI.VisibleOverride = false;
                MappingImageSettings.TexCoordLevelUI.VisibleOverride = false;
                MappingImageSettings.TexCoordNameUI.VisibleOverride = false;
                MappingImageSettings.TexCoordGeneratorTypeUI.VisibleOverride = false;
                MappingImageSettings.ParameterizerSettings.VisibleOverride = false;
                MappingImageSettings.ChartAggregatorSettings.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.MultisamplingLevelUI.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.GutterSpaceUI.VisibleOverride = false;
                VisibilitySettings.VisibleOverride = false;
                VertexWeightSettings.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline && MenuPath == "Template/Basic/Billboard cloud")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                BillboardCloudSettings.BillboardModeUI.VisibleOverride = false;
                BillboardCloudSettings.BillboardDensityUI.VisibleOverride = false;
                BillboardCloudSettings.MaxPlaneCountUI.VisibleOverride = false;
                BillboardCloudSettings.GeometricComplexityUI.VisibleOverride = false;
                BillboardCloudSettings.BillboardMode = EBillboardMode.OuterShell;
                BillboardCloudSettings.FoliageSettings.VisibleOverride = false;
                MappingImageSettings.GenerateMappingImageUI.VisibleOverride = false;
                MappingImageSettings.GenerateTexCoordsUI.VisibleOverride = false;
                MappingImageSettings.GenerateTangentsUI.VisibleOverride = false;
                MappingImageSettings.UseFullRetexturingUI.VisibleOverride = false;
                MappingImageSettings.ApplyNewMaterialIdsUI.VisibleOverride = false;
                MappingImageSettings.UseAutomaticTextureSizeUI.VisibleOverride = false;
                MappingImageSettings.AutomaticTextureSizeMultiplierUI.VisibleOverride = false;
                MappingImageSettings.ForcePower2TextureUI.VisibleOverride = false;
                MappingImageSettings.OnlyParameterizeInvalidUVsUI.VisibleOverride = false;
                MappingImageSettings.AllowTransparencyMappingUI.VisibleOverride = false;
                MappingImageSettings.MaximumLayersUI.VisibleOverride = false;
                MappingImageSettings.TexCoordLevelUI.VisibleOverride = false;
                MappingImageSettings.TexCoordNameUI.VisibleOverride = false;
                MappingImageSettings.TexCoordGeneratorTypeUI.VisibleOverride = false;
                MappingImageSettings.ParameterizerSettings.VisibleOverride = false;
                MappingImageSettings.ChartAggregatorSettings.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.MultisamplingLevelUI.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.GutterSpaceUI.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline && MenuPath == "Template/Basic/Billboard cloud for vegetation")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                BillboardCloudSettings.BillboardModeUI.VisibleOverride = false;
                BillboardCloudSettings.BillboardDensityUI.VisibleOverride = false;
                BillboardCloudSettings.MaxPlaneCountUI.VisibleOverride = false;
                BillboardCloudSettings.GeometricComplexityUI.VisibleOverride = false;
                BillboardCloudSettings.BillboardMode = EBillboardMode.Foliage;
                MappingImageSettings.GenerateMappingImageUI.VisibleOverride = false;
                MappingImageSettings.GenerateTexCoordsUI.VisibleOverride = false;
                MappingImageSettings.GenerateTangentsUI.VisibleOverride = false;
                MappingImageSettings.UseFullRetexturingUI.VisibleOverride = false;
                MappingImageSettings.ApplyNewMaterialIdsUI.VisibleOverride = false;
                MappingImageSettings.UseAutomaticTextureSizeUI.VisibleOverride = false;
                MappingImageSettings.AutomaticTextureSizeMultiplierUI.VisibleOverride = false;
                MappingImageSettings.ForcePower2TextureUI.VisibleOverride = false;
                MappingImageSettings.OnlyParameterizeInvalidUVsUI.VisibleOverride = false;
                MappingImageSettings.AllowTransparencyMappingUI.VisibleOverride = false;
                MappingImageSettings.MaximumLayersUI.VisibleOverride = false;
                MappingImageSettings.TexCoordLevelUI.VisibleOverride = false;
                MappingImageSettings.TexCoordNameUI.VisibleOverride = false;
                MappingImageSettings.TexCoordGeneratorTypeUI.VisibleOverride = false;
                MappingImageSettings.ParameterizerSettings.VisibleOverride = false;
                MappingImageSettings.ChartAggregatorSettings.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.MultisamplingLevelUI.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.GutterSpaceUI.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline && MenuPath == "Template/Basic/Impostor from single view")
            {
                MappingImageSettings.ChartAggregatorSettings.OriginalChartProportionsChannel = "diffuseColor";
                ImpostorFromSingleViewSettings.ViewDirectionX = 0;
                ImpostorFromSingleViewSettings.ViewDirectionY = 0;
                ImpostorFromSingleViewSettings.ViewDirectionZ = 1;
                MappingImageSettings.GenerateMappingImageUI.VisibleOverride = false;
                MappingImageSettings.GenerateTexCoordsUI.VisibleOverride = false;
                MappingImageSettings.GenerateTangentsUI.VisibleOverride = false;
                MappingImageSettings.UseFullRetexturingUI.VisibleOverride = false;
                MappingImageSettings.ApplyNewMaterialIdsUI.VisibleOverride = false;
                MappingImageSettings.UseAutomaticTextureSizeUI.VisibleOverride = false;
                MappingImageSettings.AutomaticTextureSizeMultiplierUI.VisibleOverride = false;
                MappingImageSettings.ForcePower2TextureUI.VisibleOverride = false;
                MappingImageSettings.OnlyParameterizeInvalidUVsUI.VisibleOverride = false;
                MappingImageSettings.AllowTransparencyMappingUI.VisibleOverride = false;
                MappingImageSettings.MaximumLayersUI.VisibleOverride = false;
                MappingImageSettings.TexCoordLevelUI.VisibleOverride = false;
                MappingImageSettings.TexCoordNameUI.VisibleOverride = false;
                MappingImageSettings.TexCoordGeneratorTypeUI.VisibleOverride = false;
                MappingImageSettings.ParameterizerSettings.VisibleOverride = false;
                MappingImageSettings.ChartAggregatorSettings.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.MultisamplingLevelUI.VisibleOverride = false;
                MappingImageSettings.OutputMaterialSettings.GutterSpaceUI.VisibleOverride = false;
                ImpostorFromSingleViewSettings.TwoSidedUI.VisibleOverride = false;
                GlobalSettings.DefaultTangentCalculatorType = ETangentSpaceMethod.MikkTSpace;
            }

            foreach(var materialCaster in MaterialCasters)
            {
                materialCaster.SetTemplateOverrides();
            }

            foreach(var cascadedPipeline in CascadedPipelines)
            {
                cascadedPipeline.SetTemplateOverrides();
            }

        }

        public void CreateUI(TreeView treeView, TreeViewItem treeViewParentItem, bool createInvisibleTreeViewItems)
        {
            if (PipelineType == ESimplygonPipeline.ReductionPipeline)
            {
                ReductionSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                RepairSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                NormalCalculationSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                VisibilitySettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                BoneSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                VertexWeightSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                MappingImageSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

            if (PipelineType == ESimplygonPipeline.RemeshingPipeline)
            {
                RemeshingSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                BoneSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                GeometryCullingSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                VisibilitySettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                MappingImageSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

            if (PipelineType == ESimplygonPipeline.AggregationPipeline)
            {
                AggregationSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                VisibilitySettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                GeometryCullingSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                VertexWeightSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                MappingImageSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudPipeline)
            {
                BillboardCloudSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                MappingImageSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

            if (PipelineType == ESimplygonPipeline.BillboardCloudVegetationPipeline)
            {
                BillboardCloudSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                MappingImageSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

            if (PipelineType == ESimplygonPipeline.FlipbookPipeline)
            {
                FlipbookSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                MappingImageSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

            if (PipelineType == ESimplygonPipeline.ImpostorFromSingleViewPipeline)
            {
                ImpostorFromSingleViewSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
                MappingImageSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

            if (PipelineType == ESimplygonPipeline.OcclusionMeshPipeline)
            {
                OcclusionMeshSettings.CreateUI(treeView, treeViewParentItem, createInvisibleTreeViewItems);
            }

        }

    }

}

