1 module d2d.rendering.shaderprogram; 2 3 import d2d; 4 5 static import std.file; 6 7 /// Class for combining shaders to a bindable ShaderProgram. 8 class ShaderProgram : IVerifiable 9 { 10 /// 11 public this() 12 { 13 program = glCreateProgram(); 14 } 15 16 /// Will directly load the content from vertex and fragment and will create and return a ShaderProgram. 17 public static ShaderProgram fromVertexFragmentFiles(string vertex, string fragment) 18 { 19 Shader v = new Shader(); 20 v.load(ShaderType.Vertex, std.file.readText(vertex)); 21 22 Shader f = new Shader(); 23 f.load(ShaderType.Fragment, std.file.readText(fragment)); 24 25 ShaderProgram program = new ShaderProgram; 26 program.attach(v); 27 program.attach(f); 28 program.link(); 29 return program; 30 } 31 32 /// Attaches a new shader to the program. 33 /// Will call `shader.compile()` if necessary. 34 public void attach(Shader shader) 35 { 36 shader.compile(); 37 glAttachShader(program, shader.id); 38 } 39 40 /// Creates the program and binds it. 41 public void link() 42 { 43 glLinkProgram(program); 44 bind(); 45 } 46 47 /// Binds `this` for usage. 48 public void bind() 49 { 50 glUseProgram(program); 51 } 52 53 /// Regsiters a uniform variable in the shader for later setting. 54 public int registerUniform(string uniform) 55 { 56 if ((uniform in _properties) !is null) 57 return _properties[uniform]; 58 _properties[uniform] = glGetUniformLocation(program, uniform.toStringz()); 59 return _properties[uniform]; 60 } 61 62 /// 63 public void set(string uniform, int value) 64 { 65 debug if ((uniform in _properties) is null) 66 { 67 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 68 } 69 glUniform1i(_properties[uniform], value); 70 } 71 72 /// 73 public void set(string uniform, float value) 74 { 75 debug if ((uniform in _properties) is null) 76 { 77 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 78 } 79 glUniform1f(_properties[uniform], value); 80 } 81 82 /// 83 public void set(string uniform, vec2 value) 84 { 85 debug if ((uniform in _properties) is null) 86 { 87 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 88 } 89 glUniform2fv(_properties[uniform], 1, value.value_ptr); 90 } 91 92 /// 93 public void set(string uniform, vec3 value) 94 { 95 debug if ((uniform in _properties) is null) 96 { 97 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 98 } 99 glUniform3fv(_properties[uniform], 1, value.value_ptr); 100 } 101 102 /// 103 public void set(string uniform, vec4 value) 104 { 105 debug if ((uniform in _properties) is null) 106 { 107 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 108 } 109 glUniform4fv(_properties[uniform], 1, value.value_ptr); 110 } 111 112 /// 113 public void set(string uniform, mat2 value) 114 { 115 debug if ((uniform in _properties) is null) 116 { 117 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 118 } 119 glUniformMatrix2fv(_properties[uniform], 1, 1, value.value_ptr); 120 } 121 122 /// 123 public void set(string uniform, mat3 value) 124 { 125 debug if ((uniform in _properties) is null) 126 { 127 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 128 } 129 glUniformMatrix3fv(_properties[uniform], 1, 1, value.value_ptr); 130 } 131 132 /// 133 public void set(string uniform, mat4 value) 134 { 135 debug if ((uniform in _properties) is null) 136 { 137 throw new Exception("Uniform '" ~ uniform ~ "' is not defined!"); 138 } 139 glUniformMatrix4fv(_properties[uniform], 1, 1, value.value_ptr); 140 } 141 142 /// 143 public void opIndexAssign(T)(T value, string uniform) 144 { 145 set(uniform, value); 146 } 147 148 /// 149 public uint id() 150 { 151 return program; 152 } 153 154 /// 155 public @property bool valid() 156 { 157 return program > 0; 158 } 159 160 private uint program; 161 private int[string] _properties; 162 163 /// Regular texture shader. 164 public static ShaderProgram defaultShader; 165 166 static void load() 167 { 168 defaultShader = new ShaderProgram(); 169 Shader vertex = new Shader(); 170 vertex.load(ShaderType.Vertex, "#version 330 171 layout(location = 0) in vec3 in_position; 172 layout(location = 1) in vec2 in_tex; 173 174 uniform mat4 transform; 175 uniform mat4 projection; 176 177 out vec2 texCoord; 178 179 void main() 180 { 181 gl_Position = projection * transform * vec4(in_position, 1); 182 183 texCoord = in_tex; 184 } 185 "); 186 Shader fragment = new Shader(); 187 fragment.load(ShaderType.Fragment, "#version 330 188 uniform sampler2D tex; 189 190 in vec2 texCoord; 191 192 layout(location = 0) out vec4 out_frag_color; 193 194 void main() 195 { 196 out_frag_color = texture(tex, texCoord); 197 } 198 "); 199 defaultShader.attach(vertex); 200 defaultShader.attach(fragment); 201 defaultShader.link(); 202 defaultShader.bind(); 203 defaultShader.registerUniform("tex"); 204 defaultShader.registerUniform("transform"); 205 defaultShader.registerUniform("projection"); 206 defaultShader.set("tex", 0); 207 } 208 }