Browse Source

Implemented custom brushes

flabbet 3 years ago
parent
commit
f775e81156

+ 13 - 29
PixiEditor/Models/Controllers/BitmapManager.cs

@@ -25,7 +25,8 @@ namespace PixiEditor.Models.Controllers
         private Tool selectedTool;
         private Coordinates? startPosition = null;
         private int halfSize;
-        private SKPaint _highlightPaint;
+        private SKColor _highlightColor;
+        private PenTool _highlightPen;
 
         public BitmapManager()
         {
@@ -39,11 +40,11 @@ namespace PixiEditor.Models.Controllers
             BitmapOperations = new BitmapOperationsUtility(this);
             ReadonlyToolUtility = new ReadonlyToolUtility();
             DocumentChanged += BitmapManager_DocumentChanged;
-            _highlightPaint = new SKPaint
-            {
-                Color = new SKColor(0, 0, 0, 77),
-                Style = SKPaintStyle.StrokeAndFill
+            _highlightPen = new PenTool(this)
+            {
+                AutomaticallyResizeCanvas = false
             };
+            _highlightColor = new SKColor(0, 0, 0, 77);
         }
 
         public event EventHandler<DocumentChangedEventArgs> DocumentChanged;
@@ -250,33 +251,16 @@ namespace PixiEditor.Models.Controllers
                 halfSize = (int)Math.Floor(ToolSize / 2f);
                 previewLayer.CreateNewBitmap(ToolSize, ToolSize);
 
-                if (ToolSize != 3)
-                {
-                    float sizeMod = ToolSize % 2 == 0 ? 0 : 0.5f;
-                    if (ToolSize == 1)
-                    {
-                        sizeMod = 1;
-                    }
+                Coordinates cords = new Coordinates(halfSize, halfSize);
 
-                    AdjustOffset(newPosition, previewLayer);
-                    int centerX = newPosition.X - previewLayer.OffsetX;
-                    int centerY = newPosition.Y - previewLayer.OffsetY;
+                previewLayer.Offset = new Thickness(0, 0, 0, 0);
+                _highlightPen.Draw(previewLayer, cords, cords, _highlightColor, ToolSize);
 
-                    previewLayer.LayerBitmap.SkiaSurface.Canvas
-                    .DrawOval(
-                        centerX,
-                        centerY,
-                        halfSize + sizeMod,
-                        halfSize + sizeMod,
-                        _highlightPaint);
-                }
-                else
-                {
-                    previewLayer.LayerBitmap.SkiaSurface.Canvas.Clear(_highlightPaint.Color);
-                }
+                AdjustOffset(newPosition, previewLayer);
 
-                previewLayer.InvokeLayerBitmapChange();
-            }
+            }
+
+            previewLayer.InvokeLayerBitmapChange();
 
             AdjustOffset(newPosition, previewLayer);
 

+ 7 - 0
PixiEditor/Models/Position/Coordinates.cs

@@ -7,6 +7,8 @@ namespace PixiEditor.Models.Position
     [DebuggerDisplay("({DebuggerDisplay,nq})")]
     public struct Coordinates
     {
+        public static Coordinates Zero => new Coordinates(0, 0);
+
         private string DebuggerDisplay => ToString();
 
         public Coordinates(int x, int y)
@@ -29,6 +31,11 @@ namespace PixiEditor.Models.Position
             return new Coordinates(coordiantes.X - size, coordiantes.Y - size);
         }
 
