浏览代码

Implemented more deferred rendering.

Implemted geometry clips and opacity masks.
Steven Kirk 8 年之前
父节点
当前提交
9121b4d3e5

+ 4 - 4
src/Avalonia.Visuals/Rendering/SceneGraph/ClipNode.cs

@@ -9,7 +9,7 @@ namespace Avalonia.Rendering.SceneGraph
     internal class ClipNode : IDrawOperation
     {
         /// <summary>
-        /// Initializes a new instance of the <see cref="ClipNode"/> class that represents an
+        /// Initializes a new instance of the <see cref="ClipNode"/> class that represents a
         /// clip push.
         /// </summary>
         /// <param name="clip">The clip to push.</param>
@@ -19,8 +19,8 @@ namespace Avalonia.Rendering.SceneGraph
         }
 
         /// <summary>
-        /// Initializes a new instance of the <see cref="ClipNode"/> class that represents an
-        /// opacity pop.
+        /// Initializes a new instance of the <see cref="ClipNode"/> class that represents a
+        /// clip pop.
         /// </summary>
         public ClipNode()
         {
@@ -30,7 +30,7 @@ namespace Avalonia.Rendering.SceneGraph
         public Rect Bounds => Rect.Empty;
 
         /// <summary>
-        /// Gets the opacity to be pushed or null if the operation represents a pop.
+        /// Gets the clip to be pushed or null if the operation represents a pop.
         /// </summary>
         public Rect? Clip { get; }
 

+ 40 - 4
src/Avalonia.Visuals/Rendering/SceneGraph/DeferredDrawingContextImpl.cs

@@ -211,7 +211,16 @@ namespace Avalonia.Rendering.SceneGraph
         /// <inheritdoc/>
         public void PopGeometryClip()
         {
-            // TODO: Implement
+            var next = NextDrawAs<GeometryClipNode>();
+
+            if (next == null || !next.Equals(null))
+            {
+                Add(new GeometryClipNode());
+            }
+            else
+            {
+                ++_drawOperationindex;
+            }
         }
 
         /// <inheritdoc/>
@@ -232,7 +241,16 @@ namespace Avalonia.Rendering.SceneGraph
         /// <inheritdoc/>
         public void PopOpacityMask()
         {
-            // TODO: Implement
+            var next = NextDrawAs<OpacityMaskNode>();
+
+            if (next == null || !next.Equals(null, null))
+            {
+                Add(new OpacityMaskNode());
+            }
+            else
+            {
+                ++_drawOperationindex;
+            }
         }
 
         /// <inheritdoc/>
@@ -253,7 +271,16 @@ namespace Avalonia.Rendering.SceneGraph
         /// <inheritdoc/>
         public void PushGeometryClip(IGeometryImpl clip)
         {
-            // TODO: Implement
+            var next = NextDrawAs<GeometryClipNode>();
+
+            if (next == null || !next.Equals(clip))
+            {
+                Add(new GeometryClipNode(clip));
+            }
+            else
+            {
+                ++_drawOperationindex;
+            }
         }
 
         /// <inheritdoc/>
@@ -274,7 +301,16 @@ namespace Avalonia.Rendering.SceneGraph
         /// <inheritdoc/>
         public void PushOpacityMask(IBrush mask, Rect bounds)
         {
-            // TODO: Implement
+            var next = NextDrawAs<OpacityMaskNode>();
+
+            if (next == null || !next.Equals(mask, bounds))
+            {
+                Add(new OpacityMaskNode(mask, bounds, CreateChildScene(mask)));
+            }
+            else
+            {
+                ++_drawOperationindex;
+            }
         }
 
         public struct UpdateState : IDisposable

+ 64 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/GeometryClipNode.cs

@@ -0,0 +1,64 @@
+using System;
+using Avalonia.Platform;
+
+namespace Avalonia.Rendering.SceneGraph
+{
+    /// <summary>
+    /// A node in the scene graph which represents a geometry clip push or pop.
+    /// </summary>
+    internal class GeometryClipNode : IDrawOperation
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GeometryClipNode"/> class that represents a
+        /// geometry clip push.
+        /// </summary>
+        /// <param name="clip">The clip to push.</param>
+        public GeometryClipNode(IGeometryImpl clip)
+        {
+            Clip = clip;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="GeometryClipNode"/> class that represents a
+        /// geometry clip pop.
+        /// </summary>
+        public GeometryClipNode()
+        {
+        }
+
+        /// <inheritdoc/>
+        public Rect Bounds => Rect.Empty;
+
+        /// <summary>
+        /// Gets the clip to be pushed or null if the operation represents a pop.
+        /// </summary>
+        public IGeometryImpl Clip { get; }
+
+        /// <inheritdoc/>
+        public bool HitTest(Point p) => false;
+
+        /// <summary>
+        /// Determines if this draw operation equals another.
+        /// </summary>
+        /// <param name="clip">The clip of the other draw operation.</param>
+        /// <returns>True if the draw operations are the same, otherwise false.</returns>
+        /// <remarks>
+        /// The properties of the other draw operation are passed in as arguments to prevent
+        /// allocation of a not-yet-constructed draw operation object.
+        /// </remarks>
+        public bool Equals(IGeometryImpl clip) => Clip == clip;
+
+        /// <inheritdoc/>
+        public void Render(IDrawingContextImpl context)
+        {
+            if (Clip != null)
+            {
+                context.PushGeometryClip(Clip);
+            }
+            else
+            {
+                context.PopGeometryClip();
+            }
+        }
+    }
+}

+ 80 - 0
src/Avalonia.Visuals/Rendering/SceneGraph/OpacityMaskNode.cs

@@ -0,0 +1,80 @@
+using System;
+using System.Collections.Generic;
+using Avalonia.Media;
+using Avalonia.Platform;
+using Avalonia.VisualTree;
+
+namespace Avalonia.Rendering.SceneGraph
+{
+    /// <summary>
+    /// A node in the scene graph which represents an opacity mask push or pop.
+    /// </summary>
+    internal class OpacityMaskNode : BrushDrawOperation
+    {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OpacityMaskNode"/> class that represents an
+        /// opacity mask push.
+        /// </summary>
+        /// <param name="mask">The opacity mask to push.</param>
+        /// <param name="bounds">The bounds of the mask.</param>
+        /// <param name="childScenes">Child scenes for drawing visual brushes.</param>
+        public OpacityMaskNode(IBrush mask, Rect bounds, IDictionary<IVisual, Scene> childScenes = null)
+        {
+            Mask = ToImmutable(mask);
+            MaskBounds = bounds;
+            ChildScenes = childScenes;
+        }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="OpacityMaskNode"/> class that represents an
+        /// opacity mask pop.
+        /// </summary>
+        public OpacityMaskNode()
+        {
+        }
+
+        /// <inheritdoc/>
+        public override Rect Bounds => Rect.Empty;
+
+        /// <summary>
+        /// Gets the mask to be pushed or null if the operation represents a pop.
+        /// </summary>
+        public IBrush Mask { get; }
+
+        /// <summary>
+        /// Gets the bounds of the opacity mask or null if the operation represents a pop.
+        /// </summary>
+        public Rect? MaskBounds { get; }
+
+        /// <inheritdoc/>
+        public override IDictionary<IVisual, Scene> ChildScenes { get; }
+
+        /// <inheritdoc/>
+        public override bool HitTest(Point p) => false;
+
+        /// <summary>
+        /// Determines if this draw operation equals another.
+        /// </summary>
+        /// <param name="mask">The opacity mask of the other draw operation.</param>
+        /// <param name="bounds">The opacity mask bounds of the other draw operation.</param>
+        /// <returns>True if the draw operations are the same, otherwise false.</returns>
+        /// <remarks>
+        /// The properties of the other draw operation are passed in as arguments to prevent
+        /// allocation of a not-yet-constructed draw operation object.
+        /// </remarks>
+        public bool Equals(IBrush mask, Rect? bounds) => Mask == mask && MaskBounds == bounds;
+
+        /// <inheritdoc/>
+        public override void Render(IDrawingContextImpl context)
+        {
+            if (Mask != null)
+            {
+                context.PushOpacityMask(Mask, MaskBounds.Value);
+            }
+            else
+            {
+                context.PopOpacityMask();
+            }
+        }
+    }
+}