skiasharp/source/SkiaSharp.Views/SkiaSharp.Views.WindowsForms/SKGLControl.cs
2024-09-19 02:04:14 +08:00

160 lines
3.7 KiB
C#

using System;
using System.ComponentModel;
using System.Windows.Forms;
using OpenTK;
#if WINDOWS
using OpenTK.GLControl;
#endif
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;
#if WINDOWS
public SKGLControl()
: base(new GLControlSettings { AlphaBits = 8, RedBits = 8, GreenBits = 8, BlueBits = 8, DepthBits = 24, StencilBits = 8 })
{
Initialize();
}
public SKGLControl(GLControlSettings settings)
: base(settings)
{
Initialize();
}
#else
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();
}
#endif
private void Initialize()
{
designMode = DesignMode || LicenseManager.UsageMode == LicenseUsageMode.Designtime;
ResizeRedraw = true;
}
public SKSize CanvasSize => lastSize;
public GRContext GRContext => grContext;
[Category("Appearance")]
public event EventHandler<SKPaintGLSurfaceEventArgs> 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;
}
}
}