1 module gfm.opengl.shader;
2 
3 import std..string,
4        std.conv;
5 
6 import derelict.opengl3.gl3;
7 
8 import gfm.opengl.opengl;
9 
10 
11 /// OpenGL Shader wrapper.
12 final class GLShader
13 {
14     public
15     {
16         /// Creates a shader devoid of source code.
17         /// Throws: $(D OpenGLException) on error.
18         this(OpenGL gl, GLenum shaderType)
19         {
20             _gl = gl;
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(OpenGL gl, GLenum shaderType, string[] lines)
30         {
31             this(gl, shaderType);
32             load(lines);
33             compile();
34         }
35 
36         /// Releases the OpenGL shader resource.
37         ~this()
38         {
39             if (_initialized)
40             {
41                 debug ensureNotInGC("GLShader");
42                 glDeleteShader(_shader);
43                 _initialized = false;
44             }
45         }
46         deprecated("Use .destroy instead") void close(){}
47 
48         /// Load source code for this shader.
49         /// Throws: $(D OpenGLException) on error.
50         void load(string[] lines)
51         {
52             size_t lineCount = lines.length;
53 
54             auto lengths = new GLint[lineCount];
55             auto addresses = new immutable(GLchar)*[lineCount];
56             auto localLines = new string[lineCount];
57 
58             for (size_t i = 0; i < lineCount; ++i)
59             {
60                 localLines[i] = lines[i] ~ "\n";
61                 lengths[i] = cast(GLint)(localLines[i].length);
62                 addresses[i] = localLines[i].ptr;
63             }
64 
65             glShaderSource(_shader,
66                            cast(GLint)lineCount,
67                            cast(const(char)**)addresses.ptr,
68                            cast(const(int)*)(lengths.ptr));
69             _gl.runtimeCheck();
70         }
71 
72         /// Compile this OpenGL shader.
73         /// Throws: $(D OpenGLException) on compilation error.
74         void compile()
75         {
76             glCompileShader(_shader);
77             _gl.runtimeCheck();
78 
79             // print info log
80             const(char)[] infoLog = getInfoLog();
81             if (infoLog != null)
82                 _gl._logger.info(infoLog);
83 
84             GLint compiled;
85             glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);
86 
87             if (compiled != GL_TRUE)
88                 throw new OpenGLException("shader did not compile");
89         }
90 
91         /// Gets the compiling report.
92         /// Returns: Log output of the GLSL compiler. Can return null!
93         /// Throws: $(D OpenGLException) on error.
94         const(char)[] getInfoLog()
95         {
96             GLint logLength;
97             glGetShaderiv(_shader, GL_INFO_LOG_LENGTH, &logLength);
98             if (logLength <= 0) // "If shader has no information log, a value of 0 is returned."
99                 return null;
100 
101             char[] log = new char[logLength];
102             GLint dummy;
103             glGetShaderInfoLog(_shader, logLength, &dummy, log.ptr);
104             _gl.runtimeCheck();
105             return fromStringz(log.ptr);
106         }
107     }
108 
109     package
110     {
111         GLuint _shader;
112     }
113 
114     private
115     {
116         OpenGL _gl;
117         bool _initialized;
118     }
119 }
120 
121