1 module prova.graphics.shaderprograms.shaderprogram; 2 3 import prova.graphics, 4 prova.math, 5 std.conv, 6 std.file, 7 std.stdio, 8 std..string; 9 10 /// 11 enum DrawMode : uint { 12 POINTS = 0, 13 LINES = 1, 14 LINE_LOOP = 2, 15 LINE_STRIP = 3, 16 TRIANGLES = 4, 17 TRIANGLE_STRIP = 5, 18 TRIANGLE_FAN = 6 19 } 20 21 /// 22 class ShaderProgram 23 { 24 private static uint currentId = -1; 25 private uint[] shaders; 26 private int _id; 27 28 /// 29 this() 30 { 31 _id = glCreateProgram(); 32 } 33 34 /// 35 final @property int id() 36 { 37 return _id; 38 } 39 40 private void useProgram() 41 { 42 if(currentId == _id) 43 return; 44 45 currentId = _id; 46 glUseProgram(_id); 47 } 48 49 /// 50 final uint getAttribute(string name) 51 { 52 const uint location = glGetAttribLocation(_id, toStringz(name)); 53 54 if(location == -1) 55 throw new Exception("Couldn't find attribute: " ~ name); 56 57 return location; 58 } 59 60 /// 61 final uint getUniform(string name) 62 { 63 const uint location = glGetUniformLocation(_id, toStringz(name)); 64 65 if(location == -1) 66 throw new Exception("Couldn't find uniform: " ~ name); 67 68 return location; 69 } 70 71 /// 72 final void setVector2(string name, Vector2 vector) 73 { 74 useProgram(); 75 76 const uint location = getUniform(name); 77 glUniform2f(location, vector.x, vector.y); 78 } 79 80 /// 81 final void setVector3(string name, Vector3 vector) 82 { 83 useProgram(); 84 85 const uint location = getUniform(name); 86 glUniform3f(location, vector.x, vector.y, vector.z); 87 } 88 89 /// 90 final void setVector4(string name, Vector4 vector) 91 { 92 useProgram(); 93 94 const uint location = getUniform(name); 95 glUniform4f(location, vector.x, vector.y, vector.z, vector.w); 96 } 97 98 /// 99 final void setVector4(string name, Rect rect) 100 { 101 useProgram(); 102 103 const uint location = getUniform(name); 104 glUniform4f(location, rect.left, rect.top, rect.width, rect.height); 105 } 106 107 /// 108 final void setVector4(string name, Color color) 109 { 110 useProgram(); 111 112 const uint location = getUniform(name); 113 glUniform4f(location, color.r, color.g, color.b, color.a); 114 } 115 116 /// 117 final void setMatrix(string name, Matrix matrix) 118 { 119 useProgram(); 120 121 const uint location = getUniform(name); 122 glUniformMatrix4fv(location, 1, true, matrix.array[0].ptr); 123 } 124 125 /// 126 final void setTexture(int sampler, Texture texture) 127 { 128 useProgram(); 129 130 glActiveTexture(GL_TEXTURE0 + sampler); 131 texture.bind(); 132 } 133 134 /// 135 final void setTexture(int sampler, uint texture) 136 { 137 useProgram(); 138 139 glActiveTexture(GL_TEXTURE0 + sampler); 140 Texture.bind(texture); 141 } 142 143 /// 144 final void setTexture(string name, Texture texture) 145 { 146 setTexture(name, texture.id); 147 } 148 149 /// 150 final void setTexture(string name, uint texture) 151 { 152 useProgram(); 153 154 const uint location = getUniform(name); 155 glActiveTexture(location); 156 Texture.bind(texture); 157 } 158 159 /// 160 final void drawMesh(Mesh mesh, RenderTarget target, DrawMode mode) 161 { 162 target.bindFrameBuffer(); 163 useProgram(); 164 165 glBindVertexArray(mesh.VAO); 166 glDrawElements(mode, mesh.indexCount, GL_UNSIGNED_INT, null); 167 } 168 169 /// 170 final void drawMesh(Mesh mesh, uint frameBufferId, DrawMode mode) 171 { 172 RenderTarget.bindFrameBuffer(frameBufferId); 173 useProgram(); 174 175 glBindVertexArray(mesh.VAO); 176 glDrawElements(mode, mesh.indexCount, GL_UNSIGNED_INT, null); 177 } 178 179 /// 180 final void loadVertexShader(string sourceFile) 181 { 182 loadShader(GL_VERTEX_SHADER, sourceFile); 183 } 184 185 /// 186 final void loadFragmentShader(string sourceFile) 187 { 188 loadShader(GL_FRAGMENT_SHADER, sourceFile); 189 } 190 191 /// 192 final void attachVertexShader(string source) 193 { 194 compileShader(GL_VERTEX_SHADER, source); 195 } 196 197 /// 198 final void attachFragmentShader(string source) 199 { 200 compileShader(GL_FRAGMENT_SHADER, source); 201 } 202 203 /// 204 final void link() 205 { 206 glLinkProgram(_id); 207 208 //Check for errors 209 int programSuccess; 210 glGetProgramiv(_id, GL_LINK_STATUS, &programSuccess); 211 212 if(programSuccess == true) 213 return; 214 215 printProgramLog(); 216 throw new Exception("Error linking program"); 217 } 218 219 /// 220 final void loadShader(uint shaderType, string sourceFile) 221 { 222 string contents = readText(sourceFile); 223 224 compileShader(shaderType, contents); 225 } 226 227 private void compileShader(uint shaderType, string source) 228 { 229 uint shader = glCreateShader(shaderType); 230 231 const char*[] shaderSource = [toStringz(source)]; 232 233 glShaderSource(shader, 1, shaderSource.ptr, null); 234 glCompileShader(shader); 235 236 int successfulCompilation; 237 glGetShaderiv(shader, GL_COMPILE_STATUS, &successfulCompilation); 238 239 if(successfulCompilation != true) { 240 printShaderLog(shader); 241 throw new Exception("Unable to compile shader"); 242 } 243 244 glAttachShader(_id, shader); 245 246 shaders ~= shader; 247 } 248 249 /// 250 final void printProgramLog() 251 { 252 int infoLogLength = 0; 253 int maxLength = 0; 254 255 glGetProgramiv(_id, GL_INFO_LOG_LENGTH, &maxLength); 256 257 char[] infoLog; 258 infoLog.length = maxLength; 259 260 glGetProgramInfoLog(_id, maxLength, &infoLogLength, infoLog.ptr); 261 262 if(infoLogLength > 0) 263 writeln(infoLog); 264 } 265 266 /// 267 final void printShaderLog(uint shader) 268 { 269 int infoLogLength = 0; 270 int maxLength = 0; 271 272 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &maxLength); 273 274 char[] infoLog; 275 infoLog.length = maxLength; 276 277 glGetShaderInfoLog(shader, maxLength, &infoLogLength, infoLog.ptr); 278 279 if(infoLogLength > 0) 280 writeln(infoLog); 281 } 282 283 ~this() 284 { 285 foreach(uint shader; shaders) { 286 glDetachShader(_id, shader); 287 glDeleteShader(shader); 288 } 289 290 glDeleteProgram(_id); 291 } 292 }