//----------------------------------------------------------------------- //----------------------------------------------------------------------- // file="Shader.cs" // Project: StgSharp // AuthorGroup: Nitload Space // Copyright (c) Nitload Space. All rights reserved. // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the “Software”), to deal in the Software without restriction, // including without limitation the rights to use, copy, modify, merge, // publish, distribute, sublicense, and/or sell copies of the Software, // and to permit persons to whom the Software is furnished to do so, // subject to the following conditions: // // The above copyright notice and // this permission notice shall be included in all copies // or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED “AS IS”, // WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH // THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //----------------------------------------------------------------------- //----------------------------------------------------------------------- using StgSharp; using StgSharp.Data; using System; using System.Collections.Generic; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using System.Xml.Linq; namespace StgSharp.Graphics.GL { public abstract partial class glRenderStream : RenderStream { [MethodImpl(MethodImplOptions.AggressiveInlining)] protected sealed override Shader CreateShaderSegment(ShaderType type, int count) { return new Shader( glFunc.CreateShaderSet(count, type), type); } /// /// Create an instance of program /// /// New instance of instance. [MethodImpl(MethodImplOptions.AggressiveInlining)] protected sealed override ShaderProgram CreateShaderProgram() { return new ShaderProgram(this); } } public class Shader : SSDSerializable { private readonly IntPtr context; internal readonly glHandleSet handle; public readonly ShaderType type; public override SerializableTypeCode SSDTypeCode => SerializableTypeCode.Shader; internal unsafe Shader(glHandleSet handle, ShaderType usage) { this.handle = handle; context = glFunc.CurrentContextHandle; type = usage; } /// /// Attach one shader code to a shader program. /// /// Shader program to attach /// Index of shader code in current shader code set. [MethodImpl(MethodImplOptions.AggressiveInlining)] public void AttachTo(int index, ShaderProgram target) { glFunc.AttachShader(target.handle, handle[index]); } public static byte[] FromCodeFile(string fileRoute) { string str = File.ReadAllText(fileRoute); if (string.IsNullOrEmpty(str)) { throw new InvalidOperationException($"Cannot load and GLSL code from {fileRoute}"); } return Encoding.UTF8.GetBytes(str); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void Compile(int index, byte[] codeStream) { if (codeStream == null) { throw new ArgumentNullException(nameof(codeStream)); } glFunc.LoadShaderSource(handle[index], codeStream); glFunc.CompileShader(handle[index]); CheckStatus(index,ShaderStatus.CompileStatus); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void Compile(int index, string codeStream) { if (codeStream == null) { throw new ArgumentNullException(nameof(codeStream)); } glFunc.LoadShaderSource(handle[index],Encoding.ASCII.GetBytes( codeStream)); glFunc.CompileShader(handle[index]); CheckStatus(index, ShaderStatus.CompileStatus); } public override string ToString() { return $"This is a {type} shader, its shader handles are {handle.ToString()}."; } //TODO shader 的序列化究极麻烦,原因是shader的架构问题 public override byte[] GetBytes() { throw new NotImplementedException(); } public void CheckStatus(int index, ShaderStatus status) { string log = glFunc.GetShaderStatus(this,index, (int)status); if (log != "") { throw new Exception($"Shader Error\n{status}\n" + log); } } public override byte[] GetBytes(out int length) { throw new NotImplementedException(); } internal override void BuildFromByteStream(byte[] stream) { throw new NotImplementedException(); } } public enum ShaderStatus : int { CompileStatus = GLconst.COMPILE_STATUS, } public class ShaderProgram { private readonly IntPtr binding; internal readonly glHandle handle; /// /// Init a program with no shader attached. /// internal unsafe ShaderProgram(glRenderStream binding) { this.binding = binding.ContextHandle; handle = glFunc.CreateProgram(); } /// /// Get a uniform form current shader, /// the value type of the uniform should be provided. /// /// Name of the Uniform in shader code /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe Uniform GetUniform(string name) where T : struct { return new Uniform(this, name, binding); } /// /// Get a uniform form current shader, /// the value type of the uniform should be provided. /// /// Name of the Uniform in shader code /// public unsafe Uniform GetUniform(string name) where T : struct where U : struct { return new Uniform(this, name, binding); } /// /// Get a uniform form current shader, /// the value type of the uniform should be provided. /// /// Name of the Uniform in shader code /// public unsafe Uniform GetUniform(string name) where T : struct where U : struct where V : struct { return new Uniform(this, name); } /// /// Get a uniform form current shader, /// the value type of the uniform should be provided. /// /// Name of the Uniform in shader code /// public unsafe Uniform GetUniform(string name) where T : struct where U : struct where V : struct where W : struct { return new Uniform(this, name); } /// /// Link the shader to current context. /// public unsafe void Link() { if (InternalIO.InternalLinkShaderProgram((GLcontext*)this.binding, handle.Value) == 0) { IntPtr logPtr = InternalIO.InternalReadSSCLog(); try { byte[] logByte = new byte[512]; Marshal.Copy(logPtr, logByte, 0, 512); string log = Encoding.UTF8.GetString(logByte); log = log.Replace("\0", string.Empty); InternalIO.InternalWriteLog(log, LogType.Error); } catch (Exception ex) { InternalIO.InternalWriteLog(ex.Message, LogType.Error); } } } /// /// Let the current context use this shader. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void Use() { glFunc.UseProgram(handle); } ~ShaderProgram() { //handle.Dispose(); } } }