8 changed files with 145 additions and 220 deletions
@ -1,209 +0,0 @@ |
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
|||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
|||
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Diagnostics; |
|||
using System.Diagnostics.CodeAnalysis; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using Avalonia.VisualTree; |
|||
|
|||
namespace Avalonia.Rendering |
|||
{ |
|||
/// <summary>
|
|||
/// Extension methods for rendering.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This class provides implements the platform-independent parts of <see cref="IRenderTarget"/>.
|
|||
/// </remarks>
|
|||
[SuppressMessage("ReSharper", "LoopCanBeConvertedToQuery")] |
|||
[SuppressMessage("ReSharper", "ForCanBeConvertedToForeach")] |
|||
public static class RendererMixin |
|||
{ |
|||
private static int s_frameNum; |
|||
private static int s_fps; |
|||
private static int s_currentFrames; |
|||
private static TimeSpan s_lastMeasure; |
|||
private static readonly Stopwatch s_stopwatch = Stopwatch.StartNew(); |
|||
private static readonly Stack<List<IVisual>> s_listPool = new Stack<List<IVisual>>(); |
|||
private static readonly ZIndexComparer s_visualComparer = new ZIndexComparer(); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets a value which determines whether an FPS counted will be drawn on each
|
|||
/// rendered frame.
|
|||
/// </summary>
|
|||
public static bool DrawFpsCounter { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Renders the specified visual.
|
|||
/// </summary>
|
|||
/// <param name="renderTarget">IRenderer instance</param>
|
|||
/// <param name="visual">The visual to render.</param>
|
|||
public static void Render(this IRenderTarget renderTarget, IVisual visual) |
|||
{ |
|||
using (var ctx = new DrawingContext(renderTarget.CreateDrawingContext())) |
|||
{ |
|||
ctx.Render(visual); |
|||
s_frameNum++; |
|||
if (DrawFpsCounter) |
|||
{ |
|||
s_currentFrames++; |
|||
var now = s_stopwatch.Elapsed; |
|||
var elapsed = now - s_lastMeasure; |
|||
if (elapsed.TotalSeconds > 1) |
|||
{ |
|||
s_fps = (int)(s_currentFrames / elapsed.TotalSeconds); |
|||
s_currentFrames = 0; |
|||
s_lastMeasure = now; |
|||
} |
|||
var pt = new Point(40, 40); |
|||
var txt = new FormattedText( |
|||
"Frame #" + s_frameNum + " FPS: " + s_fps, |
|||
"Arial", |
|||
18, |
|||
Size.Infinity, |
|||
FontStyle.Normal, |
|||
TextAlignment.Left, |
|||
FontWeight.Normal, |
|||
TextWrapping.NoWrap); |
|||
ctx.FillRectangle(Brushes.White, new Rect(pt, txt.Measure())); |
|||
ctx.DrawText(Brushes.Black, pt, txt); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Renders the specified visual.
|
|||
/// </summary>
|
|||
/// <param name="visual">The visual to render.</param>
|
|||
/// <param name="context">The drawing context.</param>
|
|||
public static void Render(this DrawingContext context, IVisual visual) |
|||
{ |
|||
context.Render(visual, visual.Bounds); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Renders the specified visual.
|
|||
/// </summary>
|
|||
/// <param name="visual">The visual to render.</param>
|
|||
/// <param name="context">The drawing context.</param>
|
|||
/// <param name="clipRect">
|
|||
/// The current clip rect, in coordinates relative to <paramref name="visual"/>.
|
|||
/// </param>
|
|||
private static void Render(this DrawingContext context, IVisual visual, Rect clipRect) |
|||
{ |
|||
var opacity = visual.Opacity; |
|||
var clipToBounds = visual.ClipToBounds; |
|||
var bounds = new Rect(visual.Bounds.Size); |
|||
|
|||
if (visual.IsVisible && opacity > 0) |
|||
{ |
|||
var m = Matrix.CreateTranslation(visual.Bounds.Position); |
|||
|
|||
var renderTransform = Matrix.Identity; |
|||
|
|||
if (visual.RenderTransform != null) |
|||
{ |
|||
var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height)); |
|||
var offset = Matrix.CreateTranslation(origin); |
|||
renderTransform = (-offset) * visual.RenderTransform.Value * (offset); |
|||
} |
|||
|
|||
m = renderTransform * m; |
|||
|
|||
if (clipToBounds) |
|||
{ |
|||
clipRect = clipRect.Intersect(new Rect(visual.Bounds.Size)); |
|||
} |
|||
|
|||
using (context.PushPostTransform(m)) |
|||
using (context.PushOpacity(opacity)) |
|||
using (clipToBounds ? context.PushClip(bounds) : default(DrawingContext.PushedState)) |
|||
using (visual.Clip != null ? context.PushGeometryClip(visual.Clip) : default(DrawingContext.PushedState)) |
|||
using (visual.OpacityMask != null ? context.PushOpacityMask(visual.OpacityMask, bounds) : default(DrawingContext.PushedState)) |
|||
using (context.PushTransformContainer()) |
|||
{ |
|||
visual.Render(context); |
|||
|
|||
#pragma warning disable 0618
|
|||
var transformed = |
|||
new TransformedBounds(bounds, new Rect(), context.CurrentContainerTransform); |
|||
#pragma warning restore 0618
|
|||
|
|||
if (visual is Visual) |
|||
{ |
|||
BoundsTracker.SetTransformedBounds((Visual)visual, transformed); |
|||
} |
|||
|
|||
var lst = GetSortedVisualList(visual.VisualChildren); |
|||
|
|||
foreach (var child in lst) |
|||
{ |
|||
var childBounds = GetTransformedBounds(child); |
|||
|
|||
if (!child.ClipToBounds || clipRect.Intersects(childBounds)) |
|||
{ |
|||
var childClipRect = clipRect.Translate(-childBounds.Position); |
|||
context.Render(child, childClipRect); |
|||
} |
|||
else |
|||
{ |
|||
ClearTransformedBounds(child); |
|||
} |
|||
} |
|||
|
|||
ReturnListToPool(lst); |
|||
} |
|||
} |
|||
|
|||
if (!visual.IsVisible) |
|||
{ |
|||
ClearTransformedBounds(visual); |
|||
} |
|||
} |
|||
|
|||
private static void ClearTransformedBounds(IVisual visual) |
|||
{ |
|||
foreach (var e in visual.GetSelfAndVisualDescendents()) |
|||
{ |
|||
BoundsTracker.SetTransformedBounds((Visual)visual, null); |
|||
} |
|||
} |
|||
|
|||
private static void ReturnListToPool(List<IVisual> lst) |
|||
{ |
|||
lst.Clear(); |
|||
s_listPool.Push(lst); |
|||
} |
|||
|
|||
private static List<IVisual> GetSortedVisualList(IReadOnlyList<IVisual> source) |
|||
{ |
|||
var lst = s_listPool.Count == 0 ? new List<IVisual>() : s_listPool.Pop(); |
|||
for (var c = 0; c < source.Count; c++) |
|||
lst.Add(source[c]); |
|||
lst.Sort(s_visualComparer); |
|||
return lst; |
|||
} |
|||
|
|||
private static Rect GetTransformedBounds(IVisual visual) |
|||
{ |
|||
if (visual.RenderTransform == null) |
|||
{ |
|||
return visual.Bounds; |
|||
} |
|||
else |
|||
{ |
|||
var origin = visual.RenderTransformOrigin.ToPixels(new Size(visual.Bounds.Width, visual.Bounds.Height)); |
|||
var offset = Matrix.CreateTranslation(visual.Bounds.Position + origin); |
|||
var m = (-offset) * visual.RenderTransform.Value * (offset); |
|||
return visual.Bounds.TransformToAABB(m); |
|||
} |
|||
} |
|||
|
|||
class ZIndexComparer : IComparer<IVisual> |
|||
{ |
|||
public int Compare(IVisual x, IVisual y) => x.ZIndex.CompareTo(y.ZIndex); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue