فهرست منبع

Added animation previews

Krzysztof Krysiński 1 هفته پیش
والد
کامیت
8f3568b24d

+ 25 - 14
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -157,7 +157,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         workingSurface.Canvas.RestoreToCount(saved);
     }
 
-    /*public override RectD? GetPreviewBounds(int frame, string elementFor = "")
+    public override RectD? GetPreviewBounds(RenderContext context, string elementFor = "")
     {
         if (IsDisposed)
         {
@@ -166,11 +166,16 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
         if (elementFor == nameof(EmbeddedMask))
         {
-            return base.GetPreviewBounds(frame, elementFor);
+            return base.GetPreviewBounds(context, elementFor);
         }
 
         if (Guid.TryParse(elementFor, out Guid guid))
         {
+            if (guid == Id)
+            {
+                return new RectD(0, 0, layerImage.CommittedSize.X, layerImage.CommittedSize.Y);
+            }
+
             var keyFrame = keyFrames.FirstOrDefault(x => x.KeyFrameGuid == guid);
 
             if (keyFrame != null)
@@ -181,19 +186,13 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
                     return null;
                 }
 
-                RectI? bounds = (RectI?)GetApproxBounds(kf);
-                if (bounds.HasValue)
-                {
-                    return new RectD(bounds.Value.X, bounds.Value.Y,
-                        Math.Min(bounds.Value.Width, kf.CommittedSize.X),
-                        Math.Min(bounds.Value.Height, kf.CommittedSize.Y));
-                }
+                return new RectD(0, 0, kf.CommittedSize.X, kf.CommittedSize.Y);
             }
         }
 
         try
         {
-            var kf = GetLayerImageAtFrame(frame);
+            var kf = GetLayerImageAtFrame(context.FrameTime.Frame);
             if (kf == null)
             {
                 return null;
@@ -213,7 +212,22 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         {
             return null;
         }
-    }*/
+    }
+
+    protected override bool ShouldRenderPreview(string elementToRenderName)
+    {
+        if (IsDisposed)
+        {
+            return false;
+        }
+
+        if (elementToRenderName == nameof(EmbeddedMask))
+        {
+            return base.ShouldRenderPreview(elementToRenderName);
+        }
+
+        return true;
+    }
 
     public override void RenderPreview(DrawingSurface renderOnto, RenderContext context,
         string elementToRenderName)
@@ -231,7 +245,6 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
         var img = GetLayerImageAtFrame(context.FrameTime.Frame);
 
-        int cacheFrame = context.FrameTime.Frame;
         if (Guid.TryParse(elementToRenderName, out Guid guid))
         {
             var keyFrame = keyFrames.FirstOrDefault(x => x.KeyFrameGuid == guid);
@@ -239,12 +252,10 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
             if (keyFrame != null)
             {
                 img = GetLayerImageByKeyFrameGuid(keyFrame.KeyFrameGuid);
-                cacheFrame = keyFrame.StartFrame;
             }
             else if (guid == Id)
             {
                 img = GetLayerImageAtFrame(0);
-                cacheFrame = 0;
             }
         }
 

+ 5 - 4
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LayerNode.cs

@@ -226,6 +226,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
     protected abstract void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
         Paint paint);
 
+    /*
     private void RenderPreviews(RenderContext ctx)
     {
         var previewTexture = ctx.GetPreviewTexturesForNode(Id);
@@ -237,9 +238,9 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
         {
             RenderPreviewFor(ctx, request.Texture, request.ElementToRender);
         }
-    }
+    }*/
 
