1 module D2DGame.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 uint id() 144 { 145 return program; 146 } 147 148 /// 149 public @property bool valid() 150 { 151 return program > 0; 152 } 153 154 private uint program; 155 private int[string] _properties; 156 157 /// Regular texture shader. 158 public static ShaderProgram defaultShader; 159 160 static void load() 161 { 162 defaultShader = new ShaderProgram(); 163 Shader vertex = new Shader(); 164 vertex.load(ShaderType.Vertex, "#version 330 165 layout(location = 0) in vec3 in_position; 166 layout(location = 1) in vec2 in_tex; 167 168 uniform mat4 transform; 169 uniform mat4 projection; 170 171 out vec2 texCoord; 172 173 void main() 174 { 175 gl_Position = projection * transform * vec4(in_position, 1); 176 177 texCoord = in_tex; 178 } 179 "); 180 Shader fragment = new Shader(); 181 fragment.load(ShaderType.Fragment, "#version 330 182 uniform sampler2D tex; 183 184 in vec2 texCoord; 185 186 layout(location = 0) out vec4 out_frag_color; 187 188 void main() 189 { 190 out_frag_color = texture(tex, texCoord); 191 } 192 "); 193 defaultShader.attach(vertex); 194 defaultShader.attach(fragment); 195 defaultShader.link(); 196 defaultShader.bind(); 197 defaultShader.registerUniform("tex"); 198 defaultShader.registerUniform("transform"); 199 defaultShader.registerUniform("projection"); 200 defaultShader.set("tex", 0); 201 } 202 }