| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- using System;
- using Avalonia;
- using Avalonia.Controls;
- using Avalonia.LogicalTree;
- using Avalonia.Markup.Xaml;
- using Avalonia.Media;
- using Avalonia.OpenGL;
- using Avalonia.Platform;
- using Avalonia.Rendering.Composition;
- using Avalonia.Skia;
- using ControlCatalog.Pages.OpenGl;
- using SkiaSharp;
- using static Avalonia.OpenGL.GlConsts;
- namespace ControlCatalog.Pages;
- public class OpenGlLeasePage : UserControl
- {
- private readonly Control _viewport;
- private readonly GlPageKnobs _knobs;
- private CompositionCustomVisual? _visual;
- class GlVisual : CompositionCustomVisualHandler
- {
- private OpenGlContent _content;
- private Parameters _parameters;
- private bool _contentInitialized;
- private OpenGlFbo? _fbo;
- private bool _reRender;
- private IGlContext? _gl;
- public GlVisual(OpenGlContent content, Parameters parameters)
- {
- _content = content;
- _parameters = parameters;
- }
- public override void OnRender(ImmediateDrawingContext drawingContext)
- {
- if (_parameters.Disco > 0.01f)
- RegisterForNextAnimationFrameUpdate();
- var bounds = GetRenderBounds();
- var size = PixelSize.FromSize(bounds.Size, 1);
- if (size.Width < 1 || size.Height < 1)
- return;
-
- if(drawingContext.TryGetFeature<ISkiaSharpApiLeaseFeature>(out var skiaFeature))
- {
- using var skiaLease = skiaFeature.Lease();
- var grContext = skiaLease.GrContext;
- if (grContext == null)
- return;
- SKImage? snapshot;
- using (var platformApiLease = skiaLease.TryLeasePlatformGraphicsApi())
- {
- if (platformApiLease?.Context is not IGlContext glContext)
- return;
- var gl = glContext.GlInterface;
- if (_gl != glContext)
- {
- // The old context is lost
- _fbo = null;
- _contentInitialized = false;
- _gl = glContext;
- }
- gl.GetIntegerv(GL_FRAMEBUFFER_BINDING, out var oldFb);
- _fbo ??= new OpenGlFbo(glContext, grContext);
- if (_fbo.Size != size)
- _fbo.Resize(size);
- gl.BindFramebuffer(GL_FRAMEBUFFER, _fbo.Fbo);
-
- if (!_contentInitialized)
- {
- _content.Init(gl, glContext.Version);
- _contentInitialized = true;
- }
-
- _content.OnOpenGlRender(gl, _fbo.Fbo, size, _parameters.Yaw, _parameters.Pitch,
- _parameters.Roll, _parameters.Disco);
- snapshot = _fbo.Snapshot();
- gl.BindFramebuffer(GL_FRAMEBUFFER, oldFb);
- }
- using(snapshot)
- if (snapshot != null)
- skiaLease.SkCanvas.DrawImage(snapshot, new SKRect(0, 0,
- (float)bounds.Width, (float)bounds.Height));
- }
- }
- public override void OnAnimationFrameUpdate()
- {
- if (_reRender || _parameters.Disco > 0.01f)
- {
- _reRender = false;
- Invalidate();
- }
- base.OnAnimationFrameUpdate();
- }
- public override void OnMessage(object message)
- {
- if (message is Parameters p)
- {
- _parameters = p;
- _reRender = true;
- RegisterForNextAnimationFrameUpdate();
- }
- else if (message is DisposeMessage)
- {
- if (_gl != null)
- {
- try
- {
- if (_fbo != null || _contentInitialized)
- {
- using (_gl.MakeCurrent())
- {
- if (_contentInitialized)
- _content.Deinit(_gl.GlInterface);
- _contentInitialized = false;
- _fbo?.Dispose();
- _fbo = null;
- }
- }
- }
- catch (Exception e)
- {
- Console.WriteLine(e.ToString());
- }
- _gl = null;
- }
- }
- base.OnMessage(message);
- }
- }
- public class Parameters
- {
- public float Yaw;
- public float Pitch;
- public float Roll;
- public float Disco;
- }
- public class DisposeMessage
- {
-
- }
-
- public OpenGlLeasePage()
- {
- AvaloniaXamlLoader.Load(this);
- _viewport = this.FindControl<Control>("Viewport")!;
- _viewport.AttachedToVisualTree += ViewportAttachedToVisualTree;
- _viewport.DetachedFromVisualTree += ViewportDetachedFromVisualTree;
- _knobs = this.FindControl<GlPageKnobs>("Knobs")!;
- _knobs.PropertyChanged += KnobsPropertyChanged;
- }
- private void KnobsPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs change)
- {
- if (change.Property == GlPageKnobs.YawProperty
- || change.Property == GlPageKnobs.RollProperty
- || change.Property == GlPageKnobs.PitchProperty
- || change.Property == GlPageKnobs.DiscoProperty)
- _visual?.SendHandlerMessage(GetParameters());
- }
- Parameters GetParameters() => new()
- {
- Yaw = _knobs!.Yaw, Pitch = _knobs.Pitch, Roll = _knobs.Roll, Disco = _knobs.Disco
- };
-
- private void ViewportAttachedToVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
- {
- var visual = ElementComposition.GetElementVisual(_viewport!);
- if(visual == null)
- return;
- _visual = visual.Compositor.CreateCustomVisual(new GlVisual(new OpenGlContent(), GetParameters()));
- ElementComposition.SetElementChildVisual(_viewport, _visual);
- UpdateSize(Bounds.Size);
- }
- private void UpdateSize(Size size)
- {
- if (_visual != null)
- _visual.Size = new Vector(size.Width, size.Height);
- }
- protected override Size ArrangeOverride(Size finalSize)
- {
- var size = base.ArrangeOverride(finalSize);
- UpdateSize(size);
- return size;
- }
- private void ViewportDetachedFromVisualTree(object? sender, VisualTreeAttachmentEventArgs e)
- {
- _visual?.SendHandlerMessage(new DisposeMessage());
- _visual = null;
- ElementComposition.SetElementChildVisual(_viewport, null);
- base.OnDetachedFromVisualTree(e);
- }
- }
|