+        public static Coordinates operator +(Coordinates coordiantes, int size)
+        {
+            return new Coordinates(coordiantes.X + size, coordiantes.Y + size);
+        }
+
         public static Coordinates operator -(Coordinates coordiantes1, Coordinates coordinates2)
         {
             return new Coordinates(coordiantes1.X - coordinates2.X, coordiantes1.Y - coordinates2.Y);

+ 23 - 0
PixiEditor/Models/Tools/Brushes/CrossBrush.cs

@@ -0,0 +1,23 @@
+using PixiEditor.Models.Layers;
+using PixiEditor.Models.Position;
+using SkiaSharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PixiEditor.Models.Tools.Brushes
+{
+    public class CrossBrush : CustomBrush
+    {
+        public static readonly int[,] CrossMatrix = new int[3, 3]
+        {
+            { 0, 1, 0 },
+            { 1, 1, 1 },
+            { 0, 1, 0 }
+        };
+
+        public override int[,] BrushMatrix => CrossMatrix;
+    }
+}

+ 87 - 0
PixiEditor/Models/Tools/Brushes/CustomBrush.cs

@@ -0,0 +1,87 @@
+using PixiEditor.Models.Layers;
+using PixiEditor.Models.Position;
+using SkiaSharp;
+using System;
+using System.Collections.Generic;
+
+namespace PixiEditor.Models.Tools.Brushes
+{
+    public abstract class CustomBrush
+    {
+        public abstract int[,] BrushMatrix { get; }
+
+        public SKPoint[] BakedMatrix => _cachedBakedMatrix;
+
+
+        private SKPoint[] _cachedBakedMatrix;
+        private SKPoint[] _cachedGetAtPointBakedMatrix;
+
+        public CustomBrush()
+        {
+            InitMatrix();
+        }
+
+        //We can easily handle .pixi to brush parsing
+
+        /// <summary>
+        ///     Creates an SKPoint[] array from BrushMatrix. All values grater than 0 will be placed in final array.
+        /// </summary>
+        /// <returns>Points array, ready to be drawn on Skia canvas.</returns>
+        public virtual SKPoint[] BakeMatrix()
+        {
+            List<SKPoint> result = new List<SKPoint>();
+
+            int brushHeight = BrushMatrix.GetLength(0);
+            int brushWidth = BrushMatrix.GetLength(1);
+
+            int centerX = (int)Math.Floor(brushWidth / 2f);
+            int centerY = (int)Math.Floor(brushHeight / 2f);
+
+            for (int i = 0; i < brushHeight; i++)
+            {
+                for (int j = 0; j < brushWidth; j++)
+                {
+                    if (BrushMatrix[i, j] > 0)
+                    {
+                        result.Add(new SKPoint(centerX - j, centerY - i));
+                    }
+                }
+            }
+
+            return result.ToArray();
+        }
+
+        /// <summary>
+        ///     Calculates BrushMatrix for given point.
+        /// </summary>
+        /// <param name="point">Point to calculate BrushMatrix for.</param>
+        /// <returns>SKPoints for given coordinate.</returns>
+        public SKPoint[] GetAtPoint(Coordinates point, int offsetX, int offsetY)
+        {
+            if (_cachedGetAtPointBakedMatrix == null)
+            {
+                InitMatrix();
+            }
+
+            for(int i = 0; i < _cachedGetAtPointBakedMatrix.Length; i++)
+            {
+                _cachedGetAtPointBakedMatrix[i] = new SKPoint(
+                    _cachedBakedMatrix[i].X + point.X - offsetX,
+                    _cachedBakedMatrix[i].Y + point.Y - offsetY);
+
+            }
+
+            return _cachedGetAtPointBakedMatrix;
+        }
+
+        private void InitMatrix()
+        {
+            if (_cachedBakedMatrix == null)
+            {
+                _cachedBakedMatrix = BakeMatrix();
+                _cachedGetAtPointBakedMatrix = new SKPoint[_cachedBakedMatrix.Length];
+                Array.Copy(_cachedBakedMatrix, _cachedGetAtPointBakedMatrix, BakedMatrix.Length);
+            }
+        }
+    }
+}

+ 18 - 0
PixiEditor/Models/Tools/Brushes/PointBrush.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PixiEditor.Models.Tools.Brushes
+{
+    public class PointBrush : CustomBrush
+    {
+        public static readonly int[,] PointMatrix = new int[,]
+        {
+            { 1 }
+        };
+
+        public override int[,] BrushMatrix => PointMatrix;
+    }
+}

+ 6 - 1
PixiEditor/Models/Tools/Tools/LineTool.cs

@@ -16,6 +16,8 @@ namespace PixiEditor.Models.Tools.Tools
         private List<Coordinates> linePoints = new List<Coordinates>();
         private SKPaint paint = new SKPaint() { Style = SKPaintStyle.Stroke };
 
+        public bool AutomaticallyResizeCanvas { get; set; } = true;
+
         public static List<Coordinates> GetBresenhamLine(Coordinates start, Coordinates end)
         {
             List<Coordinates> output = new List<Coordinates>();
@@ -163,7 +165,10 @@ namespace PixiEditor.Models.Tools.Tools
                 dirtyY,
                 Math.Max(x1, x) + thickness - dirtyX,
                 Math.Max(y1, y) + thickness - dirtyY);
-            layer.DynamicResizeAbsolute(dirtyRect.X + dirtyRect.Width - 1, dirtyRect.Y + dirtyRect.Height - 1, dirtyRect.X, dirtyRect.Y);
+            if (AutomaticallyResizeCanvas)
+            {
+                layer.DynamicResizeAbsolute(dirtyRect.X + dirtyRect.Width - 1, dirtyRect.Y + dirtyRect.Height - 1, dirtyRect.X, dirtyRect.Y);
+            }
 
             x -= layer.OffsetX;
             y -= layer.OffsetY;

+ 50 - 4
PixiEditor/Models/Tools/Tools/PenTool.cs

@@ -1,6 +1,7 @@
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
+using PixiEditor.Models.Tools.Brushes;
 using PixiEditor.Models.Tools.ToolSettings.Settings;
 using PixiEditor.Models.Tools.ToolSettings.Toolbars;
 using SkiaSharp;
@@ -25,6 +26,10 @@ namespace PixiEditor.Models.Tools.Tools
 
         private BitmapManager BitmapManager { get; }
 
+        private Dictionary<int, CustomBrush> _customBrushes = new Dictionary<int, CustomBrush>();
+
+        private bool _drawCustomBrush = false;
+
         public PenTool(BitmapManager bitmapManager)
         {
             Cursor = Cursors.Pen;
@@ -36,11 +41,16 @@ namespace PixiEditor.Models.Tools.Tools
             BitmapManager = bitmapManager;
             paint.BlendMode = SKBlendMode.Src;
             lineTool = new LineTool();
+            lineTool.AutomaticallyResizeCanvas = AutomaticallyResizeCanvas;
+            _customBrushes.Add(1, new PointBrush());
+            _customBrushes.Add(3, new CrossBrush());
         }
 
         public override string Tooltip => "Standard brush. (B)";
         public override bool UsesShift => false;
 
+        public bool AutomaticallyResizeCanvas { get; set; } = true;
+
         public override void OnRecordingLeftMouseDown(MouseEventArgs e)
         {
             base.OnRecordingLeftMouseDown(e);
@@ -52,7 +62,10 @@ namespace PixiEditor.Models.Tools.Tools
         public override void Use(Layer layer, List<Coordinates> coordinates, SKColor color)
         {
             Coordinates startingCords = coordinates.Count > 1 ? coordinates[1] : coordinates[0];
-            layer.DynamicResizeAbsolute(coordinates.Max(x => x.X), coordinates.Max(x => x.Y), coordinates.Min(x => x.X), coordinates.Min(x => x.Y));
+            if (AutomaticallyResizeCanvas)
+            {
+                layer.DynamicResizeAbsolute(coordinates.Max(x => x.X), coordinates.Max(x => x.Y), coordinates.Min(x => x.X), coordinates.Min(x => x.Y));
+            }
             Draw(
                 layer,
                 startingCords,
@@ -70,9 +83,24 @@ namespace PixiEditor.Models.Tools.Tools
             SKBlendMode blendMode = SKBlendMode.Src)
         {
 
-            SKStrokeCap cap = toolSize == 1 || toolSize == 3 ? SKStrokeCap.Square : SKStrokeCap.Round;
+            SKStrokeCap cap = SKStrokeCap.Round;
+            _drawCustomBrush = _customBrushes.ContainsKey(toolSize);
+            CustomBrush customBrush = null;
+            paint.Color = color;
+
+            if (_drawCustomBrush)
+            {
+                cap = SKStrokeCap.Butt;
+                customBrush = _customBrushes[toolSize];
+            }
+
             if (!pixelPerfect)
             {
+                if(_drawCustomBrush)
+                {
+                    DrawCustomBrush(layer, latestCords, customBrush);
+                }
+
                 lineTool.DrawLine(layer, startingCoords, latestCords, color, toolSize, blendMode, cap);
                 return;
             }
@@ -84,6 +112,11 @@ namespace PixiEditor.Models.Tools.Tools
                     confirmedPixels.Add(latestCords);
                 }
 
+                if (_drawCustomBrush)
+                {
+                    DrawCustomBrush(layer, latestCords, customBrush);
+                }
+
                 lineTool.DrawLine(layer, startingCoords, latestCords, color, toolSize, blendMode, cap);
                 SetPixelToCheck(LineTool.GetBresenhamLine(startingCoords, latestCords));
 
@@ -108,8 +141,16 @@ namespace PixiEditor.Models.Tools.Tools
             }
 
             lastChangedPixel = latestCords;
-        }

-

+        }
+
+        private void DrawCustomBrush(Layer layer, Coordinates latestCords, CustomBrush customBrush)
+        {
+            layer.LayerBitmap.SkiaSurface.Canvas.DrawPoints(
+                                    SKPointMode.Points,
+                                    customBrush.GetAtPoint(latestCords, layer.OffsetX, layer.OffsetY),
+                                    paint);
+        }
+
         private void MovePixelsToCheck(byte alpha)
         {
             if (alpha != 0)
@@ -170,5 +211,10 @@ namespace PixiEditor.Models.Tools.Tools
             layer.InvokeLayerBitmapChange(dirtyRect);
             return alpha;
         }
+
+        internal void Draw(Layer previewLayer, object zero1, object zero2, SKColor highlightColor, int toolSize)
+        {
+            throw new NotImplementedException();
+        }
     }
 }