Browse Source

Circle tool refactor and performance improvements

Equbuxu 3 years ago
parent
commit
31dd16d6b0

+ 1 - 1
PixiEditor/Models/Controllers/BitmapOperationsUtility.cs

@@ -122,7 +122,7 @@ namespace PixiEditor.Models.Controllers
             if (!tool.RequiresPreviewLayer)
             if (!tool.RequiresPreviewLayer)
             {
             {
                 tool.Use(Manager.ActiveLayer, mouseMoveCords, color);
                 tool.Use(Manager.ActiveLayer, mouseMoveCords, color);
-                // BitmapChanged was here
+                BitmapChanged?.Invoke(this, null);
             }
             }
             else
             else
             {
             {

+ 0 - 15
PixiEditor/Models/Layers/Layer.cs

@@ -31,8 +31,6 @@ namespace PixiEditor.Models.Layers
 
 
         private string layerHighlightColor = "#666666";
         private string layerHighlightColor = "#666666";
 
 
-        private BitmapPixelChanges singleCache = BitmapPixelChanges.Empty;
-
         public Layer(string name)
         public Layer(string name)
         {
         {
             Name = name;
             Name = name;
@@ -325,19 +323,6 @@ namespace PixiEditor.Models.Layers
             LayerBitmap.SetSRGBPixel(x - OffsetX, y - OffsetY, color);
             LayerBitmap.SetSRGBPixel(x - OffsetX, y - OffsetY, color);
         }
         }
 
 
-        /// <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 SetPixel(Coordinates coordinates, SKColor color, bool dynamicResize = true, bool applyOffset = true)
-        {
-            singleCache.ChangedPixels[coordinates] = color;
-            SetPixels(singleCache, dynamicResize, applyOffset);
-        }
-
         /// <summary>
         /// <summary>
         ///     Applies pixels to layer.
         ///     Applies pixels to layer.
         /// </summary>
         /// </summary>

+ 8 - 4
PixiEditor/Models/Tools/Tools/BrightnessTool.cs

@@ -11,8 +11,6 @@ using PixiEditor.Models.Position;
 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 SkiaSharp;
 using SkiaSharp;
-using System.Collections.Generic;
-using System.Windows.Input;
 
 
 namespace PixiEditor.Models.Tools.Tools
 namespace PixiEditor.Models.Tools.Tools
 {
 {
@@ -21,6 +19,8 @@ namespace PixiEditor.Models.Tools.Tools
         private const float CorrectionFactor = 5f; // Initial correction factor
         private const float CorrectionFactor = 5f; // Initial correction factor
 
 
         private readonly List<Coordinates> pixelsVisited = new List<Coordinates>();
         private readonly List<Coordinates> pixelsVisited = new List<Coordinates>();
+        private List<Coordinates> circleCache = null;
+        private int cachedCircleSize = -1;
 
 
         public BrightnessTool()
         public BrightnessTool()
         {
         {
@@ -81,7 +81,11 @@ namespace PixiEditor.Models.Tools.Tools
                 centeredCoords.Coords2.X,
                 centeredCoords.Coords2.X,
                 centeredCoords.Coords2.Y);
                 centeredCoords.Coords2.Y);
 
 
-            //using var ctx = layer.LayerBitmap.GetBitmapContext();
+            if (cachedCircleSize != toolSize)
+            {
+                cachedCircleSize = toolSize;
+                //circleCache = CircleTool.GenerateMidpointEllipse()
+            }
 
 
             foreach (Coordinates coordinate in rectangleCoordinates)
             foreach (Coordinates coordinate in rectangleCoordinates)
             {
             {
@@ -99,7 +103,7 @@ namespace PixiEditor.Models.Tools.Tools
                 SKColor newColor = ExColor.ChangeColorBrightness(
                 SKColor newColor = ExColor.ChangeColorBrightness(
                     pixel,
                     pixel,
                     correctionFactor);
                     correctionFactor);
-                layer.SetPixel(new Coordinates(coordinate.X, coordinate.Y), newColor);
+                //layer.SetPixel(new Coordinates(coordinate.X, coordinate.Y), newColor);
             }
             }
 
 
         }
         }

+ 55 - 69
PixiEditor/Models/Tools/Tools/CircleTool.cs

@@ -64,19 +64,13 @@ namespace PixiEditor.Models.Tools.Tools
                 float radiusY = (fixedCoordinates.Coords2.Y - fixedCoordinates.Coords1.Y) / 2.0f;
                 float radiusY = (fixedCoordinates.Coords2.Y - fixedCoordinates.Coords1.Y) / 2.0f;
                 float centerX = (fixedCoordinates.Coords1.X + fixedCoordinates.Coords2.X + 1) / 2.0f;
                 float centerX = (fixedCoordinates.Coords1.X + fixedCoordinates.Coords2.X + 1) / 2.0f;
                 float centerY = (fixedCoordinates.Coords1.Y + fixedCoordinates.Coords2.Y + 1) / 2.0f;
                 float centerY = (fixedCoordinates.Coords1.Y + fixedCoordinates.Coords2.Y + 1) / 2.0f;
-                paint.BlendMode = SKBlendMode.Src;
-
-                paint.Color = color;
-                paint.StrokeWidth = thickness;
-                paint.Style = SKPaintStyle.Stroke;
-                var outline = DrawEllipse(layer, color, centerX, centerY, radiusX, radiusY, thickness);
 
 
+                List<Coordinates> outline = GenerateMidpointEllipse(radiusX, radiusY, centerX, centerY);
                 if (hasFillColor)
                 if (hasFillColor)
                 {
                 {
-                    paint.Color = fillColor;
-                    paint.Style = SKPaintStyle.StrokeAndFill;
                     DrawEllipseFill(layer, fillColor, outline);
                     DrawEllipseFill(layer, fillColor, outline);
                 }
                 }
+                DrawEllipseOutline(layer, color, outline, thickness);
 
 
                 // An Idea, use Skia DrawOval for bigger sizes.
                 // An Idea, use Skia DrawOval for bigger sizes.
             }
             }
