Browse Source

Rotate layers wip

flabbet 2 years ago
parent
commit
52fdc365c1

+ 118 - 19
src/PixiEditor.ChangeableDocument/Changes/Root/RotateImage_Change.cs

@@ -8,14 +8,41 @@ using BlendMode = PixiEditor.ChangeableDocument.Enums.BlendMode;
 
 
 namespace PixiEditor.ChangeableDocument.Changes.Root;
 namespace PixiEditor.ChangeableDocument.Changes.Root;
 
 
-internal sealed class RotateImage_Change : ResizeBasedChangeBase
+internal sealed class RotateImage_Change : Change
 {
 {
     private readonly RotationAngle rotation;
     private readonly RotationAngle rotation;
+    private List<Guid> membersToRotate;
+    
+    private VecI originalSize;
+    private int originalHorAxisY;
+    private int originalVerAxisX;
+    private Dictionary<Guid, CommittedChunkStorage> deletedChunks = new();
+    private Dictionary<Guid, CommittedChunkStorage> deletedMaskChunks = new();
 
 
     [GenerateMakeChangeAction]
     [GenerateMakeChangeAction]
-    public RotateImage_Change(RotationAngle rotation)
+    public RotateImage_Change(RotationAngle rotation, List<Guid>? membersToRotate)
     {
     {
         this.rotation = rotation;
         this.rotation = rotation;
+        membersToRotate ??= new List<Guid>();
+        this.membersToRotate = membersToRotate;
+    }
+    
+    public override bool InitializeAndValidate(Document target)
+    {
+        if (membersToRotate.Count > 0)
+        {
+            membersToRotate = target.ExtractLayers(membersToRotate);
+            
+            foreach (var layer in membersToRotate)
+            {
+                if (!target.HasMember(layer)) return false;
+            }  
+        }
+        
+        originalSize = target.Size;
+        originalHorAxisY = target.HorizontalSymmetryAxisY;
+        originalVerAxisX = target.VerticalSymmetryAxisX;
+        return true;
     }
     }
 
 
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
     public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply, out bool ignoreInUndo)
@@ -26,21 +53,41 @@ internal sealed class RotateImage_Change : ResizeBasedChangeBase
         return changes;
         return changes;
     }
     }
 
 
-    protected override void Resize(ChunkyImage img, Guid memberGuid, VecI size, VecI offset, Dictionary<Guid, CommittedChunkStorage> deletedChunksDict)
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
     {
     {
+        
+    }
+
+    private void Resize(ChunkyImage img, Guid memberGuid, Dictionary<Guid, CommittedChunkStorage> deletedChunksDict)
+    {
+        RectI bounds = new RectI(VecI.Zero, img.LatestSize);
+        if (membersToRotate.Count > 0)
+        {
+            var preciseBounds = img.FindPreciseCommittedBounds();
+            if (preciseBounds.HasValue)
+            {
+                bounds = preciseBounds.Value;
+            }
+        }
+        
+        int newWidth = rotation == RotationAngle.D180 ? bounds.Size.X : bounds.Size.Y;
+        int newHeight = rotation == RotationAngle.D180 ? bounds.Size.Y : bounds.Size.X;
+        
+        VecI size = new VecI(newWidth, newHeight)''
+        
         using Paint paint = new()
         using Paint paint = new()
         {
         {
             BlendMode = DrawingApi.Core.Surface.BlendMode.Src
             BlendMode = DrawingApi.Core.Surface.BlendMode.Src
         };
         };
         
         
-        using Surface originalSurface = new(_originalSize);
+        using Surface originalSurface = new(img.LatestSize);
         img.DrawMostUpToDateRegionOn(
         img.DrawMostUpToDateRegionOn(
-            new RectI(VecI.Zero, _originalSize), 
+            new RectI(VecI.Zero, img.LatestSize), 
             ChunkResolution.Full,
             ChunkResolution.Full,
             originalSurface.DrawingSurface,
             originalSurface.DrawingSurface,
             VecI.Zero);
             VecI.Zero);
 
 
-        using Surface flipped = new Surface(size);
+        using Surface flipped = new Surface(img.LatestSize);
 
 
         float translationX = size.X;
         float translationX = size.X;
         float translationY = size.Y;
         float translationY = size.Y;
@@ -64,21 +111,59 @@ internal sealed class RotateImage_Change : ResizeBasedChangeBase
         img.EnqueueDrawImage(VecI.Zero, flipped);
         img.EnqueueDrawImage(VecI.Zero, flipped);
 
 
         deletedChunksDict.Add(memberGuid, new CommittedChunkStorage(img, img.FindAffectedChunks()));
         deletedChunksDict.Add(memberGuid, new CommittedChunkStorage(img, img.FindAffectedChunks()));
-        img.CommitChanges();
     }
     }
 
 
