CustomSkiaPage.cs 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. using System;
  2. using System.Diagnostics;
  3. using System.Globalization;
  4. using Avalonia;
  5. using Avalonia.Controls;
  6. using Avalonia.Media;
  7. using Avalonia.Platform;
  8. using Avalonia.Rendering.SceneGraph;
  9. using Avalonia.Skia;
  10. using Avalonia.Threading;
  11. using SkiaSharp;
  12. namespace RenderDemo.Pages
  13. {
  14. public class CustomSkiaPage : Control
  15. {
  16. public CustomSkiaPage()
  17. {
  18. ClipToBounds = true;
  19. }
  20. class CustomDrawOp : ICustomDrawOperation
  21. {
  22. private readonly FormattedText _noSkia;
  23. public CustomDrawOp(Rect bounds, FormattedText noSkia)
  24. {
  25. _noSkia = noSkia;
  26. Bounds = bounds;
  27. }
  28. public void Dispose()
  29. {
  30. // No-op
  31. }
  32. public Rect Bounds { get; }
  33. public bool HitTest(Point p) => false;
  34. public bool Equals(ICustomDrawOperation other) => false;
  35. static Stopwatch St = Stopwatch.StartNew();
  36. public void Render(IDrawingContextImpl context)
  37. {
  38. var leaseFeature = context.GetFeature<ISkiaSharpApiLeaseFeature>();
  39. if (leaseFeature == null)
  40. using (var c = new DrawingContext(context, false))
  41. {
  42. c.DrawText(_noSkia, new Point());
  43. }
  44. else
  45. {
  46. using var lease = leaseFeature.Lease();
  47. var canvas = lease.SkCanvas;
  48. canvas.Save();
  49. // create the first shader
  50. var colors = new SKColor[] {
  51. new SKColor(0, 255, 255),
  52. new SKColor(255, 0, 255),
  53. new SKColor(255, 255, 0),
  54. new SKColor(0, 255, 255)
  55. };
  56. var sx = Animate(100, 2, 10);
  57. var sy = Animate(1000, 5, 15);
  58. var lightPosition = new SKPoint(
  59. (float)(Bounds.Width / 2 + Math.Cos(St.Elapsed.TotalSeconds) * Bounds.Width / 4),
  60. (float)(Bounds.Height / 2 + Math.Sin(St.Elapsed.TotalSeconds) * Bounds.Height / 4));
  61. using (var sweep =
  62. SKShader.CreateSweepGradient(new SKPoint((int)Bounds.Width / 2, (int)Bounds.Height / 2), colors,
  63. null))
  64. using(var turbulence = SKShader.CreatePerlinNoiseFractalNoise(0.05f, 0.05f, 4, 0))
  65. using(var shader = SKShader.CreateCompose(sweep, turbulence, SKBlendMode.SrcATop))
  66. using(var blur = SKImageFilter.CreateBlur(Animate(100, 2, 10), Animate(100, 5, 15)))
  67. using (var paint = new SKPaint
  68. {
  69. Shader = shader,
  70. ImageFilter = blur
  71. })
  72. canvas.DrawPaint(paint);
  73. using (var pseudoLight = SKShader.CreateRadialGradient(
  74. lightPosition,
  75. (float) (Bounds.Width/3),
  76. new [] {
  77. new SKColor(255, 200, 200, 100),
  78. SKColors.Transparent,
  79. new SKColor(40,40,40, 220),
  80. new SKColor(20,20,20, (byte)Animate(100, 200,220)) },
  81. new float[] { 0.3f, 0.3f, 0.8f, 1 },
  82. SKShaderTileMode.Clamp))
  83. using (var paint = new SKPaint
  84. {
  85. Shader = pseudoLight
  86. })
  87. canvas.DrawPaint(paint);
  88. canvas.Restore();
  89. }
  90. }
  91. static int Animate(int d, int from, int to)
  92. {
  93. var ms = (int)(St.ElapsedMilliseconds / d);
  94. var diff = to - from;
  95. var range = diff * 2;
  96. var v = ms % range;
  97. if (v > diff)
  98. v = range - v;
  99. var rv = v + from;
  100. if (rv < from || rv > to)
  101. throw new Exception("WTF");
  102. return rv;
  103. }
  104. }
  105. public override void Render(DrawingContext context)
  106. {
  107. var noSkia = new FormattedText("Current rendering API is not Skia", CultureInfo.CurrentCulture,
  108. FlowDirection.LeftToRight, Typeface.Default, 12, Brushes.Black);
  109. context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), noSkia));
  110. Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
  111. }
  112. }
  113. }