-    private void RenderPreviewFor(RenderContext ctx, Texture texture, string elementToRender)
+    /*private void RenderPreviewFor(RenderContext ctx, Texture texture, string elementToRender)
     {
         if (texture == null || texture.IsDisposed)
             return;
@@ -248,7 +249,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
 
         RenderContext previewCtx = ctx.Clone();
 
-        var approxBounds = GetApproxBounds(ctx.FrameTime);
+        var approxBounds = GetPreviewBounds(ctx, elementToRender);
 
         VecD size = approxBounds?.Size ?? ctx.DocumentSize;
 
@@ -283,7 +284,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
         RenderPreview(texture.DrawingSurface, previewCtx, elementToRender);
 
         texture.DrawingSurface.Canvas.RestoreToCount(saved);
-    }
+    }*/
 
     protected Texture TryInitWorkingSurface(VecI imageSize, ChunkResolution resolution, ColorSpace processingCs, int id)
     {

+ 1 - 1
src/PixiEditor/Models/DocumentPassthroughActions/RefreshPreview_PassthroughAction.cs

@@ -4,4 +4,4 @@ using PixiEditor.Models.Position;
 
 namespace PixiEditor.Models.DocumentPassthroughActions;
 
-internal record class RefreshPreview_PassthroughAction(Guid Id) : IAction, IChangeInfo;
+internal record class RefreshPreview_PassthroughAction(Guid Id, Guid? SubId = null) : IAction, IChangeInfo;

+ 2 - 1
src/PixiEditor/Models/Handlers/ICelHandler.cs

@@ -1,12 +1,13 @@
 using ChunkyImageLib;
 using Drawie.Backend.Core;
 using PixiEditor.Models.Rendering;
+using PixiEditor.ViewModels.Document;
 
 namespace PixiEditor.Models.Handlers;
 
 internal interface ICelHandler : IDisposable
 {
-    public Texture? PreviewTexture { get; }
+    TexturePreview? PreviewTexture { get; set; }
     public int StartFrameBindable { get; }
     public int DurationBindable { get; }
     public bool IsSelected { get; set; }

+ 26 - 4
src/PixiEditor/Models/Rendering/AffectedAreasGatherer.cs

@@ -52,6 +52,7 @@ internal class AffectedAreasGatherer
             AddWholeCanvasToEveryImagePreview(false);
             AddWholeCanvasToEveryMaskPreview();
             AddAllNodesToImagePreviews();
+            AddAllKeyFrames();
             return;
         }
 
@@ -211,18 +212,39 @@ internal class AffectedAreasGatherer
                     AddWholeCanvasToEveryMaskPreview();
                     break;
                 case RefreshPreview_PassthroughAction info:
-                    AddToImagePreviews(info.Id);
-                    AddToNodePreviews(info.Id);
+                    if (info.SubId == null)
+                    {
+                        AddToImagePreviews(info.Id);
+                        AddToNodePreviews(info.Id);
+                    }
+                    else
+                    {
+                        AddKeyFrame(info.SubId.Value);
+                    }
+
                     break;
             }
         }
     }
 
+    private void AddAllKeyFrames()
+    {
+        ChangedKeyFrames ??= new HashSet<Guid>();
+        tracker.Document.ForEveryReadonlyMember((member) =>
+        {
+            foreach (var keyFrame in member.KeyFrames)
+            {
+                ChangedKeyFrames.Add(keyFrame.KeyFrameGuid);
+            }
+
+            ChangedKeyFrames.Add(member.Id);
+        });
+    }
+
     private void AddKeyFrame(Guid infoKeyFrameId)
     {
         ChangedKeyFrames ??= new HashSet<Guid>();
-        if (!ChangedKeyFrames.Contains(infoKeyFrameId))
-            ChangedKeyFrames.Add(infoKeyFrameId);
+        ChangedKeyFrames.Add(infoKeyFrameId);
     }
 
     private void AddToNodePreviews(Guid nodeId)

+ 79 - 33
src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs

@@ -64,7 +64,7 @@ internal class MemberPreviewUpdater
 
         if (!ignoreAnimationPreviews)
         {
-            //RenderAnimationPreviews(members, keyFramesToUpdate);
+            RenderAnimationPreviews(members, keyFramesToUpdate, previewTextures);
         }
 
         RenderNodePreviews(nodesToUpdate, previewTextures);
@@ -156,7 +156,8 @@ internal class MemberPreviewUpdater
         }
     }
 
