1 module evael.renderer.gl.gl_shader;
2 
3 import evael.renderer.gl.gl_wrapper;
4 import evael.renderer.gl.gl_enum_converter;
5 import evael.renderer.shader;
6 import evael.renderer.enums.shader_type;
7 
8 import evael.lib.memory;
9 
10 public
11 {
12     import evael.renderer.shader : ShaderAttribute;
13 }
14 
15 class GLShader : Shader
16 {
17     private uint m_programId;
18     private uint m_vertexShaderId;
19     private uint m_fragmentShaderId;
20     private uint m_geometryShaderId;
21 
22     /**
23      * GLShader constructor.
24      */
25     @nogc
26     public this(in uint programId, in uint vertexShaderId, in uint fragmentShaderId)
27     {
28         super();
29 
30         this.m_programId = programId;
31         this.m_vertexShaderId = vertexShaderId;
32         this.m_fragmentShaderId = fragmentShaderId;
33     }
34 
35     /**
36      * GLShader destructor.
37      */
38     @nogc
39     public ~this()
40     {
41         this.dispose();
42     }
43 
44     // TODO: remove this when IAsset is cleaned.
45     @nogc
46     public void dispose()
47     {
48         gl.DeleteShader(this.m_vertexShaderId);
49         gl.DeleteShader(this.m_fragmentShaderId);
50 
51         if (this.m_geometryShaderId)
52         {
53             gl.DeleteShader(this.m_geometryShaderId);
54         }
55     }
56 
57     /**
58      * Returns location of an uniform variable.
59      * Params:
60      *		uniformName : uniform variable to retrieve
61      */
62     @nogc
63     public int getUniformLocation(in string uniformName) const
64     {
65         return gl.GetUniformLocation(this.m_programId, cast(char*) uniformName.ptr);
66     }
67 
68     /**
69      * Loads a shader from file.
70      * Params:
71      *		fileName : shader to load
72      */
73     public static GLShader load(in string fileName)
74     {
75         import std.file : readText;
76 
77         return GLShader.load(readText(fileName ~ ".vert"), readText(fileName ~ ".frag"));
78     }
79 
80 
81     /**
82      * Loads a shader from source.
83      * Params:
84      *		vs : vertex shader
85      *		fs : fragment shader
86      */
87     public static GLShader load(in string vs, in string fs)
88     {
89         immutable uint programId = gl.CreateProgram();
90         
91         immutable uint vertexShaderId = GLShader.compileShader(vs, ShaderType.Vertex);
92         immutable uint fragmentShaderId = GLShader.compileShader(fs, ShaderType.Fragment);
93 
94         gl.AttachShader(programId, vertexShaderId);
95         gl.AttachShader(programId, fragmentShaderId);
96 
97         gl.LinkProgram(programId);
98 
99         auto shader = MemoryHelper.create!GLShader(programId, vertexShaderId, fragmentShaderId);
100 
101         return shader;
102     }
103 
104     /**
105      * Compiles a shader from a source.
106      * Params:
107      *		type : shader type
108      */
109     private static uint compileShader(in string sourceCode, in ShaderType type)
110     {
111         import std..string : format;
112         import std.exception : enforce;
113 
114         immutable uint shader = gl.CreateShader(GLEnumConverter.shaderType(type));
115 
116         assert(sourceCode.length);
117 
118         char* source = cast(char*) sourceCode.ptr;
119 
120         // Shader compilation
121         gl.ShaderSource(shader, 1, &source, [cast(int) sourceCode.length].ptr);
122         gl.CompileShader(shader);
123 
124         int compilationStatus;
125         gl.GetShaderiv(shader, GL_COMPILE_STATUS, &compilationStatus);
126 
127         // We check for compilation errors
128         if (compilationStatus == false)
129         {
130             // Compilation failed, we retrieve error logs
131             gl.GetShaderiv(shader, GL_INFO_LOG_LENGTH, &compilationStatus);
132 
133             char[] errors = new char[compilationStatus];
134 
135             gl.GetShaderInfoLog(shader, compilationStatus, &compilationStatus, errors.ptr);
136 
137             throw new Exception("Shader %s can't be compiled :\n %s.".format(sourceCode, errors));
138         }
139 
140         return shader;
141     }
142 
143     @nogc
144     @property nothrow
145     {
146         public uint programId() const
147         {
148             return this.m_programId;
149         }
150     }
151 }
152