1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Graphic.ShaderProgram; 25 26 import derelict.opengl3.gl; 27 28 import Dgame.Graphic.Color; 29 import Dgame.Graphic.Shader; 30 31 import Dgame.Math.Vector2; 32 import Dgame.Math.Vector3; 33 import Dgame.Math.Matrix4x4; 34 35 import Dgame.Internal.m3; 36 import Dgame.Internal.d2c; 37 import Dgame.Internal.Error; 38 39 /** 40 * The Program struct manages a OpenGL-Shader-Program. Multiple Shaders can be attached to it. 41 * The Program links the attached Shaders and then they can be used. 42 * 43 * Author: Randy Schuett (rswhite4@googlemail.com) 44 */ 45 struct ShaderProgram { 46 private: 47 uint _program; 48 49 @nogc 50 void _init() nothrow { 51 if (_program == 0) 52 _program = glCreateProgram(); 53 } 54 55 public: 56 /** 57 * CTor 58 * Takes multiple Shader instances and links them together 59 * 60 * Note: The shaders must be already compiled. 61 */ 62 @nogc 63 this(const Shader[] shaders...) nothrow { 64 this.link(shaders); 65 } 66 67 /** 68 * Postblit is disabled 69 */ 70 @disable 71 this(this); 72 73 /** 74 * DTor 75 */ 76 @nogc 77 ~this() nothrow { 78 glDeleteProgram(_program); 79 } 80 81 /** 82 * Returns the internal Program ID 83 */ 84 @nogc 85 @property 86 uint ID() const pure nothrow { 87 return _program; 88 } 89 90 /** 91 * Links multiple Shaders together. 92 * 93 * Note: The shaders must be already compiled. 94 */ 95 @nogc 96 bool link(const Shader[] shaders...) nothrow { 97 _init(); 98 99 // Attach the shaders 100 foreach (ref const Shader shader; shaders) { 101 glAttachShader(_program, shader.id); 102 } 103 104 //Link our program 105 glLinkProgram(_program); 106 107 int isLinked = 0; 108 glGetProgramiv(_program, GL_LINK_STATUS, &isLinked); 109 if (isLinked == GL_FALSE) { 110 int maxLength = 0; 111 glGetProgramiv(_program, GL_INFO_LOG_LENGTH, &maxLength); 112 //The maxLength includes the NULL character 113 char[] infoLog = make!(char[])(maxLength); 114 scope(exit) unmake(infoLog); 115 116 glGetProgramInfoLog(_program, maxLength, &maxLength, infoLog.ptr); 117 //We don't need the program anymore. 118 glDeleteProgram(_program); 119 120 print_fmt("Shader-Program could not be compiled: %s\n", infoLog.ptr); 121 122 return false; 123 } 124 125 // Always detach shaders after a successful link. 126 foreach (ref const Shader shader; shaders) { 127 glDetachShader(_program, shader.id); 128 } 129 130 return true; 131 } 132 133 /** 134 * Bind and use the current program 135 */ 136 @nogc 137 void bind() const nothrow { 138 glUseProgram(_program); 139 } 140 141 /** 142 * Unbind the current program. It is no longer used. 143 */ 144 @nogc 145 void unbind() const nothrow { 146 glUseProgram(0); 147 } 148 149 /** 150 * Set between 1 and 4 parameter and binds them to variables of the Shaders 151 */ 152 @nogc 153 bool setParameter(string name, const float[] values...) const nothrow { 154 immutable int loc = glGetUniformLocation(_program, toStringz(name)); 155 if (loc == -1) { 156 print_fmt("No such variable %s\n", name.ptr); 157 return false; 158 } 159 160 this.bind(); 161 162 switch (values.length) { 163 case 1: 164 glUniform1f(loc, values[0]); 165 break; 166 case 2: 167 glUniform2f(loc, values[0], values[1]); 168 break; 169 case 3: 170 glUniform3f(loc, values[0], values[1], values[2]); 171 break; 172 case 4: 173 glUniform4f(loc, values[0], values[1], values[2], values[3]); 174 break; 175 default: 176 assert(0, "Need between 1 and 4 floats"); 177 } 178 179 return true; 180 } 181 182 /** 183 * Bind a Vector2f to a specific variable name of the Shaders 184 */ 185 @nogc 186 bool setParameter(string name, const Vector2f vec) const nothrow { 187 return this.setParameter(name, vec.x, vec.y); 188 } 189 190 /** 191 * Bind a Vector3f to a specific variable name of the Shaders 192 */ 193 @nogc 194 bool setParameter(string name, const Vector3f vec) const nothrow { 195 return this.setParameter(name, vec.x, vec.y, vec.z); 196 } 197 198 /** 199 * Bind a Color4b to a specific variable name of the Shaders 200 */ 201 @nogc 202 bool setParameter(string name, const Color4b color) const nothrow { 203 const Color4f col = color; 204 return this.setParameter(name, col.red, col.green, col.blue, col.alpha); 205 } 206 207 /** 208 * Bind a Matrix4x4 to a specific variable name of the Shaders 209 */ 210 @nogc 211 bool setParameter(string name, ref const Matrix4x4 mat) const nothrow { 212 immutable int loc = glGetUniformLocation(_program, toStringz(name)); 213 if (loc == -1) { 214 print_fmt("No such variable %s\n", name.ptr); 215 return false; 216 } 217 218 this.bind(); 219 220 glUniformMatrix4fv(loc, 1, GL_FALSE, mat.getValues().ptr); 221 222 return true; 223 } 224 }