using System; using System.Runtime.CompilerServices; using Silk.NET.OpenGL; namespace gaemstone.Client; public static class GLExtensions { public static uint CreateAndCompileShader(this GL GL, ShaderType type, string label, string source) { var shader = GL.CreateShader(type); GL.ObjectLabel(ObjectIdentifier.Shader, shader, (uint)label.Length, label); GL.ShaderSource(shader, source); GL.CompileShader(shader); GL.GetShader(shader, ShaderParameterName.CompileStatus, out var result); if (result != (int)GLEnum.True) throw new Exception( $"Failed compiling shader \"{label}\" ({shader}):\n{GL.GetShaderInfoLog(shader)}"); return shader; } public static uint CreateAndLinkProgram(this GL GL, string label, params uint[] shaders) { var program = GL.CreateProgram(); GL.ObjectLabel(ObjectIdentifier.Program, program, (uint)label.Length, label); foreach (var shader in shaders) GL.AttachShader(program, shader); GL.LinkProgram(program); foreach (var shader in shaders) GL.DetachShader(program, shader); foreach (var shader in shaders) GL.DeleteShader(shader); GL.GetProgram(program, ProgramPropertyARB.LinkStatus, out var result); if (result != (int)GLEnum.True) throw new Exception( $"Failed linking Program \"{label}\" ({program}):\n{GL.GetProgramInfoLog(program)}"); return program; } // These overloads are available because without them, the implicit casting // (say from T[] to ReadOnlySpan) causes the generic type resolving to break. public static uint CreateBufferFromData(this GL GL, T[] data, BufferTargetARB target = BufferTargetARB.ArrayBuffer, BufferUsageARB usage = BufferUsageARB.StaticDraw) where T : unmanaged => GL.CreateBufferFromData((ReadOnlySpan)data, target, usage); public static uint CreateBufferFromData(this GL GL, ArraySegment data, BufferTargetARB target = BufferTargetARB.ArrayBuffer, BufferUsageARB usage = BufferUsageARB.StaticDraw) where T : unmanaged => GL.CreateBufferFromData((ReadOnlySpan)data, target, usage); public static uint CreateBufferFromData(this GL GL, Span data, BufferTargetARB target = BufferTargetARB.ArrayBuffer, BufferUsageARB usage = BufferUsageARB.StaticDraw) where T : unmanaged => GL.CreateBufferFromData((ReadOnlySpan)data, target, usage); public static uint CreateBufferFromData(this GL GL, ReadOnlySpan data, BufferTargetARB target = BufferTargetARB.ArrayBuffer, BufferUsageARB usage = BufferUsageARB.StaticDraw) where T : unmanaged { var buffer = GL.GenBuffer(); GL.BindBuffer(target, buffer); GL.BufferData(target, (nuint)(data.Length * Unsafe.SizeOf()), data, usage); return buffer; } }