Browse Source

Implemented GlControlBase

pull/3386/head
Nikita Tsukanov 7 years ago
parent
commit
021995ed35
  1. 4
      samples/ControlCatalog/ControlCatalog.csproj
  2. 1
      samples/ControlCatalog/MainView.xaml
  3. 18
      samples/ControlCatalog/Pages/OpenGlPage.xaml
  4. 288
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  5. BIN
      samples/ControlCatalog/Pages/teapot.bin
  6. 2
      src/Avalonia.Native/GlPlatformFeature.cs
  7. 4
      src/Avalonia.OpenGL/EglDisplay.cs
  8. 6
      src/Avalonia.OpenGL/GlDisplayType.cs
  9. 9
      src/Avalonia.OpenGL/GlEntryPointAttribute.cs
  10. 212
      src/Avalonia.OpenGL/GlInterface.cs
  11. 17
      src/Avalonia.OpenGL/GlInterfaceBase.cs
  12. 149
      src/Avalonia.OpenGL/OpenGlControlBase.cs
  13. 2
      src/Avalonia.X11/Glx/GlxDisplay.cs
  14. 2
      src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

4
samples/ControlCatalog/ControlCatalog.csproj

@ -1,6 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>netstandard2.0</TargetFramework>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup>
<ItemGroup>
<Compile Update="**\*.xaml.cs">
@ -17,6 +18,7 @@
<EmbeddedResource Include="Assets\Fonts\SourceSansPro-BoldItalic.ttf" />
<EmbeddedResource Include="Assets\Fonts\SourceSansPro-Italic.ttf" />
<EmbeddedResource Include="Assets\Fonts\SourceSansPro-Regular.ttf" />
<EmbeddedResource Include="Pages\teapot.bin" />
</ItemGroup>
<ItemGroup>

1
samples/ControlCatalog/MainView.xaml

@ -14,6 +14,7 @@
</Style>
</Grid.Styles>
<TabControl Classes="sidebar" Name="Sidebar">
<TabItem Header="OpenGL"><pages:OpenGlPage/></TabItem>
<TabItem Header="AutoCompleteBox"><pages:AutoCompleteBoxPage/></TabItem>
<TabItem Header="Border"><pages:BorderPage/></TabItem>
<TabItem Header="Button"><pages:ButtonPage/></TabItem>

18
samples/ControlCatalog/Pages/OpenGlPage.xaml

@ -0,0 +1,18 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.OpenGlPage"
xmlns:pages="clr-namespace:ControlCatalog.Pages">
<Grid>
<pages:OpenGlPageControl x:Name="GL"/>
<Grid ColumnDefinitions="*,Auto" Margin="20">
<StackPanel Grid.Column="1" MinWidth="300">
<TextBlock>Yaw</TextBlock>
<Slider Value="{Binding Yaw, Mode=TwoWay, ElementName=GL}" Maximum="10"/>
<TextBlock>Pitch</TextBlock>
<Slider Value="{Binding Pitch, Mode=TwoWay, ElementName=GL}" Maximum="10"/>
<TextBlock>Roll</TextBlock>
<Slider Value="{Binding Roll, Mode=TwoWay, ElementName=GL}" Maximum="10"/>
</StackPanel>
</Grid>
</Grid>
</UserControl>

288
samples/ControlCatalog/Pages/OpenGlPage.xaml.cs

