Browse Source

Pixel perfect algorithm works, thickness and apply transparent WIP

flabbet 4 years ago
parent
commit
cd9b74d997

+ 16 - 8
PixiEditor/Models/Controllers/BitmapOperationsUtility.cs

@@ -16,7 +16,9 @@ namespace PixiEditor.Models.Controllers
 {
 {
     public class BitmapOperationsUtility
     public class BitmapOperationsUtility
     {
     {
-        private LayerChange[] lastModifiedLayers;
+        public List<LayerChange> PreviewLayerChanges => previewLayerChanges;
+
+        private List<LayerChange> previewLayerChanges;
 
 
         private Coordinates lastMousePos;
         private Coordinates lastMousePos;
 
 
@@ -79,12 +81,12 @@ namespace PixiEditor.Models.Controllers
         /// </summary>
         /// </summary>
         public void ApplyPreviewLayer()
         public void ApplyPreviewLayer()
         {
         {
-            if (lastModifiedLayers == null)
+            if (previewLayerChanges == null)
             {
             {
                 return;
                 return;
             }
             }
 
 
-            foreach (var modifiedLayer in lastModifiedLayers)
+            foreach (var modifiedLayer in previewLayerChanges)
             {
             {
                 Layer layer = Manager.ActiveDocument.Layers[modifiedLayer.LayerIndex];
                 Layer layer = Manager.ActiveDocument.Layers[modifiedLayer.LayerIndex];
 
 
@@ -96,6 +98,8 @@ namespace PixiEditor.Models.Controllers
                     modifiedLayer.LayerIndex));
                     modifiedLayer.LayerIndex));
                 Manager.ActiveDocument.GeneratePreviewLayer();
                 Manager.ActiveDocument.GeneratePreviewLayer();
             }
             }
+
+            previewLayerChanges = null;
         }
         }
 
 
         private void UseTool(List<Coordinates> mouseMoveCords, BitmapOperationTool tool, Color color)
         private void UseTool(List<Coordinates> mouseMoveCords, BitmapOperationTool tool, Color color)
@@ -197,17 +201,21 @@ namespace PixiEditor.Models.Controllers
                     Manager.PrimaryColor);
                     Manager.PrimaryColor);
                 BitmapPixelChanges[] changes = modifiedLayers.Select(x => x.PixelChanges).ToArray();
                 BitmapPixelChanges[] changes = modifiedLayers.Select(x => x.PixelChanges).ToArray();
                 Manager.ActiveDocument.PreviewLayer.SetPixels(BitmapPixelChanges.CombineOverride(changes));
                 Manager.ActiveDocument.PreviewLayer.SetPixels(BitmapPixelChanges.CombineOverride(changes));
-                if (clearPreviewLayer || lastModifiedLayers == null)
+
+                foreach (var modifiedLayer in modifiedLayers)
+                {
+                    modifiedLayer.PixelChanges = modifiedLayer.PixelChanges.RemoveTransparentPixels();
+                }
+
+                if (clearPreviewLayer || previewLayerChanges == null)
                 {
                 {
-                    lastModifiedLayers = modifiedLayers;
+                    previewLayerChanges = new List<LayerChange>(modifiedLayers);
                 }
                 }
                 else
                 else
                 {
                 {
                     for (int i = 0; i < modifiedLayers.Length; i++)
                     for (int i = 0; i < modifiedLayers.Length; i++)
                     {
                     {
-                        lastModifiedLayers[i] = new LayerChange(
-                            BitmapPixelChanges.CombineOverride(
-                                lastModifiedLayers[i].PixelChanges, modifiedLayers[i].PixelChanges), lastModifiedLayers[i].LayerIndex);
+                        previewLayerChanges.Add(modifiedLayers[i]);
                     }
                     }
                 }
                 }
             }
             }

+ 6 - 0
PixiEditor/Models/DataHolders/BitmapPixelChanges.cs

@@ -1,6 +1,7 @@
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.ObjectModel;
+using System.Diagnostics;
 using System.Linq;
 using System.Linq;
 using System.Windows.Media;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Media.Imaging;
@@ -87,5 +88,10 @@ namespace PixiEditor.Models.DataHolders
 
 
             return new BitmapPixelChanges(dict);
             return new BitmapPixelChanges(dict);
         }
         }
+
+        public BitmapPixelChanges RemoveTransparentPixels()
+        {
+            return new BitmapPixelChanges(ChangedPixels.Where(x => x.Value.A > 0).ToDictionary(y => y.Key, y => y.Value));
+        }
     }
     }
 }
 }

+ 2 - 0
PixiEditor/Models/Tools/ShapeTool.cs

@@ -18,6 +18,8 @@ namespace PixiEditor.Models.Tools
             Toolbar = new BasicShapeToolbar();
             Toolbar = new BasicShapeToolbar();
         }
         }
 
 
