Browse Source

well, PixiEditor codebase became larger than I thought

flabbet 2 years ago
parent
commit
7449ae281e
40 changed files with 364 additions and 200 deletions
  1. 0 1
      src/ChunkyImageLib/Chunk.cs
  2. 9 8
      src/ChunkyImageLib/ChunkyImage.cs
  3. 17 0
      src/ChunkyImageLib/ColorEx.cs
  4. 5 5
      src/ChunkyImageLib/Operations/ImageOperation.cs
  5. 0 17
      src/ChunkyImageLib/SKColorEx.cs
  6. 2 2
      src/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/Selection_ChangeInfo.cs
  7. 2 2
      src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlySelection.cs
  8. 9 7
      src/PixiEditor.ChangeableDocument/Changeables/Selection.cs
  9. 11 9
      src/PixiEditor.ChangeableDocument/Changes/Drawing/ChangeBrightness_UpdateableChange.cs
  10. 5 5
      src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawEllipse_UpdateableChange.cs
  11. 9 8
      src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawLine_UpdateableChange.cs
  12. 2 1
      src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillChunkCache.cs
  13. 18 15
      src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillHelper.cs
  14. 6 4
      src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFill_Change.cs
  15. 13 11
      src/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs
  16. 2 2
      src/PixiEditor.ChangeableDocument/Changes/Drawing/PasteImage_UpdateableChange.cs
  17. 22 19
      src/PixiEditor.ChangeableDocument/Changes/Drawing/PathBasedPen_UpdateableChange.cs
  18. 11 9
      src/PixiEditor.ChangeableDocument/Changes/Drawing/PixelPerfectPen_UpdateableChange.cs
  19. 5 5
      src/PixiEditor.ChangeableDocument/Changes/Drawing/ReplaceColor_Change.cs
  20. 10 8
      src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelectedArea_UpdateableChange.cs
  21. 10 8
      src/PixiEditor.ChangeableDocument/Changes/Root/ResizeImage_Change.cs
  22. 7 7
      src/PixiEditor.ChangeableDocument/Changes/Selection/ClearSelection_Change.cs
  23. 6 5
      src/PixiEditor.ChangeableDocument/Changes/Selection/SelectEllipse_UpdateableChange.cs
  24. 5 4
      src/PixiEditor.ChangeableDocument/Changes/Selection/SelectionChangeHelper.cs
  25. 2 1
      src/PixiEditor.ChangeableDocument/Rendering/ChunkRenderer.cs
  26. 28 26
      src/PixiEditor.ChangeableDocument/Rendering/RenderingContext.cs
  27. 2 1
      src/PixiEditor.DrawingApi.Core/Bridge/IDrawingBackend.cs
  28. 2 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IMatrix3x3Implementation.cs
  29. 3 2
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPaintImplementation.cs
  30. 9 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPixmapImplementation.cs
  31. 7 0
      src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IVectorPathImplementation.cs
  32. 7 3
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/ICanvasOperations.cs
  33. 1 0
      src/PixiEditor.DrawingApi.Core/Bridge/Operations/IImageOperations.cs
  34. 17 3
      src/PixiEditor.DrawingApi.Core/Numerics/Matrix3X3.cs
  35. 23 1
      src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs
  36. 1 1
      src/PixiEditor.DrawingApi.Core/Surface/DrawingSurface.cs
  37. 6 0
      src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/Paint.cs
  38. 22 0
      src/PixiEditor.DrawingApi.Core/Surface/Pixmap.cs
  39. 21 0
      src/PixiEditor.DrawingApi.Core/Surface/Point.cs
  40. 27 0
      src/PixiEditor.DrawingApi.Core/Surface/Vector/VectorPath.cs

+ 0 - 1
src/ChunkyImageLib/Chunk.cs

@@ -1,7 +1,6 @@
 using ChunkyImageLib.DataHolders;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
-using PixiEditor.PixelE;
 
 namespace ChunkyImageLib;
 

+ 9 - 8
src/ChunkyImageLib/ChunkyImage.cs

@@ -7,6 +7,7 @@ using OneOf.Types;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 
 [assembly: InternalsVisibleTo("ChunkyImageLibTest")]
@@ -80,7 +81,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     private readonly List<ChunkyImage> activeClips = new();
     private BlendMode blendMode = BlendMode.Src;
     private bool lockTransparency = false;
-    private SKPath? clippingPath;
+    private VectorPath? clippingPath;
     private int? horizontalSymmetryAxis = null;
     private int? verticalSymmetryAxis = null;
 