@ -0,0 +1,288 @@
using System;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using Avalonia;
using Avalonia.Controls;
using Avalonia.OpenGL;
using static Avalonia.OpenGL.GlConsts;
// ReSharper disable StringLiteralTypo
namespace ControlCatalog.Pages
{
public class OpenGlPage : UserControl
{
}
public class OpenGlPageControl : OpenGlControlBase
{
private float _yaw;
public static readonly DirectProperty<OpenGlPageControl, float> YawProperty =
AvaloniaProperty.RegisterDirect<OpenGlPageControl, float>("Yaw", o => o.Yaw, (o, v) => o.Yaw = v);
public float Yaw
{
get => _yaw;
set => SetAndRaise(YawProperty, ref _yaw, value);
}
private float _pitch;
public static readonly DirectProperty<OpenGlPageControl, float> PitchProperty =
AvaloniaProperty.RegisterDirect<OpenGlPageControl, float>("Pitch", o => o.Pitch, (o, v) => o.Pitch = v);
public float Pitch
{
get => _pitch;
set => SetAndRaise(PitchProperty, ref _pitch, value);
}
private float _roll;
public static readonly DirectProperty<OpenGlPageControl, float> RollProperty =
AvaloniaProperty.RegisterDirect<OpenGlPageControl, float>("Roll", o => o.Roll, (o, v) => o.Roll = v);
public float Roll
{
get => _roll;
set => SetAndRaise(RollProperty, ref _roll, value);
}
static OpenGlPageControl()
{
AffectsRender<OpenGlPageControl>(YawProperty, PitchProperty, RollProperty);
}
private int _vertexShader;
private int _fragmentShader;
private int _shaderProgram;
private int _vertexBufferObject;
private int _indexBufferObject;
private int _vertexArrayObject;
private string WithVersion(string shader) =>
$"#version {(DisplayType == GlDisplayType.OpenGl ? 120 : 100)}\n" + shader;
private string WithVersionAndPrecision(string shader, string precision) =>
WithVersion(DisplayType == GlDisplayType.OpenGLES ? $"precision {precision}\n{shader}" : shader);
private string VertexShaderSource => WithVersion(@"
attribute vec3 aPos;
attribute vec3 aNormal;
uniform mat4 uModel;
uniform mat4 uProjection;
uniform mat4 uView;
varying vec3 FragPos;
varying vec3 VecPos;
varying vec3 Normal;
void main()
{
gl_Position = uProjection * uView * uModel * vec4(aPos, 1.0);
FragPos = vec3(uModel * vec4(aPos, 1.0));
VecPos = aPos;
Normal = normalize(vec3(uModel * vec4(aNormal, 1.0)));
}
");
private string FragmentShaderSource => WithVersionAndPrecision(@"
varying vec3 FragPos;
varying vec3 VecPos;
varying vec3 Normal;
uniform float uMaxY;
uniform float uMinY;
void main()
{
float y = (VecPos.y - uMinY) / (uMaxY - uMinY);
vec3 objectColor = vec3((1 - y), 0.40 + y / 4, y * 0.75+0.25);
//vec3 objectColor = normalize(FragPos);
float ambientStrength = 0.3;
vec3 lightColor = vec3(1.0, 1.0, 1.0);
vec3 lightPos = vec3(uMaxY * 2, uMaxY * 2, uMaxY * 2);
vec3 ambient = ambientStrength * lightColor;
vec3 norm = normalize(Normal);
vec3 lightDir = normalize(lightPos - FragPos);
float diff = max(dot(norm, lightDir), 0.0);
vec3 diffuse = diff * lightColor;
vec3 result = (ambient + diffuse) * objectColor;
gl_FragColor = vec4(result, 1.0);
}
", "mediump float");
[StructLayout(LayoutKind.Sequential, Pack = 4)]
private struct Vertex
{
public Vector3 Position;
public Vector3 Normal;
}
private readonly Vertex[] _points;
private readonly ushort[] _indices;
private readonly float _minY;
private readonly float _maxY;
public OpenGlPageControl()
{
var name = typeof(OpenGlPage).Assembly.GetManifestResourceNames().First(x => x.Contains("teapot.bin"));
using (var sr = new BinaryReader(typeof(OpenGlPage).Assembly.GetManifestResourceStream(name)))
{
var buf = new byte[sr.ReadInt32()];
sr.Read(buf, 0, buf.Length);
var points = new float[buf.Length / 4];
Buffer.BlockCopy(buf, 0, points, 0, buf.Length);
buf = new byte[sr.ReadInt32()];
sr.Read(buf, 0, buf.Length);
_indices = new ushort[buf.Length / 2];
Buffer.BlockCopy(buf, 0, _indices, 0, buf.Length);
_points = new Vertex[points.Length / 3];
for (var primitive = 0; primitive < points.Length / 3; primitive++)
{
var srci = primitive * 3;
_points[primitive] = new Vertex
{
Position = new Vector3(points[srci], points[srci + 1], points[srci + 2])
};
}
for (int i = 0; i < _indices.Length; i += 3)
{
Vector3 a = _points[_indices[i]].Position;
Vector3 b = _points[_indices[i + 1]].Position;
Vector3 c = _points[_indices[i + 2]].Position;
var normal = Vector3.Normalize(Vector3.Cross(c - b, a - b));
_points[_indices[i]].Normal += normal;
_points[_indices[i + 1]].Normal += normal;
_points[_indices[i + 2]].Normal += normal;
}
for (int i = 0; i < _points.Length; i++)
{
_points[i].Normal = Vector3.Normalize(_points[i].Normal);
_maxY = Math.Max(_maxY, _points[i].Position.Y);
_minY = Math.Min(_minY, _points[i].Position.Y);
}
}
}
private void CheckError(GlInterface gl)
{
int err;
while ((err = gl.GetError()) != GL_NO_ERROR)
Console.WriteLine(err);
}
protected unsafe override void OnOpenGlInit(GlInterface GL, int fb)
{
// Load the source of the vertex shader and compile it.
_vertexShader = GL.CreateShader(GL_VERTEX_SHADER);
Console.WriteLine(GL.CompileShaderAndGetError(_vertexShader, VertexShaderSource));
// Load the source of the fragment shader and compile it.
_fragmentShader = GL.CreateShader(GL_FRAGMENT_SHADER);
Console.WriteLine(GL.CompileShaderAndGetError(_fragmentShader, FragmentShaderSource));
// Create the shader program, attach the vertex and fragment shaders and link the program.
_shaderProgram = GL.CreateProgram();
GL.AttachShader(_shaderProgram, _vertexShader);
GL.AttachShader(_shaderProgram, _fragmentShader);
const int positionLocation = 0;
const int normalLocation = 1;
GL.BindAttribLocationString(_shaderProgram, positionLocation, "aPos");
GL.BindAttribLocationString(_shaderProgram, normalLocation, "aNormal");
Console.WriteLine(GL.LinkProgramAndGetError(_shaderProgram));
CheckError(GL);
// Create the vertex buffer object (VBO) for the vertex data.
_vertexBufferObject = GL.GenBuffer();
// Bind the VBO and copy the vertex data into it.
GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject);
var vertexSize = Marshal.SizeOf<Vertex>();
fixed (void* pdata = _points)
GL.BufferData(GL_ARRAY_BUFFER, new IntPtr(_points.Length * vertexSize),
new IntPtr(pdata), GL_STATIC_DRAW);
_indexBufferObject = GL.GenBuffer();
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject);
fixed (void* pdata = _indices)
GL.BufferData(GL_ELEMENT_ARRAY_BUFFER, new IntPtr(_indices.Length * sizeof(ushort)), new IntPtr(pdata),
GL_STATIC_DRAW);
_vertexArrayObject = GL.GenVertexArray();
GL.BindVertexArray(_vertexArrayObject);
GL.VertexAttribPointer(positionLocation, 3, GL_FLOAT,
0, vertexSize, IntPtr.Zero);
GL.VertexAttribPointer(normalLocation, 3, GL_FLOAT,
0, vertexSize, new IntPtr(12));
GL.EnableVertexAttribArray(positionLocation);
GL.EnableVertexAttribArray(normalLocation);
CheckError(GL);
}
protected override void OnOpenGlDeinit(GlInterface GL, int fb)
{
// Unbind everything
GL.BindBuffer(GL_ARRAY_BUFFER, 0);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
GL.BindVertexArray(0);
GL.UseProgram(0);
// Delete all resources.
GL.DeleteBuffer(_vertexBufferObject);
GL.DeleteBuffer(_indexBufferObject);
GL.DeleteVertexArray(_vertexArrayObject);
GL.DeleteProgram(_shaderProgram);
GL.DeleteShader(_fragmentShader);
GL.DeleteShader(_vertexShader);
}
protected override unsafe void OnOpenGlRender(GlInterface gl, int fb)
{
gl.ClearColor(0, 0, 0, 0);
gl.Clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
gl.Enable(GL_DEPTH_TEST);
gl.Viewport(0, 0, (int)Bounds.Width, (int)Bounds.Height);
var GL = gl;
GL.BindBuffer(GL_ARRAY_BUFFER, _vertexBufferObject);
GL.BindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBufferObject);
GL.BindVertexArray(_vertexArrayObject);
GL.UseProgram(_shaderProgram);
var projection =
Matrix4x4.CreatePerspectiveFieldOfView((float)(Math.PI / 4), (float)(Bounds.Width / Bounds.Height),
0.01f, 1000);
var view = Matrix4x4.CreateLookAt(new Vector3(25, 25, 25), new Vector3(), new Vector3(0, -1, 0));
var model = Matrix4x4.CreateFromYawPitchRoll(_yaw, _pitch, _roll);
var modelLoc = GL.GetUniformLocationString(_shaderProgram, "uModel");
var viewLoc = GL.GetUniformLocationString(_shaderProgram, "uView");
var projectionLoc = GL.GetUniformLocationString(_shaderProgram, "uProjection");
var maxYLoc = GL.GetUniformLocationString(_shaderProgram, "uMaxY");
var minYLoc = GL.GetUniformLocationString(_shaderProgram, "uMinY");
GL.UniformMatrix4fv(modelLoc, 1, false, &model);
GL.UniformMatrix4fv(viewLoc, 1, false, &view);
GL.UniformMatrix4fv(projectionLoc, 1, false, &projection);
GL.Uniform1f(maxYLoc, _maxY);
GL.Uniform1f(minYLoc, _minY);
GL.DrawElements(GL_TRIANGLES, _indices.Length, GL_UNSIGNED_SHORT, IntPtr.Zero);
CheckError(GL);
}
}
}