+        //TODO: Add cache for lines 31, 32
+
         public abstract override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color);
         public abstract override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color);
 
 
         protected IEnumerable<Coordinates> GetThickShape(IEnumerable<Coordinates> shape, int thickness)
         protected IEnumerable<Coordinates> GetThickShape(IEnumerable<Coordinates> shape, int thickness)

+ 17 - 0
PixiEditor/Models/Tools/ToolSettings/SettingValueChangedEventArgs.cs

@@ -0,0 +1,17 @@
+using System;
+
+namespace PixiEditor.Models.Tools.ToolSettings
+{
+    public class SettingValueChangedEventArgs<T> : EventArgs
+    {
+        public T OldValue { get; set; }
+
+        public T NewValue { get; set; }
+
+        public SettingValueChangedEventArgs(T oldValue, T newValue)
+        {
+            OldValue = oldValue;
+            NewValue = newValue;
+        }
+    }
+}

+ 12 - 2
PixiEditor/Models/Tools/ToolSettings/Settings/Setting.cs

@@ -1,4 +1,5 @@
-using System.Windows.Controls;
+using System;
+using System.Windows.Controls;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers;
 
 
 namespace PixiEditor.Models.Tools.ToolSettings.Settings
 namespace PixiEditor.Models.Tools.ToolSettings.Settings
@@ -14,13 +15,22 @@ namespace PixiEditor.Models.Tools.ToolSettings.Settings
         {
         {
         }
         }
 
 
+        public event EventHandler<SettingValueChangedEventArgs<T>> ValueChanged;
+
         public new T Value
         public new T Value
         {
         {
             get => (T)base.Value;
             get => (T)base.Value;
             set
             set
             {
             {
+                T oldValue = default;
+                if (base.Value != null)
+                {
+                    oldValue = Value;
+                }
+
                 base.Value = value;
                 base.Value = value;
-                RaisePropertyChanged("Value");
+                ValueChanged?.Invoke(this, new SettingValueChangedEventArgs<T>(oldValue, Value));
+                RaisePropertyChanged(nameof(Value));
             }
             }
         }
         }
     }
     }

+ 2 - 2
PixiEditor/Models/Tools/ToolSettings/Toolbars/Toolbar.cs

@@ -16,7 +16,7 @@ namespace PixiEditor.Models.Tools.ToolSettings.Toolbars
         ///     Gets setting in toolbar by name.
         ///     Gets setting in toolbar by name.
         /// </summary>
         /// </summary>
         /// <param name="name">Setting name, non case sensitive.</param>
         /// <param name="name">Setting name, non case sensitive.</param>
-        /// <returns></returns>
+        /// <returns>Generic Setting.</returns>
         public virtual Setting GetSetting(string name)
         public virtual Setting GetSetting(string name)
         {
         {
             return Settings.FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.CurrentCultureIgnoreCase));
             return Settings.FirstOrDefault(x => string.Equals(x.Name, name, StringComparison.CurrentCultureIgnoreCase));
@@ -26,7 +26,7 @@ namespace PixiEditor.Models.Tools.ToolSettings.Toolbars
         ///     Gets setting of given type T in toolbar by name.
         ///     Gets setting of given type T in toolbar by name.
         /// </summary>
         /// </summary>
         /// <param name="name">Setting name, non case sensitive.</param>
         /// <param name="name">Setting name, non case sensitive.</param>
