committed by
GitHub
85 changed files with 1052 additions and 263 deletions
@ -1 +1 @@ |
|||||
Subproject commit 4464343aef5c8ab7a42fcb20a483a6058199f8b8 |
Subproject commit aef10ae67dc55c95f49b52a505a0be33bfa297a5 |
||||
@ -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,8 @@ |
|||||
|
// 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.Reflection; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
using Avalonia.Metadata; |
||||
|
|
||||
|
[assembly: XmlnsDefinition("http://reactiveui.net", "Avalonia.ReactiveUI")] |
||||
@ -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> |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
} |
||||
@ -1 +1 @@ |
|||||
Subproject commit ab5526173722b8988bc5ca3c03c8752ce89c0975 |
Subproject commit 7452b23169e4948907fa10e2c115b672897d0e04 |
||||
@ -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,25 @@ |
|||||
|
// 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 SkiaSharp; |
||||
|
|
||||
|
namespace Avalonia.Skia |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A Skia implementation of a <see cref="Avalonia.Media.EllipseGeometry"/>.
|
||||
|
/// </summary>
|
||||
|
internal class EllipseGeometryImpl : GeometryImpl |
||||
|
{ |
||||
|
public override Rect Bounds { get; } |
||||
|
public override SKPath EffectivePath { get; } |
||||
|
|
||||
|
public EllipseGeometryImpl(Rect rect) |
||||
|
{ |
||||
|
var path = new SKPath(); |
||||
|
path.AddOval(rect.ToSKRect()); |
||||
|
|
||||
|
EffectivePath = path; |
||||
|
Bounds = rect; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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,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>
|
||||
|
/// A Skia implementation of a <see cref="Avalonia.Media.LineGeometry"/>.
|
||||
|
/// </summary>
|
||||
|
internal class LineGeometryImpl : GeometryImpl |
||||
|
{ |
||||
|
public override Rect Bounds { get; } |
||||
|
public override SKPath EffectivePath { get; } |
||||
|
|
||||
|
public LineGeometryImpl(Point p1, Point p2) |
||||
|
{ |
||||
|
var path = new SKPath(); |
||||
|
path.MoveTo(p1.ToSKPoint()); |
||||
|
path.LineTo(p2.ToSKPoint()); |
||||
|
|
||||
|
EffectivePath = path; |
||||
|
Bounds = new Rect( |
||||
|
new Point(Math.Min(p1.X, p2.X), Math.Min(p1.Y, p2.Y)), |
||||
|
new Point(Math.Max(p1.X, p2.X), Math.Max(p1.Y, p2.Y))); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
// 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 SkiaSharp; |
||||
|
|
||||
|
namespace Avalonia.Skia |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A Skia implementation of a <see cref="Avalonia.Media.RectangleGeometry"/>.
|
||||
|
/// </summary>
|
||||
|
internal class RectangleGeometryImpl : GeometryImpl |
||||
|
{ |
||||
|
public override Rect Bounds { get; } |
||||
|
public override SKPath EffectivePath { get; } |
||||
|
|
||||
|
public RectangleGeometryImpl(Rect rect) |
||||
|
{ |
||||
|
var path = new SKPath(); |
||||
|
path.AddRect(rect.ToSKRect()); |
||||
|
|
||||
|
EffectivePath = path; |
||||
|
Bounds = rect; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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; } |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// 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 SharpDX.Direct2D1; |
||||
|
|
||||
|
namespace Avalonia.Direct2D1.Media |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A Direct2D implementation of a <see cref="Avalonia.Media.EllipseGeometry"/>.
|
||||
|
/// </summary>
|
||||
|
internal class EllipseGeometryImpl : GeometryImpl |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="StreamGeometryImpl"/> class.
|
||||
|
/// </summary>
|
||||
|
public EllipseGeometryImpl(Rect rect) |
||||
|
: base(CreateGeometry(rect)) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
private static Geometry CreateGeometry(Rect rect) |
||||
|
{ |
||||
|
var ellipse = new Ellipse(rect.Center.ToSharpDX(), (float)rect.Width / 2, (float)rect.Height / 2); |
||||
|
return new EllipseGeometry(Direct2D1Platform.Direct2D1Factory, ellipse); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,27 @@ |
|||||
|
// 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 SharpDX.Direct2D1; |
||||
|
|
||||
|
namespace Avalonia.Direct2D1.Media |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A Direct2D implementation of a <see cref="Avalonia.Media.LineGeometry"/>.
|
||||
|
/// </summary>
|
||||
|
internal class LineGeometryImpl : StreamGeometryImpl |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="StreamGeometryImpl"/> class.
|
||||
|
/// </summary>
|
||||
|
public LineGeometryImpl(Point p1, Point p2) |
||||
|
{ |
||||
|
using (var sink = ((PathGeometry)Geometry).Open()) |
||||
|
{ |
||||
|
sink.BeginFigure(p1.ToSharpDX(), FigureBegin.Hollow); |
||||
|
sink.AddLine(p2.ToSharpDX()); |
||||
|
sink.EndFigure(FigureEnd.Open); |
||||
|
sink.Close(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -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 SharpDX.Direct2D1; |
||||
|
|
||||
|
namespace Avalonia.Direct2D1.Media |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// A Direct2D implementation of a <see cref="Avalonia.Media.RectangleGeometry"/>.
|
||||
|
/// </summary>
|
||||
|
internal class RectangleGeometryImpl : GeometryImpl |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Initializes a new instance of the <see cref="StreamGeometryImpl"/> class.
|
||||
|
/// </summary>
|
||||
|
public RectangleGeometryImpl(Rect rect) |
||||
|
: base(CreateGeometry(rect)) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
private static Geometry CreateGeometry(Rect rect) |
||||
|
{ |
||||
|
return new RectangleGeometry(Direct2D1Platform.Direct2D1Factory, rect.ToDirect2D()); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.5 KiB |
Loading…
Reference in new issue