Browse Source

Even more stuff

flabbet 2 years ago
parent
commit
eda03186b7
31 changed files with 1072 additions and 473 deletions
  1. 43 41
      src/ChunkyImageLib/ChunkyImage.cs
  2. 2 1
      src/ChunkyImageLib/ChunkyImageEx.cs
  3. 0 1
      src/ChunkyImageLib/DataHolders/ColorBounds.cs
  4. 5 3
      src/ChunkyImageLib/IReadOnlyChunkyImage.cs
  5. 9 8
      src/ChunkyImageLib/Operations/BresenhamLineHelper.cs
  6. 10 8
      src/ChunkyImageLib/Operations/BresenhamLineOperation.cs
  7. 8 7
      src/ChunkyImageLib/Operations/ClearPathOperation.cs
  8. 8 6
      src/ChunkyImageLib/Operations/DrawingSurfaceLineOperation.cs
  9. 24 21
      src/ChunkyImageLib/Operations/EllipseOperation.cs
  10. 4 3
      src/ChunkyImageLib/Operations/ImageOperation.cs
  11. 8 7
      src/ChunkyImageLib/Operations/OperationHelper.cs
  12. 9 7
      src/ChunkyImageLib/Operations/PixelOperation.cs
  13. 12 10
      src/ChunkyImageLib/Operations/PixelsOperation.cs
  14. 6 5
      src/ChunkyImageLib/Operations/ReplaceColorOperation.cs
  15. 1 1
      src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs
  16. 1 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IVectorPathImplementation.cs
  17. 11 3
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasOperations.cs
  18. 4 2
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/IPaintOperations.cs
  19. 436 0
      src/PixiEditor.DrawingApi.Core/ColorsImpl/Colors.cs
  20. 1 303
      src/PixiEditor.DrawingApi.Core/Numerics/Matrix3X3.cs
  21. 68 6
      src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs
  22. 5 0
      src/PixiEditor.DrawingApi.Core/Surface/DrawingSurface.cs
  23. 15 3
      src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/Paint.cs
  24. 13 0
      src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/PaintStyle.cs
  25. 13 0
      src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/StrokeCap.cs
  26. 306 0
      src/PixiEditor.DrawingApi.Core/Surface/Point.cs
  27. 14 0
      src/PixiEditor.DrawingApi.Core/Surface/PointMode.cs
  28. 6 0
      src/PixiEditor.DrawingApi.Core/Surface/Vector/VectorPath.cs
  29. 6 7
      src/PixiEditor/Models/Rendering/WriteableBitmapUpdater.cs
  30. 19 16
      src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs
  31. 5 4
      src/PixiEditor/ViewModels/SubViewModels/Document/StructureMemberViewModel.cs

+ 43 - 41
src/ChunkyImageLib/ChunkyImage.cs

@@ -4,7 +4,9 @@ using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
 using ChunkyImageLib.Operations;
 using OneOf;
 using OneOf;
 using OneOf.Types;
 using OneOf.Types;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 [assembly: InternalsVisibleTo("ChunkyImageLibTest")]
 [assembly: InternalsVisibleTo("ChunkyImageLibTest")]
@@ -31,7 +33,7 @@ namespace ChunkyImageLib;
 /// You can check the current state via queuedOperations.Count == 0
 /// You can check the current state via queuedOperations.Count == 0
 /// 
 /// 
 /// Depending on the chosen blend mode the latest chunks contain different things:
 /// Depending on the chosen blend mode the latest chunks contain different things:
-///     - SKBlendMode.Src: default mode, the latest chunks are the same as committed ones but with some or all queued operations applied. 
+///     - BlendMode.Src: default mode, the latest chunks are the same as committed ones but with some or all queued operations applied. 
 ///         This means that operations can work with the existing pixels.
 ///         This means that operations can work with the existing pixels.
 ///     - Any other blend mode: the latest chunks contain only the things drawn by the queued operations.
 ///     - Any other blend mode: the latest chunks contain only the things drawn by the queued operations.
 ///         They need to be drawn over the committed chunks to obtain the final image. In this case, operations won't have access to the existing pixels.
 ///         They need to be drawn over the committed chunks to obtain the final image. In this case, operations won't have access to the existing pixels.
@@ -55,12 +57,12 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     private int commitCounter = 0;
     private int commitCounter = 0;
 
 
     public const int FullChunkSize = ChunkPool.FullChunkSize;
     public const int FullChunkSize = ChunkPool.FullChunkSize;
-    private static SKPaint ClippingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.DstIn };
-    private static SKPaint InverseClippingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.DstOut };
-    private static SKPaint ReplacingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.Src };
-    private static SKPaint SmoothReplacingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.Src, FilterQuality = SKFilterQuality.Medium };
-    private static SKPaint AddingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.Plus };
-    private readonly SKPaint blendModePaint = new SKPaint() { BlendMode = SKBlendMode.Src };
+    private static Paint ClippingPaint { get; } = new Paint() { BlendMode = BlendMode.DstIn };
+    private static Paint InverseClippingPaint { get; } = new Paint() { BlendMode = BlendMode.DstOut };
+    private static Paint ReplacingPaint { get; } = new Paint() { BlendMode = BlendMode.Src };
+    private static Paint SmoothReplacingPaint { get; } = new Paint() { BlendMode = BlendMode.Src, FilterQuality = FilterQuality.Medium };
+    private static Paint AddingPaint { get; } = new Paint() { BlendMode = BlendMode.Plus };
+    private readonly Paint blendModePaint = new Paint() { BlendMode = BlendMode.Src };
 
 
     public VecI CommittedSize { get; private set; }
     public VecI CommittedSize { get; private set; }
     public VecI LatestSize { get; private set; }
     public VecI LatestSize { get; private set; }
@@ -76,7 +78,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
 
 
     private readonly List<(IOperation operation, HashSet<VecI> affectedChunks)> queuedOperations = new();
     private readonly List<(IOperation operation, HashSet<VecI> affectedChunks)> queuedOperations = new();
     private readonly List<ChunkyImage> activeClips = new();
     private readonly List<ChunkyImage> activeClips = new();
-    private SKBlendMode blendMode = SKBlendMode.Src;
+    private BlendMode blendMode = BlendMode.Src;
     private bool lockTransparency = false;
     private bool lockTransparency = false;
     private SKPath? clippingPath;
     private SKPath? clippingPath;
     private int? horizontalSymmetryAxis = null;
     private int? horizontalSymmetryAxis = null;
@@ -158,7 +160,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public SKColor GetCommittedPixel(VecI posOnImage)
+    public Color GetCommittedPixel(VecI posOnImage)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -167,14 +169,14 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
             var posInChunk = posOnImage - chunkPos * FullChunkSize;
             var posInChunk = posOnImage - chunkPos * FullChunkSize;
             return MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full) switch
             return MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full) switch
             {
             {
-                null => SKColors.Transparent,
+                null => Colors.Transparent,
                 var chunk => chunk.Surface.GetSRGBPixel(posInChunk)
                 var chunk => chunk.Surface.GetSRGBPixel(posInChunk)
             };
             };
         }
         }
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public SKColor GetMostUpToDatePixel(VecI posOnImage)
+    public Color GetMostUpToDatePixel(VecI posOnImage)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -188,18 +190,18 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
                 Chunk? committedChunk = MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full);
                 Chunk? committedChunk = MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full);
                 return committedChunk switch
                 return committedChunk switch
                 {
                 {
-                    null => SKColors.Transparent,
+                    null => Colors.Transparent,
                     _ => committedChunk.Surface.GetSRGBPixel(posInChunk)
                     _ => committedChunk.Surface.GetSRGBPixel(posInChunk)
                 };
                 };
             }
             }
 
 
             // something is queued, blend mode is Src so no merging needed
             // something is queued, blend mode is Src so no merging needed
-            if (blendMode == SKBlendMode.Src)
+            if (blendMode == BlendMode.Src)
             {
             {
                 Chunk? latestChunk = GetLatestChunk(chunkPos, ChunkResolution.Full);
                 Chunk? latestChunk = GetLatestChunk(chunkPos, ChunkResolution.Full);
                 return latestChunk switch
                 return latestChunk switch
                 {
                 {
-                    null => SKColors.Transparent,
+                    null => Colors.Transparent,
                     _ => latestChunk.Surface.GetSRGBPixel(posInChunk)
                     _ => latestChunk.Surface.GetSRGBPixel(posInChunk)
                 };
                 };
             }
             }
@@ -208,17 +210,17 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
             {
             {
                 Chunk? committedChunk = MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full);
                 Chunk? committedChunk = MaybeGetCommittedChunk(chunkPos, ChunkResolution.Full);
                 Chunk? latestChunk = GetLatestChunk(chunkPos, ChunkResolution.Full);
                 Chunk? latestChunk = GetLatestChunk(chunkPos, ChunkResolution.Full);
-                SKColor committedColor = committedChunk is null ?
-                    SKColors.Transparent :
+                Color committedColor = committedChunk is null ?
+                    Colors.Transparent :
                     committedChunk.Surface.GetSRGBPixel(posInChunk);
                     committedChunk.Surface.GetSRGBPixel(posInChunk);
-                SKColor latestColor = latestChunk is null ?
-                    SKColors.Transparent :
+                Color latestColor = latestChunk is null ?
+                    Colors.Transparent :
                     latestChunk.Surface.GetSRGBPixel(posInChunk);
                     latestChunk.Surface.GetSRGBPixel(posInChunk);
                 // using a whole chunk just to draw 1 pixel is kinda dumb,
                 // using a whole chunk just to draw 1 pixel is kinda dumb,
                 // but this should be faster than any approach that requires allocations
                 // but this should be faster than any approach that requires allocations
                 using Chunk tempChunk = Chunk.Create(ChunkResolution.Eighth);
                 using Chunk tempChunk = Chunk.Create(ChunkResolution.Eighth);
-                using SKPaint committedPaint = new SKPaint() { Color = committedColor, BlendMode = SKBlendMode.Src };
-                using SKPaint latestPaint = new SKPaint() { Color = latestColor, BlendMode = this.blendMode };
+                using Paint committedPaint = new Paint() { Color = committedColor, BlendMode = BlendMode.Src };
+                using Paint latestPaint = new Paint() { Color = latestColor, BlendMode = this.blendMode };
                 tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, committedPaint);
                 tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, committedPaint);
                 tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, latestPaint);
                 tempChunk.Surface.DrawingSurface.Canvas.DrawPixel(VecI.Zero, latestPaint);
                 return tempChunk.Surface.GetSRGBPixel(VecI.Zero);
                 return tempChunk.Surface.GetSRGBPixel(VecI.Zero);
@@ -230,7 +232,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     /// True if the chunk existed and was drawn, otherwise false
     /// True if the chunk existed and was drawn, otherwise false
     /// </returns>
     /// </returns>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public bool DrawMostUpToDateChunkOn(VecI chunkPos, ChunkResolution resolution, SKSurface surface, VecI pos, SKPaint? paint = null)
+    public bool DrawMostUpToDateChunkOn(VecI chunkPos, ChunkResolution resolution, DrawingSurface surface, VecI pos, Paint? paint = null)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -251,7 +253,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
             var committedChunk = GetCommittedChunk(chunkPos, resolution);
             var committedChunk = GetCommittedChunk(chunkPos, resolution);
 
 
             // draw committed directly
             // draw committed directly
-            if (latestChunk.IsT0 || latestChunk.IsT1 && committedChunk is not null && blendMode != SKBlendMode.Src)
+            if (latestChunk.IsT0 || latestChunk.IsT1 && committedChunk is not null && blendMode != BlendMode.Src)
             {
             {
                 if (committedChunk is null)
                 if (committedChunk is null)
                     return false;
                     return false;
@@ -260,7 +262,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
             }
             }
 
 
             // no need to combine with committed, draw directly
             // no need to combine with committed, draw directly
