Sfoglia il codice sorgente

Fixed preview not rendering

Krzysztof Krysiński 2 settimane fa
parent
commit
ae9ab31b2a

+ 4 - 18
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -22,7 +22,6 @@ internal class ActionAccumulator
     private IDocument document;
     private DocumentInternalParts internals;
 
-    private CanvasUpdater canvasUpdater;
     private MemberPreviewUpdater previewUpdater;
 
     private bool isChangeBlockActive = false;
@@ -32,7 +31,6 @@ internal class ActionAccumulator
         this.document = doc;
         this.internals = internals;
 
-        canvasUpdater = new(doc, internals);
         previewUpdater = new(doc, internals);
     }
 
@@ -134,20 +132,15 @@ internal class ActionAccumulator
                 if (undoBoundaryPassed)
                     internals.Updater.AfterUndoBoundaryPassed();
 
-
                 var affectedAreas = new AffectedAreasGatherer(document.AnimationHandler.ActiveFrameTime,
                     internals.Tracker,
                     optimizedChanges, refreshPreviewsRequest);
 
-                if (!allPassthrough)
-                {
-                    /*await canvasUpdater.UpdateGatheredChunks(affectedAreas,
-                        undoBoundaryPassed || viewportRefreshRequest);*/
-                }
-
-                await document.SceneRenderer.RenderAsync(internals.State.Viewports, affectedAreas.MainImageArea);
-
                 bool previewsDisabled = PixiEditorSettings.Performance.DisablePreviews.Value;
+                bool updateDelayed = undoBoundaryPassed || viewportRefreshRequest || changeFrameRequest ||
+                                     document.SizeBindable.LongestAxis <= LiveUpdatePerformanceThreshold;
+
+                await document.SceneRenderer.RenderAsync(internals.State.Viewports, affectedAreas.MainImageArea, !previewsDisabled && updateDelayed);
 
                 if (!previewsDisabled)
                 {
@@ -162,13 +155,6 @@ internal class ActionAccumulator
                             undoBoundaryPassed || refreshPreviewsRequest);
                     }
                 }
-
-                // force refresh viewports for better responsiveness
-                foreach (var (_, value) in internals.State.Viewports)
-                {
-                    if (!value.Delayed)
-                        value.InvalidateVisual();
-                }
             }
         }
         catch (Exception e)

+ 0 - 211
src/PixiEditor/Models/Rendering/CanvasUpdater.cs

