Selaa lähdekoodia

Better node should render preview logic

Krzysztof Krysiński 5 kuukautta sitten
vanhempi
sitoutus
073b9fa222

+ 18 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Matrix/Matrix3X3BaseNode.cs

@@ -40,7 +40,8 @@ public abstract class Matrix3X3BaseNode : RenderNode, IRenderInput
 
 
         Float3x3 mtx = Matrix.Value.Invoke(FuncContext.NoContext);
         Float3x3 mtx = Matrix.Value.Invoke(FuncContext.NoContext);
 
 
-        surface.Canvas.SetMatrix(surface.Canvas.TotalMatrix.Concat(mtx.GetConstant() as Matrix3X3? ?? Matrix3X3.Identity));
+        surface.Canvas.SetMatrix(
+            surface.Canvas.TotalMatrix.Concat(mtx.GetConstant() as Matrix3X3? ?? Matrix3X3.Identity));
         if (!surface.LocalClipBounds.IsZeroOrNegativeArea)
         if (!surface.LocalClipBounds.IsZeroOrNegativeArea)
         {
         {
             Background.Value?.Paint(context, surface);
             Background.Value?.Paint(context, surface);
@@ -49,5 +50,21 @@ public abstract class Matrix3X3BaseNode : RenderNode, IRenderInput
         surface.Canvas.RestoreToCount(layer);
         surface.Canvas.RestoreToCount(layer);
     }
     }
 
 
+    public override RectD? GetPreviewBounds(int frame, string elementToRenderName = "")
+    {
+        if (Background.Value == null)
+            return null;
+
+        return base.GetPreviewBounds(frame, elementToRenderName);
+    }
+
+    public override bool RenderPreview(DrawingSurface renderOn, RenderContext context, string elementToRenderName)
+    {
+        if (Background.Value == null)
+            return false;
+
+        return base.RenderPreview(renderOn, context, elementToRenderName);
+    }
+
     protected abstract Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input);
     protected abstract Float3x3 CalculateMatrix(FuncContext ctx, Float3x3 input);
 }
 }

+ 6 - 5
src/PixiEditor.ChangeableDocument/Rendering/DocumentRenderer.cs

@@ -125,18 +125,18 @@ public class DocumentRenderer : IPreviewRenderable, IDisposable
         IsBusy = false;
         IsBusy = false;
     }
     }
 
 
-    public async Task RenderNodePreview(IPreviewRenderable previewRenderable, DrawingSurface renderOn,
+    public async Task<bool> RenderNodePreview(IPreviewRenderable previewRenderable, DrawingSurface renderOn,
         RenderContext context,
         RenderContext context,
         string elementToRenderName)
         string elementToRenderName)
     {
     {
-        if (previewRenderable is Node { IsDisposed: true }) return;
+        if (previewRenderable is Node { IsDisposed: true }) return false;
         TaskCompletionSource<bool> tcs = new();
         TaskCompletionSource<bool> tcs = new();
         RenderRequest request = new(tcs, context, renderOn, previewRenderable, elementToRenderName);
         RenderRequest request = new(tcs, context, renderOn, previewRenderable, elementToRenderName);
 
 
         renderRequests.Enqueue(request);
         renderRequests.Enqueue(request);
         ExecuteRenderRequests();
         ExecuteRenderRequests();
 
 
-        await tcs.Task;
+        return await tcs.Task;
     }
     }
 
 
     public static IReadOnlyNodeGraph ConstructMembersOnlyGraph(IReadOnlyNodeGraph fullGraph)
     public static IReadOnlyNodeGraph ConstructMembersOnlyGraph(IReadOnlyNodeGraph fullGraph)
@@ -279,9 +279,10 @@ public class DocumentRenderer : IPreviewRenderable, IDisposable
 
 
             try
             try
             {
             {
+                bool result = true;
                 if (request.PreviewRenderable != null)
                 if (request.PreviewRenderable != null)
                 {
                 {
-                    request.PreviewRenderable.RenderPreview(request.RenderOn, request.Context,
+                    result = request.PreviewRenderable.RenderPreview(request.RenderOn, request.Context,
                         request.ElementToRenderName);
                         request.ElementToRenderName);
                 }
                 }
                 else if (request.NodeGraph != null)
                 else if (request.NodeGraph != null)
@@ -289,7 +290,7 @@ public class DocumentRenderer : IPreviewRenderable, IDisposable
                     request.NodeGraph.Execute(request.Context);
                     request.NodeGraph.Execute(request.Context);
                 }
                 }
 
 
