// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved. using System; using System.Collections.Generic; using FlaxEditor.Content; using FlaxEditor.CustomEditors; using FlaxEditor.Scripting; using FlaxEditor.Surface; using FlaxEditor.Viewport.Previews; using FlaxEngine; // ReSharper disable UnusedMember.Local // ReSharper disable UnusedMember.Global // ReSharper disable MemberCanBePrivate.Local namespace FlaxEditor.Windows.Assets { /// /// Particle Emitter window allows to view and edit asset. /// /// /// /// public sealed class ParticleEmitterWindow : VisjectSurfaceWindow { private readonly ScriptType[] _newParameterTypes = { new ScriptType(typeof(float)), new ScriptType(typeof(Texture)), new ScriptType(typeof(CubeTexture)), new ScriptType(typeof(GPUTexture)), new ScriptType(typeof(ChannelMask)), new ScriptType(typeof(bool)), new ScriptType(typeof(int)), new ScriptType(typeof(Vector2)), new ScriptType(typeof(Vector3)), new ScriptType(typeof(Vector4)), new ScriptType(typeof(Color)), new ScriptType(typeof(Quaternion)), new ScriptType(typeof(Transform)), new ScriptType(typeof(Matrix)), }; /// /// The properties proxy object. /// private sealed class PropertiesProxy { [EditorOrder(1000), EditorDisplay("Parameters"), CustomEditor(typeof(ParametersEditor)), NoSerialize] // ReSharper disable once UnusedAutoPropertyAccessor.Local public ParticleEmitterWindow Window { get; set; } [HideInEditor, Serialize] // ReSharper disable once UnusedMember.Local public List Parameters { get => Window.Surface.Parameters; set => throw new Exception("No setter."); } /// /// Gathers parameters from the specified ParticleEmitter. /// /// The ParticleEmitter window. public void OnLoad(ParticleEmitterWindow particleEmitterWin) { // Link Window = particleEmitterWin; } /// /// Clears temporary data. /// public void OnClean() { // Unlink Window = null; } } /// /// The graph parameters preview proxy object. /// private sealed class PreviewProxy { [EditorDisplay("Parameters"), CustomEditor(typeof(Editor)), NoSerialize] // ReSharper disable once UnusedAutoPropertyAccessor.Local public ParticleEmitterWindow Window; private class Editor : CustomEditor { public override DisplayStyle Style => DisplayStyle.InlineIntoParent; public override void Initialize(LayoutElementsContainer layout) { var window = (ParticleEmitterWindow)Values[0]; var parameters = window.Preview.PreviewActor.Parameters; var data = SurfaceUtils.InitGraphParameters(parameters); SurfaceUtils.DisplayGraphParameters(layout, data, (instance, parameter, tag) => ((ParticleEmitterWindow)instance).Preview.PreviewActor.GetParameterValue(string.Empty, parameter.Name), (instance, value, parameter, tag) => ((ParticleEmitterWindow)instance).Preview.PreviewActor.SetParameterValue(string.Empty, parameter.Name, value), Values); } } } private readonly PropertiesProxy _properties; private Tab _previewTab; /// public ParticleEmitterWindow(Editor editor, AssetItem item) : base(editor, item, true) { // Asset preview _preview = new ParticleEmitterPreview(true) { PlaySimulation = true, Parent = _split2.Panel1 }; // Asset properties proxy _properties = new PropertiesProxy(); // Preview properties editor _previewTab = new Tab("Preview"); _previewTab.Presenter.Select(new PreviewProxy { Window = this, }); _tabs.AddTab(_previewTab); // Surface _surface = new ParticleEmitterSurface(this, Save, _undo) { Parent = _split1.Panel1, Enabled = false }; // Toolstrip _toolstrip.AddSeparator(); _toolstrip.AddButton(editor.Icons.Code64, ShowSourceCode).LinkTooltip("Show generated shader source code"); _toolstrip.AddButton(editor.Icons.Docs64, () => Platform.OpenUrl(Utilities.Constants.DocsUrl + "manual/particles/index.html")).LinkTooltip("See documentation to learn more"); } private void ShowSourceCode() { var source = Editor.GetShaderSourceCode(_asset); Utilities.Utils.ShowSourceCodeWindow(source, "Particle Emitter GPU Simulation Source", RootWindow.Window); } /// public override void OnParamRenameUndo() { base.OnParamRenameUndo(); _refreshPropertiesOnLoad = true; } /// public override void OnParamAddUndo() { base.OnParamAddUndo(); _refreshPropertiesOnLoad = true; } /// public override void OnParamRemoveUndo() { base.OnParamRemoveUndo(); _refreshPropertiesOnLoad = true; } /// public override IEnumerable NewParameterTypes => _newParameterTypes; /// public override void SetParameter(int index, object value) { try { Preview.PreviewActor.Parameters[index].Value = value; } catch { // Ignored } base.SetParameter(index, value); } /// protected override void UnlinkItem() { _properties.OnClean(); _preview.Emitter = null; base.UnlinkItem(); } /// protected override void OnAssetLinked() { _preview.Emitter = _asset; base.OnAssetLinked(); } /// public override string SurfaceName => "Particle Emitter"; /// public override byte[] SurfaceData { get => _asset.LoadSurface(true); set { if (_asset.SaveSurface(value)) { _surface.MarkAsEdited(); Editor.LogError("Failed to save Particle Emitter surface data"); } _asset.Reload(); _asset.WaitForLoaded(); _preview.PreviewActor.ResetSimulation(); _previewTab.Presenter.BuildLayoutOnUpdate(); } } /// protected override bool LoadSurface() { // Load surface graph if (_surface.Load()) { // Error Editor.LogError("Failed to load Particle Emitter surface."); return true; } // Init asset properties and parameters proxy _properties.OnLoad(this); _previewTab.Presenter.BuildLayoutOnUpdate(); return false; } /// protected override bool SaveSurface() { _surface.Save(); return false; } /// protected override void OnSurfaceEditingStart() { _propertiesEditor.Select(_properties); base.OnSurfaceEditingStart(); } /// protected override bool SaveToOriginal() { // Copy shader cache from the temporary Particle Emitter (will skip compilation on Reload - faster) Guid dstId = _item.ID; Guid srcId = _asset.ID; Editor.Internal_CopyCache(ref dstId, ref srcId); return base.SaveToOriginal(); } } }