Browse Source

Fixed FloodFillTool

flabbet 5 years ago
parent
commit
c7e37b64ef

+ 45 - 5
PixiEditor/Models/Layers/Layer.cs

@@ -110,14 +110,41 @@ namespace PixiEditor.Models.Layers
         }
 
         /// <summary>
-        ///     Returns pixel color by x and y coordinates relative to document using (x - OffsetX + 1) formula.
+        /// Returns clone of layer
+        /// </summary>
+        /// <returns></returns>
+        public Layer Clone()
+        {
+            return new Layer(LayerBitmap.Clone())
+            {
+                _isVisible = this._isVisible,
+                Name = this.Name,
+                Offset = this.Offset,
+                MaxHeight = this.MaxHeight,
+                MaxWidth = this.MaxWidth
+            };
+        }
+
+        /// <summary>
+        ///     Converts coordinates relative to viewport to relative to layer
+        /// </summary>
+        /// <param name="cords"></param>
+        /// <returns></returns>
+        public Coordinates GetRelativePosition(Coordinates cords)
+        {
+            return new Coordinates(cords.X - OffsetX, cords.Y - OffsetY);
+        }
+
+        /// <summary>
+        ///     Returns pixel color by x and y coordinates relative to document using (x - OffsetX) formula.
         /// </summary>
         /// <param name="x">Viewport relative X</param>
         /// <param name="y">Viewport relative Y</param>
         /// <returns>Color of a pixel</returns>
         public Color GetPixelWithOffset(int x, int y)
         {
-            return GetPixel(x - OffsetX + 1, y - OffsetY + 1);
+            Coordinates cords = GetRelativePosition(new Coordinates(x, y));
+            return GetPixel(cords.X, cords.Y);
         }
 
         /// <summary>
@@ -130,12 +157,24 @@ namespace PixiEditor.Models.Layers
         {
             if (x > Width - 1 || x < 0 || y > Height - 1 || y < 0)
             {
-                return System.Windows.Media.Colors.Transparent;
+                return Color.FromArgb(0, 0, 0, 0);
             }
 
             return LayerBitmap.GetPixel(x, y);
         }
 
+        /// <summary>
+        ///     Applies pixel to layer
+        /// </summary>
+        /// <param name="coordinates">Position of pixel</param>
+        /// <param name="color">Color of pixel</param>
+        /// <param name="dynamicResize">Resizes bitmap to fit content</param>
+        /// <param name="applyOffset">Converts pixels coordinates to relative to bitmap</param>
+        public void ApplyPixel(Coordinates coordinates, Color color, bool dynamicResize = true, bool applyOffset = true)
+        {
+            ApplyPixels(BitmapPixelChanges.FromSingleColoredArray(new []{ coordinates }, color), dynamicResize, applyOffset);
+        }
+
         /// <summary>
         ///     Applies pixels to layer
         /// </summary>
@@ -148,7 +187,7 @@ namespace PixiEditor.Models.Layers
             if(dynamicResize)
                 DynamicResize(pixels);
             if(applyOffset)
-                pixels.ChangedPixels = ApplyOffset(pixels.ChangedPixels);
+                pixels.ChangedPixels = GetRelativePosition(pixels.ChangedPixels);
             LastRelativeCoordinates = pixels.ChangedPixels;
 
             using (var ctx = LayerBitmap.GetBitmapContext())
@@ -162,7 +201,7 @@ namespace PixiEditor.Models.Layers
             ClipIfNecessary();
         }
 
-        private Dictionary<Coordinates, Color> ApplyOffset(Dictionary<Coordinates, Color> changedPixels)
+        private Dictionary<Coordinates, Color> GetRelativePosition(Dictionary<Coordinates, Color> changedPixels)
         {
             return changedPixels.ToDictionary(d => new Coordinates(d.Key.X - OffsetX, d.Key.Y - OffsetY),
                 d => d.Value);
@@ -185,6 +224,7 @@ namespace PixiEditor.Models.Layers
         /// <param name="pixels"></param>
         public void DynamicResize(BitmapPixelChanges pixels)
         {
+            if (pixels.ChangedPixels.Count == 0) return;
             ResetOffset(pixels);
             var borderData = ExtractBorderData(pixels);
             DoubleCords minMaxCords = borderData.Item1;

+ 5 - 0
PixiEditor/Models/Tools/BitmapOperationTool.cs

@@ -10,5 +10,10 @@ namespace PixiEditor.Models.Tools
         public bool RequiresPreviewLayer { get; set; }
         public bool UseDefaultUndoMethod { get; set; } = true;
         public abstract LayerChange[] Use(Layer layer, Coordinates[] mouseMove, Color color);
+
+        protected LayerChange[] Only(BitmapPixelChanges changes, Layer layer)
+        {
+            return new[] { new LayerChange(changes, layer) };
+        }
     }
 }

