internal ShaderProgram(GraphicsLibrary gl, string vertexShaderSource, string fragmentShaderSource) { program = gl.CreateProgram(); var vertexShader = CompileShader(gl, ShaderType.Vertex, vertexShaderSource); var fragmentShader = CompileShader(gl, ShaderType.Fragment, fragmentShaderSource); LinkProgram(gl); gl.DeleteShader(vertexShader); gl.DeleteShader(fragmentShader); }
internal Shader(GraphicsLibrary gl, string vertexShaderSource, string fragmentShaderSource, bool useTexture) { program = new ShaderProgram(gl, vertexShaderSource, fragmentShaderSource); program.Use(gl); ColorLocation = program.GetUniformLocation(gl, "color"); projectionLocation = program.GetUniformLocation(gl, "projection"); if (useTexture) { var sampler = program.GetUniformLocation(gl, "sampler"); program.Uniform1i(gl, sampler, 0); } }
private unsafe uint CompileShader(GraphicsLibrary gl, ShaderType type, string source) { var shader = gl.CreateShader(type); var header = GetShaderHeader(gl); var byteCount = Encoding.UTF8.GetMaxByteCount(header.Length); byteCount += Encoding.UTF8.GetMaxByteCount(source.Length); if (byteCount + 1 > byteBuffer.Length) { byteBuffer = new byte[byteCount + 1]; } byteCount = Encoding.UTF8.GetBytes(header, 0, header.Length, byteBuffer, 0); byteCount += Encoding.UTF8.GetBytes(source, 0, source.Length, byteBuffer, byteCount); byteBuffer[byteCount] = 0; fixed(byte *p = byteBuffer) { byte *t = p; gl.ShaderSource(shader, 1, &t, null); } gl.CompileShader(shader); int len; gl.GetShaderiv(shader, ShaderParameter.InfoLogLength, &len); if (len > 1) { var buffer = new byte[len]; fixed(byte *p = buffer) { gl.GetShaderInfoLog(shader, len, &len, p); Console.WriteLine("Shader Compiler message: " + Marshal.PtrToStringAnsi(new IntPtr(p))); } } int cs; gl.GetShaderiv(shader, ShaderParameter.CompileStatus, &cs); if (cs == 0) { gl.DeleteShader(shader); throw new InvalidOperationException("Shader compilation error"); } gl.AttachShader(program, shader); return(shader); }
private static unsafe string GetShaderHeader(GraphicsLibrary gl) { if (shaderHeader == null) { string?s = Marshal.PtrToStringAnsi(new IntPtr(gl.GetString(StringParameter.ShadingLanguageVersion))); if (!string.IsNullOrEmpty(s) && s.StartsWith("4.")) { shaderHeader = $"#version 4{s.Substring(2, 2)} core\n"; } else { shaderHeader = @"#version 300 es #ifdef GL_FRAGMENT_PRECISION_HIGH precision highp float; #else precision mediump float; #endif "; } } return(shaderHeader); }
internal unsafe void LinkProgram(GraphicsLibrary gl) { gl.LinkProgram(program); int ls; gl.GetProgramiv(program, ProgramParameter.LinkStatus, &ls); if (ls == 0) { int len; gl.GetProgramiv(program, ProgramParameter.InfoLogLength, &len); if (len > 1) { var buffer = new byte[len]; fixed(byte *p = buffer) { gl.GetProgramInfoLog(program, len, &len, p); Console.WriteLine("Shader link message: " + Marshal.PtrToStringAnsi(new IntPtr(p))); } } gl.DeleteProgram(program); throw new InvalidOperationException("Shader link error"); } }
internal void SetColor(GraphicsLibrary gl, float red, float green, float blue, float alpha) => program.Uniform4f(gl, ColorLocation, red, green, blue, alpha);
internal void SetColor(GraphicsLibrary gl, RgbaColor color) => program.Uniform4f(gl, ColorLocation, color.Red / 255f, color.Green / 255f, color.Blue / 255f, color.Alpha / 255f);
internal void SetProjection(GraphicsLibrary gl, Matrix4x4 projection) => program.UniformMatrix(gl, projectionLocation, projection);
internal void Use(GraphicsLibrary gl) => program.Use(gl);
internal void Delete(GraphicsLibrary gl) => program.Delete(gl);
internal void Uniform4f(GraphicsLibrary gl, int uniform, float f0, float f1, float f2, float f3) => gl.Uniform4f(uniform, f0, f1, f2, f3);
internal void Uniform1i(GraphicsLibrary gl, int uniform, int i0) => gl.Uniform1i(uniform, i0);
internal void Use(GraphicsLibrary gl) => gl.UseProgram(program);
internal void Delete(GraphicsLibrary gl) => gl.DeleteProgram(program);