-    /*private void RenderAnimationPreviews(HashSet<Guid> memberGuids, HashSet<Guid> keyFramesGuids)
+    private void RenderAnimationPreviews(HashSet<Guid> memberGuids, HashSet<Guid> keyFramesGuids,
+        Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
     {
         foreach (var keyFrame in doc.AnimationHandler.KeyFrames)
         {
@@ -171,16 +172,16 @@ internal class MemberPreviewUpdater
                             continue;
                     }
 
-                    RenderFramePreview(childFrame);
+                    RenderFramePreview(childFrame, previewTextures);
                 }
 
-                if (!memberGuids.Contains(groupHandler.LayerGuid))
+                if (!keyFramesGuids.Contains(groupHandler.LayerGuid) && !memberGuids.Contains(groupHandler.LayerGuid))
                     continue;
 
-                RenderGroupPreview(groupHandler);
+                RenderGroupPreview(groupHandler, previewTextures);
             }
         }
-    }*/
+    }
 
     private bool IsInFrame(ICelHandler cel)
     {
@@ -188,54 +189,94 @@ internal class MemberPreviewUpdater
                cel.StartFrameBindable + cel.DurationBindable > doc.AnimationHandler.ActiveFrameBindable;
     }
 
-    /*private void RenderFramePreview(ICelHandler cel)
+    private void RenderFramePreview(ICelHandler cel, Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
     {
         if (internals.Tracker.Document.AnimationData.TryFindKeyFrame(cel.Id, out KeyFrame _))
         {
-            KeyFrameTime frameTime = doc.AnimationHandler.ActiveFrameTime;
-            if (cel.PreviewPainter == null)
+            if (cel.PreviewTexture == null)
+            {
+                cel.PreviewTexture = new TexturePreview(cel.LayerGuid, cel.Id, RequestCelRender);
+                return;
+            }
+
+            if (cel.PreviewTexture.Listeners.Count == 0)
             {
-                cel.PreviewPainter = new PreviewPainter(renderer, AnimationKeyFramePreviewRenderer, frameTime,
-                    doc.SizeBindable,
-                    internals.Tracker.Document.ProcessingColorSpace, cel.Id.ToString());
+                cel.PreviewTexture.Preview?.Dispose();
+                return;
             }
-            else
+
+            VecI textureSize = cel.PreviewTexture.GetMaxListenerSize();
+            if (textureSize.X <= 0 || textureSize.Y <= 0)
+                return;
+
+            Texture? CreateTextureForCel(bool createIfNull)
             {
-                cel.PreviewPainter.FrameTime = frameTime;
-                cel.PreviewPainter.DocumentSize = doc.SizeBindable;
-                cel.PreviewPainter.ProcessingColorSpace = internals.Tracker.Document.ProcessingColorSpace;
+                if (createIfNull)
+                {
+                    if (cel.PreviewTexture.Preview == null || cel.PreviewTexture.Preview.IsDisposed ||
+                        cel.PreviewTexture.Preview.Size != textureSize)
+                    {
+                        cel.PreviewTexture.Preview?.Dispose();
+                        cel.PreviewTexture.Preview = Texture.ForDisplay(textureSize);
+                    }
+                }
+
+                return cel.PreviewTexture.Preview;
             }
 
-            cel.PreviewPainter.Repaint();
+            if (!previewTextures.ContainsKey(cel.LayerGuid))
+                previewTextures[cel.LayerGuid] = new List<PreviewRenderRequest>();
+
+            previewTextures[cel.LayerGuid].Add(new PreviewRenderRequest(CreateTextureForCel,
+                cel.PreviewTexture.InvokeTextureUpdated, cel.Id.ToString()));
         }
-    }*/
+    }
 
