1 module gfm.opengl.shader; 2 3 import std.string, 4 std.conv, 5 std.experimental.logger; 6 7 import bindbc.opengl; 8 9 import gfm.opengl.opengl; 10 11 12 /// OpenGL Shader wrapper. 13 final class GLShader 14 { 15 public 16 { 17 /// Creates a shader devoid of source code. 18 /// Throws: $(D OpenGLException) on error. 19 this(GLenum shaderType) 20 { 21 _shader = glCreateShader(shaderType); 22 if (_shader == 0) 23 throw new OpenGLException("glCreateShader failed"); 24 _initialized = true; 25 } 26 27 /// Creates a shader with source code and compiles it. 28 /// Throws: $(D OpenGLException) on error. 29 this(GLenum shaderType, string[] lines) 30 { 31 this(shaderType); 32 try 33 { 34 load(lines); 35 compile(); 36 } 37 catch(Exception e) 38 { 39 glDeleteShader(_shader); 40 _initialized = false; 41 throw e; 42 } 43 } 44 45 /// Releases the OpenGL shader resource. 46 ~this() 47 { 48 if (_initialized) 49 { 50 debug ensureNotInGC("GLShader"); 51 glDeleteShader(_shader); 52 _initialized = false; 53 } 54 } 55 56 /// Load source code for this shader. 57 /// Throws: $(D OpenGLException) on error. 58 void load(string[] lines) 59 { 60 size_t lineCount = lines.length; 61 62 auto lengths = new GLint[lineCount]; 63 auto addresses = new immutable(GLchar)*[lineCount]; 64 auto localLines = new string[lineCount]; 65 66 for (size_t i = 0; i < lineCount; ++i) 67 { 68 localLines[i] = lines[i] ~ "\n"; 69 lengths[i] = cast(GLint)(localLines[i].length); 70 addresses[i] = localLines[i].ptr; 71 } 72 73 glShaderSource(_shader, 74 cast(GLint)lineCount, 75 cast(const(char)**)addresses.ptr, 76 cast(const(int)*)(lengths.ptr)); 77 runtimeCheck(); 78 } 79 80 /// Compile this OpenGL shader. 81 /// Throws: $(D OpenGLException) on compilation error. 82 void compile() 83 { 84 glCompileShader(_shader); 85 runtimeCheck(); 86 87 // print info log 88 const(char)[] infoLog = getInfoLog(); 89 if (infoLog != null && _logger) 90 _logger.info(infoLog); 91 92 GLint compiled; 93 glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled); 94 95 if (compiled != GL_TRUE) 96 throw new OpenGLException("shader did not compile"); 97 } 98 99 /// Gets the compiling report. 100 /// Returns: Log output of the GLSL compiler. Can return null! 101 /// Throws: $(D OpenGLException) on error. 102 const(char)[] getInfoLog() 103 { 104 GLint logLength; 105 glGetShaderiv(_shader, GL_INFO_LOG_LENGTH, &logLength); 106 if (logLength <= 0) // "If shader has no information log, a value of 0 is returned." 107 return null; 108 109 char[] log = new char[logLength]; 110 GLint dummy; 111 glGetShaderInfoLog(_shader, logLength, &dummy, log.ptr); 112 runtimeCheck(); 113 return fromStringz(log.ptr); 114 } 115 116 /// Sets a logger for the program. That allows additional output 117 /// besides error reporting. 118 void logger(Logger l) pure nothrow { _logger = l; } 119 } 120 121 package 122 { 123 GLuint _shader; 124 } 125 126 private 127 { 128 Logger _logger; 129 bool _initialized; 130 } 131 } 132 133