-    private float RotationAngleToRadians(RotationAngle rotationAngle)
+    private OneOf<None, IChangeInfo, List<IChangeInfo>> Rotate(Document target)
     {
     {
-        return rotationAngle switch
+        if (membersToRotate.Count == 0)
         {
         {
-            RotationAngle.D90 => 90f * Matrix3X3.DegreesToRadians,
-            RotationAngle.D180 => 180f * Matrix3X3.DegreesToRadians,
-            RotationAngle.D270 => 270f * Matrix3X3.DegreesToRadians,
-            _ => throw new ArgumentOutOfRangeException(nameof(rotationAngle), rotationAngle, null)
-        };
+            return RotateWholeImage(target);
+        }
+
+        return RotateMembers(target, membersToRotate);
     }
     }
-    
-    private OneOf<None, IChangeInfo, List<IChangeInfo>> Rotate(Document target)
+
+    private OneOf<None, IChangeInfo, List<IChangeInfo>> RotateMembers(Document target, List<Guid> guids)
+    {
+        List<IChangeInfo> changes = new List<IChangeInfo>();
+
+        target.ForEveryMember((member) =>
+        {
+            if (guids.Contains(member.GuidValue))
+            {
+                int newWidth;
+                int newHeight;
+
+                if (member is Layer layer)
+                {
+                    Resize(layer.LayerImage, layer.GuidValue,
+                            deletedChunks);
+                    changes.Add(
+                            new LayerImageChunks_ChangeInfo(member.GuidValue, layer.LayerImage.FindAffectedChunks()));
+                    layer.LayerImage.CommitChanges();
+                }
+
+                if (member.Mask is null)
+                    return;
+
+                var maskBounds = member.Mask.FindPreciseCommittedBounds();
+                if (maskBounds.HasValue)
+                {
+                    newWidth = rotation == RotationAngle.D180 ? maskBounds.Value.Size.X : maskBounds.Value.Size.Y;
+                    newHeight = rotation == RotationAngle.D180 ? maskBounds.Value.Size.Y : maskBounds.Value.Size.X;
+
+                    Resize(member.Mask, member.GuidValue, new VecI(newWidth, newHeight), VecI.Zero, deletedMaskChunks);
+                    changes.Add(
+                        new LayerImageChunks_ChangeInfo(member.GuidValue, member.Mask.FindAffectedChunks()));
+                    member.Mask.CommitChanges();
+                }
+            }
+        });
+
+        return changes;
+    }
+
+    private OneOf<None, IChangeInfo, List<IChangeInfo>> RotateWholeImage(Document target)
     {
     {
         int newWidth = rotation == RotationAngle.D180 ? target.Size.X : target.Size.Y;
         int newWidth = rotation == RotationAngle.D180 ? target.Size.X : target.Size.Y;
         int newHeight = rotation == RotationAngle.D180 ? target.Size.Y : target.Size.X;
         int newHeight = rotation == RotationAngle.D180 ? target.Size.Y : target.Size.X;
@@ -87,23 +172,37 @@ internal sealed class RotateImage_Change : ResizeBasedChangeBase
 
 
         float normalizedSymmX = _originalVerAxisX / Math.Max(target.Size.X, 0.1f);
         float normalizedSymmX = _originalVerAxisX / Math.Max(target.Size.X, 0.1f);
         float normalizedSymmY = _originalHorAxisY / Math.Max(target.Size.Y, 0.1f);
         float normalizedSymmY = _originalHorAxisY / Math.Max(target.Size.Y, 0.1f);
-        
+
         target.Size = newSize;
         target.Size = newSize;
         target.VerticalSymmetryAxisX = (int)(newSize.X * normalizedSymmX);
         target.VerticalSymmetryAxisX = (int)(newSize.X * normalizedSymmX);
         target.HorizontalSymmetryAxisY = (int)(newSize.Y * normalizedSymmY);
         target.HorizontalSymmetryAxisY = (int)(newSize.Y * normalizedSymmY);
-        
+
         target.ForEveryMember((member) =>
         target.ForEveryMember((member) =>
         {
         {
             if (member is Layer layer)
             if (member is Layer layer)
             {
             {
                 Resize(layer.LayerImage, layer.GuidValue, newSize, VecI.Zero, deletedChunks);
                 Resize(layer.LayerImage, layer.GuidValue, newSize, VecI.Zero, deletedChunks);
+                layer.LayerImage.CommitChanges();
             }
             }
+
             if (member.Mask is null)
             if (member.Mask is null)
                 return;
                 return;
 
 
             Resize(member.Mask, member.GuidValue, newSize, VecI.Zero, deletedMaskChunks);
             Resize(member.Mask, member.GuidValue, newSize, VecI.Zero, deletedMaskChunks);
+            member.Mask.CommitChanges();
         });
         });
-        
+
         return new Size_ChangeInfo(newSize, target.VerticalSymmetryAxisX, target.HorizontalSymmetryAxisY);
         return new Size_ChangeInfo(newSize, target.VerticalSymmetryAxisX, target.HorizontalSymmetryAxisY);
     }
     }
