using System; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using Avalonia.Platform.Interop; namespace Avalonia.OpenGL { public class GlInterfaceBase : GlInterfaceBase { public GlInterfaceBase(Func getProcAddress) : base(getProcAddress, null) { } public GlInterfaceBase(Func nativeGetProcAddress) : base(nativeGetProcAddress, null) { } } public class GlInterfaceBase { private readonly Func _getProcAddress; public GlInterfaceBase(Func getProcAddress, TContext context) { _getProcAddress = getProcAddress; foreach (var prop in this.GetType().GetProperties()) { var attrs = prop.GetCustomAttributes() .Where(a => a is IGlEntryPointAttribute || a is IGlEntryPointAttribute) .ToList(); if(attrs.Count == 0) continue; var isOptional = prop.GetCustomAttribute() != null; var fieldName = $"<{prop.Name}>k__BackingField"; var field = prop.DeclaringType.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic); if (field == null) throw new InvalidProgramException($"Expected property {prop.Name} to have {fieldName}"); IntPtr proc = IntPtr.Zero; foreach (var attr in attrs) { if (attr is IGlEntryPointAttribute typed) proc = typed.GetProcAddress(context, getProcAddress); else if (attr is IGlEntryPointAttribute untyped) proc = untyped.GetProcAddress(getProcAddress); if (proc != IntPtr.Zero) break; } if (proc != IntPtr.Zero) field.SetValue(this, Marshal.GetDelegateForFunctionPointer(proc, prop.PropertyType)); else if (!isOptional) throw new OpenGlException("Unable to find a suitable GL function for " + prop.Name); } } protected static Func ConvertNative(Func func) => (proc) => { using (var u = new Utf8Buffer(proc)) { var rv = func(u); return rv; } }; public GlInterfaceBase(Func nativeGetProcAddress, TContext context) : this(ConvertNative(nativeGetProcAddress), context) { } public IntPtr GetProcAddress(string proc) => _getProcAddress(proc); } }