@@ -1,211 +0,0 @@
-using Avalonia.Threading;
-using ChunkyImageLib.DataHolders;
-using ChunkyImageLib.Operations;
-using PixiEditor.ChangeableDocument.Changeables.Animations;
-using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
-using Drawie.Backend.Core;
-using Drawie.Backend.Core.ColorsImpl;
-using Drawie.Backend.Core.Surfaces;
-using Drawie.Backend.Core.Surfaces.PaintImpl;
-using PixiEditor.Models.DocumentModels;
-using PixiEditor.Models.Handlers;
-using Drawie.Numerics;
-
-namespace PixiEditor.Models.Rendering;
-#nullable enable
-internal class CanvasUpdater
-{
-    private readonly IDocument doc;
-    private readonly DocumentInternalParts internals;
-
-    private Dictionary<int, Texture> renderedFramesCache = new();
-    private int lastRenderedFrameNumber = -1;
-    private int lastOnionKeyFrames = -1;
-    private double lastOnionOpacity = -1;
-
-    /// <summary>
-    /// Affected chunks that have not been rerendered yet.
-    /// </summary>
-    private readonly Dictionary<ChunkResolution, HashSet<VecI>> affectedAndNonRerenderedChunks = new()
-    {
-        [ChunkResolution.Full] = new(),
-        [ChunkResolution.Half] = new(),
-        [ChunkResolution.Quarter] = new(),
-        [ChunkResolution.Eighth] = new()
-    };
-
-    /// <summary>
-    /// Affected chunks that have not been rerendered yet.
-    /// Doesn't include chunks that were affected after the last time rerenderDelayed was true.
-    /// </summary>
-    private readonly Dictionary<ChunkResolution, HashSet<VecI>> nonRerenderedChunksAffectedBeforeLastRerenderDelayed =
-        new()
-        {
-            [ChunkResolution.Full] = new(),
-            [ChunkResolution.Half] = new(),
-            [ChunkResolution.Quarter] = new(),
-            [ChunkResolution.Eighth] = new()
-        };
-
-
-    public CanvasUpdater(IDocument doc, DocumentInternalParts internals)
-    {
-        this.doc = doc;
-        this.internals = internals;
-    }
-
-    /// <summary>
-    /// Don't call this outside ActionAccumulator
-    /// </summary>
-    public async Task UpdateGatheredChunks
-        (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
-    {
-        await Dispatcher.UIThread.InvokeAsync(() => Render(chunkGatherer, rerenderDelayed), DispatcherPriority.Background);
-    }
-
-    /// <summary>
-    /// Don't call this outside ActionAccumulator
-    /// </summary>
-    public void UpdateGatheredChunksSync
-        (AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
-    {
-        Render(chunkGatherer, rerenderDelayed);
-    }
-
-    private Dictionary<ChunkResolution, HashSet<VecI>> FindChunksVisibleOnViewports(bool onDelayed, bool all)
-    {
-        Dictionary<ChunkResolution, HashSet<VecI>> chunks = new()
-        {
-            [ChunkResolution.Full] = new(),
-            [ChunkResolution.Half] = new(),
-            [ChunkResolution.Quarter] = new(),
-            [ChunkResolution.Eighth] = new()
-        };
-        foreach (var (_, viewport) in internals.State.Viewports)
-        {
-            if (onDelayed != viewport.Delayed && !all)
-                continue;
-
-            var viewportChunks = OperationHelper.FindChunksTouchingRectangle(
-                viewport.Center,
-                viewport.Dimensions,
-                -viewport.Angle,
-                ChunkResolution.Full.PixelSize());
-            chunks[viewport.Resolution].UnionWith(viewportChunks);
-        }
-
-        return chunks;
-    }
-
-    private Dictionary<ChunkResolution, HashSet<VecI>> FindGlobalChunksToRerender(AffectedAreasGatherer areasGatherer,
-        bool renderDelayed)
-    {
-        // find all affected non rerendered chunks
-        var chunksToRerender = new Dictionary<ChunkResolution, HashSet<VecI>>();
-        foreach (var (res, stored) in affectedAndNonRerenderedChunks)
-        {
-            chunksToRerender[res] = new HashSet<VecI>(stored);
-            chunksToRerender[res].UnionWith(areasGatherer.MainImageArea.Chunks);
-        }
-
-        // find all chunks that would need to be rerendered if affected
-        var chunksToMaybeRerender = FindChunksVisibleOnViewports(false, renderDelayed);
-        if (!renderDelayed)
-        {
-            var chunksOnDelayedViewports = FindChunksVisibleOnViewports(true, false);
-            foreach (var (res, stored) in nonRerenderedChunksAffectedBeforeLastRerenderDelayed)
-            {
-                chunksOnDelayedViewports[res].IntersectWith(stored);
-                chunksToMaybeRerender[res].UnionWith(chunksOnDelayedViewports[res]);
-            }
-        }
-
-        // find affected chunks that need to be rerendered right now
-        foreach (var (res, toRerender) in chunksToRerender)
-        {
-            toRerender.IntersectWith(chunksToMaybeRerender[res]);
-        }
-
-        return chunksToRerender;
-    }
-
-    private void UpdateAffectedNonRerenderedChunks(Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender,
-        AffectedArea chunkGathererAffectedArea)
-    {
-        if (chunkGathererAffectedArea.Chunks.Count > 0)
-        {
-            foreach (var (res, chunks) in chunksToRerender)
-            {
-                affectedAndNonRerenderedChunks[res].UnionWith(chunkGathererAffectedArea.Chunks);
-            }
-        }
-
-        foreach (var (res, chunks) in chunksToRerender)
-        {
-            affectedAndNonRerenderedChunks[res].ExceptWith(chunks);
-            nonRerenderedChunksAffectedBeforeLastRerenderDelayed[res].ExceptWith(chunks);
-        }
-    }
-
-    private void Render(AffectedAreasGatherer chunkGatherer, bool rerenderDelayed)
-    {
-        Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender =
-            FindGlobalChunksToRerender(chunkGatherer, rerenderDelayed);
-
-        ChunkResolution onionSkinResolution = chunksToRerender.Min(x => x.Key);
-
-        bool updatingStoredChunks = false;
-        foreach (var (res, stored) in affectedAndNonRerenderedChunks)
-        {
-            HashSet<VecI> storedCopy = new HashSet<VecI>(stored);
-            storedCopy.IntersectWith(chunksToRerender[res]);
-            if (storedCopy.Count > 0)
-            {
-                updatingStoredChunks = true;
-                break;
-            }
-        }
-
-        UpdateAffectedNonRerenderedChunks(chunksToRerender, chunkGatherer.MainImageArea);
-
-        bool anythingToUpdate = false;
-        foreach (var (_, chunks) in chunksToRerender)
-        {
-            anythingToUpdate |= chunks.Count > 0;
-        }
-
-        if (!anythingToUpdate)
-            return;
-
-        UpdateMainImage(chunksToRerender, updatingStoredChunks ? null : chunkGatherer.MainImageArea.GlobalArea.Value);
-    }
-
-    private void UpdateMainImage(Dictionary<ChunkResolution, HashSet<VecI>> chunksToRerender,
-        RectI? globalClippingRectangle)
-    {
-        if (chunksToRerender.Count == 0)
-            return;
-
-        foreach (var (resolution, chunks) in chunksToRerender)
-        {
-            int chunkSize = resolution.PixelSize();
-            RectI? globalScaledClippingRectangle = null;
-            if (globalClippingRectangle is not null)
-                globalScaledClippingRectangle =
-                    (RectI?)((RectI)globalClippingRectangle).Scale(resolution.Multiplier()).RoundOutwards();
-
-            foreach (var chunkPos in chunks)
-            {
-                RenderChunk(chunkPos, resolution);
-                RectI chunkRect = new(chunkPos * chunkSize, new(chunkSize, chunkSize));
-                if (globalScaledClippingRectangle is RectI rect)
-                    chunkRect = chunkRect.Intersect(rect);
-            }
-        }
-    }
-
-    private void RenderChunk(VecI chunkPos, ChunkResolution resolution)
-    {
-        doc.Renderer.UpdateChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameTime);
-    }
-}

+ 10 - 3
src/PixiEditor/Models/Rendering/SceneRenderer.cs

@@ -43,12 +43,18 @@ internal class SceneRenderer : IDisposable
         this.previewRenderer = previewRenderer;
     }
 