-            if (blendMode == SKBlendMode.Src || committedChunk is null)
+            if (blendMode == BlendMode.Src || committedChunk is null)
             {
             {
                 if (latestChunk.IsT2)
                 if (latestChunk.IsT2)
                 {
                 {
@@ -304,7 +306,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    internal bool DrawCommittedChunkOn(VecI chunkPos, ChunkResolution resolution, SKSurface surface, VecI pos, SKPaint? paint = null)
+    internal bool DrawCommittedChunkOn(VecI chunkPos, ChunkResolution resolution, DrawingSurface surface, VecI pos, Paint? paint = null)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -390,7 +392,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     /// Porter duff compositing operators (apart from SrcOver) likely won't have the intended effect.
     /// Porter duff compositing operators (apart from SrcOver) likely won't have the intended effect.
     /// </summary>
     /// </summary>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void SetBlendMode(SKBlendMode mode)
+    public void SetBlendMode(BlendMode mode)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -436,7 +438,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueReplaceColor(SKColor oldColor, SKColor newColor)
+    public void EnqueueReplaceColor(Color oldColor, Color newColor)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -458,7 +460,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawEllipse(RectI location, SKColor strokeColor, SKColor fillColor, int strokeWidth, SKPaint? paint = null)
+    public void EnqueueDrawEllipse(RectI location, Color strokeColor, Color fillColor, int strokeWidth, Paint? paint = null)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -475,7 +477,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     /// Surface is NOT THREAD SAFE, so if you pass a Surface here with copyImage == false you must not do anything with that surface anywhere (not even read) until CommitChanges/CancelChanges is called.
     /// Surface is NOT THREAD SAFE, so if you pass a Surface here with copyImage == false you must not do anything with that surface anywhere (not even read) until CommitChanges/CancelChanges is called.
     /// </summary>
     /// </summary>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawImage(SKMatrix transformMatrix, Surface image, SKPaint? paint = null, bool copyImage = true)
+    public void EnqueueDrawImage(SKMatrix transformMatrix, Surface image, Paint? paint = null, bool copyImage = true)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -489,7 +491,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     /// Be careful about the copyImage argument, see other overload for details
     /// Be careful about the copyImage argument, see other overload for details
     /// </summary>
     /// </summary>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawImage(ShapeCorners corners, Surface image, SKPaint? paint = null, bool copyImage = true)
+    public void EnqueueDrawImage(ShapeCorners corners, Surface image, Paint? paint = null, bool copyImage = true)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -503,7 +505,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     /// Be careful about the copyImage argument, see other overload for details
     /// Be careful about the copyImage argument, see other overload for details
     /// </summary>
     /// </summary>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawImage(VecI pos, Surface image, SKPaint? paint = null, bool copyImage = true)
+    public void EnqueueDrawImage(VecI pos, Surface image, Paint? paint = null, bool copyImage = true)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -515,7 +517,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
 
 
     /// <param name="customBounds">Bounds used for affected chunks, will be computed from path in O(n) if null is passed</param>
     /// <param name="customBounds">Bounds used for affected chunks, will be computed from path in O(n) if null is passed</param>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawPath(SKPath path, SKColor color, float strokeWidth, SKStrokeCap strokeCap, SKBlendMode blendMode, RectI? customBounds = null)
+    public void EnqueueDrawPath(SKPath path, Color color, float strokeWidth, SKStrokeCap strokeCap, BlendMode blendMode, RectI? customBounds = null)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -526,7 +528,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawBresenhamLine(VecI from, VecI to, SKColor color, SKBlendMode blendMode)
+    public void EnqueueDrawBresenhamLine(VecI from, VecI to, Color color, BlendMode blendMode)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -537,18 +539,18 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawSkiaLine(VecI from, VecI to, SKStrokeCap strokeCap, float strokeWidth, SKColor color, SKBlendMode blendMode)
+    public void EnqueueDrawSkiaLine(VecI from, VecI to, SKStrokeCap strokeCap, float strokeWidth, Color color, BlendMode blendMode)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
             ThrowIfDisposed();
             ThrowIfDisposed();
-            SkiaLineOperation operation = new(from, to, strokeCap, strokeWidth, color, blendMode);
+            DrawingSurfaceLineOperation operation = new(from, to, strokeCap, strokeWidth, color, blendMode);
             EnqueueOperation(operation);
             EnqueueOperation(operation);
         }
         }
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawPixels(IEnumerable<VecI> pixels, SKColor color, SKBlendMode blendMode)
+    public void EnqueueDrawPixels(IEnumerable<VecI> pixels, Color color, BlendMode blendMode)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -559,7 +561,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
     }
 
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawPixel(VecI pos, SKColor color, SKBlendMode blendMode)
+    public void EnqueueDrawPixel(VecI pos, Color color, BlendMode blendMode)
     {
     {
         lock (lockObject)
         lock (lockObject)
         {
         {
@@ -664,7 +666,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
 
 
             //clear additional state
             //clear additional state
             activeClips.Clear();
             activeClips.Clear();
-            blendMode = SKBlendMode.Src;
+            blendMode = BlendMode.Src;
             lockTransparency = false;
             lockTransparency = false;
             horizontalSymmetryAxis = null;
             horizontalSymmetryAxis = null;
             verticalSymmetryAxis = null;
             verticalSymmetryAxis = null;
@@ -710,7 +712,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
             CommittedSize = LatestSize;
             CommittedSize = LatestSize;
             queuedOperations.Clear();
             queuedOperations.Clear();
             activeClips.Clear();
             activeClips.Clear();
-            blendMode = SKBlendMode.Src;
+            blendMode = BlendMode.Src;
             lockTransparency = false;
             lockTransparency = false;
             horizontalSymmetryAxis = null;
             horizontalSymmetryAxis = null;
             verticalSymmetryAxis = null;
             verticalSymmetryAxis = null;
@@ -748,7 +750,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
                 }
                 }
 
 
                 // do a swap
                 // do a swap
-                if (blendMode == SKBlendMode.Src)
+                if (blendMode == BlendMode.Src)
                 {
                 {
                     // delete committed version
                     // delete committed version
                     if (committedChunks[resolution].ContainsKey(pos))
                     if (committedChunks[resolution].ContainsKey(pos))
@@ -937,7 +939,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
         }
         }
 
 
         var intersection = Chunk.Create(resolution);
         var intersection = Chunk.Create(resolution);
-        intersection.Surface.DrawingSurface.Canvas.Clear(SKColors.White);
+        intersection.Surface.DrawingSurface.Canvas.Clear(Colors.White);
 
 
         foreach (var mask in activeClips)
         foreach (var mask in activeClips)
         {
         {
@@ -1135,7 +1137,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
         if (maybeCommittedAnyRes is not null)
         if (maybeCommittedAnyRes is not null)
         {
         {
             Chunk newChunk = Chunk.Create(resolution);
             Chunk newChunk = Chunk.Create(resolution);
-            if (blendMode == SKBlendMode.Src)
+            if (blendMode == BlendMode.Src)
                 maybeCommittedAnyRes.Surface.CopyTo(newChunk.Surface);
                 maybeCommittedAnyRes.Surface.CopyTo(newChunk.Surface);
             else
             else
                 newChunk.Surface.DrawingSurface.Canvas.Clear();
                 newChunk.Surface.DrawingSurface.Canvas.Clear();

+ 2 - 1
src/ChunkyImageLib/ChunkyImageEx.cs

@@ -1,13 +1,14 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
 using ChunkyImageLib.Operations;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib;
 namespace ChunkyImageLib;
 public static class IReadOnlyChunkyImageEx
 public static class IReadOnlyChunkyImageEx
 {
 {
     public static void DrawMostUpToDateRegionOn
     public static void DrawMostUpToDateRegionOn
-        (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, SKSurface surface, VecI pos, SKPaint? paint = null)
+        (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, DrawingSurface surface, VecI pos, Paint? paint = null)
     {
     {
         surface.Canvas.Save();
         surface.Canvas.Save();
         surface.Canvas.ClipRect(SKRect.Create(pos, fullResRegion.Size));
         surface.Canvas.ClipRect(SKRect.Create(pos, fullResRegion.Size));

+ 0 - 1
src/ChunkyImageLib/DataHolders/ColorBounds.cs

@@ -1,7 +1,6 @@
 using System.Runtime.CompilerServices;
 using System.Runtime.CompilerServices;
 using ComputeSharp;
 using ComputeSharp;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
-using PixiEditor.PixelE;
 
 
 namespace ChunkyImageLib.DataHolders;
 namespace ChunkyImageLib.DataHolders;
 
 

+ 5 - 3
src/ChunkyImageLib/IReadOnlyChunkyImage.cs

@@ -1,15 +1,17 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib;
 namespace ChunkyImageLib;
 
 
 public interface IReadOnlyChunkyImage
 public interface IReadOnlyChunkyImage
 {
 {
-    bool DrawMostUpToDateChunkOn(VecI chunkPos, ChunkResolution resolution, SKSurface surface, VecI pos, SKPaint? paint = null);
+    bool DrawMostUpToDateChunkOn(VecI chunkPos, ChunkResolution resolution, DrawingSurface surface, VecI pos, Paint? paint = null);
     RectI? FindLatestBounds();
     RectI? FindLatestBounds();
-    SKColor GetCommittedPixel(VecI posOnImage);
-    SKColor GetMostUpToDatePixel(VecI posOnImage);
+    Color GetCommittedPixel(VecI posOnImage);
+    Color GetMostUpToDatePixel(VecI posOnImage);
     bool LatestOrCommittedChunkExists(VecI chunkPos);
     bool LatestOrCommittedChunkExists(VecI chunkPos);
     HashSet<VecI> FindAffectedChunks(int fromOperationIndex = 0);
     HashSet<VecI> FindAffectedChunks(int fromOperationIndex = 0);
     HashSet<VecI> FindCommittedChunks();
     HashSet<VecI> FindCommittedChunks();

+ 9 - 8
src/ChunkyImageLib/Operations/BresenhamLineHelper.cs

@@ -1,21 +1,22 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
 public static class BresenhamLineHelper
 public static class BresenhamLineHelper
 {
 {
-    public static SKPoint[] GetBresenhamLine(VecI start, VecI end)
+    public static Point[] GetBresenhamLine(VecI start, VecI end)
     {
     {
         int count = Math.Abs((start - end).LongestAxis) + 1;
         int count = Math.Abs((start - end).LongestAxis) + 1;
         if (count > 100000)
         if (count > 100000)
-            return new SKPoint[0];
-        SKPoint[] output = new SKPoint[count];
+            return Array.Empty<Point>();
+        Point[] output = new Point[count];
         CalculateBresenhamLine(start, end, output);
         CalculateBresenhamLine(start, end, output);
         return output;
         return output;
     }
     }
 
 
-    private static void CalculateBresenhamLine(VecI start, VecI end, SKPoint[] output)
+    private static void CalculateBresenhamLine(VecI start, VecI end, Point[] output)
     {
     {
         int index = 0;
         int index = 0;
 
 
@@ -26,7 +27,7 @@ public static class BresenhamLineHelper
 
 
         if (x1 == x2 && y1 == y2)
         if (x1 == x2 && y1 == y2)
         {
         {
-            output[index] = start;
+            output[index] = new Point(start);
             return;
             return;
         }
         }
 
 
@@ -55,7 +56,7 @@ public static class BresenhamLineHelper
             dy = y1 - y2;
             dy = y1 - y2;
         }
         }
 
 
-        output[index] = new SKPoint(x, y);
+        output[index] = new Point(x, y);
         index++;
         index++;
 
 
         if (dx > dy)
         if (dx > dy)
@@ -78,7 +79,7 @@ public static class BresenhamLineHelper
                     x += xi;
                     x += xi;
                 }
                 }
 
 
-                output[index] = new SKPoint(x, y);
+                output[index] = new Point(x, y);
                 index++;
                 index++;
             }
             }
         }
         }
@@ -102,7 +103,7 @@ public static class BresenhamLineHelper
                     y += yi;
                     y += yi;
                 }
                 }
 
 
-                output[index] = new SKPoint(x, y);
+                output[index] = new Point(x, y);
                 index++;
                 index++;
             }
             }
         }
         }

+ 10 - 8
src/ChunkyImageLib/Operations/BresenhamLineOperation.cs

@@ -1,5 +1,7 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
@@ -8,31 +10,31 @@ internal class BresenhamLineOperation : IDrawOperation
     public bool IgnoreEmptyChunks => false;
     public bool IgnoreEmptyChunks => false;
     private readonly VecI from;
     private readonly VecI from;
     private readonly VecI to;
     private readonly VecI to;
-    private readonly SKColor color;
-    private readonly SKBlendMode blendMode;
-    private readonly SKPoint[] points;
-    private SKPaint paint;
+    private readonly Color color;
+    private readonly BlendMode blendMode;
+    private readonly Point[] points;
+    private Paint paint;
 
 
-    public BresenhamLineOperation(VecI from, VecI to, SKColor color, SKBlendMode blendMode)
+    public BresenhamLineOperation(VecI from, VecI to, Color color, BlendMode blendMode)
     {
     {
         this.from = from;
         this.from = from;
         this.to = to;
         this.to = to;
         this.color = color;
         this.color = color;
         this.blendMode = blendMode;
         this.blendMode = blendMode;
-        paint = new SKPaint() { BlendMode = blendMode };
+        paint = new Paint() { BlendMode = blendMode };
         points = BresenhamLineHelper.GetBresenhamLine(from, to);
         points = BresenhamLineHelper.GetBresenhamLine(from, to);
     }
     }
 
 
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     {
     {
         // a hacky way to make the lines look slightly better on non full res chunks
         // a hacky way to make the lines look slightly better on non full res chunks
-        paint.Color = new SKColor(color.Red, color.Green, color.Blue, (byte)(color.Alpha * chunk.Resolution.Multiplier()));
+        paint.Color = new Color(color.R, color.G, color.B, (byte)(color.A * chunk.Resolution.Multiplier()));
 
 
         var surf = chunk.Surface.DrawingSurface;
         var surf = chunk.Surface.DrawingSurface;
         surf.Canvas.Save();
         surf.Canvas.Save();
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);
-        surf.Canvas.DrawPoints(SKPointMode.Points, points, paint);
+        surf.Canvas.DrawPoints(PointMode.Points, points, paint);
         surf.Canvas.Restore();
         surf.Canvas.Restore();
     }
     }
 
 

+ 8 - 7
src/ChunkyImageLib/Operations/ClearPathOperation.cs

@@ -1,18 +1,19 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
 internal class ClearPathOperation : IDrawOperation
 internal class ClearPathOperation : IDrawOperation
 {
 {
-    private SKPath path;
+    private VectorPath path;
     private RectI pathTightBounds;
     private RectI pathTightBounds;
 
 
     public bool IgnoreEmptyChunks => true;
     public bool IgnoreEmptyChunks => true;
 
 
-    public ClearPathOperation(SKPath path, RectI? pathTightBounds = null)
+    public ClearPathOperation(VectorPath path, RectI? pathTightBounds = null)
     {
     {
-        this.path = new SKPath(path);
+        this.path = new VectorPath(path);
         this.pathTightBounds = (RectI)(pathTightBounds ?? path.TightBounds);
         this.pathTightBounds = (RectI)(pathTightBounds ?? path.TightBounds);
     }
     }
 
 
@@ -20,10 +21,10 @@ internal class ClearPathOperation : IDrawOperation
     {
     {
         chunk.Surface.DrawingSurface.Canvas.Save();
         chunk.Surface.DrawingSurface.Canvas.Save();
 
 
-        using SKPath transformedPath = new(path);
+        using VectorPath transformedPath = new(path);
         float scale = (float)chunk.Resolution.Multiplier();
         float scale = (float)chunk.Resolution.Multiplier();
         VecD trans = -chunkPos * ChunkyImage.FullChunkSize * scale;
         VecD trans = -chunkPos * ChunkyImage.FullChunkSize * scale;
-        transformedPath.Transform(SKMatrix.CreateScaleTranslation(scale, scale, (float)trans.X, (float)trans.Y));
+        transformedPath.Transform(Matrix3X3.CreateScaleTranslation(scale, scale, (float)trans.X, (float)trans.Y));
         chunk.Surface.DrawingSurface.Canvas.ClipPath(transformedPath);
         chunk.Surface.DrawingSurface.Canvas.ClipPath(transformedPath);
         chunk.Surface.DrawingSurface.Canvas.Clear();
         chunk.Surface.DrawingSurface.Canvas.Clear();
         chunk.Surface.DrawingSurface.Canvas.Restore();
         chunk.Surface.DrawingSurface.Canvas.Restore();
@@ -40,8 +41,8 @@ internal class ClearPathOperation : IDrawOperation
 
 
     public IDrawOperation AsMirrored(int? verAxisX, int? horAxisY)
     public IDrawOperation AsMirrored(int? verAxisX, int? horAxisY)
     {
     {
-        var matrix = SKMatrix.CreateScale(verAxisX is not null ? -1 : 1, horAxisY is not null ? -1 : 1, verAxisX ?? 0, horAxisY ?? 0);
-        using var copy = new SKPath(path);
+        var matrix = Matrix3X3.CreateScale(verAxisX is not null ? -1 : 1, horAxisY is not null ? -1 : 1, verAxisX ?? 0, horAxisY ?? 0);
+        using var copy = new VectorPath(path);
         copy.Transform(matrix);
         copy.Transform(matrix);
 
 
         var newRect = pathTightBounds;
         var newRect = pathTightBounds;

+ 8 - 6
src/ChunkyImageLib/Operations/SkiaLineOperation.cs → src/ChunkyImageLib/Operations/DrawingSurfaceLineOperation.cs

@@ -1,24 +1,26 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
-internal class SkiaLineOperation : IDrawOperation
+internal class DrawingSurfaceLineOperation : IDrawOperation
 {
 {
     public bool IgnoreEmptyChunks => false;
     public bool IgnoreEmptyChunks => false;
 
 
-    private SKPaint paint;
+    private Paint paint;
     private readonly VecI from;
     private readonly VecI from;
     private readonly VecI to;
     private readonly VecI to;
 
 
-    public SkiaLineOperation(VecI from, VecI to, SKStrokeCap strokeCap, float strokeWidth, SKColor color, SKBlendMode blendMode)
+    public DrawingSurfaceLineOperation(VecI from, VecI to, StrokeCap strokeCap, float strokeWidth, Color color, BlendMode blendMode)
     {
     {
         paint = new()
         paint = new()
         {
         {
             StrokeCap = strokeCap,
             StrokeCap = strokeCap,
             StrokeWidth = strokeWidth,
             StrokeWidth = strokeWidth,
             Color = color,
             Color = color,
-            Style = SKPaintStyle.Stroke,
+            Style = PaintStyle.Stroke,
             BlendMode = blendMode,
             BlendMode = blendMode,
         };
         };
         this.from = from;
         this.from = from;
@@ -27,7 +29,7 @@ internal class SkiaLineOperation : IDrawOperation
 
 
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     {
     {
-        paint.IsAntialias = chunk.Resolution != ChunkResolution.Full;
+        paint.IsAntiAliased = chunk.Resolution != ChunkResolution.Full;
         var surf = chunk.Surface.DrawingSurface;
         var surf = chunk.Surface.DrawingSurface;
         surf.Canvas.Save();
         surf.Canvas.Save();
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
@@ -56,7 +58,7 @@ internal class SkiaLineOperation : IDrawOperation
             newFrom = newFrom.ReflectY((int)horAxisY);
             newFrom = newFrom.ReflectY((int)horAxisY);
             newTo = newTo.ReflectY((int)horAxisY);
             newTo = newTo.ReflectY((int)horAxisY);
         }
         }
-        return new SkiaLineOperation(newFrom, newTo, paint.StrokeCap, paint.StrokeWidth, paint.Color, paint.BlendMode);
+        return new DrawingSurfaceLineOperation(newFrom, newTo, paint.StrokeCap, paint.StrokeWidth, paint.Color, paint.BlendMode);
     }
     }
 
 
     public void Dispose()
     public void Dispose()

+ 24 - 21
src/ChunkyImageLib/Operations/EllipseOperation.cs

@@ -1,5 +1,8 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
@@ -8,24 +11,24 @@ internal class EllipseOperation : IDrawOperation
     public bool IgnoreEmptyChunks => false;
     public bool IgnoreEmptyChunks => false;
 
 
     private readonly RectI location;
     private readonly RectI location;
-    private readonly SKColor strokeColor;
-    private readonly SKColor fillColor;
+    private readonly Color strokeColor;
+    private readonly Color fillColor;
     private readonly int strokeWidth;
     private readonly int strokeWidth;
-    private readonly SKPaint paint;
+    private readonly Paint paint;
     private bool init = false;
     private bool init = false;
-    private SKPath? outerPath;
-    private SKPath? innerPath;
-    private SKPoint[]? ellipse;
-    private SKPoint[]? ellipseFill;
+    private VectorPath? outerPath;
+    private VectorPath? innerPath;
+    private Point[]? ellipse;
+    private Point[]? ellipseFill;
     private RectI? ellipseFillRect;
     private RectI? ellipseFillRect;
 
 
-    public EllipseOperation(RectI location, SKColor strokeColor, SKColor fillColor, int strokeWidth, SKPaint? paint = null)
+    public EllipseOperation(RectI location, Color strokeColor, Color fillColor, int strokeWidth, Paint? paint = null)
     {
     {
         this.location = location;
         this.location = location;
         this.strokeColor = strokeColor;
         this.strokeColor = strokeColor;
         this.fillColor = fillColor;
         this.fillColor = fillColor;
         this.strokeWidth = strokeWidth;
         this.strokeWidth = strokeWidth;
-        this.paint = paint?.Clone() ?? new SKPaint();
+        this.paint = paint?.Clone() ?? new Paint();
     }
     }
 
 
     private void Init()
     private void Init()
@@ -34,18 +37,18 @@ internal class EllipseOperation : IDrawOperation
         if (strokeWidth == 1)
         if (strokeWidth == 1)
         {
         {
             var ellipseList = EllipseHelper.GenerateEllipseFromRect(location);
             var ellipseList = EllipseHelper.GenerateEllipseFromRect(location);
-            ellipse = ellipseList.Select(a => (SKPoint)a).ToArray();
-            if (fillColor.Alpha > 0 || paint.BlendMode != SKBlendMode.SrcOver)
+            ellipse = ellipseList.Select(a => (Point)a).ToArray();
+            if (fillColor.A > 0 || paint.BlendMode != BlendMode.SrcOver)
             {
             {
                 (var fill, ellipseFillRect) = EllipseHelper.SplitEllipseIntoRegions(ellipseList, location);
                 (var fill, ellipseFillRect) = EllipseHelper.SplitEllipseIntoRegions(ellipseList, location);
-                ellipseFill = fill.Select(a => (SKPoint)a).ToArray();
+                ellipseFill = fill.Select(a => (Point)a).ToArray();
             }
             }
         }
         }
         else
         else
         {
         {
-            outerPath = new SKPath();
+            outerPath = new VectorPath();
             outerPath.ArcTo(location, 0, 359, true);
             outerPath.ArcTo(location, 0, 359, true);
-            innerPath = new SKPath();
+            innerPath = new VectorPath();
             innerPath.ArcTo(location.Inflate(-strokeWidth), 0, 359, true);
             innerPath.ArcTo(location.Inflate(-strokeWidth), 0, 359, true);
         }
         }
     }
     }
@@ -59,22 +62,22 @@ internal class EllipseOperation : IDrawOperation
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);
 
 
-        paint.IsAntialias = chunk.Resolution != ChunkResolution.Full;
+        paint.IsAntiAliased = chunk.Resolution != ChunkResolution.Full;
 
 
         if (strokeWidth == 1)
         if (strokeWidth == 1)
         {
         {
-            if (fillColor.Alpha > 0 || paint.BlendMode != SKBlendMode.SrcOver)
+            if (fillColor.A > 0 || paint.BlendMode != BlendMode.SrcOver)
             {
             {
                 paint.Color = fillColor;
                 paint.Color = fillColor;
-                surf.Canvas.DrawPoints(SKPointMode.Lines, ellipseFill, paint);
-                surf.Canvas.DrawRect((SKRect)ellipseFillRect!, paint);
+                surf.Canvas.DrawPoints(PointMode.Lines, ellipseFill, paint);
+                surf.Canvas.DrawRect(ellipseFillRect!, paint);
             }
             }
             paint.Color = strokeColor;
             paint.Color = strokeColor;
-            surf.Canvas.DrawPoints(SKPointMode.Points, ellipse, paint);
+            surf.Canvas.DrawPoints(PointMode.Points, ellipse, paint);
         }
         }
         else
         else
         {
         {
-            if (fillColor.Alpha > 0 || paint.BlendMode != SKBlendMode.SrcOver)
+            if (fillColor.A > 0 || paint.BlendMode != BlendMode.SrcOver)
             {
             {
                 surf.Canvas.Save();
                 surf.Canvas.Save();
                 surf.Canvas.ClipPath(innerPath);
                 surf.Canvas.ClipPath(innerPath);
@@ -94,7 +97,7 @@ internal class EllipseOperation : IDrawOperation
     {
     {
         var chunks = OperationHelper.FindChunksTouchingEllipse
         var chunks = OperationHelper.FindChunksTouchingEllipse
             (location.Center, location.Width / 2.0, location.Height / 2.0, ChunkyImage.FullChunkSize);
             (location.Center, location.Width / 2.0, location.Height / 2.0, ChunkyImage.FullChunkSize);
-        if (fillColor.Alpha == 0)
+        if (fillColor.A == 0)
         {
         {
             chunks.ExceptWith(OperationHelper.FindChunksFullyInsideEllipse
             chunks.ExceptWith(OperationHelper.FindChunksFullyInsideEllipse
                 (location.Center, location.Width / 2.0 - strokeWidth * 2, location.Height / 2.0 - strokeWidth * 2, ChunkyImage.FullChunkSize));
                 (location.Center, location.Width / 2.0 - strokeWidth * 2, location.Height / 2.0 - strokeWidth * 2, ChunkyImage.FullChunkSize));

+ 4 - 3
src/ChunkyImageLib/Operations/ImageOperation.cs

@@ -1,16 +1,17 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
 
 
 internal class ImageOperation : IDrawOperation
 internal class ImageOperation : IDrawOperation
 {
 {
-    private SKMatrix transformMatrix;
+    private Matrix3X3 transformMatrix;
     private ShapeCorners corners;
     private ShapeCorners corners;
     private Surface toPaint;
     private Surface toPaint;
     private bool imageWasCopied = false;
     private bool imageWasCopied = false;
-    private readonly SKPaint? customPaint;
+    private readonly Paint? customPaint;
 
 
     public bool IgnoreEmptyChunks => false;
     public bool IgnoreEmptyChunks => false;
 
 
@@ -26,7 +27,7 @@ internal class ImageOperation : IDrawOperation
             BottomRight = pos + image.Size,
             BottomRight = pos + image.Size,
             BottomLeft = new VecD(pos.X, pos.Y + image.Size.Y)
             BottomLeft = new VecD(pos.X, pos.Y + image.Size.Y)
         };
         };
-        transformMatrix = SKMatrix.CreateIdentity();
+        transformMatrix = Matrix3X3.CreateIdentity();
         transformMatrix.TransX = pos.X;
         transformMatrix.TransX = pos.X;
         transformMatrix.TransY = pos.Y;
         transformMatrix.TransY = pos.Y;
 
 

+ 8 - 7
src/ChunkyImageLib/Operations/OperationHelper.cs

@@ -1,5 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
@@ -21,11 +22,11 @@ public static class OperationHelper
     /// <summary>
     /// <summary>
     /// toModify[x,y].Alpha = Math.Min(toModify[x,y].Alpha, toGetAlphaFrom[x,y].Alpha)
     /// toModify[x,y].Alpha = Math.Min(toModify[x,y].Alpha, toGetAlphaFrom[x,y].Alpha)
     /// </summary>
     /// </summary>
-    public unsafe static void ClampAlpha(SKSurface toModify, SKSurface toGetAlphaFrom)
+    public unsafe static void ClampAlpha(DrawingSurface toModify, DrawingSurface toGetAlphaFrom)
     {
     {
-        using (var map = toModify.PeekPixels())
+        using (Pixmap map = toModify.PeekPixels())
         {
         {
-            using (var refMap = toGetAlphaFrom.PeekPixels())
+            using (Pixmap refMap = toGetAlphaFrom.PeekPixels())
             {
             {
                 long* pixels = (long*)map.GetPixels();
                 long* pixels = (long*)map.GetPixels();
                 long* refPixels = (long*)refMap.GetPixels();
                 long* refPixels = (long*)refMap.GetPixels();
@@ -76,11 +77,11 @@ public static class OperationHelper
         };
         };
     }
     }
 
 
-    public static SKMatrix CreateMatrixFromPoints(ShapeCorners corners, VecD size)
-        => CreateMatrixFromPoints((SKPoint)corners.TopLeft, (SKPoint)corners.TopRight, (SKPoint)corners.BottomRight, (SKPoint)corners.BottomLeft, (float)size.X, (float)size.Y);
+    public static Matrix3X3 CreateMatrixFromPoints(ShapeCorners corners, VecD size)
+        => CreateMatrixFromPoints((Point)corners.TopLeft, (Point)corners.TopRight, (Point)corners.BottomRight, (Point)corners.BottomLeft, (float)size.X, (float)size.Y);
 
 
     // see https://stackoverflow.com/questions/48416118/perspective-transform-in-skia/72364829#72364829
     // see https://stackoverflow.com/questions/48416118/perspective-transform-in-skia/72364829#72364829
-    public static SKMatrix CreateMatrixFromPoints(SKPoint topLeft, SKPoint topRight, SKPoint botRight, SKPoint botLeft, float width, float height)
+    public static Matrix3X3 CreateMatrixFromPoints(Point topLeft, Point topRight, Point botRight, Point botLeft, float width, float height)
     {
     {
         (float x1, float y1) = (topLeft.X, topLeft.Y);
         (float x1, float y1) = (topLeft.X, topLeft.Y);
         (float x2, float y2) = (topRight.X, topRight.Y);
         (float x2, float y2) = (topRight.X, topRight.Y);
@@ -98,7 +99,7 @@ public static class OperationHelper
         float persp1 = (-y1 * x2 + x1 * y2 - x1 * y3 - y2 * x4 + y3 * x4 + x2 * y4 + y1 * x3 - y4 * x3) / (x2 * y3 * h + y2 * x4 * h - y3 * x4 * h - x2 * y4 * h - y2 * h * x3 + y4 * h * x3);
         float persp1 = (-y1 * x2 + x1 * y2 - x1 * y3 - y2 * x4 + y3 * x4 + x2 * y4 + y1 * x3 - y4 * x3) / (x2 * y3 * h + y2 * x4 * h - y3 * x4 * h - x2 * y4 * h - y2 * h * x3 + y4 * h * x3);
         float persp2 = 1;
         float persp2 = 1;
 
 
-        return new SKMatrix(scaleX, skewX, transX, skewY, scaleY, transY, persp0, persp1, persp2);
+        return new Matrix3X3(scaleX, skewX, transX, skewY, scaleY, transY, persp0, persp1, persp2);
     }
     }
 
 
     public static (ShapeCorners, ShapeCorners) CreateStretchedHexagon(VecD centerPos, double hexagonSide, double stretchX)
     public static (ShapeCorners, ShapeCorners) CreateStretchedHexagon(VecD centerPos, double hexagonSide, double stretchX)

+ 9 - 7
src/ChunkyImageLib/Operations/PixelOperation.cs

@@ -1,5 +1,7 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
@@ -8,24 +10,24 @@ internal class PixelOperation : IDrawOperation
 {
 {
     public bool IgnoreEmptyChunks => false;
     public bool IgnoreEmptyChunks => false;
     private readonly VecI pixel;
     private readonly VecI pixel;
-    private readonly SKColor color;
-    private readonly SKBlendMode blendMode;
-    private readonly SKPaint paint;
+    private readonly Color color;
+    private readonly BlendMode blendMode;
+    private readonly Paint paint;
 
 
-    public PixelOperation(VecI pixel, SKColor color, SKBlendMode blendMode)
+    public PixelOperation(VecI pixel, Color color, BlendMode blendMode)
     {
     {
         this.pixel = pixel;
         this.pixel = pixel;
         this.color = color;
         this.color = color;
         this.blendMode = blendMode;
         this.blendMode = blendMode;
-        paint = new SKPaint() { BlendMode = blendMode };
+        paint = new Paint() { BlendMode = blendMode };
     }
     }
 
 
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     {
     {
         // a hacky way to make the lines look slightly better on non full res chunks
         // a hacky way to make the lines look slightly better on non full res chunks
-        paint.Color = new SKColor(color.Red, color.Green, color.Blue, (byte)(color.Alpha * chunk.Resolution.Multiplier()));
+        paint.Color = new Color(color.R, color.G, color.B, (byte)(color.A * chunk.Resolution.Multiplier()));
 
 
-        SKSurface surf = chunk.Surface.DrawingSurface;
+        DrawingSurface surf = chunk.Surface.DrawingSurface;
         surf.Canvas.Save();
         surf.Canvas.Save();
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);

+ 12 - 10
src/ChunkyImageLib/Operations/PixelsOperation.cs

@@ -1,5 +1,7 @@
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
@@ -7,29 +9,29 @@ namespace ChunkyImageLib.Operations;
 internal class PixelsOperation : IDrawOperation
 internal class PixelsOperation : IDrawOperation
 {
 {
     public bool IgnoreEmptyChunks => false;
     public bool IgnoreEmptyChunks => false;
-    private readonly SKPoint[] pixels;
-    private readonly SKColor color;
-    private readonly SKBlendMode blendMode;
-    private readonly SKPaint paint;
+    private readonly Point[] pixels;
+    private readonly Color color;
+    private readonly BlendMode blendMode;
+    private readonly Paint paint;
 
 
-    public PixelsOperation(IEnumerable<VecI> pixels, SKColor color, SKBlendMode blendMode)
+    public PixelsOperation(IEnumerable<VecI> pixels, Color color, BlendMode blendMode)
     {
     {
-        this.pixels = pixels.Select(pixel => (SKPoint)pixel).ToArray();
+        this.pixels = pixels.Select(pixel => (Point)pixel).ToArray();
         this.color = color;
         this.color = color;
         this.blendMode = blendMode;
         this.blendMode = blendMode;
-        paint = new SKPaint() { BlendMode = blendMode };
+        paint = new Paint() { BlendMode = blendMode };
     }
     }
 
 
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     public void DrawOnChunk(Chunk chunk, VecI chunkPos)
     {
     {
         // a hacky way to make the lines look slightly better on non full res chunks
         // a hacky way to make the lines look slightly better on non full res chunks
-        paint.Color = new SKColor(color.Red, color.Green, color.Blue, (byte)(color.Alpha * chunk.Resolution.Multiplier()));
+        paint.Color = new Color(color.R, color.G, color.B, (byte)(color.A * chunk.Resolution.Multiplier()));
 
 
-        SKSurface surf = chunk.Surface.DrawingSurface;
+        DrawingSurface surf = chunk.Surface.DrawingSurface;
         surf.Canvas.Save();
         surf.Canvas.Save();
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Scale((float)chunk.Resolution.Multiplier());
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);
         surf.Canvas.Translate(-chunkPos * ChunkyImage.FullChunkSize);
-        surf.Canvas.DrawPoints(SKPointMode.Points, pixels, paint);
+        surf.Canvas.DrawPoints(PointMode.Points, pixels, paint);
         surf.Canvas.Restore();
         surf.Canvas.Restore();
     }
     }
 
 

+ 6 - 5
src/ChunkyImageLib/Operations/ReplaceColorOperation.cs

@@ -8,14 +8,15 @@ using System.Threading.Tasks;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Shaders;
 using ChunkyImageLib.Shaders;
 using ComputeSharp;
 using ComputeSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using SkiaSharp;
 using SkiaSharp;
 
 
 namespace ChunkyImageLib.Operations;
 namespace ChunkyImageLib.Operations;
 internal class ReplaceColorOperation : IDrawOperation
 internal class ReplaceColorOperation : IDrawOperation
 {
 {
-    private readonly SKColor oldColor;
-    private readonly SKColor newColor;
+    private readonly Color oldColor;
+    private readonly Color newColor;
 
 
     private readonly ColorBounds oldColorBounds;
     private readonly ColorBounds oldColorBounds;
     private readonly HlslColorBounds oldColorBoundsHlsl;
     private readonly HlslColorBounds oldColorBoundsHlsl;
@@ -23,12 +24,12 @@ internal class ReplaceColorOperation : IDrawOperation
 
 
     public bool IgnoreEmptyChunks => true;
     public bool IgnoreEmptyChunks => true;
 
 
-    public ReplaceColorOperation(SKColor oldColor, SKColor newColor)
+    public ReplaceColorOperation(Color oldColor, Color newColor)
     {
     {
         this.oldColor = oldColor;
         this.oldColor = oldColor;
         this.newColor = newColor;
         this.newColor = newColor;
         oldColorBounds = new ColorBounds(oldColor);
         oldColorBounds = new ColorBounds(oldColor);
-        oldColorBoundsHlsl = new HlslColorBounds(new Float4(oldColor.Red, oldColor.Green, oldColor.Blue, oldColor.Alpha));
+        oldColorBoundsHlsl = new HlslColorBounds(new Float4(oldColor.R, oldColor.G, oldColor.B, oldColor.A));
         newColorBits = newColor.ToULong();
         newColorBits = newColor.ToULong();
     }
     }
 
 
@@ -37,7 +38,7 @@ internal class ReplaceColorOperation : IDrawOperation
         ReplaceColor(oldColorBoundsHlsl, newColor, chunk);
         ReplaceColor(oldColorBoundsHlsl, newColor, chunk);
     }
     }
 
 
-    private static void ReplaceColor(HlslColorBounds oldColorBounds, SKColor newColor, Chunk chunk)
+    private static void ReplaceColor(HlslColorBounds oldColorBounds, Color newColor, Chunk chunk)
     {
     {
         Span<UInt2> span = chunk.Surface.DrawingSurface.PeekPixels().GetPixelSpan<uint2>();
         Span<UInt2> span = chunk.Surface.DrawingSurface.PeekPixels().GetPixelSpan<uint2>();
         using var texture = GraphicsDevice.GetDefault()
         using var texture = GraphicsDevice.GetDefault()

+ 1 - 1
src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs

@@ -9,7 +9,7 @@ namespace PixiEditor.DrawingApi.Core.Bridge
         public IDrawingBackendColorOperations ColorOperations { get; }
         public IDrawingBackendColorOperations ColorOperations { get; }
         public IImageOperations ImageOperations { get; }
         public IImageOperations ImageOperations { get; }
         public ICanvasOperations CanvasOperations { get; }
         public ICanvasOperations CanvasOperations { get; }
-        public IPaintOperations PaintOperations { get; set; }
+        public IPaintOperations PaintImplementation { get; set; }
         public IVectorPathImplementation PathImplementation { get; set; }
         public IVectorPathImplementation PathImplementation { get; set; }
         public IMatrix3X3Implementation MatrixImplementation { get; set; }
         public IMatrix3X3Implementation MatrixImplementation { get; set; }
     }
     }

+ 1 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IVectorPathImplementation.cs

@@ -21,4 +21,5 @@ public interface IVectorPathImplementation
     public IntPtr Create();
     public IntPtr Create();
     public IntPtr Clone(VectorPath other);
     public IntPtr Clone(VectorPath other);
     public RectD GetTightBounds(VectorPath vectorPath);
     public RectD GetTightBounds(VectorPath vectorPath);
+    public void Transform(VectorPath vectorPath, Matrix3X3 matrix);
 }
 }

+ 11 - 3
src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasOperations.cs

@@ -7,12 +7,20 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
     public interface ICanvasOperations
     public interface ICanvasOperations
     {
     {
         public void DrawPixel(int posX, int posY, Paint drawingPaint);
         public void DrawPixel(int posX, int posY, Paint drawingPaint);
-        public void DrawSurface(DrawingSurface drawingSurface, int x, int y);
+        public void DrawSurface(DrawingSurface drawingSurface, int x, int y, Paint paint);
         public void DrawImage(Image image, int x, int y);
         public void DrawImage(Image image, int x, int y);
         public int Save();
         public int Save();
         public void Restore();
         public void Restore();
-        public void Scale(float multiplier);
-        public void Translate(VecI vector);
+        public void Scale(float sizeX, float sizeY);
+        public void Translate(float translationX, float translationY);
         public void DrawPath(VectorPath path, Paint paint);
         public void DrawPath(VectorPath path, Paint paint);
+        public void DrawPoint(VecI pos, Paint paint);
+
+        public void DrawPoints(PointMode pointMode, Point[] points, Paint paint);
+        public void DrawRect(int x, int y, int width, int height, Paint paint);
+        public void ClipPath(VectorPath clipPath);
+        public void ClipRect(RectD rect);
+        public void Clear();
+        public void DrawLine(VecI from, VecI to, Paint paint);
     }
     }
 }
 }

+ 4 - 2
src/PixiEditor.DrawingApi.Core/Bridge/Operations/IPaintOperations.cs

@@ -1,9 +1,11 @@
-using PixiEditor.DrawingApi.Core.Surface;
+using System;
+using PixiEditor.DrawingApi.Core.Surface;
 
 
 namespace PixiEditor.DrawingApi.Core.Bridge.Operations
 namespace PixiEditor.DrawingApi.Core.Bridge.Operations
 {
 {
     public interface IPaintOperations
     public interface IPaintOperations
     {
     {
-        public void Dispose(Paint paint);
+        public IntPtr CreatePaint();
+        public void Dispose(IntPtr paintObjPointer);
     }
     }
 }
 }

+ 436 - 0
src/PixiEditor.DrawingApi.Core/ColorsImpl/Colors.cs

@@ -0,0 +1,436 @@
+using System.Runtime.InteropServices;
+
+namespace PixiEditor.DrawingApi.Core.ColorsImpl;
+
+/// <summary>Definitions for some common color names.</summary>
+[StructLayout(LayoutKind.Sequential, Size = 1)]
+public struct Colors
+{
+    /// <summary>Gets the predefined color of alice blue, or #FFF0F8FF.</summary>
+    public static Color AliceBlue = new(4293982463U);
+
+    /// <summary>Gets the predefined color of antique white, or #FFFAEBD7.</summary>
+    public static Color AntiqueWhite = new(4294634455U);
+
+    /// <summary>Gets the predefined color of aqua, or #FF00FFFF.</summary>
+    public static Color Aqua = new(4278255615U);
+
+    /// <summary>Gets the predefined color of aquamarine, or #FF7FFFD4.</summary>
+    public static Color Aquamarine = new(4286578644U);
+
+    /// <summary>Gets the predefined color of azure, or #FFF0FFFF.</summary>
+    public static Color Azure = new(4293984255U);
+
+    /// <summary>Gets the predefined color of beige, or #FFF5F5DC.</summary>
+    public static Color Beige = new(4294309340U);
+
+    /// <summary>Gets the predefined color of bisque, or #FFFFE4C4.</summary>
+    public static Color Bisque = new(4294960324U);
+
+    /// <summary>Gets the predefined color of black, or #FF000000.</summary>
+    public static Color Black = new(4278190080U);
+
+    /// <summary>Gets the predefined color of blanched almond, or #FFFFEBCD.</summary>
+    public static Color BlanchedAlmond = new(4294962125U);
+
+    /// <summary>Gets the predefined color of blue, or #FF0000FF.</summary>
+    public static Color Blue = new(4278190335U);
+
+    /// <summary>Gets the predefined color of blue violet, or #FF8A2BE2.</summary>
+    public static Color BlueViolet = new(4287245282U);
+
+    /// <summary>Gets the predefined color of brown, or #FFA52A2A.</summary>
+    public static Color Brown = new(4289014314U);
+
+    /// <summary>Gets the predefined color of burly wood, or #FFDEB887.</summary>
+    public static Color BurlyWood = new(4292786311U);
+
+    /// <summary>Gets the predefined color of cadet blue, or #FF5F9EA0.</summary>
+    public static Color CadetBlue = new(4284456608U);
+
+    /// <summary>Gets the predefined color of chartreuse, or #FF7FFF00.</summary>
+    public static Color Chartreuse = new(4286578432U);
+
+    /// <summary>Gets the predefined color of chocolate, or #FFD2691E.</summary>
+    public static Color Chocolate = new(4291979550U);
+
+    /// <summary>Gets the predefined color of coral, or #FFFF7F50.</summary>
+    public static Color Coral = new(4294934352U);
+
+    /// <summary>Gets the predefined color of cornflower blue, or #FF6495ED.</summary>
+    public static Color CornflowerBlue = new(4284782061U);
+
+    /// <summary>Gets the predefined color of cornsilk, or #FFFFF8DC.</summary>
+    public static Color Cornsilk = new(4294965468U);
+
+    /// <summary>Gets the predefined color of crimson, or #FFDC143C.</summary>
+    public static Color Crimson = new(4292613180U);
+
+    /// <summary>Gets the predefined color of cyan, or #FF00FFFF.</summary>
+    public static Color Cyan = new(4278255615U);
+
+    /// <summary>Gets the predefined color of dark blue, or #FF00008B.</summary>
+    public static Color DarkBlue = new(4278190219U);
+
+    /// <summary>Gets the predefined color of dark cyan, or #FF008B8B.</summary>
+    public static Color DarkCyan = new(4278225803U);
+
+    /// <summary>Gets the predefined color of dark goldenrod, or #FFB8860B.</summary>
+    public static Color DarkGoldenrod = new(4290283019U);
+
+    /// <summary>Gets the predefined color of dark gray, or #FFA9A9A9.</summary>
+    public static Color DarkGray = new(4289309097U);
+
+    /// <summary>Gets the predefined color of dark green, or #FF006400.</summary>
+    public static Color DarkGreen = new(4278215680U);
+
+    /// <summary>Gets the predefined color of dark khaki, or #FFBDB76B.</summary>
+    public static Color DarkKhaki = new(4290623339U);
+
+    /// <summary>Gets the predefined color of dark magenta, or #FF8B008B.</summary>
+    public static Color DarkMagenta = new(4287299723U);
+
+    /// <summary>Gets the predefined color of dark olive green, or #FF556B2F.</summary>
+    public static Color DarkOliveGreen = new(4283788079U);
+
+    /// <summary>Gets the predefined color of dark orange, or #FFFF8C00.</summary>
+    public static Color DarkOrange = new(4294937600U);
+
+    /// <summary>Gets the predefined color of dark orchid, or #FF9932CC.</summary>
+    public static Color DarkOrchid = new(4288230092U);
+
+    /// <summary>Gets the predefined color of dark red, or #FF8B0000.</summary>
+    public static Color DarkRed = new(4287299584U);
+
+    /// <summary>Gets the predefined color of dark salmon, or #FFE9967A.</summary>
+    public static Color DarkSalmon = new(4293498490U);
+
+    /// <summary>Gets the predefined color of dark sea green, or #FF8FBC8B.</summary>
+    public static Color DarkSeaGreen = new(4287609995U);
+
+    /// <summary>Gets the predefined color of dark slate blue, or #FF483D8B.</summary>
+    public static Color DarkSlateBlue = new(4282924427U);
+
+    /// <summary>Gets the predefined color of dark slate gray, or #FF2F4F4F.</summary>
+    public static Color DarkSlateGray = new(4281290575U);
+
+    /// <summary>Gets the predefined color of dark turquoise, or #FF00CED1.</summary>
+    public static Color DarkTurquoise = new(4278243025U);
+
+    /// <summary>Gets the predefined color of dark violet, or #FF9400D3.</summary>
+    public static Color DarkViolet = new(4287889619U);
+
+    /// <summary>Gets the predefined color of deep pink, or #FFFF1493.</summary>
+    public static Color DeepPink = new(4294907027U);
+
+    /// <summary>Gets the predefined color of deep sky blue, or #FF00BFFF.</summary>
+    public static Color DeepSkyBlue = new(4278239231U);
+
+    /// <summary>Gets the predefined color of dim gray, or #FF696969.</summary>
+    public static Color DimGray = new(4285098345U);
+
+    /// <summary>Gets the predefined color of dodger blue, or #FF1E90FF.</summary>
+    public static Color DodgerBlue = new(4280193279U);
+
+    /// <summary>Gets the predefined color of firebrick, or #FFB22222.</summary>
+    public static Color Firebrick = new(4289864226U);
+
+    /// <summary>Gets the predefined color of floral white, or #FFFFFAF0.</summary>
+    public static Color FloralWhite = new(4294966000U);
+
+    /// <summary>Gets the predefined color of forest green, or #FF228B22.</summary>
+    public static Color ForestGreen = new(4280453922U);
+
+    /// <summary>Gets the predefined color of fuchsia, or #FFFF00FF.</summary>
+    public static Color Fuchsia = new(4294902015U);
+
+    /// <summary>Gets the predefined color of gainsboro, or #FFDCDCDC.</summary>
+    public static Color Gainsboro = new(4292664540U);
+
+    /// <summary>Gets the predefined color of ghost white, or #FFF8F8FF.</summary>
+    public static Color GhostWhite = new(4294506751U);
+
+    /// <summary>Gets the predefined color of gold, or #FFFFD700.</summary>
+    public static Color Gold = new(4294956800U);
+
+    /// <summary>Gets the predefined color of goldenrod, or #FFDAA520.</summary>
+    public static Color Goldenrod = new(4292519200U);
+
+    /// <summary>Gets the predefined color of gray, or #FF808080.</summary>
+    public static Color Gray = new(4286611584U);
+
+    /// <summary>Gets the predefined color of green, or #FF008000.</summary>
+    public static Color Green = new(4278222848U);
+
+    /// <summary>Gets the predefined color of green yellow, or #FFADFF2F.</summary>
+    public static Color GreenYellow = new(4289593135U);
+
+    /// <summary>Gets the predefined color of honeydew, or #FFF0FFF0.</summary>
+    public static Color Honeydew = new(4293984240U);
+
+    /// <summary>Gets the predefined color of hot pink, or #FFFF69B4.</summary>
+    public static Color HotPink = new(4294928820U);
+
+    /// <summary>Gets the predefined color of indian red, or #FFCD5C5C.</summary>
+    public static Color IndianRed = new(4291648604U);
+
+    /// <summary>Gets the predefined color of indigo, or #FF4B0082.</summary>
+    public static Color Indigo = new(4283105410U);
+
+    /// <summary>Gets the predefined color of ivory, or #FFFFFFF0.</summary>
+    public static Color Ivory = new(4294967280U);
+
+    /// <summary>Gets the predefined color of khaki, or #FFF0E68C.</summary>
+    public static Color Khaki = new(4293977740U);
+
+    /// <summary>Gets the predefined color of lavender, or #FFE6E6FA.</summary>
+    public static Color Lavender = new(4293322490U);
+
+    /// <summary>Gets the predefined color of lavender blush, or #FFFFF0F5.</summary>
+    public static Color LavenderBlush = new(4294963445U);
+
+    /// <summary>Gets the predefined color of lawn green, or #FF7CFC00.</summary>
+    public static Color LawnGreen = new(4286381056U);
+
+    /// <summary>Gets the predefined color of lemon chiffon, or #FFFFFACD.</summary>
+    public static Color LemonChiffon = new(4294965965U);
+
+    /// <summary>Gets the predefined color of light blue, or #FFADD8E6.</summary>
+    public static Color LightBlue = new(4289583334U);
+
+    /// <summary>Gets the predefined color of light coral, or #FFF08080.</summary>
+    public static Color LightCoral = new(4293951616U);
+
+    /// <summary>Gets the predefined color of light cyan, or #FFE0FFFF.</summary>
+    public static Color LightCyan = new(4292935679U);
+
+    /// <summary>Gets the predefined color of light goldenrod yellow, or #FFFAFAD2.</summary>
+    public static Color LightGoldenrodYellow = new(4294638290U);
+
+    /// <summary>Gets the predefined color of light gray, or #FFD3D3D3.</summary>
+    public static Color LightGray = new(4292072403U);
+
+    /// <summary>Gets the predefined color of light green, or #FF90EE90.</summary>
+    public static Color LightGreen = new(4287688336U);
+
+    /// <summary>Gets the predefined color of light pink, or #FFFFB6C1.</summary>
+    public static Color LightPink = new(4294948545U);
+
+    /// <summary>Gets the predefined color of light salmon, or #FFFFA07A.</summary>
+    public static Color LightSalmon = new(4294942842U);
+
+    /// <summary>Gets the predefined color of light sea green, or #FF20B2AA.</summary>
+    public static Color LightSeaGreen = new(4280332970U);
+
+    /// <summary>Gets the predefined color of light sky blue, or #FF87CEFA.</summary>
+    public static Color LightSkyBlue = new(4287090426U);
+
+    /// <summary>Gets the predefined color of light slate gray, or #FF778899.</summary>
+    public static Color LightSlateGray = new(4286023833U);
+
+    /// <summary>Gets the predefined color of light steel blue, or #FFB0C4DE.</summary>
+    public static Color LightSteelBlue = new(4289774814U);
+
+    /// <summary>Gets the predefined color of light yellow, or #FFFFFFE0.</summary>
+    public static Color LightYellow = new(4294967264U);
+
+    /// <summary>Gets the predefined color of lime, or #FF00FF00.</summary>
+    public static Color Lime = new(4278255360U);
+
+    /// <summary>Gets the predefined color of lime green, or #FF32CD32.</summary>
+    public static Color LimeGreen = new(4281519410U);
+
+    /// <summary>Gets the predefined color of linen, or #FFFAF0E6.</summary>
+    public static Color Linen = new(4294635750U);
+
+    /// <summary>Gets the predefined color of magenta, or #FFFF00FF.</summary>
+    public static Color Magenta = new(4294902015U);
+
+    /// <summary>Gets the predefined color of maroon, or #FF800000.</summary>
+    public static Color Maroon = new(4286578688U);
+
+    /// <summary>Gets the predefined color of medium aquamarine, or #FF66CDAA.</summary>
+    public static Color MediumAquamarine = new(4284927402U);
+
+    /// <summary>Gets the predefined color of medium blue, or #FF0000CD.</summary>
+    public static Color MediumBlue = new(4278190285U);
+
+    /// <summary>Gets the predefined color of medium orchid, or #FFBA55D3.</summary>
+    public static Color MediumOrchid = new(4290401747U);
+
+    /// <summary>Gets the predefined color of medium purple, or #FF9370DB.</summary>
+    public static Color MediumPurple = new(4287852763U);
+
+    /// <summary>Gets the predefined color of medium sea green, or #FF3CB371.</summary>
+    public static Color MediumSeaGreen = new(4282168177U);
+
+    /// <summary>Gets the predefined color of medium slate blue, or #FF7B68EE.</summary>
+    public static Color MediumSlateBlue = new(4286277870U);
+
+    /// <summary>Gets the predefined color of medium spring green, or #FF00FA9A.</summary>
+    public static Color MediumSpringGreen = new(4278254234U);
+
+    /// <summary>Gets the predefined color of medium turquoise, or #FF48D1CC.</summary>
+    public static Color MediumTurquoise = new(4282962380U);
+
+    /// <summary>Gets the predefined color of medium violet red, or #FFC71585.</summary>
+    public static Color MediumVioletRed = new(4291237253U);
+
+    /// <summary>Gets the predefined color of midnight blue, or #FF191970.</summary>
+    public static Color MidnightBlue = new(4279834992U);
+
+    /// <summary>Gets the predefined color of mint cream, or #FFF5FFFA.</summary>
+    public static Color MintCream = new(4294311930U);
+
+    /// <summary>Gets the predefined color of misty rose, or #FFFFE4E1.</summary>
+    public static Color MistyRose = new(4294960353U);
+
+    /// <summary>Gets the predefined color of moccasin, or #FFFFE4B5.</summary>
+    public static Color Moccasin = new(4294960309U);
+
+    /// <summary>Gets the predefined color of navajo white, or #FFFFDEAD.</summary>
+    public static Color NavajoWhite = new(4294958765U);
+
+    /// <summary>Gets the predefined color of navy, or #FF000080.</summary>
+    public static Color Navy = new(4278190208U);
+
+    /// <summary>Gets the predefined color of old lace, or #FFFDF5E6.</summary>
+    public static Color OldLace = new(4294833638U);
+
+    /// <summary>Gets the predefined color of olive, or #FF808000.</summary>
+    public static Color Olive = new(4286611456U);
+
+    /// <summary>Gets the predefined color of olive drab, or #FF6B8E23.</summary>
+    public static Color OliveDrab = new(4285238819U);
+
+    /// <summary>Gets the predefined color of orange, or #FFFFA500.</summary>
+    public static Color Orange = new(4294944000U);
+
+    /// <summary>Gets the predefined color of orange red, or #FFFF4500.</summary>
+    public static Color OrangeRed = new(4294919424U);
+
+    /// <summary>Gets the predefined color of orchid, or #FFDA70D6.</summary>
+    public static Color Orchid = new(4292505814U);
+
+    /// <summary>Gets the predefined color of pale goldenrod, or #FFEEE8AA.</summary>
+    public static Color PaleGoldenrod = new(4293847210U);
+
+    /// <summary>Gets the predefined color of pale green, or #FF98FB98.</summary>
+    public static Color PaleGreen = new(4288215960U);
+
+    /// <summary>Gets the predefined color of pale turquoise, or #FFAFEEEE.</summary>
+    public static Color PaleTurquoise = new(4289720046U);
+
+    /// <summary>Gets the predefined color of pale violet red, or #FFDB7093.</summary>
+    public static Color PaleVioletRed = new(4292571283U);
+
+    /// <summary>Gets the predefined color of papaya whip, or #FFFFEFD5.</summary>
+    public static Color PapayaWhip = new(4294963157U);
+
+    /// <summary>Gets the predefined color of peach puff, or #FFFFDAB9.</summary>
+    public static Color PeachPuff = new(4294957753U);
+
+    /// <summary>Gets the predefined color of peru, or #FFCD853F.</summary>
+    public static Color Peru = new(4291659071U);
+
+    /// <summary>Gets the predefined color of pink, or #FFFFC0CB.</summary>
+    public static Color Pink = new(4294951115U);
+
+    /// <summary>Gets the predefined color of plum, or #FFDDA0DD.</summary>
+    public static Color Plum = new(4292714717U);
+
+    /// <summary>Gets the predefined color of powder blue, or #FFB0E0E6.</summary>
+    public static Color PowderBlue = new(4289781990U);
+
+    /// <summary>Gets the predefined color of purple, or #FF800080.</summary>
+    public static Color Purple = new(4286578816U);
+
+    /// <summary>Gets the predefined color of red, or #FFFF0000.</summary>
+    public static Color Red = new(4294901760U);
+
+    /// <summary>Gets the predefined color of rosy brown, or #FFBC8F8F.</summary>
+    public static Color RosyBrown = new(4290547599U);
+
+    /// <summary>Gets the predefined color of royal blue, or #FF4169E1.</summary>
+    public static Color RoyalBlue = new(4282477025U);
+
+    /// <summary>Gets the predefined color of saddle brown, or #FF8B4513.</summary>
+    public static Color SaddleBrown = new(4287317267U);
+
+    /// <summary>Gets the predefined color of salmon, or #FFFA8072.</summary>
+    public static Color Salmon = new(4294606962U);
+
+    /// <summary>Gets the predefined color of sandy brown, or #FFF4A460.</summary>
+    public static Color SandyBrown = new(4294222944U);
+
+    /// <summary>Gets the predefined color of sea green, or #FF2E8B57.</summary>
+    public static Color SeaGreen = new(4281240407U);
+
+    /// <summary>Gets the predefined color of sea shell, or #FFFFF5EE.</summary>
+    public static Color SeaShell = new(4294964718U);
+
+    /// <summary>Gets the predefined color of sienna, or #FFA0522D.</summary>
+    public static Color Sienna = new(4288696877U);
+
+    /// <summary>Gets the predefined color of silver, or #FFC0C0C0.</summary>
+    public static Color Silver = new(4290822336U);
+
+    /// <summary>Gets the predefined color of sky blue, or #FF87CEEB.</summary>
+    public static Color SkyBlue = new(4287090411U);
+
+    /// <summary>Gets the predefined color of slate blue, or #FF6A5ACD.</summary>
+    public static Color SlateBlue = new(4285160141U);
+
+    /// <summary>Gets the predefined color of slate gray, or #FF708090.</summary>
+    public static Color SlateGray = new(4285563024U);
+
+    /// <summary>Gets the predefined color of snow, or #FFFFFAFA.</summary>
+    public static Color Snow = new(4294966010U);
+
+    /// <summary>Gets the predefined color of spring green, or #FF00FF7F.</summary>
+    public static Color SpringGreen = new(4278255487U);
+
+    /// <summary>Gets the predefined color of steel blue, or #FF4682B4.</summary>
+    public static Color SteelBlue = new(4282811060U);
+
+    /// <summary>Gets the predefined color of tan, or #FFD2B48C.</summary>
+    public static Color Tan = new(4291998860U);
+
+    /// <summary>Gets the predefined color of teal, or #FF008080.</summary>
+    public static Color Teal = new(4278222976U);
+
+    /// <summary>Gets the predefined color of thistle, or #FFD8BFD8.</summary>
+    public static Color Thistle = new(4292394968U);
+
+    /// <summary>Gets the predefined color of tomato, or #FFFF6347.</summary>
+    public static Color Tomato = new(4294927175U);
+
+    /// <summary>Gets the predefined color of turquoise, or #FF40E0D0.</summary>
+    public static Color Turquoise = new(4282441936U);
+
+    /// <summary>Gets the predefined color of violet, or #FFEE82EE.</summary>
+    public static Color Violet = new(4293821166U);
+
+    /// <summary>Gets the predefined color of wheat, or #FFF5DEB3.</summary>
+    public static Color Wheat = new(4294303411U);
+
+    /// <summary>Gets the predefined color of white, or #FFFFFFFF.</summary>
+    public static Color White = new(uint.MaxValue);
+
+    /// <summary>Gets the predefined color of white smoke, or #FFF5F5F5.</summary>
+    public static Color WhiteSmoke = new(4294309365U);
+
+    /// <summary>Gets the predefined color of yellow, or #FFFFFF00.</summary>
+    public static Color Yellow = new(4294967040U);
+
+    /// <summary>Gets the predefined color of yellow green, or #FF9ACD32.</summary>
+    public static Color YellowGreen = new(4288335154U);
+
+    /// <summary>Gets the predefined color of white transparent, or #00FFFFFF.</summary>
+    public static Color Transparent = new(16777215U);
+
+    /// <summary>Gets the predefined empty color (black transparent), or #00000000.</summary>
+    /// <value />
+
+    public static Color Empty => new(0U);
+}

+ 1 - 303
src/PixiEditor.DrawingApi.Core/Numerics/Matrix3X3.cs

@@ -303,7 +303,7 @@ public struct Matrix3X3 : IEquatable<Matrix3X3>
             Persp2 = 1f
             Persp2 = 1f
         };
         };
     }
     }
-    
+
     public static Matrix3X3 CreateScaleTranslation(float sx, float sy, float tx, float ty)
     public static Matrix3X3 CreateScaleTranslation(float sx, float sy, float tx, float ty)
     {
     {
         if (sx == 0.0 && sy == 0.0 && tx == 0.0 && ty == 0.0)
         if (sx == 0.0 && sy == 0.0 && tx == 0.0 && ty == 0.0)
@@ -344,308 +344,6 @@ public struct Matrix3X3 : IEquatable<Matrix3X3>
     {
     {
         return DrawingBackendApi.Current.MatrixImplementation.Concat(in first, in second);
         return DrawingBackendApi.Current.MatrixImplementation.Concat(in first, in second);
     }
     }
-    
-    public readonly unsafe Matrix3X3 PreConcat(Matrix3X3 matrix)
-    {
-        var Matrix3x3 = this;
-        SkiaApi.sk_matrix_pre_concat(&Matrix3x3, &matrix);
-        return Matrix3x3;
-    }
-    
-    public readonly unsafe Matrix3X3 PostConcat(Matrix3X3 matrix)
-    {
-        var Matrix3x3 = this;
-        SkiaApi.sk_matrix_post_concat(&Matrix3x3, &matrix);
-        return Matrix3x3;
-    }
-
-    /// <param name="target">The result matrix value.</param>
-    /// <param name="first">The first matrix to concatenate.</param>
-    /// <param name="second">The second matrix to concatenate.</param>
-    /// <summary>Concatenates the specified matrices into the resulting target matrix.</summary>
-    /// <remarks>Either source matrices can also be the target matrix.</remarks>
-    public static unsafe void Concat(ref Matrix3X3 target, Matrix3X3 first, Matrix3X3 second)
-    {
-        fixed (Matrix3X3* result = &target)
-        {
-            SkiaApi.sk_matrix_concat(result, &first, &second);
-        }
-    }
-
-    /// <param name="target">The result matrix value.</param>
-    /// <param name="first">The first matrix to concatenate.</param>
-    /// <param name="second">The second matrix to concatenate.</param>
-    /// <summary>Concatenates the specified matrices into the resulting target matrix.</summary>
-    /// <remarks>Either source matrices can also be the target matrix.</remarks>
-    public static unsafe void Concat(ref Matrix3X3 target, ref Matrix3X3 first, ref Matrix3X3 second)
-    {
-        fixed (Matrix3X3* result = &target)
-        fixed (Matrix3X3* first1 = &first)
-        fixed (Matrix3X3* second1 = &second)
-        {
-            SkiaApi.sk_matrix_concat(result, first1, second1);
-        }
-    }
-
-    /// <param name="target">The target matrix.</param>
-    /// <param name="matrix">The matrix to be post-concatenated.</param>
-    /// <summary>Pre-concatenates the matrix to the target matrix.</summary>
-    /// <remarks>This represents: result = target * matrix</remarks>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    [Obsolete("Use PreConcat(Matrix3x3) instead.")]
-    public static unsafe void PreConcat(ref Matrix3X3 target, Matrix3X3 matrix)
-    {
-        fixed (Matrix3X3* result = &target)
-        {
-            SkiaApi.sk_matrix_pre_concat(result, &matrix);
-        }
-    }
-
-    /// <param name="target">The target matrix.</param>
-    /// <param name="matrix">The matrix to be post-concatenated.</param>
-    /// <summary>Pre-concatenates the matrix to the target matrix.</summary>
-    /// <remarks>This represents: result = target * matrix</remarks>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    [Obsolete("Use PreConcat(Matrix3x3) instead.")]
-    public static unsafe void PreConcat(ref Matrix3X3 target, ref Matrix3X3 matrix)
-    {
-        fixed (Matrix3X3* result = &target)
-        fixed (Matrix3X3* matrix1 = &matrix)
-        {
-            SkiaApi.sk_matrix_pre_concat(result, matrix1);
-        }
-    }
-
-    /// <param name="target">The target matrix.</param>
-    /// <param name="matrix">The matrix to be post-concatenated.</param>
-    /// <summary>Post-concatenates the matrix to the target matrix.</summary>
-    /// <remarks>This represents: result = matrix * target</remarks>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    [Obsolete("Use PostConcat(Matrix3x3) instead.")]
-    public static unsafe void PostConcat(ref Matrix3X3 target, Matrix3X3 matrix)
-    {
-        fixed (Matrix3X3* result = &target)
-        {
-            SkiaApi.sk_matrix_post_concat(result, &matrix);
-        }
-    }
-
-    /// <param name="target">The target matrix.</param>
-    /// <param name="matrix">The matrix to be post-concatenated.</param>
-    /// <summary>Post-concatenates the matrix to the target matrix.</summary>
-    /// <remarks>This represents: result = matrix * target</remarks>
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    [Obsolete("Use PostConcat(Matrix3x3) instead.")]
-    public static unsafe void PostConcat(ref Matrix3X3 target, ref Matrix3X3 matrix)
-    {
-        fixed (Matrix3X3* result = &target)
-        fixed (Matrix3X3* matrix1 = &matrix)
-        {
-            SkiaApi.sk_matrix_post_concat(result, matrix1);
-        }
-    }
-
-    /// <param name="source">The source rectangle to map.</param>
-    /// <summary>Applies the matrix to a rectangle.</summary>
-    /// <returns>Returns the mapped rectangle.</returns>
-    /// <remarks />
-    public readonly unsafe SKRect MapRect(SKRect source)
-    {
-        SKRect skRect;
-        fixed (Matrix3X3* matrix = &this)
-        {
-            SkiaApi.sk_matrix_map_rect(matrix, &skRect, &source);
-        }
-
-        return skRect;
-    }
-
-    /// <param name="matrix">The transformation matrix.</param>
-    /// <param name="dest">The mapped rectangle.</param>
-    /// <param name="source">The source rectangle to map.</param>
-    /// <summary>Applies the matrix to a rectangle.</summary>
-    /// <remarks />
-    [EditorBrowsable(EditorBrowsableState.Never)]
-    [Obsolete("Use MapRect(SKRect) instead.")]
-    public static unsafe void MapRect(ref Matrix3X3 matrix, out SKRect dest, ref SKRect source)
-    {
-        fixed (Matrix3X3* matrix1 = &matrix)
-        fixed (SKRect* dest1 = &dest)
-        fixed (SKRect* source1 = &source)
-        {
-            SkiaApi.sk_matrix_map_rect(matrix1, dest1, source1);
-        }
-    }
-
-    /// <param name="point">The point to map.</param>
-    /// <summary>Applies the matrix to a point.</summary>
-    /// <returns>Returns the mapped point.</returns>
-    /// <remarks>
-    ///     Mapping points uses all components of the matrix. Use
-    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVector(System.Single,System.Single)" /> to ignore the translation.
-    /// </remarks>
-    public readonly SKPoint MapPoint(SKPoint point)
-    {
-        return MapPoint(point.X, point.Y);
-    }
-
-    /// <param name="x">The x-coordinate.</param>
-    /// <param name="y">The y-coordinate.</param>
-    /// <summary>Applies the matrix to a point.</summary>
-    /// <returns>Returns the mapped point.</returns>
-    /// <remarks>
-    ///     Mapping points uses all components of the matrix. Use
-    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVector(System.Single,System.Single)" /> to ignore the translation.
-    /// </remarks>
-    public readonly unsafe SKPoint MapPoint(float x, float y)
-    {
-        SKPoint skPoint;
-        fixed (Matrix3X3* matrix = &this)
-        {
-            SkiaApi.sk_matrix_map_xy(matrix, x, y, &skPoint);
-        }
-
-        return skPoint;
-    }
-
-    /// <param name="result">
-    ///     The array where the mapped results will be stored (needs to have the same number of elements of
-    ///     the <paramref name="points" /> array).
-    /// </param>
-    /// <param name="points">The array of points to be mapped.</param>
-    /// <summary>Applies the matrix to an array of points.</summary>
-    /// <remarks>
-    ///     Mapping points uses all components of the matrix. Use
-    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVectors(SkiaSharp.SKPoint[],SkiaSharp.SKPoint[])" /> to ignore the translation.
-    /// </remarks>
-    public readonly unsafe void MapPoints(SKPoint[] result, SKPoint[] points)
-    {
-        if (result == null)
-        {
-            throw new ArgumentNullException(nameof(result));
-        }
-
-        if (points == null)
-        {
-            throw new ArgumentNullException(nameof(points));
-        }
-
-        if (result.Length != points.Length)
-        {
-            throw new ArgumentException("Buffers must be the same size.");
-        }
-
-        fixed (Matrix3X3* matrix = &this)
-        fixed (SKPoint* dst = result)
-        fixed (SKPoint* src = points)
-        {
-            SkiaApi.sk_matrix_map_points(matrix, dst, src, result.Length);
-        }
-    }
-
-    /// <param name="points">The array of points to be mapped.</param>
-    /// <summary>Applies the matrix to an array of points.</summary>
-    /// <returns>Returns the new array allocated with the mapped results.</returns>
-    /// <remarks>
-    ///     Mapping points uses all components of the matrix. Use
-    ///     <see cref="M:SkiaSharp.Matrix3x3.MapVectors(SkiaSharp.SKPoint[])" /> to ignore the translation.
-    /// </remarks>
-    public readonly SKPoint[] MapPoints(SKPoint[] points)
-    {
-        var result = points != null ? new SKPoint[points.Length] : throw new ArgumentNullException(nameof(points));
-        MapPoints(result, points);
-        return result;
-    }
-
-    /// <param name="vector">To be added.</param>
-    /// <summary>To be added.</summary>
-    /// <returns>To be added.</returns>
-    /// <remarks>To be added.</remarks>
-    public readonly SKPoint MapVector(SKPoint vector)
-    {
-        return MapVector(vector.X, vector.Y);
-    }
-
-    /// <param name="x">The x-component of the vector.</param>
-    /// <param name="y">The y-component of the vector.</param>
-    /// <summary>Applies the matrix to a vector, ignoring translation.</summary>
-    /// <returns>Returns the mapped point.</returns>
-    /// <remarks>
-    ///     Mapping vectors ignores the translation component in the matrix. Use
-    ///     <see cref="M:SkiaSharp.Matrix3x3.MapXY(System.Single,System.Single)" /> to take the translation into consideration.
-    /// </remarks>
-    public readonly unsafe SKPoint MapVector(float x, float y)
-    {
-        SKPoint skPoint;
-        fixed (Matrix3X3* matrix = &this)
-        {
-            SkiaApi.sk_matrix_map_vector(matrix, x, y, &skPoint);
-        }
-
-        return skPoint;
-    }
-
-    /// <param name="result">
-    ///     The array where the mapped results will be stored (needs to have the same number of elements of
-    ///     the <paramref name="vectors" /> array).
-    /// </param>
-    /// <param name="vectors">The array of vectors to map.</param>
-    /// <summary>Apply the to the array of vectors and return the mapped results..</summary>
-    /// <remarks>
-    ///     Mapping vectors ignores the translation component in the matrix. Use
-    ///     <see cref="M:SkiaSharp.Matrix3x3.MapPoints(SkiaSharp.SKPoint[],SkiaSharp.SKPoint[])" /> to take the translation
-    ///     into consideration.
-    /// </remarks>
-    public readonly unsafe void MapVectors(SKPoint[] result, SKPoint[] vectors)
-    {
-        if (result == null)
-        {
-            throw new ArgumentNullException(nameof(result));
-        }
-
-        if (vectors == null)
-        {
-            throw new ArgumentNullException(nameof(vectors));
-        }
-
-        if (result.Length != vectors.Length)
-        {
-            throw new ArgumentException("Buffers must be the same size.");
-        }
-
-        fixed (Matrix3X3* matrix = &this)
-        fixed (SKPoint* dst = result)
-        fixed (SKPoint* src = vectors)
-        {
-            SkiaApi.sk_matrix_map_vectors(matrix, dst, src, result.Length);
-        }
-    }
-
-    /// <param name="vectors">The array of vectors to map.</param>
-    /// <summary>Applies the matrix to the array of vectors, ignoring translation, and returns the mapped results.</summary>
-    /// <returns>Returns the new array allocated with the mapped results.</returns>
-    /// <remarks>
-    ///     Mapping vectors ignores the translation component in the matrix. Use
-    ///     <see cref="M:SkiaSharp.Matrix3x3.MapPoints(SkiaSharp.SKPoint[])" /> to take the translation into consideration.
-    /// </remarks>
-    public readonly SKPoint[] MapVectors(SKPoint[] vectors)
-    {
-        var result = vectors != null ? new SKPoint[vectors.Length] : throw new ArgumentNullException(nameof(vectors));
-        MapVectors(result, vectors);
-        return result;
-    }
-
-    /// <param name="radius">The radius to map.</param>
-    /// <summary>Calculates the mean radius of a circle after it has been mapped by this matrix.</summary>
-    /// <returns>Returns the mean radius.</returns>
-    /// <remarks />
-    public readonly unsafe float MapRadius(float radius)
-    {
-        fixed (Matrix3X3* matrix = &this)
-        {
-            return SkiaApi.sk_matrix_map_radius(matrix, radius);
-        }
-    }
 
 
     private static void SetSinCos(ref Matrix3X3 matrix, float sin, float cos)
     private static void SetSinCos(ref Matrix3X3 matrix, float sin, float cos)
     {
     {

+ 68 - 6
src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs

@@ -9,8 +9,15 @@ namespace PixiEditor.DrawingApi.Core.Surface
     {
     {
         public void DrawPixel(int posX, int posY, Paint drawingPaint) => DrawingBackendApi.Current.CanvasOperations.DrawPixel(posX, posY, drawingPaint);
         public void DrawPixel(int posX, int posY, Paint drawingPaint) => DrawingBackendApi.Current.CanvasOperations.DrawPixel(posX, posY, drawingPaint);
 
 
-        public void DrawSurface(DrawingSurface original, int x, int y) 
-            => DrawingBackendApi.Current.CanvasOperations.DrawSurface(original, x, y);
+        public void DrawSurface(DrawingSurface original, int x, int y, Paint paint) 
+            => DrawingBackendApi.Current.CanvasOperations.DrawSurface(original, x, y, paint);
+        
+        public void DrawSurface(DrawingSurface original, int x, int y) => DrawSurface(original, x, y, null);
+        
+        public void DrawSurface(DrawingSurface surfaceToDraw, VecI size, Paint paint)
+        {
+            DrawSurface(surfaceToDraw, size.X, size.Y, paint);
+        }
 
 
         public void DrawImage(Image image, int x, int y) => DrawingBackendApi.Current.CanvasOperations.DrawImage(image, x, y);
         public void DrawImage(Image image, int x, int y) => DrawingBackendApi.Current.CanvasOperations.DrawImage(image, x, y);
 
 
@@ -23,20 +30,75 @@ namespace PixiEditor.DrawingApi.Core.Surface
         {
         {
             DrawingBackendApi.Current.CanvasOperations.Restore();
             DrawingBackendApi.Current.CanvasOperations.Restore();
         }
         }
+        
+        public void Scale(float s) => DrawingBackendApi.Current.CanvasOperations.Scale(s, s);
+
+        /// <param name="sx">The amount to scale in the x-direction.</param>
+        /// <param name="sy">The amount to scale in the y-direction.</param>
+        /// <summary>Pre-concatenates the current matrix with the specified scale.</summary>
+        public void Scale(float sx, float sy) => DrawingBackendApi.Current.CanvasOperations.Scale(sx, sy);
 
 
-        public void Scale(float multiplier)
+        /// <param name="size">The amount to scale.</param>
+        /// <summary>Pre-concatenates the current matrix with the specified scale.</summary>
+        public void Scale(Point size) => DrawingBackendApi.Current.CanvasOperations.Scale(size.X, size.Y);
+
+        /// <param name="sx">The amount to scale in the x-direction.</param>
+        /// <param name="sy">The amount to scale in the y-direction.</param>
+        /// <param name="px">The x-coordinate for the scaling center.</param>
+        /// <param name="py">The y-coordinate for the scaling center.</param>
+        /// <summary>Pre-concatenates the current matrix with the specified scale, at the specific offset.</summary>
+        public void Scale(float sx, float sy, float px, float py)
         {
         {
-            DrawingBackendApi.Current.CanvasOperations.Scale(multiplier);
+            Translate(px, py);
+            Scale(sx, sy);
+            Translate(-px, -py);
         }
         }
 
 
-        public void Translate(VecI vector)
+        public void Translate(float translationX, float translationY)
         {
         {
-            DrawingBackendApi.Current.CanvasOperations.Translate(vector);
+            DrawingBackendApi.Current.CanvasOperations.Translate(translationX, translationY);
         }
         }
+        
+        public void Translate(VecD vector) => Translate((float)vector.X, (float)vector.Y);
 
 
         public void DrawPath(VectorPath path, Paint paint)
         public void DrawPath(VectorPath path, Paint paint)
         {
         {
             DrawingBackendApi.Current.CanvasOperations.DrawPath(path, paint);
             DrawingBackendApi.Current.CanvasOperations.DrawPath(path, paint);
         }
         }
+        
+        public void DrawPoint(VecI pos, Paint paint)
+        {
+            DrawingBackendApi.Current.CanvasOperations.DrawPoint(pos, paint);
+        }
+
+        public void DrawPoints(PointMode pointMode, Point[] points, Paint paint)
+        {
+            DrawingBackendApi.Current.CanvasOperations.DrawPoints(pointMode, points, paint);
+        }
+
+        public void DrawRect(int x, int y, int width, int height, Paint paint)
+        {
+            DrawingBackendApi.Current.CanvasOperations.DrawRect(x, y, width, height, paint);
+        }
+
+        public void ClipPath(VectorPath clipPath)
+        {
+            DrawingBackendApi.Current.CanvasOperations.ClipPath(clipPath);
+        }
+
+        public void ClipRect(RectD rect)
+        {
+            DrawingBackendApi.Current.CanvasOperations.ClipRect(rect);
+        }
+
+        public void Clear()
+        {
+            DrawingBackendApi.Current.CanvasOperations.Clear();
+        }
+
+        public void DrawLine(VecI from, VecI to, Paint paint)
+        {
+            DrawingBackendApi.Current.CanvasOperations.DrawLine(from, to, paint);
+        }
     }
     }
 }
 }

+ 5 - 0
src/PixiEditor.DrawingApi.Core/Surface/DrawingSurface.cs

@@ -14,5 +14,10 @@ namespace PixiEditor.DrawingApi.Core.Surface
         {
         {
             return DrawingBackendApi.Current.ImageOperations.Snapshot(this);
             return DrawingBackendApi.Current.ImageOperations.Snapshot(this);
         }
         }
+
+        public Pixmap PeekPixels()
+        {
+            
+        }
     }
     }
 }
 }

+ 15 - 3
src/PixiEditor.DrawingApi.Core/Surface/Paint.cs → src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/Paint.cs

@@ -7,16 +7,28 @@ namespace PixiEditor.DrawingApi.Core.Surface
     /// <summary>
     /// <summary>
     ///     Class used to define surface paint, which is a collection of paint operations.
     ///     Class used to define surface paint, which is a collection of paint operations.
     /// </summary>
     /// </summary>
-    public class Paint : IDisposable
+    public class Paint : NativeObject
     {
     {
         public Color Color { get; set; }
         public Color Color { get; set; }
         public BlendMode BlendMode { get; set; } = BlendMode.Src;
         public BlendMode BlendMode { get; set; } = BlendMode.Src;
         public FilterQuality FilterQuality { get; set; } = FilterQuality.None;
         public FilterQuality FilterQuality { get; set; } = FilterQuality.None;
         public bool IsAntiAliased { get; set; } = false;
         public bool IsAntiAliased { get; set; } = false;
+        public PaintStyle Style { get; set; }
+        public StrokeCap StrokeCap { get; set; }
+        public float StrokeWidth { get; set; }
+        
+        
+        internal Paint(IntPtr objPtr) : base(objPtr)
+        {
+        }
+        
+        public Paint() : base(DrawingBackendApi.Current.PaintImplementation.CreatePaint())
+        {
+        }
 
 
-        public void Dispose()
+        public override void Dispose()
         {
         {
-            DrawingBackendApi.Current.PaintOperations.Dispose(this);
+            DrawingBackendApi.Current.PaintImplementation.Dispose(ObjectPointer);
         }
         }
     }
     }
 }
 }

+ 13 - 0
src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/PaintStyle.cs

@@ -0,0 +1,13 @@
+namespace PixiEditor.DrawingApi.Core.Surface;
+
+public enum PaintStyle
+{
+    /// <summary>Fill the geometry.</summary>
+    Fill,
+    
+    /// <summary>Stroke the geometry.</summary>
+    Stroke,
+    
+    /// <summary>Fill and stroke the geometry.</summary>
+    StrokeAndFill,
+}

+ 13 - 0
src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/StrokeCap.cs

@@ -0,0 +1,13 @@
+namespace PixiEditor.DrawingApi.Core.Surface;
+
+/// <summary>Various options for <see cref="Paint.StrokeCap" />.</summary>
+/// <remarks>This is the treatment that is applied to the beginning and end of each non-closed contour (e.g. lines).</remarks>
+public enum StrokeCap
+{
+    /// <summary>Begin/end contours with no extension.</summary>
+    Butt,
+    /// <summary>Begin/end contours with a semi-circle extension.</summary>
+    Round,
+    /// <summary>Begin/end contours with a half square extension.</summary>
+    Square,
+}

+ 306 - 0
src/PixiEditor.DrawingApi.Core/Surface/Point.cs

@@ -0,0 +1,306 @@
+using System;
+using PixiEditor.DrawingApi.Core.Numerics;
+
+namespace PixiEditor.DrawingApi.Core.Surface;
+
+/// <summary>
+///     Represents an ordered pair of floating-point x- and y-coordinates that defines a point in a two-dimensional
+///     plane.
+/// </summary>
+public struct Point : IEquatable<Point>
+{
+    /// <summary>Represents a new instance of the <see cref="Point" /> class with member data left uninitialized.</summary>
+    public static readonly Point Empty;
+
+    public Point(float x, float y)
+    {
+        X = x;
+        Y = y;
+    }
+
+    public Point(VecI pointPos)
+    {
+        X = pointPos.X;
+        Y = pointPos.Y;
+    }
+
+    /// <summary>Gets a value indicating whether this point is empty.</summary>
+    /// <value />
+    public readonly bool IsEmpty => this == Empty;
+
+    /// <summary>Gets the Euclidean distance from the origin (0, 0).</summary>
+    /// <value />
+    /// <remarks />
+    public readonly float Length => (float)Math.Sqrt((X * (double)X) + (Y * (double)Y));
+
+    /// <summary>Gets the Euclidean distance squared from the origin (0, 0).</summary>
+    /// <value />
+    /// <remarks />
+    public readonly float LengthSquared => (float)((X * (double)X) + (Y * (double)Y));
+
+    /// <param name="p">The offset value.</param>
+    /// <summary>Translates a given point by a specified offset.</summary>
+    /// <remarks />
+    public void Offset(Point p)
+    {
+        X += p.X;
+        Y += p.Y;
+    }
+
+    /// <param name="dx">The offset in the x-direction.</param>
+    /// <param name="dy">The offset in the y-direction.</param>
+    /// <summary>Translates a given point by a specified offset.</summary>
+    public void Offset(float dx, float dy)
+    {
+        X += dx;
+        Y += dy;
+    }
+
+    /// <summary>Converts this <see cref="Point" /> to a human readable string.</summary>
+    /// <returns>A string that represents this <see cref="Point" />.</returns>
+    public override readonly string ToString()
+    {
+        return string.Format("{{X={0}, Y={1}}}", X, Y);
+    }
+
+    /// <param name="point">The point to normalize.</param>
+    /// <summary>Returns a point with the same direction as the specified point, but with a length of one.</summary>
+    /// <returns>Returns a point with a length of one.</returns>
+    public static Point Normalize(Point point)
+    {
+        var num = 1.0 / Math.Sqrt((point.X * (double)point.X) + (point.Y * (double)point.Y));
+        return new Point(point.X * (float)num, point.Y * (float)num);
+    }
+
+    /// <param name="point">The first point.</param>
+    /// <param name="other">The second point.</param>
+    /// <summary>Calculate the Euclidean distance between two points.</summary>
+    /// <returns>Returns the Euclidean distance between two points.</returns>
+    public static float Distance(Point point, Point other)
+    {
+        var num1 = point.X - other.X;
+        var num2 = point.Y - other.Y;
+        return (float)Math.Sqrt((num1 * (double)num1) + (num2 * (double)num2));
+    }
+
+    /// <param name="point">The first point.</param>
+    /// <param name="other">The second point.</param>
+    /// <summary>Calculate the Euclidean distance squared between two points.</summary>
+    /// <returns>Returns the Euclidean distance squared between two points.</returns>
+    public static float DistanceSquared(Point point, Point other)
+    {
+        var num1 = point.X - other.X;
+        var num2 = point.Y - other.Y;
+        return (float)((num1 * (double)num1) + (num2 * (double)num2));
+    }
+
+    /// <param name="point">The point to reflect.</param>
+    /// <param name="normal">The normal.</param>
+    /// <summary>Returns the reflection of a point off a surface that has the specified normal.</summary>
+    /// <returns>Returns the reflection of a point.</returns>
+    public static Point Reflect(Point point, Point normal)
+    {
+        var num = (float)((point.X * (double)point.X) + (point.Y * (double)point.Y));
+        return new Point(point.X - (2f * num * normal.X), point.Y - (2f * num * normal.Y));
+    }
+
+    /// <param name="pt">The point to translate</param>
+    /// <param name="sz">The offset size.</param>
+    /// <summary>Translates a given point by a specified size.</summary>
+    /// <returns>Returns the translated point.</returns>
+    public static Point Add(Point pt, VecI sz)
+    {
+        return pt + sz;
+    }
+
+    /// <param name="pt">The point to translate.</param>
+    /// <param name="sz">The offset size.</param>
+    /// <summary>Translates a given point by a specified size.</summary>
+    /// <returns>Returns the translated point.</returns>
+    public static Point Add(Point pt, VecD sz)
+    {
+        return pt + sz;
+    }
+
+    /// <param name="pt">The point to translate.</param>
+    /// <param name="sz">The offset value.</param>
+    /// <summary>Translates a given point by a specified offset.</summary>
+    /// <returns>Returns the translated point.</returns>
+    public static Point Add(Point pt, Point sz)
+    {
+        return pt + sz;
+    }
+
+    /// <param name="pt">The <see cref="Point" /> to translate.</param>
+    /// <param name="sz">
+    ///     The <see cref="VecD" /> that specifies the numbers to subtract from the coordinates of
+    ///     <paramref name="pt" />.
+    /// </param>
+    /// <summary>Translates a <see cref="Point" /> by the negative of a specified size.</summary>
+    /// <returns>The translated <see cref="Point" />.</returns>
+    public static Point Subtract(Point pt, VecI sz)
+    {
+        return pt - sz;
+    }
+
+    /// <param name="pt">The <see cref="Point" /> to translate.</param>
+    /// <param name="sz">
+    ///     The <see cref="VecD" /> that specifies the numbers to subtract from the coordinates of
+    ///     <paramref name="pt" />.
+    /// </param>
+    /// <summary>Translates a <see cref="Point" /> by the negative of a specified size.</summary>
+    /// <returns>The translated <see cref="Point" />.</returns>
+    public static Point Subtract(Point pt, VecD sz)
+    {
+        return pt - sz;
+    }
+
+    /// <param name="pt">The <see cref="Point" /> to translate.</param>
+    /// <param name="sz">The offset that specifies the numbers to subtract from the coordinates of <paramref name="pt" />.</param>
+    /// <summary>Translates a given point by the negative of a specified offset.</summary>
+    /// <returns>The translated <see cref="Point" />.</returns>
+    public static Point Subtract(Point pt, Point sz)
+    {
+        return pt - sz;
+    }
+
+    /// <param name="pt">The point to translate.</param>
+    /// <param name="sz">The offset size.</param>
+    /// <summary>Translates a given point by a specified size.</summary>
+    /// <returns>Returns the translated point.</returns>
+    public static Point operator +(Point pt, VecI sz)
+    {
+        return new Point(pt.X + sz.X, pt.Y + sz.Y);
+    }
+
+    /// <param name="pt">The point to translate.</param>
+    /// <param name="sz">The offset size.</param>
+    /// <summary>Translates a given point by a specified size.</summary>
+    /// <returns>Returns the translated point.</returns>
+    public static Point operator +(Point pt, VecD sz)
+    {
+        return new Point(pt.X + (float)sz.X, pt.Y + (float)sz.Y);
+    }
+
+    /// <param name="pt">The point to translate.</param>
+    /// <param name="sz">The offset value.</param>
+    /// <summary>Translates a given point by a specified offset.</summary>
+    /// <returns>Returns the translated point.</returns>
+    public static Point operator +(Point pt, Point sz)
+    {
+        return new Point(pt.X + sz.X, pt.Y + sz.Y);
+    }
+
+    /// <param name="pt">The <see cref="Point" /> to translate.</param>
+    /// <param name="sz">
+    ///     The <see cref="VecI" /> that specifies the numbers to subtract from the coordinates of
+    ///     <paramref name="pt" />.
+    /// </param>
+    /// <summary>Translates a <see cref="Point" /> by the negative of a given <see cref="VecI" />.</summary>
+    /// <returns>The translated <see cref="Point" />.</returns>
+    public static Point operator -(Point pt, VecI sz)
+    {
+        return new Point(pt.X - sz.X, pt.Y - sz.Y);
+    }
+
+    /// <param name="pt">The <see cref="Point" /> to translate.</param>
+    /// <param name="sz">
+    ///     The <see cref="VecD" /> that specifies the numbers to subtract from the coordinates of
+    ///     <paramref name="pt" />.
+    /// </param>
+    /// <summary>Translates a <see cref="Point" /> by the negative of a given <see cref="VecD" />.</summary>
+    /// <returns>The translated <see cref="Point" />.</returns>
+    public static Point operator -(Point pt, VecD sz)
+    {
+        return new Point(pt.X - (float)sz.X, pt.Y - (float)sz.Y);
+    }
+
+    /// <param name="pt">The <see cref="Point" /> to translate.</param>
+    /// <param name="sz">The point that specifies the numbers to subtract from the coordinates of <paramref name="pt" />.</param>
+    /// <summary>Translates a given point by the negative of a specified offset.</summary>
+    /// <returns>The translated <see cref="Point" />.</returns>
+    public static Point operator -(Point pt, Point sz)
+    {
+        return new Point(pt.X - sz.X, pt.Y - sz.Y);
+    }
+
+    /// <summary>Gets or sets the x-coordinate of this <see cref="Point" />.</summary>
+    /// <value />
+    public float X { get; set; }
+
+    /// <summary>Gets or sets the x-coordinate of this <see cref="Point" />.</summary>
+    /// <value />
+    public float Y { get; set; }
+
+    /// <param name="obj">The <see cref="Point" /> to test.</param>
+    /// <summary>
+    ///     Specifies whether this <see cref="Point" /> contains the same coordinates as the specified
+    ///     <see cref="Point" />.
+    /// </summary>
+    /// <returns>
+    ///     This method returns true if <paramref name="obj" /> has the same coordinates as this
+    ///     <see cref="Point" />.
+    /// </returns>
+    public readonly bool Equals(Point obj)
+    {
+        return X == (double)obj.X && Y == (double)obj.Y;
+    }
+
+    /// <param name="obj">The <see cref="T:System.Object" /> to test.</param>
+    /// <summary>
+    ///     Specifies whether this <see cref="Point" /> contains the same coordinates as the specified
+    ///     <see cref="T:System.Object" />.
+    /// </summary>
+    /// <returns>
+    ///     This method returns true if <paramref name="obj" /> is a <see cref="Point" /> and has the same
+    ///     coordinates as this <see cref="Point" />.
+    /// </returns>
+    /// <remarks />
+    public override readonly bool Equals(object obj)
+    {
+        return obj is Point Point && Equals(Point);
+    }
+
+    /// <param name="left">A <see cref="Point" /> to compare.</param>
+    /// <param name="right">A <see cref="Point" /> to compare with.</param>
+    /// <summary>
+    ///     Compares two <see cref="Point" /> structures. The result specifies whether the values of the
+    ///     <see cref="P:.Point.X" /> and <see cref="P:.Point.Y" /> properties of the two
+    ///     <see cref="Point" /> structures are equal.
+    /// </summary>
+    /// <returns>
+    ///     true if the <see cref="P:.Point.X" /> and <see cref="P:.Point.Y" /> values of the left and
+    ///     right <see cref="Point" /> structures are equal; otherwise, false.
+    /// </returns>
+    public static bool operator ==(Point left, Point right)
+    {
+        return left.Equals(right);
+    }
+
+    /// <param name="left">A <see cref="Point" /> to compare.</param>
+    /// <param name="right">A <see cref="Point" /> to compare with.</param>
+    /// <summary>Determines whether the coordinates of the specified points are not equal.</summary>
+    /// <returns>
+    ///     true if the <see cref="Point.X" /> and <see cref="Point.Y" /> values of the left and
+    ///     right <see cref="Point" /> structures differ; otherwise, false.
+    /// </returns>
+    public static bool operator !=(Point left, Point right)
+    {
+        return !left.Equals(right);
+    }
+
+    /// <summary>Calculates the hashcode for this point.</summary>
+    /// <returns>Returns the hashcode for this point.</returns>
+    /// <remarks>
+    ///     You should avoid depending on GetHashCode for unique values, as two <see cref="T:System.Drawing.Point" />
+    ///     objects with the same values for their X and Y properties may return the same hash code. This behavior could change
+    ///     in a future release.
+    /// </remarks>
+    public override readonly int GetHashCode()
+    {
+        var hashCode = new HashCode();
+        hashCode.Add(X);
+        hashCode.Add(Y);
+        return hashCode.ToHashCode();
+    }
+}

+ 14 - 0
src/PixiEditor.DrawingApi.Core/Surface/PointMode.cs

@@ -0,0 +1,14 @@
+namespace PixiEditor.DrawingApi.Core.Surface;
+
+/// <summary>Possible values to interpret the incoming array of points.</summary>
+public enum PointMode
+{
+    /// <summary>Interpret the data as coordinates for points.</summary>
+    Points,
+    
+    /// <summary>Interpret the data as coordinates for lines.</summary>
+    Lines,
+    
+    /// <summary>Interpret the data as coordinates for polygons.</summary>
+    Polygon,
+}

+ 6 - 0
src/PixiEditor.DrawingApi.Core/Surface/Vector/VectorPath.cs

@@ -45,6 +45,8 @@ public class VectorPath : NativeObject
     /// <value>The tight bounds of the path.</value>
     /// <value>The tight bounds of the path.</value>
     public RectD TightBounds => DrawingBackendApi.Current.PathImplementation.GetTightBounds(this);
     public RectD TightBounds => DrawingBackendApi.Current.PathImplementation.GetTightBounds(this);
 
 
+    public bool IsEmpty => VerbCount == 0;
+
     public VectorPath() : base(DrawingBackendApi.Current.PathImplementation.Create())
     public VectorPath() : base(DrawingBackendApi.Current.PathImplementation.Create())
     {
     {
     }
     }
@@ -52,6 +54,10 @@ public class VectorPath : NativeObject
     public VectorPath(VectorPath other) : base(DrawingBackendApi.Current.PathImplementation.Clone(other))
     public VectorPath(VectorPath other) : base(DrawingBackendApi.Current.PathImplementation.Clone(other))
     {
     {
     }
     }
+    
+    /// <param name="matrix">The matrix to use for transformation.</param>
+    /// <summary>Applies a transformation matrix to the all the elements in the path.</summary>
+    public void Transform(Matrix3X3 matrix) => DrawingBackendApi.Current.PathImplementation.Transform(this, matrix);
 
 
     public override void Dispose()
     public override void Dispose()
     {
     {

+ 6 - 7
src/PixiEditor/Models/Rendering/WriteableBitmapUpdater.cs

@@ -1,14 +1,13 @@
 using ChunkyImageLib;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.Operations;
 using ChunkyImageLib.Operations;
-using OneOf;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Rendering.RenderInfos;
 using PixiEditor.Models.Rendering.RenderInfos;
 using PixiEditor.ViewModels.SubViewModels.Document;
 using PixiEditor.ViewModels.SubViewModels.Document;
-using SkiaSharp;
 
 
 namespace PixiEditor.Models.Rendering;
 namespace PixiEditor.Models.Rendering;
 #nullable enable
 #nullable enable
@@ -17,9 +16,9 @@ internal class WriteableBitmapUpdater
     private readonly DocumentViewModel doc;
     private readonly DocumentViewModel doc;
     private readonly DocumentInternalParts internals;
     private readonly DocumentInternalParts internals;
 
 
-    private static readonly SKPaint ReplacingPaint = new SKPaint() { BlendMode = SKBlendMode.Src };
-    private static readonly SKPaint SmoothReplacingPaint = new SKPaint() { BlendMode = SKBlendMode.Src, FilterQuality = SKFilterQuality.Medium, IsAntialias = true };
-    private static readonly SKPaint ClearPaint = new SKPaint() { BlendMode = SKBlendMode.Src, Color = SKColors.Transparent };
+    private static readonly Paint ReplacingPaint = new() { BlendMode = BlendMode.Src };
+    private static readonly Paint SmoothReplacingPaint = new() { BlendMode = BlendMode.Src, FilterQuality = FilterQuality.Medium, IsAntiAliased = true };
+    private static readonly Paint ClearPaint = new() { BlendMode = BlendMode.Src, Color = PixiEditor.DrawingApi.Core.ColorsImpl.Colors.Transparent };
 
 
     /// <summary>
     /// <summary>
     /// Chunks that have been updated but don't need to be re-rendered because they are out of view
     /// Chunks that have been updated but don't need to be re-rendered because they are out of view
@@ -271,7 +270,7 @@ internal class WriteableBitmapUpdater
         foreach (var (resolution, chunks) in chunksToRerender)
         foreach (var (resolution, chunks) in chunksToRerender)
         {
         {
             int chunkSize = resolution.PixelSize();
             int chunkSize = resolution.PixelSize();
-            SKSurface screenSurface = doc.Surfaces[resolution];
+            DrawingSurface screenSurface = doc.Surfaces[resolution];
             foreach (var chunkPos in chunks)
             foreach (var chunkPos in chunks)
             {
             {
                 RenderChunk(chunkPos, screenSurface, resolution);
                 RenderChunk(chunkPos, screenSurface, resolution);
@@ -284,7 +283,7 @@ internal class WriteableBitmapUpdater
         }
         }
     }
     }
 
 
-    private void RenderChunk(VecI chunkPos, SKSurface screenSurface, ChunkResolution resolution)
+    private void RenderChunk(VecI chunkPos, DrawingSurface screenSurface, ChunkResolution resolution)
     {
     {
         ChunkRenderer.MergeWholeStructure(chunkPos, resolution, internals.Tracker.Document.StructureRoot).Switch(
         ChunkRenderer.MergeWholeStructure(chunkPos, resolution, internals.Tracker.Document.StructureRoot).Switch(
             (Chunk chunk) =>
             (Chunk chunk) =>

+ 19 - 16
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.cs

@@ -11,11 +11,14 @@ using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels.Public;
 using PixiEditor.Models.DocumentModels.Public;
+using Color = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
+using Colors = PixiEditor.DrawingApi.Core.ColorsImpl.Colors;
 
 
 namespace PixiEditor.ViewModels.SubViewModels.Document;
 namespace PixiEditor.ViewModels.SubViewModels.Document;
 
 
@@ -128,7 +131,7 @@ internal class DocumentViewModel : NotifyableObject
 
 
     public StructureMemberViewModel? SelectedStructureMember { get; private set; } = null;
     public StructureMemberViewModel? SelectedStructureMember { get; private set; } = null;
 
 
-    public Dictionary<ChunkResolution, SKSurface> Surfaces { get; set; } = new();
+    public Dictionary<ChunkResolution, DrawingSurface> Surfaces { get; set; } = new();
     public Dictionary<ChunkResolution, WriteableBitmap> Bitmaps { get; set; } = new()
     public Dictionary<ChunkResolution, WriteableBitmap> Bitmaps { get; set; } = new()
     {
     {
         [ChunkResolution.Full] = new WriteableBitmap(64, 64, 96, 96, PixelFormats.Pbgra32, null),
         [ChunkResolution.Full] = new WriteableBitmap(64, 64, 96, 96, PixelFormats.Pbgra32, null),
@@ -140,8 +143,8 @@ internal class DocumentViewModel : NotifyableObject
     public DrawingSurface PreviewSurface { get; set; }
     public DrawingSurface PreviewSurface { get; set; }
 
 
 
 
-    private SKPath selectionPath = new SKPath();
-    public SKPath SelectionPathBindable => selectionPath;
+    private VectorPath selectionPath = new VectorPath();
+    public VectorPath SelectionPathBindable => selectionPath;
 
 
     public WpfObservableRangeCollection<SKColor> Swatches { get; set; } = new WpfObservableRangeCollection<SKColor>();
     public WpfObservableRangeCollection<SKColor> Swatches { get; set; } = new WpfObservableRangeCollection<SKColor>();
     public WpfObservableRangeCollection<SKColor> Palette { get; set; } = new WpfObservableRangeCollection<SKColor>();
     public WpfObservableRangeCollection<SKColor> Palette { get; set; } = new WpfObservableRangeCollection<SKColor>();
@@ -166,7 +169,7 @@ internal class DocumentViewModel : NotifyableObject
 
 
         foreach (KeyValuePair<ChunkResolution, WriteableBitmap> bitmap in Bitmaps)
         foreach (KeyValuePair<ChunkResolution, WriteableBitmap> bitmap in Bitmaps)
         {
         {
-            SKSurface? surface = SKSurface.Create(
+            DrawingSurface? surface = DrawingSurface.Create(
                 new SKImageInfo(bitmap.Value.PixelWidth, bitmap.Value.PixelHeight, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb()),
                 new SKImageInfo(bitmap.Value.PixelWidth, bitmap.Value.PixelHeight, SKColorType.Bgra8888, SKAlphaType.Premul, SKColorSpace.CreateSrgb()),
                 bitmap.Value.BackBuffer, bitmap.Value.BackBufferStride);
                 bitmap.Value.BackBuffer, bitmap.Value.BackBufferStride);
             Surfaces[bitmap.Key] = surface;
             Surfaces[bitmap.Key] = surface;
@@ -174,7 +177,7 @@ internal class DocumentViewModel : NotifyableObject
 
 
         VecI previewSize = StructureMemberViewModel.CalculatePreviewSize(SizeBindable);
         VecI previewSize = StructureMemberViewModel.CalculatePreviewSize(SizeBindable);
         PreviewBitmap = new WriteableBitmap(previewSize.X, previewSize.Y, 96, 96, PixelFormats.Pbgra32, null);
         PreviewBitmap = new WriteableBitmap(previewSize.X, previewSize.Y, 96, 96, PixelFormats.Pbgra32, null);
-        PreviewSurface = SKSurface.Create(new SKImageInfo(previewSize.X, previewSize.Y, SKColorType.Bgra8888), PreviewBitmap.BackBuffer, PreviewBitmap.BackBufferStride);
+        PreviewSurface = DrawingSurface.Create(new SKImageInfo(previewSize.X, previewSize.Y, SKColorType.Bgra8888), PreviewBitmap.BackBuffer, PreviewBitmap.BackBufferStride);
     }
     }
 
 
     public static DocumentViewModel Build(Action<DocumentViewModelBuilder> builder)
     public static DocumentViewModel Build(Action<DocumentViewModelBuilder> builder)
@@ -290,8 +293,8 @@ internal class DocumentViewModel : NotifyableObject
 
 
         Surface output = new(bounds.Size);
         Surface output = new(bounds.Size);
 
 
-        SKPath clipPath = new SKPath(SelectionPathBindable) { FillType = SKPathFillType.EvenOdd };
-        clipPath.Transform(SKMatrix.CreateTranslation(-bounds.X, -bounds.Y));
+        VectorPath clipPath = new VectorPath(SelectionPathBindable) { FillType = PathFillType.EvenOdd };
+        clipPath.Transform(Matrix3X3.CreateTranslation(-bounds.X, -bounds.Y));
         output.DrawingSurface.Canvas.Save();
         output.DrawingSurface.Canvas.Save();
         output.DrawingSurface.Canvas.ClipPath(clipPath);
         output.DrawingSurface.Canvas.ClipPath(clipPath);
         try
         try
@@ -308,7 +311,7 @@ internal class DocumentViewModel : NotifyableObject
         return (output, bounds);
         return (output, bounds);
     }
     }
 
 
-    public SKColor PickColor(VecI pos, bool fromAllLayers)
+    public Color PickColor(VecI pos, bool fromAllLayers)
     {
     {
         // there is a tiny chance that the image might get disposed by another thread
         // there is a tiny chance that the image might get disposed by another thread
         try
         try
@@ -319,28 +322,28 @@ internal class DocumentViewModel : NotifyableObject
             {
             {
                 VecI chunkPos = OperationHelper.GetChunkPos(pos, ChunkyImage.FullChunkSize);
                 VecI chunkPos = OperationHelper.GetChunkPos(pos, ChunkyImage.FullChunkSize);
                 return ChunkRenderer.MergeWholeStructure(chunkPos, ChunkResolution.Full, Internals.Tracker.Document.StructureRoot)
                 return ChunkRenderer.MergeWholeStructure(chunkPos, ChunkResolution.Full, Internals.Tracker.Document.StructureRoot)
-                    .Match<SKColor>(
+                    .Match<Color>(
                         (Chunk chunk) =>
                         (Chunk chunk) =>
                         {
                         {
                             VecI posOnChunk = pos - chunkPos * ChunkyImage.FullChunkSize;
                             VecI posOnChunk = pos - chunkPos * ChunkyImage.FullChunkSize;
-                            SKColor color = chunk.Surface.GetSRGBPixel(posOnChunk);
+                            var color = chunk.Surface.GetSRGBPixel(posOnChunk);
                             chunk.Dispose();
                             chunk.Dispose();
                             return color;
                             return color;
                         },
                         },
-                        _ => SKColors.Transparent
+                        _ => Colors.Transparent
                     );
                     );
             }
             }
 
 
             if (SelectedStructureMember is not LayerViewModel layerVm)
             if (SelectedStructureMember is not LayerViewModel layerVm)
-                return SKColors.Transparent;
+                return Colors.Transparent;
             IReadOnlyStructureMember? maybeMember = Internals.Tracker.Document.FindMember(layerVm.GuidValue);
             IReadOnlyStructureMember? maybeMember = Internals.Tracker.Document.FindMember(layerVm.GuidValue);
             if (maybeMember is not IReadOnlyLayer layer)
             if (maybeMember is not IReadOnlyLayer layer)
-                return SKColors.Transparent;
+                return Colors.Transparent;
             return layer.LayerImage.GetMostUpToDatePixel(pos);
             return layer.LayerImage.GetMostUpToDatePixel(pos);
         }
         }
         catch (ObjectDisposedException)
         catch (ObjectDisposedException)
         {
         {
-            return SKColors.Transparent;
+            return Colors.Transparent;
         }
         }
     }
     }
 
 
@@ -383,9 +386,9 @@ internal class DocumentViewModel : NotifyableObject
         RaisePropertyChanged(nameof(Height));
         RaisePropertyChanged(nameof(Height));
     }
     }
 
 
-    public void InternalUpdateSelectionPath(SKPath selectionPath)
+    public void InternalUpdateSelectionPath(SKPath VectorPath)
     {
     {
-        (SKPath? toDispose, this.selectionPath) = (this.selectionPath, selectionPath);
+        (VectorPath? toDispose, this.selectionPath) = (this.selectionPath, selectionPath);
         toDispose.Dispose();
         toDispose.Dispose();
         RaisePropertyChanged(nameof(SelectionPathBindable));
         RaisePropertyChanged(nameof(SelectionPathBindable));
     }
     }

+ 5 - 4
src/PixiEditor/ViewModels/SubViewModels/Document/StructureMemberViewModel.cs

@@ -2,10 +2,11 @@
 using System.Windows.Media;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Media.Imaging;
 using ChunkyImageLib.DataHolders;
 using ChunkyImageLib.DataHolders;
-using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Enums;
+using BlendMode = PixiEditor.ChangeableDocument.Enums.BlendMode;
 
 
 namespace PixiEditor.ViewModels.SubViewModels.Document;
 namespace PixiEditor.ViewModels.SubViewModels.Document;
 #nullable enable
 #nullable enable
@@ -137,10 +138,10 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
 
 
     public const int PreviewSize = 48;
     public const int PreviewSize = 48;
     public WriteableBitmap PreviewBitmap { get; set; }
     public WriteableBitmap PreviewBitmap { get; set; }
-    public SKSurface PreviewSurface { get; set; }
+    public DrawingSurface PreviewSurface { get; set; }
 
 
     public WriteableBitmap? MaskPreviewBitmap { get; set; }
     public WriteableBitmap? MaskPreviewBitmap { get; set; }
-    public SKSurface? MaskPreviewSurface { get; set; }
+    public DrawingSurface? MaskPreviewSurface { get; set; }
 
 
     public void RaisePropertyChanged(string name)
     public void RaisePropertyChanged(string name)
     {
     {
@@ -164,6 +165,6 @@ internal abstract class StructureMemberViewModel : INotifyPropertyChanged
         this.guidValue = guidValue;
         this.guidValue = guidValue;
         VecI previewSize = CalculatePreviewSize(doc.SizeBindable);
         VecI previewSize = CalculatePreviewSize(doc.SizeBindable);
         PreviewBitmap = new WriteableBitmap(previewSize.X, previewSize.Y, 96, 96, PixelFormats.Pbgra32, null);
         PreviewBitmap = new WriteableBitmap(previewSize.X, previewSize.Y, 96, 96, PixelFormats.Pbgra32, null);
-        PreviewSurface = SKSurface.Create(new SKImageInfo(previewSize.X, previewSize.Y, SKColorType.Bgra8888), PreviewBitmap.BackBuffer, PreviewBitmap.BackBufferStride);
+        PreviewSurface = DrawingSurface.Create(new SKImageInfo(previewSize.X, previewSize.Y, SKColorType.Bgra8888), PreviewBitmap.BackBuffer, PreviewBitmap.BackBufferStride);
     }
     }
 }
 }