Explorar o código

Implemented GlControlBase

Nikita Tsukanov %!s(int64=5) %!d(string=hai) anos
pai
achega
021995ed35

+ 3 - 1
samples/ControlCatalog/ControlCatalog.csproj

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

+ 1 - 0
samples/ControlCatalog/MainView.xaml

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

+ 18 - 0
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 - 0
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=BIN
samples/ControlCatalog/Pages/teapot.bin


+ 1 - 1
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; }
         public GlInterface GlInterface { get; }
 
 

+ 2 - 2
src/Avalonia.OpenGL/EglDisplay.cs

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

+ 3 - 3
src/Avalonia.OpenGL/GlDisplayType.cs

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

+ 7 - 2
src/Avalonia.OpenGL/GlEntryPointAttribute.cs

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

+ 212 - 0
src/Avalonia.OpenGL/GlInterface.cs

@@ -1,6 +1,8 @@
 using System;
 using System;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices;
+using System.Text;
 using Avalonia.Platform.Interop;
 using Avalonia.Platform.Interop;
+using static Avalonia.OpenGL.GlConsts;
 
 
 namespace Avalonia.OpenGL
 namespace Avalonia.OpenGL
 {
 {
@@ -74,6 +76,10 @@ namespace Avalonia.OpenGL
         [GlEntryPoint("glGenFramebuffers")]
         [GlEntryPoint("glGenFramebuffers")]
         public GlGenFramebuffers GenFramebuffers { get; }
         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);
         public delegate void GlBindFramebuffer(int target, int fb);
         [GlEntryPoint("glBindFramebuffer")]
         [GlEntryPoint("glBindFramebuffer")]
         public GlBindFramebuffer BindFramebuffer { get; }
         public GlBindFramebuffer BindFramebuffer { get; }
@@ -106,6 +112,11 @@ namespace Avalonia.OpenGL
         public delegate void GlBindTexture(int target, int fb);
         public delegate void GlBindTexture(int target, int fb);
         [GlEntryPoint("glBindTexture")]
         [GlEntryPoint("glBindTexture")]
         public GlBindTexture BindTexture { get; }
         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,
         public delegate void GlTexImage2D(int target, int level, int internalFormat, int width, int height, int border,
             int format, int type, IntPtr data);
             int format, int type, IntPtr data);
@@ -125,6 +136,207 @@ namespace Avalonia.OpenGL
         [GlEntryPoint("glDrawBuffers")]
         [GlEntryPoint("glDrawBuffers")]
         public GlDrawBuffers DrawBuffers { get; }
         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
         // ReSharper restore UnassignedGetOnlyAutoProperty
     }
     }
 }
 }

+ 16 - 1
src/Avalonia.OpenGL/GlInterfaceBase.cs

@@ -22,7 +22,22 @@ namespace Avalonia.OpenGL
                         BindingFlags.Instance | BindingFlags.NonPublic);
                         BindingFlags.Instance | BindingFlags.NonPublic);
                     if (field == null)
                     if (field == null)
                         throw new InvalidProgramException($"Expected property {prop.Name} to have {fieldName}");
                         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)
                     if (proc != IntPtr.Zero)
                         field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType));
                         field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType));
                 }
                 }

+ 149 - 0
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);
+    }
+}

+ 1 - 1
src/Avalonia.X11/Glx/GlxDisplay.cs

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

+ 1 - 1
src/Skia/Avalonia.Skia/Gpu/OpenGl/GlSkiaGpu.cs

@@ -16,7 +16,7 @@ namespace Avalonia.Skia
             using (immediateContext.MakeCurrent())
             using (immediateContext.MakeCurrent())
             {
             {
                 var display = gl.Display;
                 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.AssembleGlInterface((_, proc) => display.GlInterface.GetProcAddress(proc)) :
                     GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc)))
                     GRGlInterface.AssembleGlesInterface((_, proc) => display.GlInterface.GetProcAddress(proc)))
                 {
                 {