1 /*
2     Copyright © 2020, Inochi2D Project
3     Distributed under the 2-Clause BSD License, see LICENSE file.
4     
5     Authors: Luna Nielsen
6 */
7 module inochi2d.core.shader;
8 import inochi2d.math;
9 import std.string;
10 import bindbc.opengl;
11 
12 /**
13     A shader
14 */
15 class Shader {
16 private:
17     GLuint shaderProgram;
18     GLuint fragShader;
19     GLuint vertShader;
20 
21     void compileShaders(string vertex, string fragment) {
22 
23         // Compile vertex shader
24         vertShader = glCreateShader(GL_VERTEX_SHADER);
25         auto c_vert = vertex.toStringz;
26         glShaderSource(vertShader, 1, &c_vert, null);
27         glCompileShader(vertShader);
28         verifyShader(vertShader);
29 
30         // Compile fragment shader
31         fragShader = glCreateShader(GL_FRAGMENT_SHADER);
32         auto c_frag = fragment.toStringz;
33         glShaderSource(fragShader, 1, &c_frag, null);
34         glCompileShader(fragShader);
35         verifyShader(fragShader);
36 
37         // Attach and link them
38         shaderProgram = glCreateProgram();
39         glAttachShader(shaderProgram, vertShader);
40         glAttachShader(shaderProgram, fragShader);
41         glLinkProgram(shaderProgram);
42         verifyProgram();
43     }
44 
45     void verifyShader(GLuint shader) {
46 
47         // Get the length of the error log
48         GLint logLength;
49         glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
50         if (logLength > 0) {
51 
52             // Fetch the error log
53             char[] log = new char[logLength];
54             glGetShaderInfoLog(shader, logLength, null, log.ptr);
55 
56             throw new Exception(cast(string)log);
57         }
58     }
59 
60     void verifyProgram() {
61 
62         // Get the length of the error log
63         GLint logLength;
64         glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &logLength);
65         if (logLength > 0) {
66 
67             // Fetch the error log
68             char[] log = new char[logLength];
69             glGetProgramInfoLog(shaderProgram, logLength, null, log.ptr);
70 
71             throw new Exception(cast(string)log);
72         }
73     }
74 
75 public:
76 
77     /**
78         Destructor
79     */
80     ~this() {
81         glDetachShader(shaderProgram, vertShader);
82         glDetachShader(shaderProgram, fragShader);
83         glDeleteProgram(shaderProgram);
84         
85         glDeleteShader(fragShader);
86         glDeleteShader(vertShader);
87     }
88 
89     /**
90         Creates a new shader object from source
91     */
92     this(string vertex, string fragment) {
93         compileShaders(vertex, fragment);
94     }
95 
96     /**
97         Use the shader
98     */
99     void use() {
100         glUseProgram(shaderProgram);
101     }
102 
103     GLint getUniformLocation(string name) {
104         return glGetUniformLocation(shaderProgram, name.ptr);
105     }
106 
107     void setUniform(GLint uniform, bool value) {
108         glUniform1i(uniform, cast(int)value);
109     }
110 
111     void setUniform(GLint uniform, int value) {
112         glUniform1i(uniform, value);
113     }
114 
115     void setUniform(GLint uniform, float value) {
116         glUniform1f(uniform, value);
117     }
118 
119     void setUniform(GLint uniform, vec2 value) {
120         glUniform2f(uniform, value.x, value.y);
121     }
122 
123     void setUniform(GLint uniform, vec3 value) {
124         glUniform3f(uniform, value.x, value.y, value.z);
125     }
126 
127     void setUniform(GLint uniform, vec4 value) {
128         glUniform4f(uniform, value.x, value.y, value.z, value.w);
129     }
130 
131     void setUniform(GLint uniform, mat4 value) {
132         glUniformMatrix4fv(uniform, 1, GL_TRUE, value.value_ptr);
133     }
134 }