Explorar o código

Improved transformations for paitning and vector toolset

Krzysztof Krysiński hai 3 semanas
pai
achega
7a66d1dd85

+ 2 - 2
src/ChunkyImageLib/ChunkyImage.cs

@@ -636,12 +636,12 @@ public class ChunkyImage : IReadOnlyChunkyImage, IDisposable, ICloneable, ICache
     /// 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(Matrix3X3 transformMatrix, Surface image, Paint? paint = null, bool copyImage = true)
+    public void EnqueueDrawImage(Matrix3X3 transformMatrix, Surface image, SamplingOptions samplingOptions, Paint? paint = null, bool copyImage = true)
     {
         lock (lockObject)
         {
             ThrowIfDisposed();
-            ImageOperation operation = new(transformMatrix, image, paint, copyImage);
+            ImageOperation operation = new(transformMatrix, image, samplingOptions, paint, copyImage);
             EnqueueOperation(operation);
         }
     }

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

@@ -1,6 +1,7 @@
 using ChunkyImageLib.DataHolders;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core.Numerics;
+using Drawie.Backend.Core.Surfaces;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Numerics;
 
@@ -12,6 +13,7 @@ internal class ImageOperation : IMirroredDrawOperation
     private ShapeCorners corners;
     private Surface toPaint;
     private bool imageWasCopied = false;
+    private SamplingOptions samplingOptions = SamplingOptions.Default;
     private readonly Paint? customPaint;
 
     public bool IgnoreEmptyChunks => false;
@@ -31,6 +33,7 @@ internal class ImageOperation : IMirroredDrawOperation
         transformMatrix = Matrix3X3.CreateIdentity();
         transformMatrix.TransX = pos.X;
         transformMatrix.TransY = pos.Y;
+        this.samplingOptions = samplingOptions;
 
         // copying is needed for thread safety
         if (copyImage)
@@ -56,7 +59,7 @@ internal class ImageOperation : IMirroredDrawOperation
         imageWasCopied = copyImage;
     }
 
-    public ImageOperation(Matrix3X3 transformMatrix, Surface image, Paint? paint = null, bool copyImage = true)
+    public ImageOperation(Matrix3X3 transformMatrix, Surface image, SamplingOptions samplingOptions, Paint? paint = null, bool copyImage = true)
     {
         if (paint is not null)
             customPaint = paint.Clone();
@@ -69,6 +72,7 @@ internal class ImageOperation : IMirroredDrawOperation
             BottomRight = transformMatrix.MapPoint(image.Size),
         };
         this.transformMatrix = transformMatrix;
+        this.samplingOptions = samplingOptions;
 
         // copying is needed for thread safety
         if (copyImage)
@@ -100,12 +104,12 @@ internal class ImageOperation : IMirroredDrawOperation
             ShapeCorners chunkCorners = new ShapeCorners(new RectD(VecD.Zero, targetChunk.PixelSize));
             RectD rect = chunkCorners.WithMatrix(finalMatrix.Invert()).AABBBounds;
 
-            targetChunk.Surface.DrawingSurface.Canvas.DrawImage(snapshot, rect, rect, customPaint);
+            targetChunk.Surface.DrawingSurface.Canvas.DrawImage(snapshot, rect, rect, customPaint, samplingOptions);
         }
         else
         {
             // Slower, but works with perspective transformation
-            targetChunk.Surface.DrawingSurface.Canvas.DrawImage(snapshot, 0, 0, customPaint);
+            targetChunk.Surface.DrawingSurface.Canvas.DrawImage(snapshot, 0, 0, samplingOptions, customPaint);
         }
 
         targetChunk.Surface.DrawingSurface.Canvas.Restore();

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit b62a0dca915a92c020e9e9145fb287fa69da4e64
+Subproject commit 081ed88104da2c20e7356cdf34400c1e35c71c63

+ 4 - 1
src/PixiEditor.ChangeableDocument/Changes/Drawing/TransformSelected_UpdateableChange.cs

@@ -28,6 +28,7 @@ internal class TransformSelected_UpdateableChange : InterruptableUpdateableChang
     private VecD tightBoundsSize;
     private RectD cornersToSelectionOffset;
     private VecD originalCornersSize;
+    private bool bilinearFiltering;
 
     private bool isTransformingSelection;
     private bool hasEnqueudImages = false;