-    /*private void RenderGroupPreview(ICelGroupHandler groupHandler)
+    private void RenderGroupPreview(ICelGroupHandler groupHandler,
+        Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
     {
         var group = internals.Tracker.Document.AnimationData.KeyFrames.FirstOrDefault(x => x.Id == groupHandler.Id);
         if (group != null)
         {
-            KeyFrameTime frameTime = doc.AnimationHandler.ActiveFrameTime;
-            ColorSpace processingColorSpace = internals.Tracker.Document.ProcessingColorSpace;
-            VecI documentSize = doc.SizeBindable;
+            if (groupHandler.PreviewTexture == null)
+            {
+                groupHandler.PreviewTexture = new TexturePreview(groupHandler.LayerGuid, groupHandler.LayerGuid, RequestCelRender);
+                return;
+            }
 
-            if (groupHandler.PreviewPainter == null)
+            if (groupHandler.PreviewTexture.Listeners.Count == 0)
             {
-                groupHandler.PreviewPainter =
-                    new PreviewPainter(renderer, AnimationKeyFramePreviewRenderer, frameTime, documentSize,
-                        processingColorSpace,
-                        groupHandler.Id.ToString());
+                groupHandler.PreviewTexture.Preview?.Dispose();
+                return;
             }
-            else
+
+            VecI textureSize = groupHandler.PreviewTexture.GetMaxListenerSize();
+            if (textureSize.X <= 0 || textureSize.Y <= 0)
+                return;
+
+            Texture? CreateTextureForGroup(bool createIfNull)
             {
-                groupHandler.PreviewPainter.FrameTime = frameTime;
-                groupHandler.PreviewPainter.DocumentSize = documentSize;
-                groupHandler.PreviewPainter.ProcessingColorSpace = processingColorSpace;
+                if (createIfNull)
+                {
+                    if (groupHandler.PreviewTexture.Preview == null ||
+                        groupHandler.PreviewTexture.Preview.IsDisposed ||
+                        groupHandler.PreviewTexture.Preview.Size != textureSize)
+                    {
+                        groupHandler.PreviewTexture.Preview?.Dispose();
+                        groupHandler.PreviewTexture.Preview = Texture.ForDisplay(textureSize);
+                    }
+                }
+
+                return groupHandler.PreviewTexture.Preview;
             }
 
-            groupHandler.PreviewPainter.Repaint();
+            if (!previewTextures.ContainsKey(groupHandler.LayerGuid))
+                previewTextures[groupHandler.LayerGuid] = new List<PreviewRenderRequest>();
+
+            previewTextures[groupHandler.LayerGuid].Add(new PreviewRenderRequest(CreateTextureForGroup,
+                groupHandler.PreviewTexture.InvokeTextureUpdated, groupHandler.Id.ToString()));
         }
-    }*/
+    }
 
     private void RenderMaskPreviews(HashSet<Guid> members,
         Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
@@ -392,4 +433,9 @@ internal class MemberPreviewUpdater
     {
         internals.ActionAccumulator.AddActions(new RefreshPreview_PassthroughAction(id));
     }
+
+    private void RequestCelRender(Guid nodeId, Guid? celId)
+    {
+        internals.ActionAccumulator.AddActions(new RefreshPreview_PassthroughAction(nodeId, celId));
+    }
 }

+ 2 - 6
src/PixiEditor/Models/Rendering/SceneRenderer.cs

@@ -1,13 +1,10 @@
-using System.Diagnostics;
-using Avalonia.Threading;
+using Avalonia.Threading;
 using ChunkyImageLib.DataHolders;
 using Drawie.Backend.Core;
-using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.Numerics;
 using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 using Drawie.Backend.Core.Surfaces;
-using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Numerics;
 using PixiEditor.ChangeableDocument.Changeables.Animations;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
@@ -15,7 +12,6 @@ using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Workspace;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Position;
-using PixiEditor.Views.Main.ViewportControls;
 
 namespace PixiEditor.Models.Rendering;
 