-                request.TaskCompletionSource.SetResult(true);
+                request.TaskCompletionSource.SetResult(result);
             }
             }
             catch (Exception e)
             catch (Exception e)
             {
             {

+ 18 - 2
src/PixiEditor/Models/Rendering/PreviewPainter.cs

@@ -23,6 +23,10 @@ public class PreviewPainter : IDisposable
     public VecI DocumentSize { get; set; }
     public VecI DocumentSize { get; set; }
     public DocumentRenderer Renderer { get; set; }
     public DocumentRenderer Renderer { get; set; }
 
 
+    public bool CanRender => canRender;
+
+    public event Action<bool>? CanRenderChanged;
+
     private Dictionary<int, Texture> renderTextures = new();
     private Dictionary<int, Texture> renderTextures = new();
     private Dictionary<int, PainterInstance> painterInstances = new();
     private Dictionary<int, PainterInstance> painterInstances = new();
 
 
@@ -32,6 +36,8 @@ public class PreviewPainter : IDisposable
     private Dictionary<int, VecI> pendingResizes = new();
     private Dictionary<int, VecI> pendingResizes = new();
     private HashSet<int> pendingRemovals = new();
     private HashSet<int> pendingRemovals = new();
 
 
+    private bool canRender;
+
     private int lastRequestId = 0;
     private int lastRequestId = 0;
 
 
     public PreviewPainter(DocumentRenderer renderer, IPreviewRenderable previewRenderable, KeyFrameTime frameTime,
     public PreviewPainter(DocumentRenderer renderer, IPreviewRenderable previewRenderable, KeyFrameTime frameTime,
@@ -126,11 +132,21 @@ public class PreviewPainter : IDisposable
         RepaintDirty();
         RepaintDirty();
     }
     }
 
 
-
-
     private void RepaintDirty()
     private void RepaintDirty()
     {
     {
         var dirtyArray = dirtyTextures.ToArray();
         var dirtyArray = dirtyTextures.ToArray();
+        bool couldRender = canRender;
+        canRender = PreviewRenderable?.GetPreviewBounds(FrameTime.Frame, ElementToRenderName) != null;
+        if (couldRender != canRender)
+        {
+            CanRenderChanged?.Invoke(canRender);
+        }
+
+        if (!CanRender)
+        {
+            return;
+        }
+
         foreach (var texture in dirtyArray)
         foreach (var texture in dirtyArray)
         {
         {
             if (!renderTextures.TryGetValue(texture, out var renderTexture))
             if (!renderTextures.TryGetValue(texture, out var renderTexture))

+ 1 - 1
src/PixiEditor/Styles/Templates/NodeView.axaml

@@ -56,7 +56,7 @@
                                 </ItemsControl>
                                 </ItemsControl>
                             </StackPanel>
                             </StackPanel>
                         </Border>
                         </Border>
-                        <Border IsVisible="{Binding !!ResultPreview, RelativeSource={RelativeSource TemplatedParent}}"
+                        <Border IsVisible="{Binding CanRenderPreview, RelativeSource={RelativeSource TemplatedParent}, FallbackValue=False}"
                                 CornerRadius="0, 0, 4.5, 4.5" Grid.Row="2" ClipToBounds="True">
                                 CornerRadius="0, 0, 4.5, 4.5" Grid.Row="2" ClipToBounds="True">
                             <Panel RenderOptions.BitmapInterpolationMode="None" Width="200" Height="200">
                             <Panel RenderOptions.BitmapInterpolationMode="None" Width="200" Height="200">
                                 <Panel.Background>
                                 <Panel.Background>

+ 2 - 0
src/PixiEditor/Views/Nodes/NodeGraphView.cs

@@ -666,6 +666,8 @@ internal class NodeGraphView : Zoombox.Zoombox
 
 
     private void UpdateConnectionView(NodePropertyViewModel? propertyView)
     private void UpdateConnectionView(NodePropertyViewModel? propertyView)
     {
     {
+        if (connectionItemsControl == null) return;
+
         foreach (var connection in connectionItemsControl.ItemsPanelRoot.Children)
         foreach (var connection in connectionItemsControl.ItemsPanelRoot.Children)
         {
         {
             if (connection is ContentPresenter contentPresenter)
             if (connection is ContentPresenter contentPresenter)

+ 36 - 0
src/PixiEditor/Views/Nodes/NodeView.cs

@@ -5,6 +5,7 @@ using Avalonia;
 using Avalonia.Controls;
 using Avalonia.Controls;
 using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
 using Avalonia.Controls.Primitives;
+using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.Input;
 using Avalonia.Media;
 using Avalonia.Media;
 using Avalonia.Threading;
 using Avalonia.Threading;
@@ -66,6 +67,15 @@ public class NodeView : TemplatedControl
     public static readonly StyledProperty<string> IconProperty = AvaloniaProperty.Register<NodeView, string>(
     public static readonly StyledProperty<string> IconProperty = AvaloniaProperty.Register<NodeView, string>(
         nameof(Icon));
         nameof(Icon));
 
 
+    public static readonly StyledProperty<bool> CanRenderPreviewProperty = AvaloniaProperty.Register<NodeView, bool>(
+        nameof(CanRenderPreview));
+
+    public bool CanRenderPreview
+    {
+        get => GetValue(CanRenderPreviewProperty);
+        private set => SetValue(CanRenderPreviewProperty, value);
+    }
+
     public string Icon
     public string Icon
     {
     {
         get => GetValue(IconProperty);
         get => GetValue(IconProperty);
@@ -167,6 +177,7 @@ public class NodeView : TemplatedControl
     static NodeView()
     static NodeView()
     {
     {
         IsSelectedProperty.Changed.Subscribe(NodeSelectionChanged);
         IsSelectedProperty.Changed.Subscribe(NodeSelectionChanged);
+        ResultPreviewProperty.Changed.Subscribe(PainterChanged);
     }
     }
 
 
     protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
     protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
@@ -300,4 +311,29 @@ public class NodeView : TemplatedControl
             nodeView.PseudoClasses.Set(":selected", e.NewValue.Value);
             nodeView.PseudoClasses.Set(":selected", e.NewValue.Value);
         }
         }
     }
     }
+
+    private static void PainterChanged(AvaloniaPropertyChangedEventArgs<PreviewPainter> e)
+    {
+        if (e.Sender is NodeView nodeView)
+        {
+            if (e.OldValue.Value is not null)
+            {
+                e.OldValue.Value.CanRenderChanged -= nodeView.ResultPreview_CanRenderChanged;
+            }
+
+            if (e.NewValue.Value is not null)
+            {
+                e.NewValue.Value.CanRenderChanged += nodeView.ResultPreview_CanRenderChanged;
+                nodeView.ResultPreview_CanRenderChanged(e.NewValue.Value.CanRender);
+            }
+        }
+    }
+
+    private void ResultPreview_CanRenderChanged(bool canRender)
+    {
+        if (CanRenderPreview != canRender)
+        {
+            CanRenderPreview = canRender;
+        }
+    }
 }
 }

+ 12 - 0
src/PixiEditor/Views/Visuals/PreviewPainterControl.cs

@@ -57,6 +57,18 @@ public class PreviewPainterControl : DrawieControl
         FrameToRender = frameToRender;
         FrameToRender = frameToRender;
     }
     }
 
 
+    protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
+    {
+        base.OnDetachedFromVisualTree(e);
+        if (PreviewPainter != null && painterInstance != null)
+        {
+            PreviewPainter.RemovePainterInstance(painterInstance.RequestId);
+            painterInstance.RequestMatrix = null;
+            painterInstance.RequestRepaint = null;
+            painterInstance = null;
+        }
+    }
+
     private static void PainterChanged(AvaloniaPropertyChangedEventArgs<PreviewPainter> args)
     private static void PainterChanged(AvaloniaPropertyChangedEventArgs<PreviewPainter> args)
     {
     {
         var sender = args.Sender as PreviewPainterControl;
         var sender = args.Sender as PreviewPainterControl;