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 
47         /// Load source code for this shader.
48         /// Throws: $(D OpenGLException) on error.
49         void load(string[] lines)
50         {
51             size_t lineCount = lines.length;
52 
53             auto lengths = new GLint[lineCount];
54             auto addresses = new immutable(GLchar)*[lineCount];
55             auto localLines = new string[lineCount];
56 
57             for (size_t i = 0; i < lineCount; ++i)
58             {
59                 localLines[i] = lines[i] ~ "\n";
60                 lengths[i] = cast(GLint)(localLines[i].length);
61                 addresses[i] = localLines[i].ptr;
62             }
63 
64             glShaderSource(_shader,
65                            cast(GLint)lineCount,
66                            cast(const(char)**)addresses.ptr,
67                            cast(const(int)*)(lengths.ptr));
68             _gl.runtimeCheck();
69         }
70 
71         /// Compile this OpenGL shader.
72         /// Throws: $(D OpenGLException) on compilation error.
73         void compile()
74         {
75             glCompileShader(_shader);
76             _gl.runtimeCheck();
77 
78             // print info log
79             const(char)[] infoLog = getInfoLog();
80             if (infoLog != null)
81                 _gl._logger.info(infoLog);
82 
83             GLint compiled;
84             glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);
85 
86             if (compiled != GL_TRUE)
87                 throw new OpenGLException("shader did not compile");
88         }
89 
90         /// Gets the compiling report.
91         /// Returns: Log output of the GLSL compiler. Can return null!
92         /// Throws: $(D OpenGLException) on error.
93         const(char)[] getInfoLog()
94         {
95             GLint logLength;
96             glGetShaderiv(_shader, GL_INFO_LOG_LENGTH, &logLength);
97             if (logLength <= 0) // "If shader has no information log, a value of 0 is returned."
98                 return null;
99 
100             char[] log = new char[logLength];
101             GLint dummy;
102             glGetShaderInfoLog(_shader, logLength, &dummy, log.ptr);
103             _gl.runtimeCheck();
104             return fromStringz(log.ptr);
105         }
106     }
107 
108     package
109     {
110         GLuint _shader;
111     }
112 
113     private
114     {
115         OpenGL _gl;
116         bool _initialized;
117     }
118 }
119 
120