CPF/CPF.Skia/GlView.cs
2024-06-07 09:58:49 +08:00

179 lines
6.1 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using CPF.Drawing;
using System;
using System.Collections.Generic;
using System.Text;
using SkiaSharp;
using CPF.OpenGL;
using System.Runtime.InteropServices;
namespace CPF.Skia
{
/// <summary>
/// 支持OpenGL绘制的控件在GLRender事件里绘制开启GPU硬件加速才能使用 new SkiaDrawingFactory { UseGPU = true }
/// </summary>
public class GLView : UIElement
{
int Id;
int ColorBuffer;
int DepthRenderBuffer;
Size oldSize;
SKImage image;
SKPaint paint;
GRBackendTexture backendTexture;
/// <summary>
/// 支持OpenGL绘制的控件在GLRender事件里绘制开启GPU硬件加速才能使用 new SkiaDrawingFactory { UseGPU = true }
/// </summary>
public GLView() { }
/// <summary>
/// 绑定的FB id
/// </summary>
public int FramebufferId
{
get { return Id; }
}
//IGlContext context;
protected unsafe override void OnRender(DrawingContext dc)
{
var cSize = ActualSize;
if (cSize.Width <= 0 || cSize.Height <= 0 || DesignMode)
{
return;
}
var size = new PixelSize((int)Math.Round(cSize.Width * Root.RenderScaling), (int)Math.Round(cSize.Height * Root.RenderScaling));
var skia = dc as SkiaDrawingContext;
var _gl = skia?.GlContext;
if (_gl == null)
{
return;
}
if (paint == null)
{
paint = new SKPaint();
}
paint.IsAntialias = IsAntiAlias;
paint.FilterQuality = IsAntiAlias ? SKFilterQuality.Medium : SKFilterQuality.None;
if (Id == 0)
{
Id = _gl.GenFramebuffer();
ColorBuffer = _gl.GenTexture();
DepthRenderBuffer = _gl.GenRenderbuffer();
_gl.BindTexture(GlConsts.GL_TEXTURE_2D, ColorBuffer);
_gl.TexParameter(GlConsts.GL_TEXTURE_2D, GlConsts.GL_TEXTURE_MIN_FILTER, (int)GlConsts.GL_LINEAR);
_gl.TexParameter(GlConsts.GL_TEXTURE_2D, GlConsts.GL_TEXTURE_MAG_FILTER, GlConsts.GL_LINEAR);
_gl.BindTexture(GlConsts.GL_TEXTURE_2D, 0);
OnGLLoaded(_gl);
}
if (cSize != oldSize)
{
oldSize = cSize;
_gl.BindTexture(GlConsts.GL_TEXTURE_2D, ColorBuffer);
_gl.TexImage2D(GlConsts.GL_TEXTURE_2D, 0, GlConsts.GL_RGBA, (int)size.Width, (int)size.Height, 0, GlConsts.GL_RGB, GlConsts.GL_UNSIGNED_BYTE, IntPtr.Zero);
_gl.BindTexture(GlConsts.GL_TEXTURE_2D, 0);
_gl.BindRenderbuffer(GlConsts.GL_RENDERBUFFER, DepthRenderBuffer);
_gl.RenderbufferStorage(GlConsts.GL_RENDERBUFFER, GlConsts.GL_DEPTH32F_STENCIL8, (int)size.Width, (int)size.Height);
_gl.BindRenderbuffer(GlConsts.GL_RENDERBUFFER, 0);
_gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, Id);
_gl.FramebufferTexture2D(GlConsts.GL_FRAMEBUFFER, GlConsts.GL_COLOR_ATTACHMENT0, GlConsts.GL_TEXTURE_2D, ColorBuffer, 0);
_gl.FramebufferRenderbuffer(GlConsts.GL_FRAMEBUFFER, GlConsts.GL_DEPTH_STENCIL_ATTACHMENT, GlConsts.GL_RENDERBUFFER, DepthRenderBuffer);
_gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0);
if (image != null)
{
image.Dispose();
}
if (backendTexture != null)
{
backendTexture.Dispose();
}
backendTexture = new GRBackendTexture((int)(size.Width), (int)(size.Height), false, new GRGlTextureInfo(0x0DE1, (uint)ColorBuffer, SKColorType.Rgba8888.ToGlSizedFormat()));
image = SKImage.FromTexture((GRContext)skia.GlContext.GRContext, backendTexture, GRSurfaceOrigin.BottomLeft, SKColorType.Rgba8888);
}
_gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, Id);
var vp = new float[4];
_gl.GetFloatv(GlConsts.GL_VIEWPORT, vp);
_gl.Viewport(0, 0, (int)size.Width, (int)size.Height);
OnGLRender(_gl);
_gl.Viewport((int)vp[0], (int)vp[1], (int)vp[2], (int)vp[3]);
_gl.BindFramebuffer(GlConsts.GL_FRAMEBUFFER, 0);
//_gl.Flush();
skia.SKCanvas.DrawImage(image, new SKRect(0, 0, size.Width, size.Height), new SKRect(0, 0, cSize.Width, cSize.Height), paint);
}
protected virtual void OnGLRender(IGlContext gl)
{
this.RaiseEvent(new GLEventArgs(gl), nameof(GLRender));
}
protected virtual void OnGLLoaded(IGlContext gl)
{
this.RaiseEvent(new GLEventArgs(gl), nameof(GLLoaded));
}
public event EventHandler<GLEventArgs> GLLoaded
{
add { AddHandler(value); }
remove { RemoveHandler(value); }
}
public event EventHandler<GLEventArgs> GLRender
{
add { AddHandler(value); }
remove { RemoveHandler(value); }
}
protected override void Dispose(bool disposing)
{
if (Id != 0)
{
OpenglEx.DeleteFramebuffers(null, 1, new int[] { Id });
OpenglEx.DeleteTextures(null, 1, new int[] { ColorBuffer });
OpenglEx.DeleteRenderbuffers(null, 1, new int[] { DepthRenderBuffer });
Id = 0;
}
if (image != null)
{
image.Dispose();
image = null;
}
if (paint != null)
{
paint.Dispose();
paint = null;
}
if (backendTexture != null)
{
backendTexture.Dispose();
backendTexture = null;
}
base.Dispose(disposing);
}
}
public class GLEventArgs : EventArgs
{
public GLEventArgs(IGlContext gl)
{
Context = gl;
}
public IGlContext Context { get; private set; }
}
}