/src/dgl/program.d

https://github.com/zoadianCollection/dgl · D · 289 lines · 140 code · 43 blank · 106 comment · 6 complexity · eee08503c26d64355cde25f16d0a6731 MD5 · raw file

  1. /*
  2. * Copyright Andrej Mitrovic 2013.
  3. * Distributed under the Boost Software License, Version 1.0.
  4. * (See accompanying file LICENSE_1_0.txt or copy at
  5. * http://www.boost.org/LICENSE_1_0.txt)
  6. */
  7. module dgl.program;
  8. import std.array;
  9. import std.exception;
  10. import std.stdio;
  11. import std.string;
  12. import std.typecons;
  13. import dgl.attribute;
  14. import dgl.loader;
  15. import dgl.shader;
  16. import dgl.uniform;
  17. ///
  18. /+ class ProgramException : Exception
  19. {
  20. this(in char[] log)
  21. {
  22. string error = format("Failed to link shaders:\n%s", log);
  23. super(error);
  24. }
  25. } +/
  26. //
  27. /+ private enum isSupported(alias symbol, T = typeof(symbol))
  28. = is(T == Attribute) || is(T == Uniform); +/
  29. /** A generic getter for uniforms and attributes in a program. */
  30. /+ @property typeof(symbol) get(alias symbol)(Program program)
  31. if (isSupported!symbol)
  32. {
  33. return get!(symbol, __traits(identifier, symbol))(program);
  34. } +/
  35. /**
  36. Ditto, but supports using a custom name in the shader
  37. that doesn't match the symbol name.
  38. */
  39. /+ @property typeof(symbol) get(alias symbol, string name)(Program program)
  40. if (isSupported!symbol)
  41. {
  42. return get!symbol(program, name);
  43. } +/
  44. /** Ditto, but the custom shader field name is a runtime value. */
  45. /+ @property typeof(symbol) get(alias symbol)(Program program, string name)
  46. if (isSupported!symbol)
  47. {
  48. alias Type = typeof(symbol);
  49. static if (is(Type == Attribute))
  50. return symbol = program.getAttribute(name);
  51. else
  52. static if (is(Type == Uniform))
  53. return symbol = program.getUniform(name);
  54. else
  55. static assert(0);
  56. } +/
  57. /** A generic setter for uniforms and attributes in a program. */
  58. /+ void set(alias symbol, Args...)(Program program, Args args)
  59. if (isSupported!symbol)
  60. {
  61. alias Type = typeof(symbol);
  62. static if (is(Type == Attribute))
  63. program.setAttribute(symbol, args);
  64. else
  65. static if (is(Type == Uniform))
  66. program.setUniform(symbol, args);
  67. else
  68. static assert(0);
  69. } +/
  70. /**
  71. The OpenGL program type.
  72. The $(D release) method should be called for manual release of OpenGL resources.
  73. $(B Note:) The program will not call the shaders' $(B release()) method after construction.
  74. */
  75. class Program
  76. {
  77. /**
  78. Initialize the program with a list of shaders,
  79. and create and link the program.
  80. */
  81. this(Shader[] shaders...)
  82. {
  83. _data = Data(shaders);
  84. }
  85. /** Explicitly delete the OpenGL program. */
  86. void release()
  87. {
  88. _data.release();
  89. }
  90. /** Start using this OpenGL program. */
  91. void bind()
  92. {
  93. _data.bind();
  94. }
  95. /** Stop using this OpenGL program. */
  96. void unbind()
  97. {
  98. _data.unbind();
  99. }
  100. /**
  101. Get the attribute of name $(D attributeName) in the program.
  102. Note that if the attribute is not used in the shader program
  103. by any of its code, an invalid $(D Attribute) will be returned,
  104. and a message will be written to $(D stderr).
  105. */
  106. Attribute getAttribute(string attributeName)
  107. {
  108. return _data.getAttribute(attributeName);
  109. }
  110. /**
  111. Get the uniform of name $(D uniformName) in the program.
  112. Note that if the uniform is not used in the shader program
  113. by any of its code, an invalid $(D Uniform) will be returned,
  114. and a message will be written to $(D stderr).
  115. */
  116. Uniform getUniform(string uniformName)
  117. {
  118. return _data.getUniform(uniformName);
  119. }
  120. // todo: add getFragment: glGetFragDataLocation
  121. /** Set the $(D uniform) value in this program. */
  122. void setUniform(Uniform uniform, float value)
  123. {
  124. _data.setUniform1f(uniform, value);
  125. }
  126. /// ditto
  127. void setUniform1i(Uniform uniform, int value)
  128. {
  129. _data.setUniform1i(uniform, value);
  130. }
  131. /// ditto
  132. void setUniform2f(Uniform uniform, float value1, float value2)
  133. {
  134. _data.setUniform2f(uniform, value1, value2);
  135. }
  136. /// ditto
  137. void setUniform4f(Uniform uniform, float value1, float value2, float value3, float value4)
  138. {
  139. _data.setUniform4f(uniform, value1, value2, value3, value4);
  140. }
  141. void setUniform2i(Uniform uniform, int value1, int value2)
  142. {
  143. _data.setUniform2i(uniform, value1, value2);
  144. }
  145. private:
  146. alias Data = ProgramImpl;
  147. Data _data;
  148. }
  149. private struct ProgramImpl
  150. {
  151. this(Shader[] shaders...)
  152. {
  153. _programID = glCreateProgram();
  154. foreach (shader; shaders)
  155. glAttachShader(_programID, shader.shaderID);
  156. this.link();
  157. foreach (shader; shaders)
  158. glDetachShader(_programID, shader.shaderID);
  159. }
  160. private void link()
  161. {
  162. glLinkProgram(_programID);
  163. GLint status;
  164. glGetProgramiv(_programID, GL_LINK_STATUS, &status);
  165. if (status == GL_TRUE)
  166. return;
  167. // todo: need to figure out why this path is continued even when
  168. // dgl_error_callback throws.
  169. /+ /* read the error log and throw */
  170. GLint logLength;
  171. glGetProgramiv(_programID, GL_INFO_LOG_LENGTH, &logLength);
  172. GLchar[] logBuff = new GLchar[logLength];
  173. glGetProgramInfoLog(_programID, logLength, null, logBuff.ptr);
  174. auto log = logBuff[0 .. logLength - 1];
  175. throw new ProgramException(log); +/
  176. }
  177. private void bind()
  178. {
  179. glUseProgram(_programID);
  180. }
  181. private void unbind()
  182. {
  183. glUseProgram(nullProgramID);
  184. }
  185. private Attribute getAttribute(string attributeName)
  186. {
  187. auto attributeLocation = glGetAttribLocation(_programID, attributeName.toStringz);
  188. enforce(attributeLocation >= 0,
  189. format("glGetAttribLocation returned '%s' for location: '%s'",
  190. attributeLocation, attributeName));
  191. return Attribute(attributeLocation);
  192. }
  193. private Uniform getUniform(string uniformName)
  194. {
  195. auto uniformLocation = glGetUniformLocation(_programID, uniformName.toStringz);
  196. enforce(uniformLocation >= 0,
  197. format("glGetUniformLocation returned '%s' for location: '%s'",
  198. uniformLocation, uniformName));
  199. return Uniform(uniformLocation);
  200. }
  201. private void setUniform1i(Uniform uniform, int value)
  202. {
  203. glUniform1i(uniform._uniformID, value);
  204. }
  205. private void setUniform1f(Uniform uniform, float value)
  206. {
  207. glUniform1f(uniform._uniformID, value);
  208. }
  209. private void setUniform2i(Uniform uniform, int value1, int value2)
  210. {
  211. glUniform2i(uniform._uniformID, value1, value2);
  212. }
  213. private void setUniform2f(Uniform uniform, float value1, float value2)
  214. {
  215. glUniform2f(uniform._uniformID, value1, value2);
  216. }
  217. private void setUniform4f(Uniform uniform, float value1, float value2, float value3, float value4)
  218. {
  219. glUniform4f(uniform._uniformID, value1, value2, value3, value4);
  220. }
  221. private void release()
  222. {
  223. if (_programID != invalidProgramID)
  224. {
  225. glDeleteProgram(_programID);
  226. _programID = invalidProgramID;
  227. }
  228. }
  229. debug ~this()
  230. {
  231. if (_programID != invalidProgramID)
  232. stderr.writefln("%s(%s): OpenGL: Program resources not released.", __FILE__, __LINE__);
  233. }
  234. // data
  235. GLuint _programID = invalidProgramID;
  236. // sentinel
  237. private enum invalidProgramID = -1;
  238. // unbind
  239. private enum nullProgramID = 0;
  240. }