3 using System.Collections.Generic;
7 using Microsoft.Xna.Framework;
8 using Microsoft.Xna.Framework.Graphics;
9 using Microsoft.Xna.Framework.Input;
15 private struct EditorImageContainer
17 public float Rotation;
19 public Vector2 Position;
32 DrawTarget = DrawTarget
36 public static EditorImageContainer?
Load(XElement element)
38 string path = element.GetAttributeString(
"path",
"");
39 if (
string.IsNullOrWhiteSpace(path)) {
return null; }
41 Vector2 pos = element.GetAttributeVector2(
"pos", Vector2.Zero);
42 float scale = element.GetAttributeFloat(
"scale", 1f);
43 float rotation = element.GetAttributeFloat(
"rotation", 0f);
44 float opacity = element.GetAttributeFloat(
"opacity", 1f);
45 string drawTargetString = element.GetAttributeString(
"drawtarget",
"");
51 return new EditorImageContainer
58 DrawTarget = drawTarget
62 public static EditorImageContainer ImageToContainer(
EditorImage img)
64 return new EditorImageContainer
75 public static XElement SerializeImage(EditorImageContainer image)
77 return new XElement(
"image",
78 new XAttribute(
"pos", XMLExtensions.Vector2ToString(image.Position)),
79 new XAttribute(
"rotation", image.Rotation),
80 new XAttribute(
"opacity", image.Opacity),
81 new XAttribute(
"path", image.Path),
82 new XAttribute(
"scale", image.Scale),
83 new XAttribute(
"drawtarget", image.DrawTarget.ToString()));
87 private readonly List<EditorImageContainer> PendingImages =
new List<EditorImageContainer>();
89 public readonly List<EditorImage>
Images =
new List<EditorImage>();
91 private readonly List<EditorImage> screenImages =
new List<EditorImage>(),
92 worldImages =
new List<EditorImage>();
97 private Vector2 textSize = Vector2.Zero;
99 public void Save(XElement element)
101 XElement saveElement =
new XElement(
"editorimages");
104 EditorImageContainer container = EditorImageContainer.ImageToContainer(image);
105 saveElement.Add(EditorImageContainer.SerializeImage(container));
108 foreach (EditorImageContainer container
in PendingImages)
110 saveElement.Add(EditorImageContainer.SerializeImage(container));
113 element.Add(saveElement);
116 public void Load(XElement element)
118 Clear(alsoPending:
true);
120 foreach (var subElement
in element.Elements())
122 EditorImageContainer? tempImage = EditorImageContainer.Load(subElement);
123 if (tempImage !=
null)
125 PendingImages.Add(tempImage.Value);
132 editModeText = TextManager.Get(
"SubEditor.ImageEditingMode");
133 textSize = GUIStyle.LargeFont.MeasureString(editModeText);
135 TryLoadPendingImages();
138 private void TryLoadPendingImages()
140 if (PendingImages.Count == 0) {
return; }
142 Clear(alsoPending:
false);
144 foreach (EditorImageContainer pendingImage
in PendingImages)
146 EditorImage img = pendingImage.CreateImage();
147 if (img.Image ==
null) {
continue; }
149 img.UpdateRectangle();
152 UpdateImageCategories();
153 PendingImages.Clear();
156 public void Clear(
bool alsoPending =
false)
160 img.
Image?.Dispose();
164 screenImages.Clear();
168 PendingImages.Clear();
198 UpdateImageCategories();
234 UpdateImageCategories();
240 private void UpdateImageCategories()
242 screenImages.Clear();
250 worldImages.Add(image);
253 screenImages.Add(image);
261 string home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
262 if (!Directory.Exists(home)) {
return; }
264 FileSelection.OnFileSelected = file =>
269 UpdateImageCategories();
270 GameSettings.SaveCurrentConfig();
273 FileSelection.ClearFileTypeFilters();
274 FileSelection.AddFileTypeFilter(
"PNG",
"*.png");
275 FileSelection.AddFileTypeFilter(
"JPEG",
"*.jpg, *.jpeg");
276 FileSelection.AddFileTypeFilter(
"All files",
"*.*");
277 FileSelection.SelectFileTypeFilter(
"*.png");
278 FileSelection.CurrentDirectory = home;
279 FileSelection.Open =
true;
286 DrawImages(spriteBatch, cam);
288 spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
290 GUI.DrawString(spriteBatch, textPos, editModeText, GUIStyle.Yellow, Color.Black * 0.4f, 8, GUIStyle.LargeFont);
298 DrawImages(spriteBatch, cam);
301 private void DrawImages(SpriteBatch spriteBatch,
Camera cam)
303 if (screenImages.Count > 0)
305 spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState);
308 image.
Draw(spriteBatch);
315 if (worldImages.Count > 0)
317 spriteBatch.Begin(SpriteSortMode.Deferred, samplerState: GUI.SamplerState, transformMatrix: cam.
Transform);
318 foreach (EditorImage image
in worldImages)
320 image.Draw(spriteBatch);
321 if (
EditorMode) { image.DrawEditing(spriteBatch, cam); }
347 private float prevAngle;
348 private bool disableMove;
349 private bool isDragging;
351 private readonly Dictionary<string, Widget> widgets =
new Dictionary<string, Widget>();
382 if (widgets.Values.Any(w => w.IsSelected)) {
return; }
397 mouseSpeed /= cam.
Zoom;
428 private void DrawWidgets(SpriteBatch spriteBatch)
430 float widgetSize =
Image ==
null ? 100f : Math.Max(
Image.Width,
Image.Height) / 2f;
439 Widget currentWidget = GetWidget(
"transform", size, width, widget =>
441 widget.MouseDown += () =>
443 widget.Color = GUIStyle.Green;
447 widget.Deselected += () =>
449 widget.Color = Color.Yellow;
452 widget.MouseHeld += (deltaTime) =>
456 Scale = Math.Abs(distance) / widgetSize;
457 if (PlayerInput.IsShiftDown())
459 const float rotationStep = (float) (Math.PI / 4f);
463 if (PlayerInput.IsCtrlDown())
465 const float scaleStep = 0.1f;
466 Scale = (float) Math.Round(
Scale / scaleStep) * scaleStep;
471 widget.PreUpdate += (deltaTime) =>
475 widget.DrawPos =
new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
476 widget.DrawPos = Screen.Selected.Cam.WorldToScreen(widget.DrawPos);
478 widget.PostUpdate += (deltaTime) =>
482 widget.DrawPos = Screen.Selected.Cam.ScreenToWorld(widget.DrawPos);
483 widget.DrawPos =
new Vector2(widget.DrawPos.X, -widget.DrawPos.Y);
485 widget.PreDraw += (sprtBtch, deltaTime) =>
487 widget.Tooltip = $
"Scale: {Math.Round(Scale, 2)}\n" +
488 $
"Rotation: {(int) MathHelper.ToDegrees(Rotation)}";
489 float rotation =
Rotation - (float) Math.PI / 2f;
490 widget.DrawPos =
Position +
new Vector2((
float) Math.Cos(rotation), (float) Math.Sin(rotation)) * (
Scale * widgetSize);
491 widget.Update(deltaTime);
495 currentWidget.Draw(spriteBatch, (
float) Timing.Step);
496 GUI.DrawLine(spriteBatch,
Position, currentWidget.DrawPos, GUIStyle.Green, width: width);
499 private float GetRotationAngle(Vector2 drawPosition)
501 Vector2 rotationVector =
GetMousePos() - drawPosition;
502 rotationVector.Normalize();
503 double angle = Math.Atan2(MathHelper.ToRadians(rotationVector.Y), MathHelper.ToRadians(rotationVector.X));
506 angle = Math.Abs(angle - prevAngle) < Math.Abs((angle + Math.PI * 2) - prevAngle) ? angle : angle + Math.PI * 2;
510 angle = Math.Abs(angle - prevAngle) < Math.Abs((angle - Math.PI * 2) - prevAngle) ? angle : angle - Math.PI * 2;
513 angle = MathHelper.Clamp((
float) angle, -((
float) Math.PI * 2), (
float) Math.PI * 2);
514 prevAngle = (float) angle;
515 return (
float) angle;
518 private Widget GetWidget(
string id,
int size,
float thickness = 1f, Action<Widget>? initMethod =
null)
520 if (!widgets.TryGetValue(
id, out Widget? widget))
522 widget =
new Widget(
id, size,
WidgetShape.Rectangle)
524 Color = Color.Yellow,
525 RequireMouseOn =
false
527 widgets.Add(
id, widget);
528 initMethod?.Invoke(widget);
532 widget.Thickness = thickness;
548 public void Draw(SpriteBatch spriteBatch)
550 if (
Image ==
null) {
return; }
561 width = (int) (width / cam.
Zoom);
564 GUI.DrawRectangle(spriteBatch, bounds,
Selected ? GUIStyle.Red : GUIStyle.Green, thickness: width);
567 DrawWidgets(spriteBatch);
Vector2 WorldToScreen(Vector2 coords)
Vector2 ScreenToWorld(Vector2 coords)
EditorImage(string path, Vector2 pos)
DrawTargetType DrawTarget
void Update(float deltaTime)
void DrawEditing(SpriteBatch spriteBatch, Camera cam)
void Draw(SpriteBatch spriteBatch)
void Clear(bool alsoPending=false)
void Save(XElement element)
void Update(float deltaTime)
readonly List< EditorImage > Images
void Draw(SpriteBatch spriteBatch, Camera cam)
void Load(XElement element)
void DrawEditing(SpriteBatch spriteBatch, Camera cam)
static int GraphicsHeight
static bool DisableSelect