386 lines
15 KiB
C#
386 lines
15 KiB
C#
using Microsoft.Xna.Framework.Graphics;
|
|
using Microsoft.Xna.Framework;
|
|
using Barotrauma.Particles;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Xml.Linq;
|
|
using System.Text;
|
|
using Barotrauma.Extensions;
|
|
using FarseerPhysics;
|
|
#if DEBUG
|
|
using System.IO;
|
|
using System.Xml;
|
|
#else
|
|
using Barotrauma.IO;
|
|
#endif
|
|
|
|
namespace Barotrauma
|
|
{
|
|
class ParticleEditorScreen : EditorScreen
|
|
{
|
|
private GUIComponent rightPanel, leftPanel;
|
|
private GUIListBox prefabList;
|
|
private GUITextBox filterBox;
|
|
private GUITextBlock filterLabel;
|
|
|
|
private ParticlePrefab selectedPrefab;
|
|
|
|
private readonly ParticleEmitterProperties emitterProperties = new ParticleEmitterProperties(null)
|
|
{
|
|
ScaleMax = 1f,
|
|
ScaleMin = 1f,
|
|
AngleMax = 360f,
|
|
AngleMin = 0,
|
|
ParticlesPerSecond = 1f
|
|
};
|
|
|
|
private ParticleEmitterPrefab emitterPrefab;
|
|
private ParticleEmitter emitter;
|
|
|
|
private readonly Camera cam;
|
|
|
|
public override Camera Cam => cam;
|
|
|
|
private const string sizeRefFilePath = "Content/size_reference.png";
|
|
private readonly Texture2D sizeReference;
|
|
private Vector2 sizeRefPosition = Vector2.Zero;
|
|
private readonly Vector2 sizeRefOrigin;
|
|
private bool sizeRefEnabled;
|
|
|
|
public ParticleEditorScreen()
|
|
{
|
|
cam = new Camera();
|
|
GameMain.Instance.ResolutionChanged += CreateUI;
|
|
CreateUI();
|
|
if (File.Exists(sizeRefFilePath))
|
|
{
|
|
sizeReference = TextureLoader.FromFile(sizeRefFilePath, compress: false);
|
|
sizeRefOrigin = new Vector2(sizeReference.Width / 2f, sizeReference.Height / 2f);
|
|
}
|
|
}
|
|
|
|
private void CreateUI()
|
|
{
|
|
Frame.ClearChildren();
|
|
|
|
leftPanel = new GUIFrame(new RectTransform(new Vector2(0.125f, 1.0f), Frame.RectTransform) { MinSize = new Point(150, 0) },
|
|
style: "GUIFrameLeft");
|
|
var paddedLeftPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.95f), leftPanel.RectTransform, Anchor.CenterLeft) { RelativeOffset = new Vector2(0.02f, 0.0f) })
|
|
{
|
|
RelativeSpacing = 0.01f,
|
|
Stretch = true
|
|
};
|
|
|
|
rightPanel = new GUIFrame(new RectTransform(new Vector2(0.25f, 1.0f), Frame.RectTransform, Anchor.TopRight) { MinSize = new Point(350, 0) },
|
|
style: "GUIFrameRight");
|
|
var paddedRightPanel = new GUILayoutGroup(new RectTransform(new Vector2(0.95f, 0.95f), rightPanel.RectTransform, Anchor.Center) { RelativeOffset = new Vector2(0.02f, 0.0f) })
|
|
{
|
|
RelativeSpacing = 0.01f,
|
|
Stretch = true
|
|
};
|
|
|
|
var saveAllButton = new GUIButton(new RectTransform(new Vector2(1.0f, 0.03f), paddedRightPanel.RectTransform),
|
|
TextManager.Get("editor.saveall"))
|
|
{
|
|
OnClicked = (btn, obj) =>
|
|
{
|
|
SerializeAll();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
new GUIButton(new RectTransform(new Vector2(1.0f, 0.03f), paddedRightPanel.RectTransform),
|
|
TextManager.Get("ParticleEditor.CopyPrefabToClipboard"))
|
|
{
|
|
OnClicked = (btn, obj) =>
|
|
{
|
|
SerializeToClipboard(selectedPrefab);
|
|
return true;
|
|
}
|
|
};
|
|
|
|
new GUIButton(new RectTransform(new Vector2(1.0f, 0.03f), paddedRightPanel.RectTransform),
|
|
TextManager.Get("ParticleEditor.CopyEmitterToClipboard"))
|
|
{
|
|
OnClicked = (btn, obj) =>
|
|
{
|
|
SerializeEmitterToClipboard();
|
|
return true;
|
|
}
|
|
};
|
|
|
|
var emitterListBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.25f), paddedRightPanel.RectTransform));
|
|
new SerializableEntityEditor(emitterListBox.Content.RectTransform, emitterProperties, false, true, elementHeight: 20, titleFont: GUI.SubHeadingFont);
|
|
|
|
var listBox = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.6f), paddedRightPanel.RectTransform));
|
|
|
|
var filterArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.03f), paddedLeftPanel.RectTransform) { MinSize = new Point(0, 20) }, isHorizontal: true)
|
|
{
|
|
Stretch = true,
|
|
UserData = "filterarea"
|
|
};
|
|
|
|
filterLabel = new GUITextBlock(new RectTransform(Vector2.One, filterArea.RectTransform), TextManager.Get("serverlog.filter"), font: GUI.Font) { IgnoreLayoutGroups = true };
|
|
filterBox = new GUITextBox(new RectTransform(new Vector2(0.8f, 1.0f), filterArea.RectTransform), font: GUI.Font);
|
|
filterBox.OnTextChanged += (textBox, text) => { FilterEmitters(text); return true; };
|
|
new GUIButton(new RectTransform(new Vector2(0.05f, 1.0f), filterArea.RectTransform, scaleBasis: ScaleBasis.BothHeight), style: "GUICancelButton")
|
|
{
|
|
OnClicked = (btn, userdata) => { FilterEmitters(""); filterBox.Text = ""; filterBox.Flash(Color.White); return true; }
|
|
};
|
|
|
|
prefabList = new GUIListBox(new RectTransform(new Vector2(1.0f, 0.8f), paddedLeftPanel.RectTransform));
|
|
prefabList.OnSelected += (GUIComponent component, object obj) =>
|
|
{
|
|
cam.Position = Vector2.Zero;
|
|
selectedPrefab = obj as ParticlePrefab;
|
|
emitterPrefab = new ParticleEmitterPrefab(selectedPrefab, emitterProperties);
|
|
emitter = new ParticleEmitter(emitterPrefab);
|
|
listBox.ClearChildren();
|
|
new SerializableEntityEditor(listBox.Content.RectTransform, selectedPrefab, false, true, elementHeight: 20, titleFont: GUI.SubHeadingFont);
|
|
//listBox.Content.RectTransform.NonScaledSize = particlePrefabEditor.RectTransform.NonScaledSize;
|
|
//listBox.UpdateScrollBarSize();
|
|
return true;
|
|
};
|
|
|
|
if (GameMain.ParticleManager != null) { RefreshPrefabList(); }
|
|
}
|
|
|
|
public override void Select()
|
|
{
|
|
base.Select();
|
|
GameMain.ParticleManager.Camera = cam;
|
|
RefreshPrefabList();
|
|
}
|
|
|
|
public override void Deselect()
|
|
{
|
|
base.Deselect();
|
|
GameMain.ParticleManager.Camera = GameMain.GameScreen.Cam;
|
|
filterBox.Text = "";
|
|
}
|
|
|
|
private void RefreshPrefabList()
|
|
{
|
|
prefabList.ClearChildren();
|
|
|
|
var particlePrefabs = GameMain.ParticleManager.GetPrefabList();
|
|
foreach (ParticlePrefab particlePrefab in particlePrefabs)
|
|
{
|
|
new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.05f), prefabList.Content.RectTransform) { MinSize = new Point(0, 20) },
|
|
particlePrefab.DisplayName)
|
|
{
|
|
Padding = Vector4.Zero,
|
|
UserData = particlePrefab
|
|
};
|
|
}
|
|
}
|
|
|
|
private void FilterEmitters(string text)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(text))
|
|
{
|
|
filterLabel.Visible = true;
|
|
prefabList.Content.Children.ForEach(c => c.Visible = true);
|
|
return;
|
|
}
|
|
|
|
text = text.ToLower();
|
|
filterLabel.Visible = false;
|
|
foreach (GUIComponent child in prefabList.Content.Children)
|
|
{
|
|
if (!(child is GUITextBlock textBlock)) { continue; }
|
|
textBlock.Visible = textBlock.Text.ToLower().Contains(text);
|
|
}
|
|
}
|
|
|
|
private void SerializeAll()
|
|
{
|
|
Barotrauma.IO.Validation.SkipValidationInDebugBuilds = true;
|
|
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.Particles))
|
|
{
|
|
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
|
if (doc == null) { continue; }
|
|
|
|
var prefabList = GameMain.ParticleManager.GetPrefabList();
|
|
foreach (ParticlePrefab prefab in prefabList)
|
|
{
|
|
foreach (XElement element in doc.Root.Elements())
|
|
{
|
|
if (!element.Name.ToString().Equals(prefab.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
|
|
SerializableProperty.SerializeProperties(prefab, element, true);
|
|
}
|
|
}
|
|
|
|
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
|
|
{
|
|
Indent = true,
|
|
OmitXmlDeclaration = true,
|
|
NewLineOnAttributes = true
|
|
};
|
|
|
|
using (var writer = XmlWriter.Create(configFile.Path, settings))
|
|
{
|
|
doc.WriteTo(writer);
|
|
writer.Flush();
|
|
}
|
|
}
|
|
Barotrauma.IO.Validation.SkipValidationInDebugBuilds = false;
|
|
}
|
|
|
|
private void SerializeEmitterToClipboard()
|
|
{
|
|
XElement element = new XElement(nameof(ParticleEmitter));
|
|
if (selectedPrefab is { } prefab)
|
|
{
|
|
element.Add(new XAttribute("particle", prefab.Identifier));
|
|
}
|
|
|
|
SerializableProperty.SerializeProperties(emitterProperties, element, saveIfDefault: false, ignoreEditable: true);
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
|
|
{
|
|
OmitXmlDeclaration = true
|
|
};
|
|
|
|
using (var writer = System.Xml.XmlWriter.Create(sb, settings))
|
|
{
|
|
element.WriteTo(writer);
|
|
writer.Flush();
|
|
}
|
|
|
|
Clipboard.SetText(sb.ToString());
|
|
}
|
|
|
|
private void SerializeToClipboard(ParticlePrefab prefab)
|
|
{
|
|
if (prefab == null) { return; }
|
|
|
|
System.Xml.XmlWriterSettings settings = new System.Xml.XmlWriterSettings
|
|
{
|
|
Indent = true,
|
|
OmitXmlDeclaration = true,
|
|
NewLineOnAttributes = true
|
|
};
|
|
|
|
XElement originalElement = null;
|
|
foreach (ContentFile configFile in GameMain.Instance.GetFilesOfType(ContentType.Particles))
|
|
{
|
|
XDocument doc = XMLExtensions.TryLoadXml(configFile.Path);
|
|
if (doc == null) { continue; }
|
|
|
|
var prefabList = GameMain.ParticleManager.GetPrefabList();
|
|
foreach (ParticlePrefab otherPrefab in prefabList)
|
|
{
|
|
foreach (XElement subElement in doc.Root.Elements())
|
|
{
|
|
if (!subElement.Name.ToString().Equals(prefab.Name, StringComparison.OrdinalIgnoreCase)) { continue; }
|
|
SerializableProperty.SerializeProperties(prefab, subElement, true);
|
|
originalElement = subElement;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (originalElement == null)
|
|
{
|
|
originalElement = new XElement(prefab.Name);
|
|
SerializableProperty.SerializeProperties(prefab, originalElement, true);
|
|
}
|
|
|
|
StringBuilder sb = new StringBuilder();
|
|
using (var writer = System.Xml.XmlWriter.Create(sb, settings))
|
|
{
|
|
originalElement.WriteTo(writer);
|
|
writer.Flush();
|
|
}
|
|
|
|
Clipboard.SetText(sb.ToString());
|
|
}
|
|
|
|
public override void Update(double deltaTime)
|
|
{
|
|
cam.MoveCamera((float)deltaTime, allowMove: true, allowZoom: GUI.MouseOn == null);
|
|
|
|
if (GUI.MouseOn is null && PlayerInput.PrimaryMouseButtonHeld())
|
|
{
|
|
sizeRefPosition = cam.ScreenToWorld(PlayerInput.MousePosition);
|
|
}
|
|
|
|
if (PlayerInput.SecondaryMouseButtonClicked())
|
|
{
|
|
CreateContextMenu();
|
|
}
|
|
|
|
if (selectedPrefab != null && emitter != null)
|
|
{
|
|
emitter.Emit((float) deltaTime, Vector2.Zero);
|
|
}
|
|
|
|
GameMain.ParticleManager.Update((float)deltaTime);
|
|
}
|
|
|
|
private void CreateContextMenu()
|
|
{
|
|
GUIContextMenu.CreateContextMenu
|
|
(
|
|
new ContextMenuOption("subeditor.editbackgroundcolor", true, CreateBackgroundColorPicker),
|
|
new ContextMenuOption("editor.togglereferencecharacter", true, delegate { sizeRefEnabled = !sizeRefEnabled; })
|
|
);
|
|
}
|
|
|
|
public override void Draw(double deltaTime, GraphicsDevice graphics, SpriteBatch spriteBatch)
|
|
{
|
|
cam.UpdateTransform();
|
|
GameMain.ParticleManager.UpdateTransforms();
|
|
|
|
//-------------------------------------------------------
|
|
|
|
spriteBatch.Begin(SpriteSortMode.Deferred,
|
|
BlendState.NonPremultiplied,
|
|
null, null, null, null,
|
|
cam.Transform);
|
|
|
|
graphics.Clear(BackgroundColor);
|
|
|
|
GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.AlphaBlend);
|
|
GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.AlphaBlend);
|
|
|
|
spriteBatch.End();
|
|
|
|
spriteBatch.Begin(SpriteSortMode.Deferred,
|
|
BlendState.Additive,
|
|
null, null, null, null,
|
|
cam.Transform);
|
|
|
|
GameMain.ParticleManager.Draw(spriteBatch, false, false, ParticleBlendState.Additive);
|
|
GameMain.ParticleManager.Draw(spriteBatch, true, false, ParticleBlendState.Additive);
|
|
|
|
spriteBatch.End();
|
|
|
|
if (sizeRefEnabled && !(sizeReference is null))
|
|
{
|
|
spriteBatch.Begin(SpriteSortMode.Deferred,
|
|
BlendState.NonPremultiplied,
|
|
null, null, null, null,
|
|
cam.Transform);
|
|
|
|
Vector2 pos = sizeRefPosition;
|
|
pos.Y = -pos.Y;
|
|
spriteBatch.Draw(sizeReference, pos, null, Color.White, 0f, sizeRefOrigin, new Vector2(0.4f), SpriteEffects.None, 0f);
|
|
|
|
spriteBatch.End();
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
|
|
spriteBatch.Begin(SpriteSortMode.Deferred, null, GUI.SamplerState, null, GameMain.ScissorTestEnable);
|
|
|
|
GUI.Draw(Cam, spriteBatch);
|
|
|
|
spriteBatch.End();
|
|
}
|
|
}
|
|
}
|