@@ -377,7 +378,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void SetClippingPath(SKPath clippingPath)
+    public void SetClippingPath(VectorPath clippingPath)
     {
         lock (lockObject)
         {
@@ -477,7 +478,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.
     /// </summary>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawImage(SKMatrix transformMatrix, Surface image, Paint? paint = null, bool copyImage = true)
+    public void EnqueueDrawImage(Matrix3X3 transformMatrix, Surface image, Paint? paint = null, bool copyImage = true)
     {
         lock (lockObject)
         {
@@ -517,7 +518,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>
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawPath(SKPath path, Color color, float strokeWidth, SKStrokeCap strokeCap, BlendMode blendMode, RectI? customBounds = null)
+    public void EnqueueDrawPath(VectorPath path, Color color, float strokeWidth, StrokeCap strokeCap, BlendMode blendMode, RectI? customBounds = null)
     {
         lock (lockObject)
         {
@@ -539,7 +540,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueDrawSkiaLine(VecI from, VecI to, SKStrokeCap strokeCap, float strokeWidth, Color color, BlendMode blendMode)
+    public void EnqueueDrawSkiaLine(VecI from, VecI to, StrokeCap strokeCap, float strokeWidth, Color color, BlendMode blendMode)
     {
         lock (lockObject)
         {
@@ -594,7 +595,7 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
     }
 
     /// <exception cref="ObjectDisposedException">This image is disposed</exception>
-    public void EnqueueClearPath(SKPath path, RectI? pathTightBounds = null)
+    public void EnqueueClearPath(VectorPath path, RectI? pathTightBounds = null)
     {
         lock (lockObject)
         {
@@ -1015,10 +1016,10 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable
         {
             int count = targetChunk.Surface.DrawingSurface.Canvas.Save();
 
-            using SKPath transformedPath = new(clippingPath);
+            using VectorPath transformedPath = new(clippingPath);
             float scale = (float)resolution.Multiplier();
             VecD trans = -chunkPos * 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));
             targetChunk.Surface.DrawingSurface.Canvas.ClipPath(transformedPath);
             operation.DrawOnChunk(targetChunk, chunkPos);
             targetChunk.Surface.DrawingSurface.Canvas.RestoreToCount(count);

+ 17 - 0
src/ChunkyImageLib/ColorEx.cs

@@ -0,0 +1,17 @@
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+
+namespace ChunkyImageLib;
+public static class ColorEx
+{
+    public static unsafe ulong ToULong(this Color color)
+    {
+        ulong result = 0;
+        Half* ptr = (Half*)&result;
+        float normalizedAlpha = color.A / 255.0f;
+        ptr[0] = (Half)(color.R / 255f * normalizedAlpha);
+        ptr[1] = (Half)(color.G / 255f * normalizedAlpha);
+        ptr[2] = (Half)(color.B / 255f * normalizedAlpha);
+        ptr[3] = (Half)(normalizedAlpha);
+        return result;
+    }
+}

+ 5 - 5
src/ChunkyImageLib/Operations/ImageOperation.cs

@@ -15,7 +15,7 @@ internal class ImageOperation : IDrawOperation
 
     public bool IgnoreEmptyChunks => false;
 
-    public ImageOperation(VecI pos, Surface image, SKPaint? paint = null, bool copyImage = true)
+    public ImageOperation(VecI pos, Surface image, Paint? paint = null, bool copyImage = true)
     {
         if (paint is not null)
             customPaint = paint.Clone();
@@ -39,7 +39,7 @@ internal class ImageOperation : IDrawOperation
         imageWasCopied = copyImage;
     }
 
-    public ImageOperation(ShapeCorners corners, Surface image, SKPaint? paint = null, bool copyImage = true)
+    public ImageOperation(ShapeCorners corners, Surface image, Paint? paint = null, bool copyImage = true)
     {
         if (paint is not null)
             customPaint = paint.Clone();
@@ -55,7 +55,7 @@ internal class ImageOperation : IDrawOperation
         imageWasCopied = copyImage;
     }
 
-    public ImageOperation(SKMatrix transformMatrix, Surface image, SKPaint? paint = null, bool copyImage = true)
+    public ImageOperation(Matrix3X3 transformMatrix, Surface image, Paint? paint = null, bool copyImage = true)
     {
         if (paint is not null)
             customPaint = paint.Clone();
@@ -85,8 +85,8 @@ internal class ImageOperation : IDrawOperation
         float scaleMult = (float)chunk.Resolution.Multiplier();
         VecD trans = -chunkPos * ChunkPool.FullChunkSize;
 
-        var scaleTrans = SKMatrix.CreateScaleTranslation(scaleMult, scaleMult, (float)trans.X * scaleMult, (float)trans.Y * scaleMult);
-        var finalMatrix = SKMatrix.Concat(scaleTrans, transformMatrix);
+        var scaleTrans = Matrix3X3.CreateScaleTranslation(scaleMult, scaleMult, (float)trans.X * scaleMult, (float)trans.Y * scaleMult);
+        var finalMatrix = Matrix3X3.Concat(scaleTrans, transformMatrix);
 
         chunk.Surface.DrawingSurface.Canvas.Save();
         chunk.Surface.DrawingSurface.Canvas.SetMatrix(finalMatrix);

+ 0 - 17
src/ChunkyImageLib/SKColorEx.cs

@@ -1,17 +0,0 @@
-using SkiaSharp;
-
-namespace ChunkyImageLib;
-public static class SKColorEx
-{
-    public static unsafe ulong ToULong(this SKColor color)
-    {
-        ulong result = 0;
-        Half* ptr = (Half*)&result;
-        float normalizedAlpha = color.Alpha / 255.0f;
-        ptr[0] = (Half)(color.Red / 255f * normalizedAlpha);
-        ptr[1] = (Half)(color.Green / 255f * normalizedAlpha);
-        ptr[2] = (Half)(color.Blue / 255f * normalizedAlpha);
-        ptr[3] = (Half)(normalizedAlpha);
-        return result;
-    }
-}

+ 2 - 2
src/PixiEditor.ChangeableDocument/ChangeInfos/Drawing/Selection_ChangeInfo.cs

@@ -1,5 +1,5 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 
 namespace PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
 
-public record class Selection_ChangeInfo(SKPath NewPath) : IChangeInfo;
+public record class Selection_ChangeInfo(VectorPath NewPath) : IChangeInfo;

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlySelection.cs

@@ -1,4 +1,4 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Interfaces;
 
@@ -7,5 +7,5 @@ public interface IReadOnlySelection
     /// <summary>
     /// The path of the selection
     /// </summary>
-    public SKPath SelectionPath { get; }
+    public VectorPath SelectionPath { get; }
 }

+ 9 - 7
src/PixiEditor.ChangeableDocument/Changeables/Selection.cs

@@ -1,23 +1,25 @@
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 
 namespace PixiEditor.ChangeableDocument.Changeables;
 
 internal class Selection : IReadOnlySelection, IDisposable
 {
-    public static SKColor SelectionColor { get; } = SKColors.CornflowerBlue;
-    public SKPath SelectionPath { get; set; } = new();
-    SKPath IReadOnlySelection.SelectionPath 
+    public static Color SelectionColor { get; } = Colors.CornflowerBlue;
+    public VectorPath SelectionPath { get; set; } = new();
+    VectorPath IReadOnlySelection.SelectionPath 
     {
-        get {
+        get 
+        {
             try
             {
                 // I think this might throw if another thread disposes SelectionPath at the wrong time?
-                return new SKPath(SelectionPath) { FillType = SKPathFillType.EvenOdd };
+                return new VectorPath(SelectionPath) { FillType = PathFillType.EvenOdd };
             }
             catch (Exception)
             {
-                return new SKPath();
+                return new VectorPath();
             }
         }
     }

+ 11 - 9
src/PixiEditor.ChangeableDocument/Changes/Drawing/ChangeBrightness_UpdateableChange.cs

@@ -1,4 +1,6 @@
-using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
@@ -11,8 +13,8 @@ internal class ChangeBrightness_UpdateableChange : UpdateableChange
     private bool ignoreUpdate = false;
     private readonly bool repeat;
     private readonly bool darken;
-    private readonly SKPaint paint;
-    private readonly SKColor color;
+    private readonly Paint paint;
+    private readonly Color color;
     private CommittedChunkStorage? savedChunks;
 
     [GenerateUpdateableChangeActions]
@@ -24,9 +26,9 @@ internal class ChangeBrightness_UpdateableChange : UpdateableChange
         this.repeat = repeat;
         this.darken = darken;
 
-        color = (darken ? SKColors.Black : SKColors.White)
+        color = (darken ? Colors.Black : Colors.White)
             .WithAlpha((byte)Math.Clamp(correctionFactor * 255 / 100, 0, 255)); 
-        paint = new SKPaint { BlendMode = repeat ? SKBlendMode.SrcOver : SKBlendMode.Src };
+        paint = new Paint { BlendMode = repeat ? BlendMode.SrcOver : BlendMode.Src };
     }
 
     [UpdateChangeMethod]
@@ -43,7 +45,7 @@ internal class ChangeBrightness_UpdateableChange : UpdateableChange
             return new Error();
         Layer layer = (Layer)target.FindMemberOrThrow(layerGuid);
         DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, layer.LayerImage, layerGuid, false);
-        layer.LayerImage.SetBlendMode(darken ? SKBlendMode.Multiply : SKBlendMode.Screen);
+        layer.LayerImage.SetBlendMode(darken ? BlendMode.Multiply : BlendMode.Screen);
         return new Success();
     }
 
@@ -57,7 +59,7 @@ internal class ChangeBrightness_UpdateableChange : UpdateableChange
         int queueLength = layer.LayerImage.QueueLength;
         layer.LayerImage.EnqueueDrawEllipse(
             new RectI(pos + new VecI(-strokeWidth/2), new(strokeWidth)),
-            SKColors.Transparent, color, 0, paint);
+            Colors.Transparent, color, 0, paint);
         var affected = layer.LayerImage.FindAffectedChunks(queueLength);
         
         return new LayerImageChunks_ChangeInfo(layerGuid, affected);
@@ -74,12 +76,12 @@ internal class ChangeBrightness_UpdateableChange : UpdateableChange
         if (!firstApply)
         {
             DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, layer.LayerImage, layerGuid, false);
-            layer.LayerImage.SetBlendMode(darken ? SKBlendMode.Multiply : SKBlendMode.Screen);
+            layer.LayerImage.SetBlendMode(darken ? BlendMode.Multiply : BlendMode.Screen);
             foreach (VecI pos in positions)
             {
                 layer.LayerImage.EnqueueDrawEllipse(
                     new RectI(pos + new VecI(-strokeWidth/2), new(strokeWidth)),
-                    SKColors.Transparent, color, 0, paint);
+                    Colors.Transparent, color, 0, paint);
             }
         }
 

+ 5 - 5
src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawEllipse_UpdateableChange.cs

@@ -1,20 +1,20 @@
-using PixiEditor.DrawingApi.Core.Numerics;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class DrawEllipse_UpdateableChange : UpdateableChange
 {
     private readonly Guid memberGuid;
     private RectI location;
-    private readonly SKColor strokeColor;
-    private readonly SKColor fillColor;
+    private readonly Color strokeColor;
+    private readonly Color fillColor;
     private readonly int strokeWidth;
     private readonly bool drawOnMask;
 
     private CommittedChunkStorage? storedChunks;
 
     [GenerateUpdateableChangeActions]
-    public DrawEllipse_UpdateableChange(Guid memberGuid, RectI location, SKColor strokeColor, SKColor fillColor, int strokeWidth, bool drawOnMask)
+    public DrawEllipse_UpdateableChange(Guid memberGuid, RectI location, Color strokeColor, Color fillColor, int strokeWidth, bool drawOnMask)
     {
         this.memberGuid = memberGuid;
         this.location = location;

+ 9 - 8
src/PixiEditor.ChangeableDocument/Changes/Drawing/DrawLine_UpdateableChange.cs

@@ -1,5 +1,6 @@
-using PixiEditor.DrawingApi.Core.Numerics;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 
@@ -9,14 +10,14 @@ internal class DrawLine_UpdateableChange : UpdateableChange
     private VecI from;
     private VecI to;
     private int strokeWidth;
-    private SKColor color;
-    private SKStrokeCap caps;
+    private Color color;
+    private StrokeCap caps;
     private readonly bool drawOnMask;
     private CommittedChunkStorage? savedChunks;
 
     [GenerateUpdateableChangeActions]
     public DrawLine_UpdateableChange
-        (Guid memberGuid, VecI from, VecI to, int strokeWidth, SKColor color, SKStrokeCap caps, bool drawOnMask)
+        (Guid memberGuid, VecI from, VecI to, int strokeWidth, Color color, StrokeCap caps, bool drawOnMask)
     {
         this.memberGuid = memberGuid;
         this.from = from;
@@ -28,7 +29,7 @@ internal class DrawLine_UpdateableChange : UpdateableChange
     }
 
     [UpdateChangeMethod]
-    public void Update(VecI from, VecI to, int strokeWidth, SKColor color, SKStrokeCap caps)
+    public void Update(VecI from, VecI to, int strokeWidth, Color color, StrokeCap caps)
     {
         this.from = from;
         this.to = to;
@@ -53,9 +54,9 @@ internal class DrawLine_UpdateableChange : UpdateableChange
         {
             DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
             if (strokeWidth == 1)
-                image.EnqueueDrawBresenhamLine(from, to, color, SKBlendMode.SrcOver);
+                image.EnqueueDrawBresenhamLine(from, to, color, BlendMode.SrcOver);
             else
-                image.EnqueueDrawSkiaLine(from, to, caps, strokeWidth, color, SKBlendMode.SrcOver);
+                image.EnqueueDrawSkiaLine(from, to, caps, strokeWidth, color, BlendMode.SrcOver);
         }
         var totalAffected = image.FindAffectedChunks();
         totalAffected.UnionWith(oldAffected);

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillChunkCache.cs

@@ -1,13 +1,14 @@
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;
 
 internal class FloodFillChunkCache : IDisposable
 {
-    private SKPaint ReplacingPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.Src };
+    private Paint ReplacingPaint { get; } = new Paint() { BlendMode = BlendMode.Src };
 
     private readonly HashSet<Guid>? membersToRender;
     private readonly IReadOnlyFolder? structureRoot;

+ 18 - 15
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFillHelper.cs

@@ -3,7 +3,10 @@ using ChunkyImageLib.Operations;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using SkiaSharp;
 using ChunkyImageLib;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;
 
@@ -28,9 +31,9 @@ internal static class FloodFillHelper
     public static Dictionary<VecI, Chunk> FloodFill(
         HashSet<Guid> membersToFloodFill,
         IReadOnlyDocument document,
-        SKPath? selection,
+        VectorPath? selection,
         VecI startingPos,
-        SKColor drawingColor)
+        Color drawingColor)
     {
         int chunkSize = ChunkResolution.Full.PixelSize();
 
@@ -39,12 +42,12 @@ internal static class FloodFillHelper
         VecI initChunkPos = OperationHelper.GetChunkPos(startingPos, chunkSize);
         VecI imageSizeInChunks = (VecI)(document.Size / (double)chunkSize).Ceiling();
         VecI initPosOnChunk = startingPos - initChunkPos * chunkSize;
-        SKColor colorToReplace = cache.GetChunk(initChunkPos).Match(
+        Color colorToReplace = cache.GetChunk(initChunkPos).Match(
             (Chunk chunk) => chunk.Surface.GetSRGBPixel(initPosOnChunk),
-            static (EmptyChunk _) => SKColors.Transparent
+            static (EmptyChunk _) => Colors.Transparent
         );
 
-        if ((colorToReplace.Alpha == 0 && drawingColor.Alpha == 0) || colorToReplace == drawingColor)
+        if ((colorToReplace.A == 0 && drawingColor.A == 0) || colorToReplace == drawingColor)
             return new();
 
         RectI globalSelectionBounds = (RectI?)selection?.TightBounds ?? new RectI(VecI.Zero, document.Size);
@@ -67,7 +70,7 @@ internal static class FloodFillHelper
             if (!drawingChunks.ContainsKey(chunkPos))
             {
                 var chunk = Chunk.Create();
-                chunk.Surface.DrawingSurface.Canvas.Clear(SKColors.Transparent);
+                chunk.Surface.DrawingSurface.Canvas.Clear(Colors.Transparent);
                 drawingChunks[chunkPos] = chunk;
             }
             var drawingChunk = drawingChunks[chunkPos];
@@ -76,7 +79,7 @@ internal static class FloodFillHelper
             // don't call floodfill if the chunk is empty
             if (referenceChunk.IsT1)
             {
-                if (colorToReplace.Alpha == 0 && !processedEmptyChunks.Contains(chunkPos))
+                if (colorToReplace.A == 0 && !processedEmptyChunks.Contains(chunkPos))
                 {
                     drawingChunk.Surface.DrawingSurface.Canvas.Clear(drawingColor);
                     for (int i = 0; i < chunkSize; i++)
@@ -129,12 +132,12 @@ internal static class FloodFillHelper
     private static unsafe byte[]? FloodFillChunk(
         Chunk referenceChunk,
         Chunk drawingChunk,
-        SKPath? selection,
+        VectorPath? selection,
         RectI globalSelectionBounds,
         VecI chunkPos,
         int chunkSize,
         ulong colorBits,
-        SKColor color,
+        Color color,
         VecI pos,
         ColorBounds bounds)
     {
@@ -177,7 +180,7 @@ internal static class FloodFillHelper
     /// <summary>
     /// Use skia to set all pixels in array that are inside selection to InSelection
     /// </summary>
-    private static unsafe void DrawSelection(byte[] array, SKPath? selection, RectI globalBounds, VecI chunkPos, int chunkSize)
+    private static unsafe void DrawSelection(byte[] array, VectorPath? selection, RectI globalBounds, VecI chunkPos, int chunkSize)
     {
         if (selection is null)
         {
@@ -191,15 +194,15 @@ internal static class FloodFillHelper
         RectI localBounds = globalBounds.Offset(-chunkPos * chunkSize).Intersect(new(0, 0, chunkSize, chunkSize));
         if (localBounds.IsZeroOrNegativeArea)
             return;
-        SKPath shiftedSelection = new SKPath(selection);
-        shiftedSelection.Transform(SKMatrix.CreateTranslation(-chunkPos.X * chunkSize, -chunkPos.Y * chunkSize));
+        VectorPath shiftedSelection = new VectorPath(selection);
+        shiftedSelection.Transform(Matrix3X3.CreateTranslation(-chunkPos.X * chunkSize, -chunkPos.Y * chunkSize));
 
         fixed (byte* arr = array)
         {
-            using SKSurface drawingSurface = SKSurface.Create(
-                new SKImageInfo(localBounds.Right, localBounds.Bottom, SKColorType.Gray8, SKAlphaType.Opaque), (IntPtr)arr, chunkSize);
+            using DrawingSurface drawingSurface = SKSurface.Create(
+                new SKImageInfo(localBounds.Right, localBounds.Bottom, ColorType.Gray8, AlphaType.Opaque), (IntPtr)arr, chunkSize);
             drawingSurface.Canvas.ClipPath(shiftedSelection);
-            drawingSurface.Canvas.Clear(new SKColor(InSelection, InSelection, InSelection));
+            drawingSurface.Canvas.Clear(new Color(InSelection, InSelection, InSelection));
             drawingSurface.Canvas.Flush();
         }
     }

+ 6 - 4
src/PixiEditor.ChangeableDocument/Changes/Drawing/FloodFill/FloodFill_Change.cs

@@ -1,4 +1,6 @@
-using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing.FloodFill;
@@ -7,13 +9,13 @@ internal class FloodFill_Change : Change
 {
     private readonly Guid memberGuid;
     private readonly VecI pos;
-    private readonly SKColor color;
+    private readonly Color color;
     private readonly bool referenceAll;
     private readonly bool drawOnMask;
     private CommittedChunkStorage? chunkStorage = null;
 
     [GenerateMakeChangeAction]
-    public FloodFill_Change(Guid memberGuid, VecI pos, SKColor color, bool referenceAll, bool drawOnMask)
+    public FloodFill_Change(Guid memberGuid, VecI pos, Color color, bool referenceAll, bool drawOnMask)
     {
         this.memberGuid = memberGuid;
         this.pos = pos;
@@ -35,7 +37,7 @@ internal class FloodFill_Change : Change
     {
         var image = DrawingChangeHelper.GetTargetImageOrThrow(target, memberGuid, drawOnMask);
 
-        SKPath? selection = target.Selection.SelectionPath.IsEmpty ? null : target.Selection.SelectionPath;
+        VectorPath? selection = target.Selection.SelectionPath.IsEmpty ? null : target.Selection.SelectionPath;
         HashSet<Guid> membersToReference = new();
         if (referenceAll)
             target.ForEveryReadonlyMember(member => membersToReference.Add(member.GuidValue));

+ 13 - 11
src/PixiEditor.ChangeableDocument/Changes/Drawing/LineBasedPen_UpdateableChange.cs

@@ -1,21 +1,23 @@
-using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class LineBasedPen_UpdateableChange : UpdateableChange
 {
     private readonly Guid memberGuid;
-    private readonly SKColor color;
+    private readonly Color color;
     private readonly int strokeWidth;
     private readonly bool replacing;
     private readonly bool drawOnMask;
-    private readonly SKPaint srcPaint = new SKPaint() { BlendMode = SKBlendMode.Src };
+    private readonly Paint srcPaint = new Paint() { BlendMode = BlendMode.Src };
 
     private CommittedChunkStorage? storedChunks;
     private readonly List<VecI> points = new();
 
     [GenerateUpdateableChangeActions]
-    public LineBasedPen_UpdateableChange(Guid memberGuid, SKColor color, VecI pos, int strokeWidth, bool replacing, bool drawOnMask)
+    public LineBasedPen_UpdateableChange(Guid memberGuid, Color color, VecI pos, int strokeWidth, bool replacing, bool drawOnMask)
     {
         this.memberGuid = memberGuid;
         this.color = color;
@@ -39,7 +41,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
             return new Error();
         var image = DrawingChangeHelper.GetTargetImageOrThrow(target, memberGuid, drawOnMask);
         if (!replacing)
-            image.SetBlendMode(SKBlendMode.SrcOver);
+            image.SetBlendMode(BlendMode.SrcOver);
         DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
         return new Success();
     }
@@ -54,13 +56,13 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
 
         if (strokeWidth == 1)
         {
-            image.EnqueueDrawBresenhamLine(from, to, color, SKBlendMode.Src);
+            image.EnqueueDrawBresenhamLine(from, to, color, BlendMode.Src);
         }
         else
         {
             var rect = new RectI(to - new VecI(strokeWidth / 2), new VecI(strokeWidth));
             image.EnqueueDrawEllipse(rect, color, color, 1, srcPaint);
-            image.EnqueueDrawSkiaLine(from, to, SKStrokeCap.Butt, strokeWidth, color, SKBlendMode.Src);
+            image.EnqueueDrawSkiaLine(from, to, StrokeCap.Butt, strokeWidth, color, BlendMode.Src);
         }
         var affChunks = image.FindAffectedChunks(opCount);
 
@@ -73,7 +75,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         {
             if (strokeWidth == 1)
             {
-                targetImage.EnqueueDrawBresenhamLine(points[0], points[0], color, SKBlendMode.Src);
+                targetImage.EnqueueDrawBresenhamLine(points[0], points[0], color, BlendMode.Src);
             }
             else
             {
@@ -90,13 +92,13 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         {
             if (strokeWidth == 1)
             {
-                targetImage.EnqueueDrawBresenhamLine(points[i - 1], points[i], color, SKBlendMode.Src);
+                targetImage.EnqueueDrawBresenhamLine(points[i - 1], points[i], color, BlendMode.Src);
             }
             else
             {
                 var rect = new RectI(points[i] - new VecI(strokeWidth / 2), new VecI(strokeWidth));
                 targetImage.EnqueueDrawEllipse(rect, color, color, 1, srcPaint);
-                targetImage.EnqueueDrawSkiaLine(points[i - 1], points[i], SKStrokeCap.Butt, strokeWidth, color, SKBlendMode.Src);
+                targetImage.EnqueueDrawSkiaLine(points[i - 1], points[i], StrokeCap.Butt, strokeWidth, color, BlendMode.Src);
             }
         }
     }
@@ -119,7 +121,7 @@ internal class LineBasedPen_UpdateableChange : UpdateableChange
         else
         {
             if (!replacing)
-                image.SetBlendMode(SKBlendMode.SrcOver);
+                image.SetBlendMode(BlendMode.SrcOver);
             DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
 
             FastforwardEnqueueDrawLines(image);

+ 2 - 2
src/PixiEditor.ChangeableDocument/Changes/Drawing/PasteImage_UpdateableChange.cs

@@ -1,5 +1,5 @@
 using PixiEditor.DrawingApi.Core.Numerics;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Surface;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class PasteImage_UpdateableChange : UpdateableChange
@@ -10,7 +10,7 @@ internal class PasteImage_UpdateableChange : UpdateableChange
     private readonly bool drawOnMask;
     private readonly Surface imageToPaste;
     private CommittedChunkStorage? savedChunks;
-    private static SKPaint RegularPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
+    private static Paint RegularPaint { get; } = new Paint() { BlendMode = BlendMode.SrcOver };
 
     private bool hasEnqueudImage = false;
 

+ 22 - 19
src/PixiEditor.ChangeableDocument/Changes/Drawing/PathBasedPen_UpdateableChange.cs

@@ -1,21 +1,24 @@
-using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class PathBasedPen_UpdateableChange : UpdateableChange
 {
     private readonly Guid memberGuid;
-    private readonly SKColor color;
+    private readonly Color color;
     private readonly float strokeWidth;
     private readonly bool drawOnMask;
 
     private CommittedChunkStorage? storedChunks;
-    private SKPath tempPath = new();
+    private VectorPath tempPath = new();
 
     private List<VecD> points = new();
 
     [GenerateUpdateableChangeActions]
-    public PathBasedPen_UpdateableChange(Guid memberGuid, VecD pos, SKColor color, float strokeWidth, bool drawOnMask)
+    public PathBasedPen_UpdateableChange(Guid memberGuid, VecD pos, Color color, float strokeWidth, bool drawOnMask)
     {
         this.memberGuid = memberGuid;
         this.color = color;
@@ -35,7 +38,7 @@ internal class PathBasedPen_UpdateableChange : UpdateableChange
         if (!DrawingChangeHelper.IsValidForDrawing(target, memberGuid, drawOnMask))
             return new Error();
         var image = DrawingChangeHelper.GetTargetImageOrThrow(target, memberGuid, drawOnMask);
-        image.SetBlendMode(SKBlendMode.SrcOver);
+        image.SetBlendMode(BlendMode.SrcOver);
         DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
         return new Success();
     }
@@ -53,7 +56,7 @@ internal class PathBasedPen_UpdateableChange : UpdateableChange
         for (int i = 0; i < points.Count; i++)
         {
             UpdateTempPath(i + 1);
-            image.EnqueueDrawPath(tempPath, color, strokeWidth, SKStrokeCap.Round, SKBlendMode.Src);
+            image.EnqueueDrawPath(tempPath, color, strokeWidth, StrokeCap.Round, BlendMode.Src);
         }
     }
 
@@ -62,18 +65,18 @@ internal class PathBasedPen_UpdateableChange : UpdateableChange
         tempPath.Reset();
         if (points.Count == 1)
         {
-            tempPath.MoveTo((SKPoint)points[0]);
+            tempPath.MoveTo((Point)points[0]);
             return;
         }
         if (points.Count == 2)
         {
-            tempPath.MoveTo((SKPoint)points[0]);
-            tempPath.LineTo((SKPoint)points[1]);
+            tempPath.MoveTo((Point)points[0]);
+            tempPath.LineTo((Point)points[1]);
             return;
         }
         var (mid, _) = FindCubicPoints(points[^3], points[^2], points[^1], points[^1]);
-        tempPath.MoveTo((SKPoint)points[^2]);
-        tempPath.QuadTo((SKPoint)mid, (SKPoint)points[^1]);
+        tempPath.MoveTo((Point)points[^2]);
+        tempPath.QuadTo((Point)mid, (Point)points[^1]);
     }
 
     private void UpdateTempPath(int pointsCount)
@@ -81,20 +84,20 @@ internal class PathBasedPen_UpdateableChange : UpdateableChange
         tempPath.Reset();
         if (pointsCount is 1 or 2)
         {
-            tempPath.MoveTo((SKPoint)points[0]);
+            tempPath.MoveTo((Point)points[0]);
             return;
         }
         if (pointsCount == 3)
         {
             var (mid, _) = FindCubicPoints(points[0], points[1], points[2], points[2]);
-            tempPath.MoveTo((SKPoint)points[0]);
-            tempPath.QuadTo((SKPoint)mid, (SKPoint)points[2]);
+            tempPath.MoveTo((Point)points[0]);
+            tempPath.QuadTo((Point)mid, (Point)points[2]);
             return;
         }
 
         var (mid1, mid2) = FindCubicPoints(points[pointsCount - 4], points[pointsCount - 3], points[pointsCount - 2], points[pointsCount - 1]);
-        tempPath.MoveTo((SKPoint)points[pointsCount - 3]);
-        tempPath.CubicTo((SKPoint)mid1, (SKPoint)mid2, (SKPoint)points[pointsCount - 2]);
+        tempPath.MoveTo((Point)points[pointsCount - 3]);
+        tempPath.CubicTo((Point)mid1, (Point)mid2, (Point)points[pointsCount - 2]);
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
@@ -108,7 +111,7 @@ internal class PathBasedPen_UpdateableChange : UpdateableChange
         {
             UpdateTempPathFinish();
 
-            image.EnqueueDrawPath(tempPath, color, strokeWidth, SKStrokeCap.Round, SKBlendMode.Src);
+            image.EnqueueDrawPath(tempPath, color, strokeWidth, StrokeCap.Round, BlendMode.Src);
             var affChunks = image.FindAffectedChunks();
             storedChunks = new CommittedChunkStorage(image, affChunks);
             image.CommitChanges();
@@ -117,7 +120,7 @@ internal class PathBasedPen_UpdateableChange : UpdateableChange
         }
         else
         {
-            image.SetBlendMode(SKBlendMode.SrcOver);
+            image.SetBlendMode(BlendMode.SrcOver);
             DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
 
             FastforwardEnqueueDrawPath(image);
@@ -135,7 +138,7 @@ internal class PathBasedPen_UpdateableChange : UpdateableChange
         var image = DrawingChangeHelper.GetTargetImageOrThrow(target, memberGuid, drawOnMask);
 
         int opCount = image.QueueLength;
-        image.EnqueueDrawPath(tempPath, color, strokeWidth, SKStrokeCap.Round, SKBlendMode.Src);
+        image.EnqueueDrawPath(tempPath, color, strokeWidth, StrokeCap.Round, BlendMode.Src);
         var affChunks = image.FindAffectedChunks(opCount);
 
         return DrawingChangeHelper.CreateChunkChangeInfo(memberGuid, affChunks, drawOnMask);

+ 11 - 9
src/PixiEditor.ChangeableDocument/Changes/Drawing/PixelPerfectPen_UpdateableChange.cs

@@ -1,12 +1,14 @@
 using ChunkyImageLib.Operations;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 
 internal class PixelPerfectPen_UpdateableChange : UpdateableChange
 {
-    private readonly SKColor color;
+    private readonly Color color;
     private readonly bool drawOnMask;
     private readonly Guid memberGuid;
     private readonly HashSet<VecI> confirmedPixels = new();
@@ -16,7 +18,7 @@ internal class PixelPerfectPen_UpdateableChange : UpdateableChange
     private CommittedChunkStorage? chunkStorage;
 
     [GenerateUpdateableChangeActions]
-    public PixelPerfectPen_UpdateableChange(Guid memberGuid, VecI pos, SKColor color, bool drawOnMask)
+    public PixelPerfectPen_UpdateableChange(Guid memberGuid, VecI pos, Color color, bool drawOnMask)
     {
         this.memberGuid = memberGuid;
         this.color = color;
@@ -34,7 +36,7 @@ internal class PixelPerfectPen_UpdateableChange : UpdateableChange
         if (!DrawingChangeHelper.IsValidForDrawing(target, memberGuid, drawOnMask))
             return new Error();
         var image = DrawingChangeHelper.GetTargetImageOrThrow(target, memberGuid, drawOnMask);
-        image.SetBlendMode(SKBlendMode.SrcOver);
+        image.SetBlendMode(BlendMode.SrcOver);
         DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
         return new Success();
     }
@@ -53,7 +55,7 @@ internal class PixelPerfectPen_UpdateableChange : UpdateableChange
     {
         if (pointsCount == 1)
         {
-            image.EnqueueDrawPixel(incomingPoints![0], color, SKBlendMode.Src);
+            image.EnqueueDrawPixel(incomingPoints![0], color, BlendMode.Src);
             confirmedPixels.Add(incomingPoints[0]);
             return;
         }
@@ -69,17 +71,17 @@ internal class PixelPerfectPen_UpdateableChange : UpdateableChange
         (pixelsToConfirm2, pixelsToConfirm) = (pixelsToConfirm, pixelsToConfirm2);
         pixelsToConfirm.Clear();
 
-        SKPoint[] line = BresenhamLineHelper.GetBresenhamLine(incomingPoints[pointsCount - 2], incomingPoints[pointsCount - 1]);
+        Point[] line = BresenhamLineHelper.GetBresenhamLine(incomingPoints[pointsCount - 2], incomingPoints[pointsCount - 1]);
         foreach (VecI pixel in line)
         {
             pixelsToConfirm.Add(pixel);
         }
-        image.EnqueueDrawPixels(line.Select(point => (VecI)point), color, SKBlendMode.Src);
+        image.EnqueueDrawPixels(line.Select(point => (VecI)point), color, BlendMode.Src);
 
         if (pointsCount >= 3 && IsLShape(pointsCount - 1) && !confirmedPixels.Contains(incomingPoints[pointsCount - 2]))
         {
             VecI pixelToErase = incomingPoints[pointsCount - 2];
-            image.EnqueueDrawPixel(pixelToErase, SKColors.Transparent, SKBlendMode.Src);
+            image.EnqueueDrawPixel(pixelToErase, Colors.Transparent, BlendMode.Src);
             pixelsToConfirm.Remove(pixelToErase);
             pixelsToConfirm2.Remove(pixelToErase);
             incomingPoints.RemoveAt(pointsCount - 2);
@@ -111,9 +113,9 @@ internal class PixelPerfectPen_UpdateableChange : UpdateableChange
         }
         else
         {
-            image.SetBlendMode(SKBlendMode.SrcOver);
+            image.SetBlendMode(BlendMode.SrcOver);
             DrawingChangeHelper.ApplyClipsSymmetriesEtc(target, image, memberGuid, drawOnMask);
-            image.EnqueueDrawPixels(confirmedPixels, color, SKBlendMode.Src);
+            image.EnqueueDrawPixels(confirmedPixels, color, BlendMode.Src);
         }
 
         var affChunks = image.FindAffectedChunks();

+ 5 - 5
src/PixiEditor.ChangeableDocument/Changes/Drawing/ReplaceColor_Change.cs

@@ -1,16 +1,16 @@
-using PixiEditor.DrawingApi.Core.Numerics;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
 internal class ReplaceColor_Change : Change
 {
-    private readonly SKColor oldColor;
-    private readonly SKColor newColor;
+    private readonly Color oldColor;
+    private readonly Color newColor;
 
     private Dictionary<Guid, CommittedChunkStorage>? savedChunks;
 
     [GenerateMakeChangeAction]
-    public ReplaceColor_Change(SKColor oldColor, SKColor newColor)
+    public ReplaceColor_Change(Color oldColor, Color newColor)
     {
         this.oldColor = oldColor;
         this.newColor = newColor;

+ 10 - 8
src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelectedArea_UpdateableChange.cs

@@ -1,6 +1,8 @@
 using ChunkyImageLib.Operations;
 using PixiEditor.ChangeableDocument.Changes.Selection;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Drawing;
@@ -12,15 +14,15 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
     private ShapeCorners corners;
 
     private Dictionary<Guid, (Surface surface, VecI pos)>? images;
-    private SKMatrix globalMatrix;
+    private Matrix3X3 globalMatrix;
     private RectI originalTightBounds;
     private Dictionary<Guid, CommittedChunkStorage>? savedChunks;
 
-    private SKPath? originalPath;
+    private VectorPath? originalPath;
 
     private bool hasEnqueudImages = false;
 
-    private static SKPaint RegularPaint { get; } = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
+    private static Paint RegularPaint { get; } = new () { BlendMode = BlendMode.SrcOver };
 
     [GenerateUpdateableChangeActions]
     public TransformSelectedArea_UpdateableChange(
@@ -46,7 +48,7 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
                 return new Error();
         }
 
-        originalPath = new SKPath(target.Selection.SelectionPath) { FillType = SKPathFillType.EvenOdd };
+        originalPath = new VectorPath(target.Selection.SelectionPath) { FillType = PathFillType.EvenOdd };
         RectI bounds = (RectI)originalPath.TightBounds;
 
         images = new();
@@ -65,7 +67,7 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
         return new Success();
     }
 
-    public OneOf<None, (Surface image, RectI extractedRect)> ExtractArea(ChunkyImage image, SKPath path, RectI pathBounds)
+    public OneOf<None, (Surface image, RectI extractedRect)> ExtractArea(ChunkyImage image, VectorPath path, RectI pathBounds)
     {
         // get rid of transparent areas on edges
         var memberImageBounds = image.FindLatestBounds();
@@ -77,8 +79,8 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
             return new None();
 
         // shift the clip to account for the image being smaller than the selection
-        SKPath clipPath = new SKPath(path) { FillType = SKPathFillType.EvenOdd };
-        clipPath.Transform(SKMatrix.CreateTranslation(-pathBounds.X, -pathBounds.Y));
+        VectorPath clipPath = new VectorPath(path) { FillType = PathFillType.EvenOdd };
+        clipPath.Transform(Matrix3X3.CreateTranslation(-pathBounds.X, -pathBounds.Y));
 
         // draw
         Surface output = new(pathBounds.Size);
@@ -106,7 +108,7 @@ internal class TransformSelectedArea_UpdateableChange : UpdateableChange
 
         if (!keepOriginal)
             memberImage.EnqueueClearPath(originalPath!, originalTightBounds);
-        SKMatrix localMatrix = SKMatrix.CreateTranslation(originalPos.X - originalTightBounds.Left, originalPos.Y - originalTightBounds.Top);
+        Matrix3X3 localMatrix = Matrix3X3.CreateTranslation(originalPos.X - originalTightBounds.Left, originalPos.Y - originalTightBounds.Top);
         localMatrix = localMatrix.PostConcat(globalMatrix);
         memberImage.EnqueueDrawImage(localMatrix, image, RegularPaint, false);
         hasEnqueudImages = true;

+ 10 - 8
src/PixiEditor.ChangeableDocument/Changes/Root/ResizeImage_Change.cs

@@ -1,7 +1,9 @@
 using PixiEditor.ChangeableDocument.ChangeInfos.Root;
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
+using BlendMode = PixiEditor.DrawingApi.Core.Surface.BlendMode;
 
 namespace PixiEditor.ChangeableDocument.Changes.Root;
 
@@ -34,13 +36,13 @@ internal class ResizeImage_Change : Change
         return new Success();
     }
 
-    private static SKFilterQuality ToFilterQuality(ResamplingMethod method, bool downscaling) =>
+    private static FilterQuality ToFilterQuality(ResamplingMethod method, bool downscaling) =>
         (method, downscaling) switch
         {
-            (ResamplingMethod.NearestNeighbor, _) => SKFilterQuality.None,
-            (ResamplingMethod.Bilinear, true) => SKFilterQuality.Medium,
-            (ResamplingMethod.Bilinear, false) => SKFilterQuality.Low,
-            (ResamplingMethod.Bicubic, _) => SKFilterQuality.High,
+            (ResamplingMethod.NearestNeighbor, _) => FilterQuality.None,
+            (ResamplingMethod.Bilinear, true) => FilterQuality.Medium,
+            (ResamplingMethod.Bilinear, false) => FilterQuality.Low,
+            (ResamplingMethod.Bicubic, _) => FilterQuality.High,
             _ => throw new ArgumentOutOfRangeException(),
         };
 
@@ -54,11 +56,11 @@ internal class ResizeImage_Change : Change
             VecI.Zero);
         
         bool downscaling = newSize.LengthSquared < originalSize.LengthSquared;
-        SKFilterQuality quality = ToFilterQuality(method, downscaling);
-        using SKPaint paint = new()
+        FilterQuality quality = ToFilterQuality(method, downscaling);
+        using Paint paint = new()
         {
             FilterQuality = quality, 
-            BlendMode = SKBlendMode.Src,
+            BlendMode = BlendMode.Src,
         };
 
         using Surface newSurface = new(newSize);

+ 7 - 7
src/PixiEditor.ChangeableDocument/Changes/Selection/ClearSelection_Change.cs

@@ -1,10 +1,10 @@
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;
 
 internal class ClearSelection_Change : Change
 {
-    private SKPath? originalPath;
+    private VectorPath? originalPath;
 
     [GenerateMakeChangeAction]
     public ClearSelection_Change() { }
@@ -13,25 +13,25 @@ internal class ClearSelection_Change : Change
     {
         if (target.Selection.SelectionPath.IsEmpty)
             return new Error();
-        originalPath = new SKPath(target.Selection.SelectionPath);
+        originalPath = new VectorPath(target.Selection.SelectionPath);
         return new Success();
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
     {
-        (var toDispose, target.Selection.SelectionPath) = (target.Selection.SelectionPath, new SKPath());
+        (var toDispose, target.Selection.SelectionPath) = (target.Selection.SelectionPath, new VectorPath());
         toDispose.Dispose();
 
         ignoreInUndo = false;
-        return new Selection_ChangeInfo(new SKPath());
+        return new Selection_ChangeInfo(new VectorPath());
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     {
-        (var toDispose, target.Selection.SelectionPath) = (target.Selection.SelectionPath, new SKPath(originalPath));
+        (var toDispose, target.Selection.SelectionPath) = (target.Selection.SelectionPath, new VectorPath(originalPath!));
         toDispose.Dispose();
 
-        return new Selection_ChangeInfo(new SKPath(originalPath));
+        return new Selection_ChangeInfo(new VectorPath(originalPath!));
     }
 
     public override void Dispose()

+ 6 - 5
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectEllipse_UpdateableChange.cs

@@ -1,5 +1,6 @@
 using PixiEditor.ChangeableDocument.Enums;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;
@@ -25,13 +26,13 @@ internal class SelectEllipse_UpdateableChange : UpdateableChange
 
     public override OneOf<Success, Error> InitializeAndValidate(Document target)
     {
-        originalPath = new SKPath(target.Selection.SelectionPath);
+        originalPath = new VectorPath(target.Selection.SelectionPath);
         return new Success();
     }
 
     private Selection_ChangeInfo CommonApply(Document target)
     {
-        using var ellipsePath = new SKPath() { FillType = SKPathFillType.EvenOdd };
+        using var ellipsePath = new VectorPath() { FillType = PathFillType.EvenOdd };
         if (!borders.IsZeroArea)
             ellipsePath.AddOval(borders);
 
@@ -42,7 +43,7 @@ internal class SelectEllipse_UpdateableChange : UpdateableChange
             target.Selection.SelectionPath = originalPath!.Op(ellipsePath, mode.ToSKPathOp());
         toDispose.Dispose();
 
-        return new Selection_ChangeInfo(new SKPath(target.Selection.SelectionPath));
+        return new Selection_ChangeInfo(new VectorPath(target.Selection.SelectionPath));
     }
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> ApplyTemporarily(Document target)
@@ -59,9 +60,9 @@ internal class SelectEllipse_UpdateableChange : UpdateableChange
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     {
-        (var toDispose, target.Selection.SelectionPath) = (target.Selection.SelectionPath, new SKPath(originalPath));
+        (var toDispose, target.Selection.SelectionPath) = (target.Selection.SelectionPath, new VectorPath(originalPath));
         toDispose.Dispose();
-        return new Selection_ChangeInfo(new SKPath(target.Selection.SelectionPath));
+        return new Selection_ChangeInfo(new VectorPath(target.Selection.SelectionPath));
     }
 
     public override void Dispose()

+ 5 - 4
src/PixiEditor.ChangeableDocument/Changes/Selection/SelectionChangeHelper.cs

@@ -1,16 +1,17 @@
 using ChunkyImageLib.Operations;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Changes.Selection;
 internal class SelectionChangeHelper
 {
     public static Selection_ChangeInfo DoSelectionTransform(
-        Document target, SKPath originalPath, RectI originalPathTightBounds, ShapeCorners to)
+        Document target, VectorPath originalPath, RectI originalPathTightBounds, ShapeCorners to)
     {
-        SKPath newPath = new(originalPath);
+        VectorPath newPath = new(originalPath);
 
-        var matrix = SKMatrix.CreateTranslation((float)-originalPathTightBounds.X, (float)-originalPathTightBounds.Y).PostConcat(
+        var matrix = Matrix3X3.CreateTranslation((float)-originalPathTightBounds.X, (float)-originalPathTightBounds.Y).PostConcat(
             OperationHelper.CreateMatrixFromPoints(to, originalPathTightBounds.Size));
         newPath.Transform(matrix);
 
@@ -18,6 +19,6 @@ internal class SelectionChangeHelper
         target.Selection.SelectionPath = newPath;
         toDispose.Dispose();
 
-        return new Selection_ChangeInfo(new SKPath(target.Selection.SelectionPath));
+        return new Selection_ChangeInfo(new VectorPath(target.Selection.SelectionPath));
     }
 }

+ 2 - 1
src/PixiEditor.ChangeableDocument/Rendering/ChunkRenderer.cs

@@ -1,13 +1,14 @@
 using ChunkyImageLib.Operations;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 
 namespace PixiEditor.ChangeableDocument.Rendering;
 
 public static class ChunkRenderer
 {
-    private static readonly SKPaint ClippingPaint = new SKPaint() { BlendMode = SKBlendMode.DstIn };
+    private static readonly Paint ClippingPaint = new Paint() { BlendMode = BlendMode.DstIn };
 
     public static OneOf<Chunk, EmptyChunk> MergeWholeStructure(VecI chunkPos, ChunkResolution resolution, IReadOnlyFolder root)
     {

+ 28 - 26
src/PixiEditor.ChangeableDocument/Rendering/RenderingContext.cs

@@ -1,18 +1,20 @@
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
-using PixiEditor.ChangeableDocument.Enums;
-using SkiaSharp;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surface;
+using BlendMode = PixiEditor.ChangeableDocument.Enums.BlendMode;
+using DrawingApiBlendMode = PixiEditor.DrawingApi.Core.Surface.BlendMode;
 
 namespace PixiEditor.ChangeableDocument.Rendering;
 internal class RenderingContext : IDisposable
 {
-    public SKPaint BlendModePaint = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
-    public SKPaint BlendModeOpacityPaint = new SKPaint() { BlendMode = SKBlendMode.SrcOver };
-    public SKPaint ReplacingPaintWithOpacity = new SKPaint() { BlendMode = SKBlendMode.Src };
+    public Paint BlendModePaint = new () { BlendMode = DrawingApiBlendMode.SrcOver };
+    public Paint BlendModeOpacityPaint = new () { BlendMode = DrawingApiBlendMode.SrcOver };
+    public Paint ReplacingPaintWithOpacity = new () { BlendMode = DrawingApiBlendMode.Src };
 
     public void UpdateFromMember(IReadOnlyStructureMember member)
     {
-        SKColor opacityColor = new(255, 255, 255, (byte)Math.Round(member.Opacity * 255));
-        SKBlendMode blendMode = GetSKBlendMode(member.BlendMode);
+        Color opacityColor = new(255, 255, 255, (byte)Math.Round(member.Opacity * 255));
+        DrawingApiBlendMode blendMode = GetDrawingBlendMode(member.BlendMode);
 
         BlendModeOpacityPaint.Color = opacityColor;
         BlendModeOpacityPaint.BlendMode = blendMode;
@@ -20,28 +22,28 @@ internal class RenderingContext : IDisposable
         ReplacingPaintWithOpacity.Color = opacityColor;
     }
 
-    private static SKBlendMode GetSKBlendMode(BlendMode blendMode)
+    private static DrawingApiBlendMode GetDrawingBlendMode(BlendMode blendMode)
     {
         return blendMode switch
         {
-            BlendMode.Normal => SKBlendMode.SrcOver,
-            BlendMode.Darken => SKBlendMode.Darken,
-            BlendMode.Multiply => SKBlendMode.Multiply,
-            BlendMode.ColorBurn => SKBlendMode.ColorBurn,
-            BlendMode.Lighten => SKBlendMode.Lighten,
-            BlendMode.Screen => SKBlendMode.Screen,
-            BlendMode.ColorDodge => SKBlendMode.ColorDodge,
-            BlendMode.LinearDodge => SKBlendMode.Plus,
-            BlendMode.Overlay => SKBlendMode.Overlay,
-            BlendMode.SoftLight => SKBlendMode.SoftLight,
-            BlendMode.HardLight => SKBlendMode.HardLight,
-            BlendMode.Difference => SKBlendMode.Difference,
-            BlendMode.Exclusion => SKBlendMode.Exclusion,
-            BlendMode.Hue => SKBlendMode.Hue,
-            BlendMode.Saturation => SKBlendMode.Saturation,
-            BlendMode.Luminosity => SKBlendMode.Luminosity,
-            BlendMode.Color => SKBlendMode.Color,
-            _ => SKBlendMode.SrcOver,
+            BlendMode.Normal => DrawingApiBlendMode.SrcOver,
+            BlendMode.Darken => DrawingApiBlendMode.Darken,
+            BlendMode.Multiply => DrawingApiBlendMode.Multiply,
+            BlendMode.ColorBurn => DrawingApiBlendMode.ColorBurn,
+            BlendMode.Lighten => DrawingApiBlendMode.Lighten,
+            BlendMode.Screen => DrawingApiBlendMode.Screen,
+            BlendMode.ColorDodge => DrawingApiBlendMode.ColorDodge,
+            BlendMode.LinearDodge => DrawingApiBlendMode.Plus,
+            BlendMode.Overlay => DrawingApiBlendMode.Overlay,
+            BlendMode.SoftLight => DrawingApiBlendMode.SoftLight,
+            BlendMode.HardLight => DrawingApiBlendMode.HardLight,
+            BlendMode.Difference => DrawingApiBlendMode.Difference,
+            BlendMode.Exclusion => DrawingApiBlendMode.Exclusion,
+            BlendMode.Hue => DrawingApiBlendMode.Hue,
+            BlendMode.Saturation => DrawingApiBlendMode.Saturation,
+            BlendMode.Luminosity => DrawingApiBlendMode.Luminosity,
+            BlendMode.Color => DrawingApiBlendMode.Color,
+            _ => DrawingApiBlendMode.SrcOver,
         };
     }
 

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

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

+ 2 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IMatrix3x3Implementation.cs

@@ -6,4 +6,6 @@ public interface IMatrix3X3Implementation
 {
     public bool TryInvert(Matrix3X3 matrix, out Matrix3X3 inversedResult);
     public Matrix3X3 Concat(in Matrix3X3 first, in Matrix3X3 second);
+    public Matrix3X3 PostConcat(in Matrix3X3 first, in Matrix3X3 second);
+    public VecD MapPoint(Matrix3X3 matrix, int p0, int p1);
 }

+ 3 - 2
src/PixiEditor.DrawingApi.Core/Bridge/Operations/IPaintOperations.cs → src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPaintImplementation.cs

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

+ 9 - 0
src/PixiEditor.DrawingApi.Core/Bridge/NativeObjectsImpl/IPixmapImplementation.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
+
+public interface IPixmapImplementation
+{
+    public void Dispose(IntPtr objectPointer);
+    public IntPtr GetPixels(IntPtr objectPointer);
+}

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

@@ -1,5 +1,6 @@
 using System;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.Vector;
 
 namespace PixiEditor.DrawingApi.Core.Bridge.NativeObjectsImpl;
@@ -22,4 +23,10 @@ public interface IVectorPathImplementation
     public IntPtr Clone(VectorPath other);
     public RectD GetTightBounds(VectorPath vectorPath);
     public void Transform(VectorPath vectorPath, Matrix3X3 matrix);
+    public RectD GetBounds(VectorPath vectorPath);
+    public void Reset(VectorPath vectorPath);
+    public void MoveTo(VectorPath vectorPath, Point point);
+    public void LineTo(VectorPath vectorPath, Point point);
+    public void QuadTo(VectorPath vectorPath, Point mid, Point point);
+    public void CubicTo(VectorPath vectorPath, Point mid1, Point mid2, Point point);
 }

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

@@ -1,4 +1,5 @@
-using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
 using PixiEditor.DrawingApi.Core.Surface.Vector;
 
@@ -7,7 +8,7 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
     public interface ICanvasOperations
     {
         public void DrawPixel(int posX, int posY, Paint drawingPaint);
-        public void DrawSurface(DrawingSurface drawingSurface, int x, int y, Paint paint);
+        public void DrawSurface(DrawingSurface drawingSurface, int x, int y, Paint? paint);
         public void DrawImage(Image image, int x, int y);
         public int Save();
         public void Restore();
@@ -15,12 +16,15 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
         public void Translate(float translationX, float translationY);
         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 Clear(Color color);
         public void DrawLine(VecI from, VecI to, Paint paint);
+        public void Flush();
+        public void SetMatrix(Matrix3X3 finalMatrix);
+        public void RestoreToCount(int count);
     }
 }

+ 1 - 0
src/PixiEditor.DrawingApi.Core/Bridge/Operations/IImageOperations.cs

@@ -7,5 +7,6 @@ namespace PixiEditor.DrawingApi.Core.Bridge.Operations
         public Image Snapshot(DrawingSurface drawingSurface);
         public void DisposeImage(Image image);
         public Image FromEncodedData(string path);
+        public Pixmap PeekPixels(DrawingSurface drawingSurface);
     }
 }

+ 17 - 3
src/PixiEditor.DrawingApi.Core/Numerics/Matrix3X3.cs

@@ -1,6 +1,7 @@
 using System;
 using System.ComponentModel;
 using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.Surface;
 using SkiaSharp;
 
 namespace PixiEditor.DrawingApi.Core.Numerics;
@@ -9,8 +10,8 @@ namespace PixiEditor.DrawingApi.Core.Numerics;
 /// <remarks>
 ///     It extends the traditional 2D affine transformation matrix with three perspective components that allow simple
 ///     3D effects to be created with it. Those components must be manually set by using the
-///     <see cref="P:SkiaSharp.Matrix3x3.Persp0" />, <see cref="P:SkiaSharp.Matrix3x3.Persp1" />,
-///     <see cref="P:SkiaSharp.Matrix3x3.Persp2" /> fields of the matrix.
+///     <see cref="Matrix3X3.Persp0" />, <see cref="Matrix3X3.Persp1" />,
+///     <see cref="Matrix3X3.Persp2" /> fields of the matrix.
 /// </remarks>
 public struct Matrix3X3 : IEquatable<Matrix3X3>
 {
@@ -196,10 +197,17 @@ public struct Matrix3X3 : IEquatable<Matrix3X3>
         values[7] = Persp1;
         values[8] = Persp2;
     }
+    
+    public VecD MapPoint(int p0, int p1)
+    {
+        return DrawingBackendApi.Current.MatrixImplementation.MapPoint(this, p0, p1);   
+    }
+    
+    public VecD MapPoint(VecI size) => MapPoint(size.X, size.Y);
 
     public static Matrix3X3 CreateIdentity()
     {
-        return new Matrix3X3() {ScaleX = 1f, ScaleY = 1f, Persp2 = 1f};
+        return new Matrix3X3() { ScaleX = 1f, ScaleY = 1f, Persp2 = 1f };
     }
 
     public static Matrix3X3 CreateTranslation(float x, float y)
@@ -344,6 +352,11 @@ public struct Matrix3X3 : IEquatable<Matrix3X3>
     {
         return DrawingBackendApi.Current.MatrixImplementation.Concat(in first, in second);
     }
+    
+    public Matrix3X3 PostConcat(Matrix3X3 globalMatrix)
+    {
+        return DrawingBackendApi.Current.MatrixImplementation.PostConcat(in this, in globalMatrix);
+    }
 
     private static void SetSinCos(ref Matrix3X3 matrix, float sin, float cos)
     {
@@ -386,6 +399,7 @@ public struct Matrix3X3 : IEquatable<Matrix3X3>
     {
         return (float)((a * (double)b) - (c * (double)d));
     }
+    
 
     private class Indices
     {

+ 23 - 1
src/PixiEditor.DrawingApi.Core/Surface/Canvas.cs

@@ -1,4 +1,5 @@
 using PixiEditor.DrawingApi.Core.Bridge;
+using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface.Vector;
 using SkiaSharp;
@@ -7,9 +8,10 @@ namespace PixiEditor.DrawingApi.Core.Surface
 {
     public class Canvas
     {
+        public void DrawPixel(VecI position, Paint drawingPaint) => DrawPixel(position.X, position.Y, 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, Paint paint) 
+        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);
@@ -95,10 +97,30 @@ namespace PixiEditor.DrawingApi.Core.Surface
         {
             DrawingBackendApi.Current.CanvasOperations.Clear();
         }
+        
+        public void Clear(Color color)
+        {
+            DrawingBackendApi.Current.CanvasOperations.Clear(color);
+        }
 
         public void DrawLine(VecI from, VecI to, Paint paint)
         {
             DrawingBackendApi.Current.CanvasOperations.DrawLine(from, to, paint);
         }
+
+        public void Flush()
+        {
+            DrawingBackendApi.Current.CanvasOperations.Flush();
+        }
+
+        public void SetMatrix(Matrix3X3 finalMatrix)
+        {
+            DrawingBackendApi.Current.CanvasOperations.SetMatrix(finalMatrix);
+        }
+
+        public void RestoreToCount(int count)
+        {
+            DrawingBackendApi.Current.CanvasOperations.RestoreToCount(count);
+        }
     }
 }

+ 1 - 1
src/PixiEditor.DrawingApi.Core/Surface/DrawingSurface.cs

@@ -17,7 +17,7 @@ namespace PixiEditor.DrawingApi.Core.Surface
 
         public Pixmap PeekPixels()
         {
-            
+            return DrawingBackendApi.Current.ImageOperations.PeekPixels(this);
         }
     }
 }

+ 6 - 0
src/PixiEditor.DrawingApi.Core/Surface/PaintImpl/Paint.cs

@@ -1,6 +1,7 @@
 using System;
 using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using SkiaSharp;
 
 namespace PixiEditor.DrawingApi.Core.Surface
 {
@@ -25,6 +26,11 @@ namespace PixiEditor.DrawingApi.Core.Surface
         public Paint() : base(DrawingBackendApi.Current.PaintImplementation.CreatePaint())
         {
         }
+        
+        public Paint Clone()
+        {
+            return DrawingBackendApi.Current.PaintImplementation.Clone(ObjectPointer);
+        }
 
         public override void Dispose()
         {

+ 22 - 0
src/PixiEditor.DrawingApi.Core/Surface/Pixmap.cs

@@ -0,0 +1,22 @@
+using System;
+using PixiEditor.DrawingApi.Core.Bridge;
+using SkiaSharp;
+
+namespace PixiEditor.DrawingApi.Core.Surface;
+
+public class Pixmap : NativeObject
+{
+    internal Pixmap(IntPtr objPtr) : base(objPtr)
+    {
+    }
+
+    public override void Dispose()
+    {
+        DrawingBackendApi.Current.PixmapImplementation.Dispose(ObjectPointer);
+    }
+
+    public IntPtr GetPixels()
+    {
+        return DrawingBackendApi.Current.PixmapImplementation.GetPixels(ObjectPointer);
+    }
+}

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

@@ -23,6 +23,7 @@ public struct Point : IEquatable<Point>
         X = pointPos.X;
         Y = pointPos.Y;
     }
+    
 
     /// <summary>Gets a value indicating whether this point is empty.</summary>
     /// <value />
@@ -288,6 +289,26 @@ public struct Point : IEquatable<Point>
     {
         return !left.Equals(right);
     }
+    
+    public static explicit operator Point(VecI vec)
+    {
+        return new Point(vec.X, vec.Y);
+    }
+    
+    public static explicit operator Point(VecD vec)
+    {
+        return new Point((float)vec.X, (float)vec.Y);
+    }
+    
+    public static explicit operator VecI(Point vec)
+    {
+        return new VecI((int)vec.X, (int)vec.Y);
+    }
+    
+    public static explicit operator VecD(Point vec)
+    {
+        return new VecD(vec.X, vec.Y);
+    }
 
     /// <summary>Calculates the hashcode for this point.</summary>
     /// <returns>Returns the hashcode for this point.</returns>

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

@@ -1,6 +1,7 @@
 using System;
 using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
+using SkiaSharp;
 
 namespace PixiEditor.DrawingApi.Core.Surface.Vector;
 
@@ -46,6 +47,7 @@ public class VectorPath : NativeObject
     public RectD TightBounds => DrawingBackendApi.Current.PathImplementation.GetTightBounds(this);
 
     public bool IsEmpty => VerbCount == 0;
+    public RectD Bounds => DrawingBackendApi.Current.PathImplementation.GetBounds(this);
 
     public VectorPath() : base(DrawingBackendApi.Current.PathImplementation.Create())
     {
@@ -63,4 +65,29 @@ public class VectorPath : NativeObject
     {
         DrawingBackendApi.Current.PathImplementation.Dispose(this);
     }
+
+    public void Reset()
+    {
+        DrawingBackendApi.Current.PathImplementation.Reset(this);
+    }
+
+    public void MoveTo(Point point)
+    {
+        DrawingBackendApi.Current.PathImplementation.MoveTo(this, point);
+    }
+
+    public void LineTo(Point point)
+    {
+        DrawingBackendApi.Current.PathImplementation.LineTo(this, point);
+    }
+
+    public void QuadTo(Point mid, Point point)
+    {
+        DrawingBackendApi.Current.PathImplementation.QuadTo(this, mid, point);
+    }
+
+    public void CubicTo(Point mid1, Point mid2, Point point)
+    {
+        DrawingBackendApi.Current.PathImplementation.CubicTo(this, mid1, mid2, point);
+    }
 }