Browse Source

Make floodfill work

Equbuxu 3 years ago
parent
commit
d4145b85a7

+ 29 - 27
PixiEditor/Models/Tools/Tools/FloodFill.cs → PixiEditor/Models/Tools/Tools/FloodFillTool.cs

@@ -1,19 +1,20 @@
-using PixiEditor.Models.Controllers;
-using PixiEditor.Models.DataHolders;
+using PixiEditor.Helpers.Extensions;
+using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Position;
 using SkiaSharp;
 using SkiaSharp;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Diagnostics;
+using System.Windows;
 
 
 namespace PixiEditor.Models.Tools.Tools
 namespace PixiEditor.Models.Tools.Tools
 {
 {
-    public class FloodFill : BitmapOperationTool
+    public class FloodFillTool : BitmapOperationTool
     {
     {
         private BitmapManager BitmapManager { get; }
         private BitmapManager BitmapManager { get; }
+        private SKPaint fillPaint = new SKPaint() { BlendMode = SKBlendMode.Src };
 
 
-
-        public FloodFill(BitmapManager bitmapManager)
+        public FloodFillTool(BitmapManager bitmapManager)
         {
         {
             ActionDisplay = "Press on an area to fill it.";
             ActionDisplay = "Press on an area to fill it.";
             BitmapManager = bitmapManager;
             BitmapManager = bitmapManager;
@@ -32,7 +33,6 @@ namespace PixiEditor.Models.Tools.Tools
 
 
         public void LinearFill(Layer layer, Coordinates startingCoords, SKColor newColor)
         public void LinearFill(Layer layer, Coordinates startingCoords, SKColor newColor)
         {
         {
-            List<Coordinates> changedCoords = new List<Coordinates>();
             Queue<FloodFillRange> floodFillQueue = new Queue<FloodFillRange>();
             Queue<FloodFillRange> floodFillQueue = new Queue<FloodFillRange>();
             SKColor colorToReplace = layer.GetPixelWithOffset(startingCoords.X, startingCoords.Y);
             SKColor colorToReplace = layer.GetPixelWithOffset(startingCoords.X, startingCoords.Y);
             if ((colorToReplace.Alpha == 0 && newColor.Alpha == 0) ||
             if ((colorToReplace.Alpha == 0 && newColor.Alpha == 0) ||
@@ -45,23 +45,25 @@ namespace PixiEditor.Models.Tools.Tools
                 return;
                 return;
             var visited = new bool[width * height];
             var visited = new bool[width * height];
 
 
-            PerformLinearFill(layer, changedCoords, floodFillQueue, startingCoords, width, colorToReplace, visited);
-            PerformFloodFIll(layer, changedCoords, floodFillQueue, colorToReplace, width, height, visited);
+            fillPaint.Color = newColor;
+
+            Int32Rect dirtyRect = new Int32Rect(startingCoords.X, startingCoords.Y, 1, 1);
+
+            PerformLinearFill(layer, floodFillQueue, startingCoords, width, colorToReplace, ref dirtyRect, visited);
+            PerformFloodFIll(layer, floodFillQueue, colorToReplace, ref dirtyRect, width, height, visited);
+
+            layer.InvokeLayerBitmapChange(dirtyRect);
         }
         }
 
 
         private void PerformLinearFill(
         private void PerformLinearFill(
-            Layer layer,
-            List<Coordinates> changedCoords, Queue<FloodFillRange> floodFillQueue,
-            Coordinates coords, int width, SKColor colorToReplace, bool[] visited)
+            Layer layer, Queue<FloodFillRange> floodFillQueue,
+            Coordinates coords, int width, SKColor colorToReplace, ref Int32Rect dirtyRect, bool[] visited)
         {
         {
             // Find the Left Edge of the Color Area
             // Find the Left Edge of the Color Area
             int fillXLeft = coords.X;
             int fillXLeft = coords.X;
             while (true)
             while (true)
             {
             {
-                // Fill with the color
-                changedCoords.Add(new Coordinates(fillXLeft, coords.Y));
-
-                // Indicate that this pixel has already been checked and filled
+                // Indicate that this pixel has been checked
                 int pixelIndex = (coords.Y * width) + fillXLeft;
                 int pixelIndex = (coords.Y * width) + fillXLeft;
                 visited[pixelIndex] = true;
                 visited[pixelIndex] = true;
 
 
@@ -71,15 +73,12 @@ namespace PixiEditor.Models.Tools.Tools
                 if (fillXLeft < 0 || visited[pixelIndex - 1] || layer.GetPixelWithOffset(fillXLeft, coords.Y) != colorToReplace)
                 if (fillXLeft < 0 || visited[pixelIndex - 1] || layer.GetPixelWithOffset(fillXLeft, coords.Y) != colorToReplace)
                     break;
                     break;
             }
             }
-            int lastFilledPixelLeft = fillXLeft + 1;
-
+            int lastCheckedPixelLeft = fillXLeft + 1;
 
 
             // Find the Right Edge of the Color Area
             // Find the Right Edge of the Color Area
             int fillXRight = coords.X;
             int fillXRight = coords.X;
             while (true)
             while (true)
             {
             {
-                changedCoords.Add(new Coordinates(fillXRight, coords.Y));
-
                 int pixelIndex = (coords.Y * width) + fillXRight;
                 int pixelIndex = (coords.Y * width) + fillXRight;
                 visited[pixelIndex] = true;
                 visited[pixelIndex] = true;
 
 
@@ -87,17 +86,20 @@ namespace PixiEditor.Models.Tools.Tools
                 if (fillXRight >= width || visited[pixelIndex + 1] || layer.GetPixelWithOffset(fillXRight, coords.Y) != colorToReplace)
                 if (fillXRight >= width || visited[pixelIndex + 1] || layer.GetPixelWithOffset(fillXRight, coords.Y) != colorToReplace)
                     break;
                     break;
             }
             }
-            int lastFilledPixelRight = fillXRight - 1;
+            int lastCheckedPixelRight = fillXRight - 1;
 
 
+            layer.DynamicResizeAbsolute(lastCheckedPixelRight, coords.Y, lastCheckedPixelLeft, coords.Y);
+            int relativeY = coords.Y - layer.OffsetY;
+            layer.LayerBitmap.SkiaSurface.Canvas.DrawLine(lastCheckedPixelLeft - layer.OffsetX, relativeY, lastCheckedPixelRight - layer.OffsetX + 1, relativeY, fillPaint);
+            dirtyRect = dirtyRect.Expand(new Int32Rect(lastCheckedPixelLeft, coords.Y, lastCheckedPixelRight - lastCheckedPixelLeft + 1, 1));
 
 
-            FloodFillRange range = new FloodFillRange(lastFilledPixelLeft, lastFilledPixelRight, coords.Y);
+            FloodFillRange range = new FloodFillRange(lastCheckedPixelLeft, lastCheckedPixelRight, coords.Y);
             floodFillQueue.Enqueue(range);
             floodFillQueue.Enqueue(range);
         }
         }
 
 
         private void PerformFloodFIll(
         private void PerformFloodFIll(
-            Layer layer,
-            List<Coordinates> changedCords, Queue<FloodFillRange> floodFillQueue,
-            SKColor colorToReplace, int width, int height, bool[] pixelsVisited)
+            Layer layer, Queue<FloodFillRange> floodFillQueue,
+            SKColor colorToReplace, ref Int32Rect dirtyRect, int width, int height, bool[] pixelsVisited)
         {
         {
             while (floodFillQueue.Count > 0)
             while (floodFillQueue.Count > 0)
             {
             {
@@ -113,10 +115,10 @@ namespace PixiEditor.Models.Tools.Tools
                     //START LOOP UPWARDS
                     //START LOOP UPWARDS
                     //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance
                     //if we're not above the top of the bitmap and the pixel above this one is within the color tolerance
                     if (range.Y > 0 && (!pixelsVisited[upPixelIndex]) && layer.GetPixelWithOffset(i, upY) == colorToReplace)
                     if (range.Y > 0 && (!pixelsVisited[upPixelIndex]) && layer.GetPixelWithOffset(i, upY) == colorToReplace)
-                        PerformLinearFill(layer, changedCords, floodFillQueue, new Coordinates(i, upY), width, colorToReplace, pixelsVisited);
+                        PerformLinearFill(layer, floodFillQueue, new Coordinates(i, upY), width, colorToReplace, ref dirtyRect, pixelsVisited);
                     //START LOOP DOWNWARDS
                     //START LOOP DOWNWARDS
-                    if (range.Y < (height - 1) && (!pixelsVisited[downPixelxIndex]) && layer.GetPixel(i, downY) == colorToReplace)
-                        PerformLinearFill(layer, changedCords, floodFillQueue, new Coordinates(i, downY), width, colorToReplace, pixelsVisited);
+                    if (range.Y < (height - 1) && (!pixelsVisited[downPixelxIndex]) && layer.GetPixelWithOffset(i, downY) == colorToReplace)
+                        PerformLinearFill(layer, floodFillQueue, new Coordinates(i, downY), width, colorToReplace, ref dirtyRect, pixelsVisited);
                     downPixelxIndex++;
                     downPixelxIndex++;
                     upPixelIndex++;
                     upPixelIndex++;
                 }
                 }

+ 2 - 2
PixiEditor/Models/Tools/Tools/MagicWandTool.cs

@@ -17,7 +17,7 @@ namespace PixiEditor.Models.Tools.Tools
 {
 {
     public class MagicWandTool : ReadonlyTool, ICachedDocumentTool
     public class MagicWandTool : ReadonlyTool, ICachedDocumentTool
     {
     {
-        private readonly FloodFill floodFill;
+        private readonly FloodFillTool floodFill;
 
 
         private static Selection ActiveSelection { get => ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection; }
         private static Selection ActiveSelection { get => ViewModelMain.Current.BitmapManager.ActiveDocument.ActiveSelection; }
 
 
@@ -69,7 +69,7 @@ namespace PixiEditor.Models.Tools.Tools
 
 
         public MagicWandTool(BitmapManager manager)
         public MagicWandTool(BitmapManager manager)
         {
         {
-            floodFill = new FloodFill(manager);
+            floodFill = new FloodFillTool(manager);
             BitmapManager = manager;
             BitmapManager = manager;
 
 
             Toolbar = new MagicWandToolbar();
             Toolbar = new MagicWandToolbar();

+ 1 - 1
PixiEditor/ViewModels/SubViewModels/Main/ToolsViewModel.cs

@@ -46,7 +46,7 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
         {
         {
             ToolSet = new ObservableCollection<Tool>(
             ToolSet = new ObservableCollection<Tool>(
                 new ToolBuilder(services)
                 new ToolBuilder(services)
-                .Add<MoveViewportTool>().Add<MoveTool>().Add<PenTool>().Add<SelectTool>().Add<MagicWandTool>().Add<FloodFill>()
+                .Add<MoveViewportTool>().Add<MoveTool>().Add<PenTool>().Add<SelectTool>().Add<MagicWandTool>().Add<FloodFillTool>()
                 .Add<LineTool>().Add<CircleTool>().Add<RectangleTool>().Add<EraserTool>().Add<ColorPickerTool>()
                 .Add<LineTool>().Add<CircleTool>().Add<RectangleTool>().Add<EraserTool>().Add<ColorPickerTool>()
                 .Add<BrightnessTool>().Add<ZoomTool>()
                 .Add<BrightnessTool>().Add<ZoomTool>()
                 .Build());
                 .Build());

+ 1 - 1
PixiEditor/ViewModels/ViewModelMain.cs

@@ -178,7 +178,7 @@ namespace PixiEditor.ViewModels
                         CreateToolShortcut<RectangleTool>(Key.R, "Select Rectangle Tool"),
                         CreateToolShortcut<RectangleTool>(Key.R, "Select Rectangle Tool"),
                         CreateToolShortcut<CircleTool>(Key.C, "Select Circle Tool"),
                         CreateToolShortcut<CircleTool>(Key.C, "Select Circle Tool"),
                         CreateToolShortcut<LineTool>(Key.L, "Select Line Tool"),
                         CreateToolShortcut<LineTool>(Key.L, "Select Line Tool"),
-                        CreateToolShortcut<FloodFill>(Key.G, "Select Flood Fill Tool"),
+                        CreateToolShortcut<FloodFillTool>(Key.G, "Select Flood Fill Tool"),
                         CreateToolShortcut<BrightnessTool>(Key.U, "Select Brightness Tool"),
                         CreateToolShortcut<BrightnessTool>(Key.U, "Select Brightness Tool"),
                         CreateToolShortcut<MoveTool>(Key.V, "Select Move Tool"),
                         CreateToolShortcut<MoveTool>(Key.V, "Select Move Tool"),
                         CreateToolShortcut<SelectTool>(Key.M, "Select Select Tool"),
                         CreateToolShortcut<SelectTool>(Key.M, "Select Select Tool"),