1 module gfmod.opengl.shader;
2 
3 import std..string,
4        std.exception,
5        std.conv;
6 
7 import derelict.opengl3.gl3;
8 
9 import gfmod.core.text,
10        gfmod.opengl.opengl;
11 
12 /// OpenGL Shader wrapper.
13 struct GLShader
14 {
15 public:
16     @disable this();
17 
18     /// Creates a shader with source code and compiles it.
19     /// Throws: $(D OpenGLException) on error.
20     this(OpenGL gl, GLenum shaderType, string[] lines) @trusted
21     {
22         _gl = gl;
23         _shader = glCreateShader(shaderType);
24         if(_shader == 0) { throw new OpenGLException("glCreateShader failed"); }
25 
26         load(lines);
27         if(!compile()) { throw new OpenGLException("Shader failed to compile"); }
28     }
29 
30 private:
31     /// Load source code for this shader.
32     void load(string[] lines) nothrow
33     {
34         size_t lineCount = lines.length;
35 
36         auto lengths    = new GLint[lineCount];
37         auto addresses  = new immutable(GLchar)*[lineCount];
38         auto localLines = new string[lineCount];
39 
40         foreach(i; 0 .. lineCount)
41         {
42             localLines[i] = lines[i] ~ "\n";
43             lengths[i]    = cast(GLint)(localLines[i].length);
44             addresses[i]  = localLines[i].ptr;
45         }
46 
47         glShaderSource(_shader, cast(GLint)lineCount, cast(const(char)**)addresses.ptr,
48                        lengths.ptr);
49     }
50 
51     /// Compile this OpenGL shader.
52     ///
53     /// Returns: true on success, false on failure.
54     bool compile() nothrow
55     {
56         glCompileShader(_shader);
57         _gl.runtimeCheck();
58 
59         // print info log
60         char[4096] logBuffer;
61         string infoLog = getInfoLog(logBuffer[]);
62         if(infoLog != null) { _gl._logger.info(infoLog).assumeWontThrow; }
63 
64         GLint compiled;
65         glGetShaderiv(_shader, GL_COMPILE_STATUS, &compiled);
66 
67         return compiled == GL_TRUE ? true : false;
68     }
69 
70 
71     /// Gets the compiling report. 
72     /// Returns: Log output of the GLSL compiler. Can return null!
73     string getInfoLog(char[] logBuffer) nothrow const @nogc
74     {
75         GLint length;
76         glGetShaderInfoLog(_shader, cast(int)logBuffer.length, &length, logBuffer.ptr);
77         char[] log = logBuffer[0 .. length];
78         log.sanitizeASCIIInPlace();
79         return log.assumeUnique();
80     }
81 
82 package:
83     // Handle to the GL shader.
84     GLuint _shader;
85 
86 private:
87     // OpenGL info, logging, etc.
88     OpenGL _gl;
89 }