-    public async Task RenderAsync(Dictionary<Guid, ViewportInfo> stateViewports, AffectedArea affectedArea)
+    public async Task RenderAsync(Dictionary<Guid, ViewportInfo> stateViewports, AffectedArea affectedArea,
+        bool updateDelayed)
     {
         await Dispatcher.UIThread.InvokeAsync(() =>
         {
             foreach (var viewport in stateViewports)
             {
+                if (viewport.Value.Delayed && !updateDelayed)
+                {
+                    continue;
+                }
+
                 if (viewport.Value.RealDimensions.ShortestAxis <= 0) continue;
 
                 var rendered = RenderScene(
@@ -68,6 +74,7 @@ internal class SceneRenderer : IDisposable
                 }
 
                 DocumentViewModel.SceneTextures[viewport.Key] = rendered;
+                viewport.Value.InvalidateVisual();
             }
         }, DispatcherPriority.Background);
     }
@@ -363,7 +370,6 @@ internal class SceneRenderer : IDisposable
     }
 }
 
-
 struct RenderState
 {
     public ChunkResolution ChunkResolution { get; set; }
@@ -373,6 +379,7 @@ struct RenderState
 
     public bool Equals(RenderState other)
     {
-        return ChunkResolution.Equals(other.ChunkResolution) && HighResRendering == other.HighResRendering && TargetOutput == other.TargetOutput && GraphCacheHash == other.GraphCacheHash;
+        return ChunkResolution.Equals(other.ChunkResolution) && HighResRendering == other.HighResRendering &&
+               TargetOutput == other.TargetOutput && GraphCacheHash == other.GraphCacheHash;
     }
 }