+    
+    private float RotationAngleToRadians(RotationAngle rotationAngle)
+    {
+        return rotationAngle switch
+        {
+            RotationAngle.D90 => 90f * Matrix3X3.DegreesToRadians,
+            RotationAngle.D180 => 180f * Matrix3X3.DegreesToRadians,
+            RotationAngle.D270 => 270f * Matrix3X3.DegreesToRadians,
+            _ => throw new ArgumentOutOfRangeException(nameof(rotationAngle), rotationAngle, null)
+        };
+    }
 }
 }

+ 2 - 2
src/PixiEditor/Models/DocumentModels/Public/DocumentOperationsModule.cs

@@ -300,12 +300,12 @@ internal class DocumentOperationsModule
         Internals.ActionAccumulator.AddFinishedActions(new FlipImage_Action(flipType, membersToFlip));
         Internals.ActionAccumulator.AddFinishedActions(new FlipImage_Action(flipType, membersToFlip));
     }
     }
 
 
-    public void RotateImage(RotationAngle rotation)
+    public void RotateImage(RotationAngle rotation, List<Guid> membersToRotate)
     {
     {
         if (Internals.ChangeController.IsChangeActive)
         if (Internals.ChangeController.IsChangeActive)
             return;
             return;
         
         
-        Internals.ActionAccumulator.AddFinishedActions(new RotateImage_Action(rotation));
+        Internals.ActionAccumulator.AddFinishedActions(new RotateImage_Action(rotation, membersToRotate));
     }
     }
 
 
     public void CenterContent(IReadOnlyList<Guid> structureMembers)
     public void CenterContent(IReadOnlyList<Guid> structureMembers)

+ 6 - 6
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentManagerViewModel.cs

@@ -97,28 +97,28 @@ internal class DocumentManagerViewModel : SubViewModel<ViewModelMain>
     [Command.Basic("PixiEditor.Document.Rotate90Deg", "Rotate Image 90 deg", "Rotate Image 90 deg", CanExecute = "PixiEditor.HasDocument")]
     [Command.Basic("PixiEditor.Document.Rotate90Deg", "Rotate Image 90 deg", "Rotate Image 90 deg", CanExecute = "PixiEditor.HasDocument")]
     public void Rotate90Deg()
     public void Rotate90Deg()
     {
     {
-        if (ActiveDocument?.SelectedStructureMember == null)
+        if (ActiveDocument == null)
             return;
             return;
         
         
-        ActiveDocument?.Operations.RotateImage(RotationAngle.D90);
+        ActiveDocument?.Operations.RotateImage(RotationAngle.D90, ActiveDocument.GetSelectedMembers());
     }
     }
     
     
     [Command.Basic("PixiEditor.Document.Rotate180Deg", "Rotate Image 180 deg", "Rotate Image 180 deg", CanExecute = "PixiEditor.HasDocument")]
     [Command.Basic("PixiEditor.Document.Rotate180Deg", "Rotate Image 180 deg", "Rotate Image 180 deg", CanExecute = "PixiEditor.HasDocument")]
     public void Rotate180Deg()
     public void Rotate180Deg()
     {
     {
-        if (ActiveDocument?.SelectedStructureMember == null)
+        if (ActiveDocument == null)
             return;
             return;
         
         
-        ActiveDocument?.Operations.RotateImage(RotationAngle.D180);
+        ActiveDocument?.Operations.RotateImage(RotationAngle.D180, ActiveDocument.GetSelectedMembers());
     }
     }
     
     
     [Command.Basic("PixiEditor.Document.Rotate270Deg", "Rotate Image 270 deg", "Rotate Image 270 deg", CanExecute = "PixiEditor.HasDocument")]
     [Command.Basic("PixiEditor.Document.Rotate270Deg", "Rotate Image 270 deg", "Rotate Image 270 deg", CanExecute = "PixiEditor.HasDocument")]
     public void Rotate270Deg()
     public void Rotate270Deg()
     {
     {
-        if (ActiveDocument?.SelectedStructureMember == null)
+        if (ActiveDocument == null)
             return;
             return;
         
         
-        ActiveDocument?.Operations.RotateImage(RotationAngle.D270);
+        ActiveDocument?.Operations.RotateImage(RotationAngle.D270, ActiveDocument.GetSelectedMembers());
     }
     }