+ 28 - 21
PixiEditor/Models/Tools/Tools/FloodFill.cs

@@ -5,6 +5,7 @@ using System.Windows.Media.Imaging;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.ViewModels;
 
 namespace PixiEditor.Models.Tools.Tools
 {
@@ -19,39 +20,45 @@ namespace PixiEditor.Models.Tools.Tools
 
         public override LayerChange[] Use(Layer layer, Coordinates[] coordinates, Color color)
         {
-            return new[] {new LayerChange(ForestFire(layer, coordinates[0], color), layer)};
+            return Only(ForestFire(layer, coordinates[0], color), layer);
         }
 
         public BitmapPixelChanges ForestFire(Layer layer, Coordinates startingCoords, Color newColor)
         {
             List<Coordinates> changedCoords = new List<Coordinates>();
 
-            WriteableBitmap bitmap = layer.LayerBitmap.Clone();
-            Color colorToReplace = bitmap.GetPixel(startingCoords.X, startingCoords.Y);
+            Layer clone = layer.Clone();
+            int width = ViewModelMain.Current.BitmapManager.ActiveDocument.Width;
+            int height = ViewModelMain.Current.BitmapManager.ActiveDocument.Height;
 
-            var stack = new Stack<Tuple<int, int>>();
-            stack.Push(Tuple.Create(startingCoords.X, startingCoords.Y));
+            Color colorToReplace = layer.GetPixelWithOffset(startingCoords.X, startingCoords.Y);
 
-            bitmap.Lock();
-            while (stack.Count > 0)
+            var stack = new Stack<Coordinates>();
+            stack.Push(new Coordinates(startingCoords.X, startingCoords.Y));
+            
+            using(clone.LayerBitmap.GetBitmapContext(ReadWriteMode.ReadWrite))
             {
-                var point = stack.Pop();
-                if (point.Item1 < 0 || point.Item1 > layer.Height - 1) continue;
-                if (point.Item2 < 0 || point.Item2 > layer.Width - 1) continue;
-                if (bitmap.GetPixel(point.Item1, point.Item2) == newColor) continue;
-
-                if (bitmap.GetPixel(point.Item1, point.Item2) == colorToReplace)
+                while (stack.Count > 0)
                 {
-                    changedCoords.Add(new Coordinates(point.Item1, point.Item2));
-                    bitmap.SetPixel(point.Item1, point.Item2, newColor);
-                    stack.Push(Tuple.Create(point.Item1, point.Item2 - 1));
-                    stack.Push(Tuple.Create(point.Item1 + 1, point.Item2));
-                    stack.Push(Tuple.Create(point.Item1, point.Item2 + 1));
-                    stack.Push(Tuple.Create(point.Item1 - 1, point.Item2));
+                    var cords = stack.Pop();
+                    var relativeCords = clone.GetRelativePosition(cords);
+
+                    if (cords.X < 0 || cords.X > width - 1) continue;
+                    if (cords.Y < 0 || cords.Y > height - 1) continue;
+                    if (clone.GetPixel(relativeCords.X, relativeCords.Y) == newColor) continue;
+
+                    if (clone.GetPixel(relativeCords.X, relativeCords.Y) == colorToReplace)
+                    {
+                        changedCoords.Add(new Coordinates(cords.X, cords.Y));
+                        clone.ApplyPixel(new Coordinates(cords.X, cords.Y), newColor);
+                        stack.Push(new Coordinates(cords.X, cords.Y - 1));
+                        stack.Push(new Coordinates(cords.X + 1, cords.Y));
+                        stack.Push(new Coordinates(cords.X, cords.Y + 1));
+                        stack.Push(new Coordinates(cords.X - 1, cords.Y));
+                    }
                 }
-            }
 
-            bitmap.Unlock();
+            }
             return BitmapPixelChanges.FromSingleColoredArray(changedCoords.ToArray(), newColor);
         }
     }