BIN
samples/ControlCatalog/Pages/teapot.bin

Binary file not shown.

2
src/Avalonia.Native/GlPlatformFeature.cs

@ -49,7 +49,7 @@ namespace Avalonia.Native
});
}
public GlDisplayType Type => GlDisplayType.OpenGL2;
public GlDisplayType Type => GlDisplayType.OpenGl;
public GlInterface GlInterface { get; }

4
src/Avalonia.OpenGL/EglDisplay.cs

@ -81,7 +81,7 @@ namespace Avalonia.OpenGL
Attributes = new[] {EGL_NONE},
Api = EGL_OPENGL_API,
RenderableTypeBit = EGL_OPENGL_BIT,
Type = GlDisplayType.OpenGL2
Type = GlDisplayType.OpenGl
},
new
{
@ -92,7 +92,7 @@ namespace Avalonia.OpenGL
},
Api = EGL_OPENGL_ES_API,
RenderableTypeBit = EGL_OPENGL_ES2_BIT,
Type = GlDisplayType.OpenGLES2
Type = GlDisplayType.OpenGLES
}
})
{

6
src/Avalonia.OpenGL/GlDisplayType.cs

@ -2,7 +2,7 @@ namespace Avalonia.OpenGL
{
public enum GlDisplayType
{
OpenGL2,
OpenGLES2
OpenGl,
OpenGLES
}
}
}