@@ -42,11 +43,13 @@ internal class TransformSelected_UpdateableChange : InterruptableUpdateableChang
     public TransformSelected_UpdateableChange(
         ShapeCorners masterCorners,
         bool keepOriginal,
+        bool bilinearFiltering,
         Dictionary<Guid, ShapeCorners> memberCorners,
         bool transformMask,
         int frame)
     {
         memberData = new();
+        this.bilinearFiltering = bilinearFiltering;
         foreach (var corners in memberCorners)
         {
             memberData.Add(new MemberTransformationData(corners.Key) { MemberCorners = corners.Value });
@@ -417,7 +420,7 @@ internal class TransformSelected_UpdateableChange : InterruptableUpdateableChang
             finalPaint = LockedAlphaPaint;
         }
 
-        memberImage.EnqueueDrawImage(data.LocalMatrix, data.Image, finalPaint, false);
+        memberImage.EnqueueDrawImage(data.LocalMatrix, data.Image, bilinearFiltering ? SamplingOptions.Bilinear : SamplingOptions.Default, finalPaint, false);
         hasEnqueudImages = true;
 
         var affectedArea = memberImage.FindAffectedArea();

+ 18 - 3
src/PixiEditor/Data/Configs/ToolSetsConfig.json

@@ -5,7 +5,12 @@
     "Tools": [
       "MoveViewport",
       "RotateViewport",
-      "Move",
+      {
+        "ToolName": "Move",
+        "Settings": {
+          "BilinearTransform": false
+        }
+      },
       {
         "ToolName": "Pen",
         "Settings": {
@@ -52,7 +57,12 @@
     "Tools": [
       "MoveViewport",
       "RotateViewport",
-      "Move",
+      {
+        "ToolName": "Move",
+        "Settings": {
+          "BilinearTransform": true
+        }
+      },
       {
         "ToolName": "Pen",
         "Settings": {
@@ -127,7 +137,12 @@
     "Tools": [
       "MoveViewport",
       "RotateViewport",
-      "Move",
+      {
+        "ToolName": "Move",
+        "Settings": {
+          "BilinearTransform": true
+        }
+      },
       "VectorPath",
       "VectorLine",
       "VectorEllipse",

+ 2 - 2
src/PixiEditor/Models/DocumentModels/UpdateableChangeExecutors/TransformSelectedExecutor.cs

@@ -341,14 +341,14 @@ internal class TransformSelectedExecutor : UpdateableChangeExecutor, ITransforma
         if (!movedOnce)
         {
             internals!.ActionAccumulator.AddActions(
-                new TransformSelected_Action(lastCorners, tool.KeepOriginalImage, memberCorners, false,
+                new TransformSelected_Action(lastCorners, tool.KeepOriginalImage, tool.BilinearTransform, memberCorners, false,
                     document.AnimationHandler.ActiveFrameBindable));
 
             movedOnce = true;
         }
 
         internals!.ActionAccumulator.AddActions(
-            new TransformSelected_Action(corners, tool!.KeepOriginalImage, memberCorners, false,
+            new TransformSelected_Action(corners, tool!.KeepOriginalImage, tool.BilinearTransform, memberCorners, false,
                 document!.AnimationHandler.ActiveFrameBindable));
     }
 

+ 1 - 0
src/PixiEditor/Models/Handlers/Tools/IMoveToolHandler.cs

@@ -7,4 +7,5 @@ internal interface IMoveToolHandler : IToolHandler
     public bool KeepOriginalImage { get; }
     public bool TransformingSelectedArea { get; set; }
     public bool DuplicateOnMove { get; set; }
+    public bool BilinearTransform { get; set; }
 }

+ 7 - 0
src/PixiEditor/ViewModels/Tools/Tools/MoveToolViewModel.cs

@@ -49,6 +49,13 @@ internal class MoveToolViewModel : ToolViewModel, IMoveToolHandler
         set => SetValue(value);
     }
 
+    [Settings.Bool("_bilinear_transform", false, ExposedByDefault = false)]
+    public bool BilinearTransform
+    {
+        get => GetValue<bool>();
+        set => SetValue(value);
+    }
+
     public override BrushShape FinalBrushShape => BrushShape.Hidden;
     public override Type[]? SupportedLayerTypes { get; } = null;
     public override Type LayerTypeToCreateOnEmptyUse { get; } = null;