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