shader.d 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Written in the D programming language.
  2. /**
  3. Copyright: Copyright Felix 'Zoadian' Hufnagel 2014-.
  4. License: $(WEB http://www.gnu.org/licenses/lgpl.html, LGPLv3).
  5. Authors: $(WEB zoadian.de, Felix 'Zoadian' Hufnagel)
  6. */
  7. module three.gl.shader;
  8. import derelict.opengl3.gl3;
  9. import three.gl.util;
  10. import std.string;
  11. import std.stdio;
  12. //==============================================================================
  13. ///
  14. enum ShaderType {
  15. Vertex = GL_VERTEX_SHADER,
  16. Fragment = GL_FRAGMENT_SHADER,
  17. Geometry = GL_GEOMETRY_SHADER,
  18. TesselationControl = GL_TESS_CONTROL_SHADER,
  19. TesselationEvaluation = GL_TESS_EVALUATION_SHADER
  20. }
  21. private template shaderTypeBitIdentifier(ShaderType TYPE)
  22. {
  23. static if(TYPE == ShaderType.Vertex) enum shaderTypeBitIdentifier = GL_VERTEX_SHADER_BIT;
  24. else static if(TYPE == ShaderType.Fragment) enum shaderTypeBitIdentifier = GL_FRAGMENT_SHADER_BIT;
  25. else static if(TYPE == ShaderType.Geometry) enum shaderTypeBitIdentifier = GL_GEOMETRY_SHADER_BIT;
  26. else static if(TYPE == ShaderType.TesselationControl) enum shaderTypeBitIdentifier = GL_TESS_CONTROL_SHADER_BIT;
  27. else static if(TYPE == ShaderType.TesselationEvaluation) enum shaderTypeBitIdentifier = GL_TESS_EVALUATION_SHADER_BIT;
  28. }
  29. //==============================================================================
  30. ///
  31. final class Shader(ShaderType TYPE) {
  32. private:
  33. uint _id;
  34. int[string] _uniformLocationCache;
  35. alias type = TYPE;
  36. public:
  37. ///
  38. this(string source) {
  39. auto szSource = [source.toStringz()];
  40. this._id = check!glCreateShaderProgramv(TYPE, 1, szSource.ptr);
  41. writeln("Shader created: ", this._id);
  42. }
  43. ///
  44. ~this() {
  45. check!glDeleteProgram(this._id);
  46. writeln("Shader deleted: ", this._id);
  47. }
  48. public:
  49. ///
  50. @property bool isValid() const {
  51. return (this._id > 0 && this.isLinked);
  52. }
  53. ///
  54. @property bool isLinked() const {
  55. GLint linked;
  56. check!glGetProgramiv(this._id, GL_LINK_STATUS, &linked);
  57. return linked != 0;
  58. }
  59. public:
  60. ///
  61. int getUniformLocation(string name) {
  62. int* px = (name in this._uniformLocationCache);
  63. if(px !is null) return *px;
  64. auto szName = name.toStringz();
  65. assert(this._id > 0);
  66. int x = check!glGetUniformLocation(this._id, &szName[0]);
  67. assert(x != -1, "wrong uniform location : " ~ name);
  68. //try{if(x == -1) "wrong uniform location : ".writeln(name);}catch(Exception e){}
  69. this._uniformLocationCache[name] = x;
  70. //if(x == -1) throw new Exception("uniform location "~name~" not found");
  71. return x;
  72. }
  73. ///
  74. string infoLog() const {
  75. int len;
  76. check!glGetProgramiv(this._id, GL_INFO_LOG_LENGTH , &len);
  77. if (len > 1) {
  78. char[] msg = new char[len];
  79. check!glGetProgramInfoLog(this._id, len, null, cast(char*) msg);
  80. return cast(string)msg;
  81. }
  82. return "";
  83. }
  84. }
  85. //==============================================================================
  86. ///
  87. final class ShaderPipeline {
  88. private:
  89. GLuint _id;
  90. uint[ShaderType] _currentlyUsed;
  91. public:
  92. ///
  93. this() {
  94. glGenProgramPipelines(1, &this._id);
  95. writeln("ShaderPipeline created: ", this._id);
  96. }
  97. ///
  98. ~this() {
  99. glDeleteProgramPipelines(1, &this._id);
  100. writeln("ShaderPipeline deleted: ", this._id);
  101. }
  102. public:
  103. ///
  104. @property bool isValid() const {
  105. return (this._id > 0 && this.isValidProgramPipeline);
  106. }
  107. ///
  108. @property bool isValidProgramPipeline() const {
  109. glValidateProgramPipeline(this._id);
  110. GLint status;
  111. glGetProgramPipelineiv(this._id, GL_VALIDATE_STATUS, &status);
  112. return status != 0;
  113. }
  114. public:
  115. ///
  116. void bind() {
  117. assert(this.isValid);
  118. glBindProgramPipeline(this._id);
  119. }
  120. ///
  121. static void unbind() {
  122. glBindProgramPipeline(0);
  123. }
  124. ///
  125. void activate(T)(T shaderProgram) { // TODO: add check if it is a shaderProgram
  126. glActiveShaderProgram(this._id, shaderProgram._id);
  127. }
  128. ///
  129. void use(T)(T shaderProgram) { // TODO: add check if it is a shaderProgram
  130. //check if shaderProgram is already in use by this pipeline
  131. if(_currentlyUsed.get(T.type, 0) == shaderProgram._id) return;
  132. glUseProgramStages(this._id, shaderTypeBitIdentifier!(shaderProgram.type), shaderProgram._id);
  133. }
  134. ///
  135. string infoLog() const {
  136. int len;
  137. glGetProgramiv(this._id, GL_INFO_LOG_LENGTH , &len);
  138. if (len > 1) {
  139. char[] msg = new char[len];
  140. glGetProgramPipelineInfoLog(this._id, len, null, cast(char*) msg);
  141. return cast(string)msg;
  142. }
  143. return "";
  144. }
  145. }