-        /// <returns></returns>
+        /// <returns>Setting of given type.</returns>
         public T GetSetting<T>(string name)
         public T GetSetting<T>(string name)
             where T : Setting
             where T : Setting
         {
         {

+ 75 - 10
PixiEditor/Models/Tools/Tools/PenTool.cs

@@ -9,17 +9,20 @@ using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.ToolSettings;
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
+using PixiEditor.ViewModels;
 
 
 namespace PixiEditor.Models.Tools.Tools
 namespace PixiEditor.Models.Tools.Tools
 {
 {
-    public class PenTool : BitmapOperationTool
+    public class PenTool : ShapeTool
     {
     {
         private readonly SizeSetting toolSizeSetting;
         private readonly SizeSetting toolSizeSetting;
         private readonly BoolSetting pixelPerfectSetting;
         private readonly BoolSetting pixelPerfectSetting;
         private readonly LineTool lineTool;
         private readonly LineTool lineTool;
-        private IEnumerable<Coordinates> lastCords = Array.Empty<Coordinates>();
+        private Coordinates[] lastChangedPixels = new Coordinates[3];
+        private byte changedPixelsindex = 0;
 
 
         public PenTool()
         public PenTool()
         {
         {
@@ -29,28 +32,90 @@ namespace PixiEditor.Models.Tools.Tools
             Toolbar = new PenToolbar();
             Toolbar = new PenToolbar();
             toolSizeSetting = Toolbar.GetSetting<SizeSetting>("ToolSize");
             toolSizeSetting = Toolbar.GetSetting<SizeSetting>("ToolSize");
             pixelPerfectSetting = Toolbar.GetSetting<BoolSetting>("PixelPerfectEnabled");
             pixelPerfectSetting = Toolbar.GetSetting<BoolSetting>("PixelPerfectEnabled");
+            pixelPerfectSetting.ValueChanged += PixelPerfectSettingValueChanged;
             lineTool = new LineTool();
             lineTool = new LineTool();
-            RequiresPreviewLayer = true;
             ClearPreviewLayerOnEachIteration = false;
             ClearPreviewLayerOnEachIteration = false;
         }
         }
 
 
-        public override void AfterAddedUndo(UndoManager undoManager)
+        public override void OnRecordingLeftMouseDown(MouseEventArgs e)
         {
         {
-            base.AfterAddedUndo(undoManager);
-            lastCords = Array.Empty<Coordinates>();
+            base.OnRecordingLeftMouseDown(e);
+            changedPixelsindex = 0;
+            lastChangedPixels = new Coordinates[3];
         }
         }
 
 
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
         {
             Coordinates startingCords = coordinates.Length > 1 ? coordinates[1] : coordinates[0];
             Coordinates startingCords = coordinates.Length > 1 ? coordinates[1] : coordinates[0];
-            BitmapPixelChanges pixels = Draw(startingCords, coordinates[0], color, toolSizeSetting.Value);
+            BitmapPixelChanges pixels = Draw(startingCords, coordinates[0], color, toolSizeSetting.Value, pixelPerfectSetting.Value);
             return Only(pixels, layer);
             return Only(pixels, layer);
         }
         }
 
 
-        public BitmapPixelChanges Draw(Coordinates startingCoords, Coordinates latestCords, Color color, int toolSize)
+        public BitmapPixelChanges Draw(Coordinates startingCoords, Coordinates latestCords, Color color, int toolSize, bool pixelPerfect = false)
         {
         {
-            return BitmapPixelChanges.FromSingleColoredArray(
-                lineTool.CreateLine(startingCoords, latestCords, toolSize), color);
+            if (!pixelPerfect)
+            {
+                return BitmapPixelChanges.FromSingleColoredArray(
+                    lineTool.CreateLine(startingCoords, latestCords, toolSize), color);
+            }
+
+            var latestPixels = lineTool.CreateLine(startingCoords, latestCords, 1);
+            if (latestPixels.Count() == 1)
+            {
+                lastChangedPixels[changedPixelsindex] = latestPixels.First();
+            }
+            else
+            {
+                lastChangedPixels[changedPixelsindex] = latestPixels.ElementAt(1);
+            }
+
+            if (changedPixelsindex == 2)
+            {
+                var changes = ApplyPixelPerfectToPixels(
+                    lastChangedPixels[0],
+                    lastChangedPixels[1],
+                    lastChangedPixels[2],
+                    color,
+                    toolSize);
+
+                if (changes.ChangedPixels[lastChangedPixels[1]].A != 0)
+                {
+                    lastChangedPixels[0] = lastChangedPixels[1];
+                    lastChangedPixels[1] = lastChangedPixels[2];
+                    changedPixelsindex = 2;
+                }
+                else
+                {
+                    lastChangedPixels[0] = lastChangedPixels[2];
+                    changedPixelsindex = 1;
+                }
+
+                return changes;
+            }
+
+            changedPixelsindex += changedPixelsindex >= 2 ? 0 : 1;
+
+            return BitmapPixelChanges.FromSingleColoredArray(GetThickShape(latestPixels, toolSize), color);
+        }
+
+        private BitmapPixelChanges ApplyPixelPerfectToPixels(Coordinates p1, Coordinates p2, Coordinates p3, Color color, int toolSize)
+        {
+            if (Math.Abs(p3.X - p1.X) == 1 && Math.Abs(p3.Y - p1.Y) == 1)
+            {
+                var changes = BitmapPixelChanges.FromSingleColoredArray(GetThickShape(new Coordinates[] { p1, p3 }, toolSize), color);
+                changes.ChangedPixels.AddRangeNewOnly(
+                    BitmapPixelChanges.FromSingleColoredArray(
+                        GetThickShape(new[] { p2 }, toolSize),
+                        System.Windows.Media.Colors.Transparent).ChangedPixels);
+                return changes;
+            }
+
+            return BitmapPixelChanges.FromSingleColoredArray(GetThickShape(new Coordinates[] { p2, p3 }.Distinct(), toolSize), color);
+        }
+
+        private void PixelPerfectSettingValueChanged(object sender, SettingValueChangedEventArgs<bool> e)
+        {
+            RequiresPreviewLayer = e.NewValue;
         }
         }
     }
     }
 }
 }