9
src/Avalonia.OpenGL/GlEntryPointAttribute.cs

@ -5,13 +5,18 @@ namespace Avalonia.OpenGL
[AttributeUsage(AttributeTargets.Property)]
public class GlEntryPointAttribute : Attribute
{
public string EntryPoint { get; }
public string[] EntryPoints { get; }
public bool Optional { get; }
public GlEntryPointAttribute(string entryPoint, bool optional = false)
{
EntryPoint = entryPoint;
EntryPoints = new []{entryPoint};
Optional = optional;
}
public GlEntryPointAttribute(params string[] entryPoints)
{
EntryPoints = entryPoints;
}
}
}

212
src/Avalonia.OpenGL/GlInterface.cs

@ -1,6 +1,8 @@
using System;
using System.Runtime.InteropServices;
using System.Text;
using Avalonia.Platform.Interop;
using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.OpenGL
{
@ -74,6 +76,10 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glGenFramebuffers")]
public GlGenFramebuffers GenFramebuffers { get; }
public delegate void GlDeleteFramebuffers(int count, int[] framebuffers);
[GlEntryPoint("glDeleteFramebuffers")]
public GlDeleteFramebuffers DeleteFramebuffers { get; }
public delegate void GlBindFramebuffer(int target, int fb);
[GlEntryPoint("glBindFramebuffer")]
public GlBindFramebuffer BindFramebuffer { get; }
@ -106,6 +112,11 @@ namespace Avalonia.OpenGL
public delegate void GlBindTexture(int target, int fb);
[GlEntryPoint("glBindTexture")]
public GlBindTexture BindTexture { get; }
public delegate void GlDeleteTextures(int count, int[] textures);
[GlEntryPoint("glDeleteTextures")]
public GlDeleteTextures DeleteTextures { get; }
public delegate void GlTexImage2D(int target, int level, int internalFormat, int width, int height, int border,
int format, int type, IntPtr data);
@ -125,6 +136,207 @@ namespace Avalonia.OpenGL
[GlEntryPoint("glDrawBuffers")]
public GlDrawBuffers DrawBuffers { get; }
public delegate int GlCreateShader(int shaderType);
[GlEntryPoint("glCreateShader")]
public GlCreateShader CreateShader { get; }
public delegate void GlShaderSource(int shader, int count, IntPtr strings, IntPtr lengths);
[GlEntryPoint("glShaderSource")]
public GlShaderSource ShaderSource { get; }
public void ShaderSourceString(int shader, string source)
{
using (var b = new Utf8Buffer(source))
{
var ptr = b.DangerousGetHandle();
var len = new IntPtr(b.ByteLen);
ShaderSource(shader, 1, new IntPtr(&ptr), new IntPtr(&len));
}
}
public delegate void GlCompileShader(int shader);
[GlEntryPoint("glCompileShader")]
public GlCompileShader CompileShader { get; }
public delegate void GlGetShaderiv(int shader, int name, int* parameters);
[GlEntryPoint("glGetShaderiv")]
public GlGetShaderiv GetShaderiv { get; }
public delegate void GlGetShaderInfoLog(int shader, int maxLength, out int length, void*infoLog);
[GlEntryPoint("glGetShaderInfoLog")]
public GlGetShaderInfoLog GetShaderInfoLog { get; }
public unsafe string CompileShaderAndGetError(int shader, string source)
{
ShaderSourceString(shader, source);
CompileShader(shader);
int compiled;
GetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
if (compiled != 0)
return null;
int logLength;
GetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
if (logLength == 0)
logLength = 4096;
var logData = new byte[logLength];
int len;
fixed (void* ptr = logData)
GetShaderInfoLog(shader, logLength, out len, ptr);
return Encoding.UTF8.GetString(logData,0, len);
}
public delegate int GlCreateProgram();
[GlEntryPoint("glCreateProgram")]
public GlCreateProgram CreateProgram { get; }
public delegate void GlAttachShader(int program, int shader);
[GlEntryPoint("glAttachShader")]
public GlAttachShader AttachShader { get; }
public delegate void GlLinkProgram(int program);
[GlEntryPoint("glLinkProgram")]
public GlLinkProgram LinkProgram { get; }
public delegate void GlGetProgramiv(int program, int name, int* parameters);
[GlEntryPoint("glGetProgramiv")]
public GlGetProgramiv GetProgramiv { get; }
public delegate void GlGetProgramInfoLog(int program, int maxLength, out int len, void* infoLog);
[GlEntryPoint("glGetProgramInfoLog")]
public GlGetProgramInfoLog GetProgramInfoLog { get; }
public unsafe string LinkProgramAndGetError(int program)
{
LinkProgram(program);
int compiled;
GetProgramiv(program, GL_LINK_STATUS, &compiled);
if (compiled != 0)
return null;
int logLength;
GetProgramiv(program, GL_INFO_LOG_LENGTH, &logLength);
var logData = new byte[logLength];
int len;
fixed (void* ptr = logData)
GetProgramInfoLog(program, logLength, out len, ptr);
return Encoding.UTF8.GetString(logData,0, len);
}
public delegate void GlBindAttribLocation(int program, int index, IntPtr name);
[GlEntryPoint("glBindAttribLocation")]
public GlBindAttribLocation BindAttribLocation { get; }
public void BindAttribLocationString(int program, int index, string name)
{
using (var b = new Utf8Buffer(name))
BindAttribLocation(program, index, b.DangerousGetHandle());
}
public delegate void GlGenBuffers(int len, int[] rv);
[GlEntryPoint("glGenBuffers")]
public GlGenBuffers GenBuffers { get; }
public int GenBuffer()
{
var rv = new int[1];
GenBuffers(1, rv);
return rv[0];
}
public delegate void GlBindBuffer(int target, int buffer);
[GlEntryPoint("glBindBuffer")]
public GlBindBuffer BindBuffer { get; }
public delegate void GlBufferData(int target, IntPtr size, IntPtr data, int usage);
[GlEntryPoint("glBufferData")]
public GlBufferData BufferData { get; }
public delegate int GlGetAttribLocation(int program, IntPtr name);
[GlEntryPoint("glGetAttribLocation")]
public GlGetAttribLocation GetAttribLocation { get; }
public int GetAttribLocationString(int program, string name)
{
using (var b = new Utf8Buffer(name))
return GetAttribLocation(program, b.DangerousGetHandle());
}
public delegate void GlVertexAttribPointer(int index, int size, int type,
int normalized, int stride, IntPtr pointer);
[GlEntryPoint("glVertexAttribPointer")]
public GlVertexAttribPointer VertexAttribPointer { get; }
public delegate void GlEnableVertexAttribArray(int index);
[GlEntryPoint("glEnableVertexAttribArray")]
public GlEnableVertexAttribArray EnableVertexAttribArray { get; }
public delegate void GlUseProgram(int program);
[GlEntryPoint("glUseProgram")]
public GlUseProgram UseProgram { get; }
public delegate void GlDrawArrays(int mode, int first, IntPtr count);
[GlEntryPoint("glDrawArrays")]
public GlDrawArrays DrawArrays { get; }
public delegate void GlDrawElements(int mode, int count, int type, IntPtr indices);
[GlEntryPoint("glDrawElements")]
public GlDrawElements DrawElements { get; }
public delegate void GlGenVertexArrays(int n, int[] rv);
[GlEntryPoint("glGenVertexArrays", "glGenVertexArraysOES")]
public GlGenVertexArrays GenVertexArrays { get; }
public int GenVertexArray()
{
var rv = new int[1];
GenVertexArrays(1, rv);
return rv[0];
}
public delegate void GlBindVertexArray(int array);
[GlEntryPoint("glBindVertexArray", "glBindVertexArrayOES")]
public GlBindVertexArray BindVertexArray { get; }
public delegate int GlGetUniformLocation(int program, IntPtr name);
[GlEntryPoint("glGetUniformLocation")]
public GlGetUniformLocation GetUniformLocation { get; }
public int GetUniformLocationString(int program, string name)
{
using (var b = new Utf8Buffer(name))
return GetUniformLocation(program, b.DangerousGetHandle());
}
public delegate void GlUniform1f(int location, float falue);
[GlEntryPoint("glUniform1f")]
public GlUniform1f Uniform1f { get; }
public delegate void GlUniformMatrix4fv(int location, int count, bool transpose, void* value);
[GlEntryPoint("glUniformMatrix4fv")]
public GlUniformMatrix4fv UniformMatrix4fv { get; }
public delegate void GlEnable(int what);
[GlEntryPoint("glEnable")]
public GlEnable Enable { get; }
public delegate void GlDeleteBuffer(int buffer);
[GlEntryPoint("glDeleteBuffer")]
public GlDeleteBuffer DeleteBuffer { get; }
public delegate void GlDeleteVertexArray(int array);
[GlEntryPoint("glDeleteVertexArray", "glDeleteVertexArrayOES")]
public GlDeleteVertexArray DeleteVertexArray { get; }
public delegate void GlDeleteProgram(int program);
[GlEntryPoint("glDeleteProgram")]
public GlDeleteProgram DeleteProgram { get; }
public delegate void GlDeleteShader(int shader);
[GlEntryPoint("glDeleteShader")]
public GlDeleteShader DeleteShader { get; }
// ReSharper restore UnassignedGetOnlyAutoProperty
}
}

17
src/Avalonia.OpenGL/GlInterfaceBase.cs

@ -22,7 +22,22 @@ namespace Avalonia.OpenGL
BindingFlags.Instance | BindingFlags.NonPublic);
if (field == null)
throw new InvalidProgramException($"Expected property {prop.Name} to have {fieldName}");
var proc = getProcAddress(a.EntryPoint, a.Optional);
IntPtr proc = IntPtr.Zero;
if (a.EntryPoints.Length == 1)
proc = getProcAddress(a.EntryPoints[0], a.Optional);
else
{
foreach (var ep in a.EntryPoints)
{
proc = getProcAddress(ep, true);
}
if (proc == IntPtr.Zero && !a.Optional)
throw new OpenGlException("Unable to resolve function by any of aliases " +
string.Join(", ", a.EntryPoints));
}
if (proc != IntPtr.Zero)
field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType));
}

149
src/Avalonia.OpenGL/OpenGlControlBase.cs

@ -0,0 +1,149 @@
using System;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.OpenGL.Imaging;
using static Avalonia.OpenGL.GlConsts;
namespace Avalonia.OpenGL
{
public abstract class OpenGlControlBase : Control
{
private IGlContext _context;
private int _fb, _texture, _renderBuffer;
private OpenGlTextureBitmap _bitmap;
private Size _oldSize;
protected GlDisplayType DisplayType { get; private set; }
public sealed override void Render(DrawingContext context)
{
if(!EnsureInitialized())
return;
using (_context.MakeCurrent())
{
using (_bitmap.Lock())
{
var gl = _context.Display.GlInterface;
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
if (_oldSize != Bounds.Size)
ResizeTexture(gl);
OnOpenGlRender(gl, _fb);
gl.Flush();
}
}
context.DrawImage(_bitmap, 1, new Rect(_bitmap.Size), Bounds);
base.Render(context);
}
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
if (_context != null)
{
using (_context.MakeCurrent())
{
OnOpenGlDeinit(_context.Display.GlInterface, _fb);
var gl = _context.Display.GlInterface;
gl.BindTexture(GL_TEXTURE_2D, 0);
gl.BindFramebuffer(GL_FRAMEBUFFER, 0);
gl.DeleteFramebuffers(1, new[] { _fb });
using (_bitmap.Lock())
{
_bitmap.SetTexture(0, 0, new PixelSize(1, 1), 1);
gl.DeleteTextures(1, new[] { _texture });
}
_bitmap.Dispose();
_context.Dispose();
_context = null;
}
}
base.OnDetachedFromVisualTree(e);
}
bool EnsureInitialized()
{
if (_context != null)
return true;
var feature = AvaloniaLocator.Current.GetService<IWindowingPlatformGlFeature>();
if (feature == null)
return false;
_context = feature.CreateContext();
DisplayType = feature.Display.Type;
try
{
_bitmap = new OpenGlTextureBitmap();
}
catch (PlatformNotSupportedException)
{
_context.Dispose();
_context = null;
return false;
}
using (_context.MakeCurrent())
{
_oldSize = Bounds.Size;
var gl = _context.Display.GlInterface;
var oneArr = new int[1];
gl.GenFramebuffers(1, oneArr);
_fb = oneArr[0];
gl.BindFramebuffer(GL_FRAMEBUFFER, _fb);
gl.GenTextures(1, oneArr);
_texture = oneArr[0];
gl.BindTexture(GL_TEXTURE_2D, _texture);
ResizeTexture(gl);
gl.FramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, _texture, 0);
gl.DrawBuffers(1, new[] { GL_COLOR_ATTACHMENT0 });
var status = gl.CheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
//TODO: Cleanup
return false;
}
OnOpenGlInit(_context.Display.GlInterface, _fb);
}
return true;
}
void ResizeTexture(GlInterface gl)
{
var size = GetPixelSize();
gl.TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
size.Width, size.Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, IntPtr.Zero);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
gl.TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
//TODO: destroy the previous one
var oneArr = new int[1];
gl.GenRenderbuffers(1, oneArr);
_renderBuffer = oneArr[0];
gl.BindRenderbuffer(GL_RENDERBUFFER, _renderBuffer);
gl.RenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, size.Width, size.Height);
gl.FramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer);
using (_bitmap.Lock())
_bitmap.SetTexture(_texture, GL_RGBA8, size, 1);
}
//TODO: dpi
PixelSize GetPixelSize() =>
new PixelSize(Math.Max(1, (int)Bounds.Width),
Math.Max(1, (int)Bounds.Height));
protected virtual void OnOpenGlInit(GlInterface gl, int fb)
{
}
protected virtual void OnOpenGlDeinit(GlInterface gl, int fb)
{
}
protected abstract void OnOpenGlRender(GlInterface gl, int fb);
}
}

2
src/Avalonia.X11/Glx/GlxDisplay.cs

@ -10,7 +10,7 @@ namespace Avalonia.X11.Glx
private readonly X11Info _x11;
private readonly IntPtr _fbconfig;
private readonly XVisualInfo* _visual;
public GlDisplayType Type => GlDisplayType.OpenGL2;
public GlDisplayType Type => GlDisplayType.OpenGl;
public GlInterface GlInterface { get; }
public XVisualInfo* VisualInfo => _visual;

2
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

@ -16,7 +16,7 @@ namespace Avalonia.Skia
using (immediateContext.MakeCurrent())
{
var display = gl.Display;
using (var iface = display.Type == GlDisplayType.OpenGL2 ?
using (var iface = display.Type == GlDisplayType.OpenGl ?
GRGlInterface.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc)) :
GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc)))
{

Loading…
Cancel
Save