@@ -146,7 +142,7 @@ internal class SceneRenderer : IDisposable
         {
             finalSize = (VecI)(finalSize * resolution.Multiplier());
 
-            renderTexture = textureCache.RequestTexture(0, finalSize, Document.ProcessingColorSpace);
+            renderTexture = textureCache.RequestTexture(viewportId.GetHashCode(), finalSize, Document.ProcessingColorSpace);
             renderTarget = renderTexture.DrawingSurface;
             renderTarget.Canvas.Save();
             renderTexture.DrawingSurface.Canvas.Save();

+ 3 - 3
src/PixiEditor/Styles/Templates/KeyFrame.axaml

@@ -36,10 +36,10 @@
                                 </ImageBrush.Transform>
                             </ImageBrush>
                         </Border.Background>
-                        <visuals:TextureControl
-                            Texture="{Binding Item.PreviewTexture, RelativeSource={RelativeSource TemplatedParent}}"
+                        <visuals:PreviewTextureControl
+                            TexturePreview="{Binding Item.PreviewTexture, RelativeSource={RelativeSource TemplatedParent}}"
                             Width="60" Height="60" RenderOptions.BitmapInterpolationMode="None">
-                        </visuals:TextureControl>
+                        </visuals:PreviewTextureControl>
                     </Border>
                 </Grid>
             </ControlTemplate>

+ 2 - 2
src/PixiEditor/Styles/Templates/TimelineGroupHeader.axaml

@@ -25,8 +25,8 @@
                                     </ImageBrush.Transform>
                                 </ImageBrush>
                             </Border.Background>
-                            <visuals:TextureControl
-                                Texture="{Binding Item.PreviewTexture, RelativeSource={RelativeSource TemplatedParent}}"
+                            <visuals:PreviewTextureControl
+                                TexturePreview="{Binding Item.PreviewTexture, RelativeSource={RelativeSource TemplatedParent}}"
                                 Width="60" Height="60" RenderOptions.BitmapInterpolationMode="None"/>
                         </Border>
                         <TextBlock Margin="5 0 0 0" VerticalAlignment="Center" Text="{Binding Item.LayerName, RelativeSource={RelativeSource TemplatedParent}}" />

+ 3 - 4
src/PixiEditor/ViewModels/Document/CelViewModel.cs

@@ -15,9 +15,9 @@ internal abstract class CelViewModel : ObservableObject, ICelHandler
     private bool isVisibleBindable = true;
     private bool isSelected;
     private bool isCollapsed;
-    private Texture? previewTexture;
+    private TexturePreview? previewTexture;
 
-    public Texture? PreviewTexture
+    public TexturePreview? PreviewTexture
     {
         get => previewTexture;
         set => SetProperty(ref previewTexture, value);
@@ -148,7 +148,6 @@ internal abstract class CelViewModel : ObservableObject, ICelHandler
 
     public void Dispose()
     {
-        PreviewTexture?.Dispose();
-        PreviewTexture = null;
+        PreviewTexture?.Preview?.Dispose();
     }
 }

+ 12 - 3
src/PixiEditor/ViewModels/Document/TexturePreview.cs

@@ -10,6 +10,8 @@ public class TexturePreview : ObservableObject
 
     public Guid Id { get; }
 
+    public Guid? SubId { get; init; }
+
     public Texture Preview
     {
         get => preview;
@@ -25,18 +27,25 @@ public class TexturePreview : ObservableObject
 
     public event Action TextureUpdated;
 
-    private Action<Guid> requestRender;
+    private Action<Guid, Guid?> requestRender;
 
     public TexturePreview(Guid forId, Action<Guid> requestRender)
     {
         Id = forId;
+        this.requestRender = (id, _) => requestRender(id);
+    }
+
+    public TexturePreview(Guid forId, Guid subId, Action<Guid, Guid?> requestRender)
+    {
+        Id = forId;
+        SubId = subId;
         this.requestRender = requestRender;
     }
 
     public void Attach(object source, Func<VecI> getSize)
     {
-        Listeners.TryAdd(source, getSize);
-        requestRender(Id);
+        if(Listeners.TryAdd(source, getSize))
+            requestRender(Id, SubId);
     }
 
     public void Detach(object source)