1 module evael.renderer.gl.gl_shader; 2 3 import evael.renderer.gl.gl_wrapper; 4 import evael.renderer.gl.gl_enum_converter; 5 import evael.renderer.shader; 6 import evael.renderer.enums.shader_type; 7 8 import evael.lib.memory; 9 10 public 11 { 12 import evael.renderer.shader : ShaderAttribute; 13 } 14 15 class GLShader : Shader 16 { 17 private uint m_programId; 18 private uint m_vertexShaderId; 19 private uint m_fragmentShaderId; 20 private uint m_geometryShaderId; 21 22 /** 23 * GLShader constructor. 24 */ 25 @nogc 26 public this(in uint programId, in uint vertexShaderId, in uint fragmentShaderId) 27 { 28 super(); 29 30 this.m_programId = programId; 31 this.m_vertexShaderId = vertexShaderId; 32 this.m_fragmentShaderId = fragmentShaderId; 33 } 34 35 /** 36 * GLShader destructor. 37 */ 38 @nogc 39 public ~this() 40 { 41 this.dispose(); 42 } 43 44 // TODO: remove this when IAsset is cleaned. 45 @nogc 46 public void dispose() 47 { 48 gl.DeleteShader(this.m_vertexShaderId); 49 gl.DeleteShader(this.m_fragmentShaderId); 50 51 if (this.m_geometryShaderId) 52 { 53 gl.DeleteShader(this.m_geometryShaderId); 54 } 55 } 56 57 /** 58 * Returns location of an uniform variable. 59 * Params: 60 * uniformName : uniform variable to retrieve 61 */ 62 @nogc 63 public int getUniformLocation(in string uniformName) const 64 { 65 return gl.GetUniformLocation(this.m_programId, cast(char*) uniformName.ptr); 66 } 67 68 /** 69 * Loads a shader from file. 70 * Params: 71 * fileName : shader to load 72 */ 73 public static GLShader load(in string fileName) 74 { 75 import std.file : readText; 76 77 return GLShader.load(readText(fileName ~ ".vert"), readText(fileName ~ ".frag")); 78 } 79 80 81 /** 82 * Loads a shader from source. 83 * Params: 84 * vs : vertex shader 85 * fs : fragment shader 86 */ 87 public static GLShader load(in string vs, in string fs) 88 { 89 immutable uint programId = gl.CreateProgram(); 90 91 immutable uint vertexShaderId = GLShader.compileShader(vs, ShaderType.Vertex); 92 immutable uint fragmentShaderId = GLShader.compileShader(fs, ShaderType.Fragment); 93 94 gl.AttachShader(programId, vertexShaderId); 95 gl.AttachShader(programId, fragmentShaderId); 96 97 gl.LinkProgram(programId); 98 99 auto shader = MemoryHelper.create!GLShader(programId, vertexShaderId, fragmentShaderId); 100 101 return shader; 102 } 103 104 /** 105 * Compiles a shader from a source. 106 * Params: 107 * type : shader type 108 */ 109 private static uint compileShader(in string sourceCode, in ShaderType type) 110 { 111 import std..string : format; 112 import std.exception : enforce; 113 114 immutable uint shader = gl.CreateShader(GLEnumConverter.shaderType(type)); 115 116 assert(sourceCode.length); 117 118 char* source = cast(char*) sourceCode.ptr; 119 120 // Shader compilation 121 gl.ShaderSource(shader, 1, &source, [cast(int) sourceCode.length].ptr); 122 gl.CompileShader(shader); 123 124 int compilationStatus; 125 gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compilationStatus); 126 127 // We check for compilation errors 128 if (compilationStatus == false) 129 { 130 // Compilation failed, we retrieve error logs 131 gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &compilationStatus); 132 133 char[] errors = new char[compilationStatus]; 134 135 gl.GetShaderInfoLog(shader, compilationStatus, &compilationStatus, errors.ptr); 136 137 throw new Exception("Shader %s can't be compiled :\n %s.".format(sourceCode, errors)); 138 } 139 140 return shader; 141 } 142 143 @nogc 144 @property nothrow 145 { 146 public uint programId() const 147 { 148 return this.m_programId; 149 } 150 } 151 } 152