using System; using System.ComponentModel; using System.Windows.Forms; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.ES20; namespace SkiaSharp.Views.Desktop { [DefaultEvent("PaintSurface")] [DefaultProperty("Name")] public class SKGLControl : GLControl { private const SKColorType colorType = SKColorType.Rgba8888; private const GRSurfaceOrigin surfaceOrigin = GRSurfaceOrigin.BottomLeft; private bool designMode; private GRContext grContext; private GRGlFramebufferInfo glInfo; private GRBackendRenderTarget renderTarget; private SKSurface surface; private SKCanvas canvas; private SKSizeI lastSize; public SKGLControl() : base(new GraphicsMode(new ColorFormat(8, 8, 8, 8), 24, 8)) { Initialize(); } public SKGLControl(GraphicsMode mode) : base(mode) { Initialize(); } public SKGLControl(GraphicsMode mode, int major, int minor, GraphicsContextFlags flags) : base(mode, major, minor, flags) { Initialize(); } private void Initialize() { designMode = DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime; ResizeRedraw = true; } public SKSize CanvasSize => lastSize; public GRContext GRContext => grContext; [Category("Appearance")] public event EventHandler PaintSurface; protected override void OnPaint(PaintEventArgs e) { if (designMode) { e.Graphics.Clear(BackColor); return; } base.OnPaint(e); MakeCurrent(); // create the contexts if not done already if (grContext == null) { var glInterface = GRGlInterface.Create(); grContext = GRContext.CreateGl(glInterface); } // get the new surface size var newSize = new SKSizeI(Width, Height); // manage the drawing surface if (renderTarget == null || lastSize != newSize || !renderTarget.IsValid) { // create or update the dimensions lastSize = newSize; GL.GetInteger(GetPName.FramebufferBinding, out var framebuffer); GL.GetInteger(GetPName.StencilBits, out var stencil); GL.GetInteger(GetPName.Samples, out var samples); var maxSamples = grContext.GetMaxSurfaceSampleCount(colorType); if (samples > maxSamples) samples = maxSamples; glInfo = new GRGlFramebufferInfo((uint)framebuffer, colorType.ToGlSizedFormat()); // destroy the old surface surface?.Dispose(); surface = null; canvas = null; // re-create the render target renderTarget?.Dispose(); renderTarget = new GRBackendRenderTarget(newSize.Width, newSize.Height, samples, stencil, glInfo); } // create the surface if (surface == null) { surface = SKSurface.Create(grContext, renderTarget, surfaceOrigin, colorType); canvas = surface.Canvas; } using (new SKAutoCanvasRestore(canvas, true)) { // start drawing OnPaintSurface(new SKPaintGLSurfaceEventArgs(surface, renderTarget, surfaceOrigin, colorType)); } // update the control canvas.Flush(); SwapBuffers(); } protected virtual void OnPaintSurface(SKPaintGLSurfaceEventArgs e) { // invoke the event PaintSurface?.Invoke(this, e); } protected override void Dispose(bool disposing) { base.Dispose(disposing); // clean up canvas = null; surface?.Dispose(); surface = null; renderTarget?.Dispose(); renderTarget = null; grContext?.Dispose(); grContext = null; } } }