+ 10 - 15
src/PixiEditor/Views/Main/ViewportControls/FixedViewport.axaml

@@ -8,24 +8,19 @@
              xmlns:ui="clr-namespace:PixiEditor.Helpers.UI"
              xmlns:visuals="clr-namespace:PixiEditor.Views.Visuals"
              xmlns:ui1="clr-namespace:PixiEditor.Extensions.UI;assembly=PixiEditor.Extensions"
+             xmlns:viewportControls="clr-namespace:PixiEditor.Views.Main.ViewportControls"
              mc:Ignorable="d"
              x:Name="uc"
              HorizontalAlignment="Center"
              VerticalAlignment="Center"
              d:DesignHeight="450" d:DesignWidth="800">
-    
-        <visuals:PreviewPainterControl
-            x:Name="mainImage"
-            Focusable="True"
-            PreviewPainter="{Binding Document.PreviewPainter, ElementName=uc}"
-            CustomRenderSize="{Binding CustomRenderSize, ElementName=uc}"
-            FrameToRender="{Binding Document.AnimationDataViewModel.ActiveFrameBindable, ElementName=uc}"
-            SizeChanged="OnImageSizeChanged">
-            <ui1:RenderOptionsBindable.BitmapInterpolationMode>
-                <MultiBinding Converter="{converters1:WidthToBitmapScalingModeConverter}">
-                    <Binding ElementName="uc" Path="Document.SizeBindable.X" />
-                    <Binding ElementName="mainImage" Path="Bounds.Width" />
-                </MultiBinding>
-            </ui1:RenderOptionsBindable.BitmapInterpolationMode>
-        </visuals:PreviewPainterControl>
+
+    <visuals:TextureControl
+        x:Name="mainImage"
+        Focusable="True"
+        Stretch="Uniform"
+        Texture="{Binding  SceneTexture,
+        RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=viewportControls:FixedViewport}}"
+        SizeChanged="OnImageSizeChanged">
+    </visuals:TextureControl>
 </UserControl>

+ 7 - 2
src/PixiEditor/Views/Main/ViewportControls/FixedViewport.axaml.cs

@@ -57,6 +57,8 @@ internal partial class FixedViewport : UserControl, INotifyPropertyChanged
         set => SetValue(DocumentProperty, value);
     }
 
+    public Texture? SceneTexture => Document?.SceneTextures.TryGetValue(GuidValue, out var tex) == true ? tex : null;
+
     public Guid GuidValue { get; } = Guid.NewGuid();
 
     static FixedViewport()
@@ -112,6 +114,7 @@ internal partial class FixedViewport : UserControl, INotifyPropertyChanged
 
     private void ForceRefreshFinalImage()
     {
+        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(SceneTexture)));
         mainImage.InvalidateVisual();
     }
 
@@ -121,11 +124,13 @@ internal partial class FixedViewport : UserControl, INotifyPropertyChanged
         if (Document is not null)
             docSize = Document.SizeBindable;
 
+        Matrix3X3 scaling = Matrix3X3.CreateScale((float)Bounds.Width / (float)docSize.X, (float)Bounds.Height / (float)docSize.Y);
+
         return new ViewportInfo(
             0,
             docSize / 2,
-            new VecD(mainImage.Bounds.Width, mainImage.Bounds.Height),
-            Matrix3X3.Identity,
+            new VecD(Bounds.Width, Bounds.Height),
+            scaling,
             null,
             "DEFAULT",
             SamplingOptions.Bilinear,