-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
CustomSkiaPage.cs
124 lines (114 loc) · 4.8 KB
/
CustomSkiaPage.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
using System;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Skia;
using Avalonia.Threading;
using Avalonia.Utilities;
using SkiaSharp;
namespace RenderDemo.Pages
{
public class CustomSkiaPage : Control
{
private readonly GlyphRun _noSkia;
public CustomSkiaPage()
{
ClipToBounds = true;
var text = "Current rendering API is not Skia";
var glyphs = text.Select(ch => Typeface.Default.GlyphTypeface.GetGlyph(ch)).ToArray();
_noSkia = new GlyphRun(Typeface.Default.GlyphTypeface, 12, text.AsMemory(), glyphs);
}
class CustomDrawOp : ICustomDrawOperation
{
private readonly IImmutableGlyphRunReference _noSkia;
public CustomDrawOp(Rect bounds, GlyphRun noSkia)
{
_noSkia = noSkia.TryCreateImmutableGlyphRunReference();
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(ImmediateDrawingContext context)
{
var leaseFeature = context.TryGetFeature<ISkiaSharpApiLeaseFeature>();
if (leaseFeature == null)
context.DrawGlyphRun(Brushes.Black, _noSkia);
else
{
using var lease = leaseFeature.Lease();
var canvas = lease.SkCanvas;
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)
{
context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), _noSkia));
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
}
}
}