@@ -84,27 +78,59 @@ namespace PixiEditor.Models.Tools.Tools
             layer.InvokeLayerBitmapChange(dirtyRect);
             layer.InvokeLayerBitmapChange(dirtyRect);
         }
         }
 
 
+        public static void DrawEllipseFill(Layer layer, SKColor color, List<Coordinates> outlineCoordinates)
+        {
+            if (!outlineCoordinates.Any())
+                return;
+
+            int bottom = outlineCoordinates.Max(x => x.Y);
+            int top = outlineCoordinates.Min(x => x.Y);
+
+            using SKPaint fillPaint = new();
+            fillPaint.Color = color;
+            fillPaint.BlendMode = SKBlendMode.Src;
+
+            for (int i = top + 1; i < bottom; i++)
+            {
+                IEnumerable<Coordinates> rowCords = outlineCoordinates.Where(x => x.Y == i);
+                int right = rowCords.Max(x => x.X);
+                int left = rowCords.Min(x => x.X);
+                layer.LayerBitmap.SkiaSurface.Canvas.DrawLine(left - layer.OffsetX, i - layer.OffsetY, right - layer.OffsetX, i - layer.OffsetY, fillPaint);
+            }
+        }
+
         /// <summary>
         /// <summary>
         ///     Calculates ellipse points for specified coordinates and thickness.
         ///     Calculates ellipse points for specified coordinates and thickness.
         /// </summary>
         /// </summary>
         /// <param name="thickness">Thickness of ellipse.</param>
         /// <param name="thickness">Thickness of ellipse.</param>
-        public static IEnumerable<Coordinates> DrawEllipse(Layer layer, SKColor color, float centerX, float centerY, float radiusX, float radiusY, int thickness)
+        public static void DrawEllipseOutline(Layer layer, SKColor color, List<Coordinates> ellipse, int thickness)
         {
         {
-
-            IEnumerable<Coordinates> ellipse = GenerateMidpointEllipse(layer, color, radiusX, radiusY, centerX, centerY);
-            if (thickness > 1)
+            if (thickness == 1)
             {
             {
-                ShapeTool.ThickenShape(layer, color, ellipse, thickness);
+                foreach (var coords in ellipse)
+                {
+                    layer.LayerBitmap.SetSRGBPixel(coords.X - layer.OffsetX, coords.Y - layer.OffsetY, color);
+                }
+            }
+            else
+            {
+                using SKPaint paint = new();
+                paint.Color = color;
+                paint.BlendMode = SKBlendMode.Src;
+                float offsetX = thickness % 2 == 1 ? layer.OffsetX - 0.5f : layer.OffsetX;
+                float offsetY = thickness % 2 == 1 ? layer.OffsetY - 0.5f : layer.OffsetY;
+                foreach (var coords in ellipse)
+                {
+                    layer.LayerBitmap.SkiaSurface.Canvas.DrawCircle(coords.X - offsetX, coords.Y - offsetY, thickness / 2f, paint);
+                }
             }
             }
-
-            return ellipse;
         }
         }
 
 
-        public static List<Coordinates> GenerateMidpointEllipse(Layer layer, SKColor color, double halfWidth, double halfHeight, double centerX, double centerY)
+        public static List<Coordinates> GenerateMidpointEllipse(double halfWidth, double halfHeight, double centerX, double centerY)
         {
         {
             if (halfWidth < 1 || halfHeight < 1)
             if (halfWidth < 1 || halfHeight < 1)
             {
             {
-                return DrawFallbackRectangle(layer, color, halfWidth, halfHeight, centerX, centerY);
+                return GenerateFallbackRectangle(halfWidth, halfHeight, centerX, centerY);
             }
             }
 
 
             // ellipse formula: halfHeight^2 * x^2 + halfWidth^2 * y^2 - halfHeight^2 * halfWidth^2 = 0
             // ellipse formula: halfHeight^2 * x^2 + halfWidth^2 * y^2 - halfHeight^2 * halfWidth^2 = 0
@@ -120,7 +146,7 @@ namespace PixiEditor.Models.Tools.Tools
             // from PI/2 to middle
             // from PI/2 to middle
             do
             do
             {
             {
-                outputCoordinates.AddRange(DrawRegionPoints(layer, color, currentX, centerX, currentY, centerY));
+                AddRegionPoints(outputCoordinates, currentX, centerX, currentY, centerY);
 
 
                 // calculate next pixel coords
                 // calculate next pixel coords
                 currentX++;
                 currentX++;
@@ -142,7 +168,7 @@ namespace PixiEditor.Models.Tools.Tools
             // from middle to 0
             // from middle to 0
             while (currentY - centerY >= 0)
             while (currentY - centerY >= 0)
             {
             {
-                outputCoordinates.AddRange(DrawRegionPoints(layer, color, currentX, centerX, currentY, centerY));
+                AddRegionPoints(outputCoordinates, currentX, centerX, currentY, centerY);
 
 
                 currentY--;
                 currentY--;
                 if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX + 0.5, 2)) +
                 if ((Math.Pow(halfHeight, 2) * Math.Pow(currentX - centerX + 0.5, 2)) +
@@ -156,71 +182,31 @@ namespace PixiEditor.Models.Tools.Tools
             return outputCoordinates;
             return outputCoordinates;
         }
         }
 
 
-        public static void DrawEllipseFill(Layer layer, SKColor color, IEnumerable<Coordinates> outlineCoordinates)
-        {
-            if (!outlineCoordinates.Any())
-            {
-                return;
-            }
-
-            int bottom = outlineCoordinates.Max(x => x.Y);
-            int top = outlineCoordinates.Min(x => x.Y);
-            for (int i = top + 1; i < bottom; i++)
-            {
-                IEnumerable<Coordinates> rowCords = outlineCoordinates.Where(x => x.Y == i);
-                int right = rowCords.Max(x => x.X);
-                int left = rowCords.Min(x => x.X);
-                for (int j = left + 1; j < right; j++)
-                {
-                    layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(j - layer.OffsetX, i - layer.OffsetY), color);
-                }
-            }
-        }
-
-        private static List<Coordinates> DrawFallbackRectangle(Layer layer, SKColor color, double halfWidth, double halfHeight, double centerX, double centerY)
+        private static List<Coordinates> GenerateFallbackRectangle(double halfWidth, double halfHeight, double centerX, double centerY)
         {
         {
             List<Coordinates> coordinates = new List<Coordinates>();
             List<Coordinates> coordinates = new List<Coordinates>();
 
 
             for (double x = centerX - halfWidth; x <= centerX + halfWidth; x++)
             for (double x = centerX - halfWidth; x <= centerX + halfWidth; x++)
             {
             {
-                var cords = new Coordinates((int)x, (int)(centerY - halfHeight));
-                coordinates.Add(cords);
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(cords.X - layer.OffsetX, cords.Y - layer.OffsetY), color);
-
-                cords = new Coordinates((int)x, (int)(centerY + halfHeight));
-                coordinates.Add(cords);
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(cords.X - layer.OffsetX, cords.Y - layer.OffsetY), color);
-
+                coordinates.Add(new Coordinates((int)x, (int)(centerY - halfHeight)));
+                coordinates.Add(new Coordinates((int)x, (int)(centerY + halfHeight)));
             }
             }
 
 
             for (double y = centerY - halfHeight + 1; y <= centerY + halfHeight - 1; y++)
             for (double y = centerY - halfHeight + 1; y <= centerY + halfHeight - 1; y++)
             {
             {
-                var cords = new Coordinates((int)(centerX - halfWidth), (int)y);
-                coordinates.Add(cords);
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(cords.X - layer.OffsetX, cords.Y - layer.OffsetY), color);
-
-                cords = new Coordinates((int)(centerX + halfWidth), (int)y);
-                coordinates.Add(cords);
-                layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(cords.X - layer.OffsetX, cords.Y - layer.OffsetY), color);
-
+                coordinates.Add(new Coordinates((int)(centerX - halfWidth), (int)y));
+                coordinates.Add(new Coordinates((int)(centerX + halfWidth), (int)y));
             }
             }
 
 
             return coordinates;
             return coordinates;
         }
         }
 
 
-        private static Coordinates[] DrawRegionPoints(Layer layer, SKColor color, double x, double xc, double y, double yc)
+        private static void AddRegionPoints(List<Coordinates> coordinates, double x, double xc, double y, double yc)
         {
         {
-            Coordinates[] outputCoordinates = new Coordinates[4];
-            outputCoordinates[0] = new Coordinates((int)Math.Floor(x), (int)Math.Floor(y));
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(outputCoordinates[0].X - layer.OffsetX, outputCoordinates[0].Y - layer.OffsetY), color);
-            outputCoordinates[1] = new Coordinates((int)Math.Floor(-(x - xc) + xc), (int)Math.Floor(y));
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(outputCoordinates[1].X - layer.OffsetX, outputCoordinates[1].Y - layer.OffsetY), color);
-            outputCoordinates[2] = new Coordinates((int)Math.Floor(x), (int)Math.Floor(-(y - yc) + yc));
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(outputCoordinates[2].X - layer.OffsetX, outputCoordinates[2].Y - layer.OffsetY), color);
-            outputCoordinates[3] = new Coordinates((int)Math.Floor(-(x - xc) + xc), (int)Math.Floor(-(y - yc) + yc));
-            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoint(new SKPoint(outputCoordinates[3].X - layer.OffsetX, outputCoordinates[3].Y - layer.OffsetY), color);
-
-            return outputCoordinates;
+            coordinates.Add(new Coordinates((int)Math.Floor(x), (int)Math.Floor(y)));
+            coordinates.Add(new Coordinates((int)Math.Floor(-(x - xc) + xc), (int)Math.Floor(y)));
+            coordinates.Add(new Coordinates((int)Math.Floor(x), (int)Math.Floor(-(y - yc) + yc)));
+            coordinates.Add(new Coordinates((int)Math.Floor(-(x - xc) + xc), (int)Math.Floor(-(y - yc) + yc)));
         }
         }
     }
     }
 }
 }