committed by
GitHub
28 changed files with 393 additions and 21 deletions
@ -0,0 +1,119 @@ |
|||
using System; |
|||
using System.Diagnostics; |
|||
using Avalonia; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
using Avalonia.Rendering.SceneGraph; |
|||
using Avalonia.Skia; |
|||
using Avalonia.Threading; |
|||
using SkiaSharp; |
|||
|
|||
namespace RenderDemo.Pages |
|||
{ |
|||
public class CustomSkiaPage : Control |
|||
{ |
|||
public CustomSkiaPage() |
|||
{ |
|||
ClipToBounds = true; |
|||
} |
|||
|
|||
class CustomDrawOp : ICustomDrawOperation |
|||
{ |
|||
private readonly FormattedText _noSkia; |
|||
|
|||
public CustomDrawOp(Rect bounds, FormattedText noSkia) |
|||
{ |
|||
_noSkia = noSkia; |
|||
Bounds = bounds; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
// No-op
|
|||
} |
|||
|
|||
public Rect Bounds { get; } |
|||
public bool HitTest(Point p) => false; |
|||
public bool Equals(ICustomDrawOperation other) => false; |
|||
static Stopwatch St = Stopwatch.StartNew(); |
|||
public void Render(IDrawingContextImpl context) |
|||
{ |
|||
var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas; |
|||
if (canvas == null) |
|||
context.DrawText(Brushes.Black, new Point(), _noSkia.PlatformImpl); |
|||
else |
|||
{ |
|||
canvas.Save(); |
|||
// create the first shader
|
|||
var colors = new SKColor[] { |
|||
new SKColor(0, 255, 255), |
|||
new SKColor(255, 0, 255), |
|||
new SKColor(255, 255, 0), |
|||
new SKColor(0, 255, 255) |
|||
}; |
|||
|
|||
var sx = Animate(100, 2, 10); |
|||
var sy = Animate(1000, 5, 15); |
|||
var lightPosition = new SKPoint( |
|||
(float)(Bounds.Width / 2 + Math.Cos(St.Elapsed.TotalSeconds) * Bounds.Width / 4), |
|||
(float)(Bounds.Height / 2 + Math.Sin(St.Elapsed.TotalSeconds) * Bounds.Height / 4)); |
|||
using (var sweep = |
|||
SKShader.CreateSweepGradient(new SKPoint((int)Bounds.Width / 2, (int)Bounds.Height / 2), colors, |
|||
null)) |
|||
using(var turbulence = SKShader.CreatePerlinNoiseFractalNoise(0.05f, 0.05f, 4, 0)) |
|||
using(var shader = SKShader.CreateCompose(sweep, turbulence, SKBlendMode.SrcATop)) |
|||
using(var blur = SKImageFilter.CreateBlur(Animate(100, 2, 10), Animate(100, 5, 15))) |
|||
using (var paint = new SKPaint |
|||
{ |
|||
Shader = shader, |
|||
ImageFilter = blur |
|||
}) |
|||
canvas.DrawPaint(paint); |
|||
|
|||
using (var pseudoLight = SKShader.CreateRadialGradient( |
|||
lightPosition, |
|||
(float) (Bounds.Width/3), |
|||
new [] { |
|||
new SKColor(255, 200, 200, 100), |
|||
SKColors.Transparent, |
|||
new SKColor(40,40,40, 220), |
|||
new SKColor(20,20,20, (byte)Animate(100, 200,220)) }, |
|||
new float[] { 0.3f, 0.3f, 0.8f, 1 }, |
|||
SKShaderTileMode.Clamp)) |
|||
using (var paint = new SKPaint |
|||
{ |
|||
Shader = pseudoLight |
|||
}) |
|||
canvas.DrawPaint(paint); |
|||
canvas.Restore(); |
|||
} |
|||
} |
|||
static int Animate(int d, int from, int to) |
|||
{ |
|||
var ms = (int)(St.ElapsedMilliseconds / d); |
|||
var diff = to - from; |
|||
var range = diff * 2; |
|||
var v = ms % range; |
|||
if (v > diff) |
|||
v = range - v; |
|||
var rv = v + from; |
|||
if (rv < from || rv > to) |
|||
throw new Exception("WTF"); |
|||
return rv; |
|||
} |
|||
} |
|||
|
|||
|
|||
|
|||
public override void Render(DrawingContext context) |
|||
{ |
|||
var noSkia = new FormattedText() |
|||
{ |
|||
Text = "Current rendering API is not Skia" |
|||
}; |
|||
context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), noSkia)); |
|||
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using Avalonia.Media; |
|||
using Avalonia.Platform; |
|||
|
|||
namespace Avalonia.Rendering.SceneGraph |
|||
{ |
|||
internal sealed class CustomDrawOperation : DrawOperation |
|||
{ |
|||
public Matrix Transform { get; } |
|||
public ICustomDrawOperation Custom { get; } |
|||
public CustomDrawOperation(ICustomDrawOperation custom, Matrix transform) |
|||
: base(custom.Bounds, transform, null) |
|||
{ |
|||
Transform = transform; |
|||
Custom = custom; |
|||
} |
|||
|
|||
public override bool HitTest(Point p) |
|||
{ |
|||
return Custom.HitTest(p * Transform); |
|||
} |
|||
|
|||
public override void Render(IDrawingContextImpl context) |
|||
{ |
|||
context.Transform = Transform; |
|||
Custom.Render(context); |
|||
} |
|||
|
|||
public override void Dispose() => Custom.Dispose(); |
|||
|
|||
public bool Equals(Matrix transform, ICustomDrawOperation custom) => |
|||
Transform == transform && Custom?.Equals(custom) == true; |
|||
} |
|||
|
|||
public interface ICustomDrawOperation : IDrawOperation, IEquatable<ICustomDrawOperation> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,42 @@ |
|||
// 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 Avalonia.Platform; |
|||
using Avalonia.Rendering; |
|||
|
|||
namespace Avalonia.Skia |
|||
{ |
|||
/// <summary>
|
|||
/// Adapts <see cref="ICustomSkiaRenderTarget"/> to be used within Skia rendering pipeline.
|
|||
/// </summary>
|
|||
internal class CustomRenderTarget : IRenderTarget |
|||
{ |
|||
private readonly ICustomSkiaRenderTarget _renderTarget; |
|||
|
|||
public CustomRenderTarget(ICustomSkiaRenderTarget renderTarget) |
|||
{ |
|||
_renderTarget = renderTarget; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
_renderTarget.Dispose(); |
|||
} |
|||
|
|||
public IDrawingContextImpl CreateDrawingContext(IVisualBrushRenderer visualBrushRenderer) |
|||
{ |
|||
ICustomSkiaRenderSession session = _renderTarget.BeginRendering(); |
|||
|
|||
var nfo = new DrawingContextImpl.CreateInfo |
|||
{ |
|||
GrContext = session.GrContext, |
|||
Canvas = session.Canvas, |
|||
Dpi = SkiaPlatform.DefaultDpi * session.ScaleFactor, |
|||
VisualBrushRenderer = visualBrushRenderer, |
|||
DisableTextLcdRendering = true |
|||
}; |
|||
|
|||
return new DrawingContextImpl(nfo, session); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
// 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.Collections.Generic; |
|||
using SkiaSharp; |
|||
|
|||
namespace Avalonia.Skia |
|||
{ |
|||
/// <summary>
|
|||
/// Custom Skia gpu instance.
|
|||
/// </summary>
|
|||
public interface ICustomSkiaGpu |
|||
{ |
|||
/// <summary>
|
|||
/// Skia GrContext used.
|
|||
/// </summary>
|
|||
GRContext GrContext { get; } |
|||
|
|||
/// <summary>
|
|||
/// Attempts to create custom render target from given surfaces.
|
|||
/// </summary>
|
|||
/// <param name="surfaces">Surfaces.</param>
|
|||
/// <returns>Created render target or <see langword="null"/> if it fails.</returns>
|
|||
ICustomSkiaRenderTarget TryCreateRenderTarget(IEnumerable<object> surfaces); |
|||
} |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
// 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 SkiaSharp; |
|||
|
|||
namespace Avalonia.Skia |
|||
{ |
|||
/// <summary>
|
|||
/// Custom render session for Skia render target.
|
|||
/// </summary>
|
|||
public interface ICustomSkiaRenderSession : IDisposable |
|||
{ |
|||
/// <summary>
|
|||
/// GrContext used by this session.
|
|||
/// </summary>
|
|||
GRContext GrContext { get; } |
|||
|
|||
/// <summary>
|
|||
/// Canvas that will be used to render.
|
|||
/// </summary>
|
|||
SKCanvas Canvas { get; } |
|||
|
|||
/// <summary>
|
|||
/// Scaling factor.
|
|||
/// </summary>
|
|||
double ScaleFactor { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
// 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; |
|||
|
|||
namespace Avalonia.Skia |
|||
{ |
|||
/// <summary>
|
|||
/// Custom Skia render target.
|
|||
/// </summary>
|
|||
public interface ICustomSkiaRenderTarget : IDisposable |
|||
{ |
|||
/// <summary>
|
|||
/// Start rendering to this render target.
|
|||
/// </summary>
|
|||
/// <returns></returns>
|
|||
ICustomSkiaRenderSession BeginRendering(); |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using Avalonia.Platform; |
|||
using SkiaSharp; |
|||
|
|||
namespace Avalonia.Skia |
|||
{ |
|||
public interface ISkiaDrawingContextImpl : IDrawingContextImpl |
|||
{ |
|||
SKCanvas SkCanvas { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
// 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 Avalonia.Skia; |
|||
|
|||
namespace Avalonia |
|||
{ |
|||
/// <summary>
|
|||
/// Options for Skia rendering subsystem.
|
|||
/// </summary>
|
|||
public class SkiaOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Custom gpu factory to use. Can be used to customize behavior of Skia renderer.
|
|||
/// </summary>
|
|||
public Func<ICustomSkiaGpu> CustomGpuFactory { get; set; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue