]> git.localhorst.tv Git - gong.git/blob - src/graphics/shader.cpp
code, assets, and other stuff stolen from blank
[gong.git] / src / graphics / shader.cpp
1 #include "BlendedSprite.hpp"
2 #include "PlainColor.hpp"
3 #include "Program.hpp"
4 #include "Shader.hpp"
5 #include "SkyBoxShader.hpp"
6
7 #include "ArrayTexture.hpp"
8 #include "CubeMap.hpp"
9 #include "Texture.hpp"
10 #include "../app/error.hpp"
11
12 #include <algorithm>
13 #include <iostream>
14 #include <memory>
15 #include <ostream>
16 #include <stdexcept>
17 #include <string>
18 #include <glm/gtc/type_ptr.hpp>
19
20
21 namespace gong {
22 namespace graphics {
23
24 Shader::Shader(GLenum type)
25 : handle(glCreateShader(type)) {
26         if (handle == 0) {
27                 throw app::GLError("glCreateShader");
28         }
29 }
30
31 Shader::~Shader() {
32         if (handle != 0) {
33                 glDeleteShader(handle);
34         }
35 }
36
37 Shader::Shader(Shader &&other) noexcept
38 : handle(other.handle) {
39         other.handle = 0;
40 }
41
42 Shader &Shader::operator =(Shader &&other) noexcept {
43         std::swap(handle, other.handle);
44         return *this;
45 }
46
47
48 void Shader::Source(const GLchar *src) noexcept {
49         const GLchar* src_arr[] = { src };
50         glShaderSource(handle, 1, src_arr, nullptr);
51 }
52
53 void Shader::Compile() noexcept {
54         glCompileShader(handle);
55 }
56
57 bool Shader::Compiled() const noexcept {
58         GLint compiled = GL_FALSE;
59         glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled);
60         return compiled == GL_TRUE;
61 }
62
63 void Shader::Log(std::ostream &out) const {
64         int log_len = 0, max_len = 0;
65         glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &max_len);
66         std::unique_ptr<char[]> log(new char[max_len]);
67         glGetShaderInfoLog(handle, max_len, &log_len, log.get());
68         out.write(log.get(), log_len);
69 }
70
71
72 void Shader::AttachToProgram(GLuint id) const noexcept {
73         glAttachShader(id, handle);
74 }
75
76
77 Program::Program()
78 : handle(glCreateProgram()) {
79         if (handle == 0) {
80                 throw app::GLError("glCreateProgram");
81         }
82 }
83
84 Program::~Program() {
85         if (handle != 0) {
86                 glDeleteProgram(handle);
87         }
88 }
89
90
91 const Shader &Program::LoadShader(GLenum type, const GLchar *src) {
92         shaders.emplace_back(type);
93         Shader &shader = shaders.back();
94         shader.Source(src);
95         shader.Compile();
96         if (!shader.Compiled()) {
97                 shader.Log(std::cerr);
98                 throw std::runtime_error("compile shader");
99         }
100         Attach(shader);
101         return shader;
102 }
103
104 void Program::Attach(Shader &shader) noexcept {
105         shader.AttachToProgram(handle);
106 }
107
108 void Program::Link() noexcept {
109         glLinkProgram(handle);
110 }
111
112 bool Program::Linked() const noexcept {
113         GLint linked = GL_FALSE;
114         glGetProgramiv(handle, GL_LINK_STATUS, &linked);
115         return linked == GL_TRUE;
116 }
117
118 void Program::Log(std::ostream &out) const {
119         int log_len = 0, max_len = 0;
120         glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &max_len);
121         std::unique_ptr<char[]> log(new char[max_len]);
122         glGetProgramInfoLog(handle, max_len, &log_len, log.get());
123         out.write(log.get(), log_len);
124 }
125
126
127 GLint Program::AttributeLocation(const GLchar *name) const noexcept {
128         return glGetAttribLocation(handle, name);
129 }
130
131 GLint Program::UniformLocation(const GLchar *name) const noexcept {
132         return glGetUniformLocation(handle, name);
133 }
134
135
136 void Program::Uniform(GLint loc, GLint val) noexcept {
137         glUniform1i(loc, val);
138 }
139
140 void Program::Uniform(GLint loc, float val) noexcept {
141         glUniform1f(loc, val);
142 }
143
144 void Program::Uniform(GLint loc, const glm::vec3 &val) noexcept {
145         glUniform3fv(loc, 1, glm::value_ptr(val));
146 }
147
148 void Program::Uniform(GLint loc, const glm::vec4 &val) noexcept {
149         glUniform4fv(loc, 1, glm::value_ptr(val));
150 }
151
152 void Program::Uniform(GLint loc, const glm::mat4 &val) noexcept {
153         glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
154 }
155
156
157 BlendedSprite::BlendedSprite()
158 : program()
159 , vp(1.0f)
160 , mvp_handle(0)
161 , sampler_handle(0) {
162         program.LoadShader(
163                 GL_VERTEX_SHADER,
164                 "#version 330 core\n"
165                 "layout(location = 0) in vec3 vtx_position;\n"
166                 "layout(location = 1) in vec2 vtx_tex_uv;\n"
167                 "uniform mat4 MVP;\n"
168                 "out vec2 frag_tex_uv;\n"
169                 "void main() {\n"
170                         "gl_Position = MVP * vec4(vtx_position, 1);\n"
171                         "frag_tex_uv = vtx_tex_uv;\n"
172                 "}\n"
173         );
174         program.LoadShader(
175                 GL_FRAGMENT_SHADER,
176                 "#version 330 core\n"
177                 "in vec2 frag_tex_uv;\n"
178                 "uniform sampler2D tex_sampler;\n"
179                 "uniform vec4 fg_factor;\n"
180                 "uniform vec4 bg_factor;\n"
181                 "out vec4 color;\n"
182                 "void main() {\n"
183                         "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
184                         "vec4 factor = mix(bg_factor, fg_factor, tex_color.a);\n"
185                         "color = tex_color * factor;\n"
186                         "color.a = factor.a;\n"
187                 "}\n"
188         );
189         program.Link();
190         if (!program.Linked()) {
191                 program.Log(std::cerr);
192                 throw std::runtime_error("link program");
193         }
194
195         mvp_handle = program.UniformLocation("MVP");
196         sampler_handle = program.UniformLocation("tex_sampler");
197         fg_handle = program.UniformLocation("fg_factor");
198         bg_handle = program.UniformLocation("bg_factor");
199
200         Activate();
201         SetFG(glm::vec4(1.0f, 1.0f, 1.0f, 1.0f));
202         SetBG(glm::vec4(1.0f, 1.0f, 1.0f, 0.0f));
203 }
204
205
206 void BlendedSprite::Activate() noexcept {
207         program.Use();
208 }
209
210 void BlendedSprite::SetM(const glm::mat4 &m) noexcept {
211         program.Uniform(mvp_handle, vp * m);
212 }
213
214 void BlendedSprite::SetProjection(const glm::mat4 &p) noexcept {
215         projection = p;
216         vp = p * view;
217 }
218
219 void BlendedSprite::SetView(const glm::mat4 &v) noexcept {
220         view = v;
221         vp = projection * v;
222 }
223
224 void BlendedSprite::SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept {
225         projection = p;
226         view = v;
227         vp = p * v;
228 }
229
230 void BlendedSprite::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept {
231         SetVP(v, p);
232         SetM(m);
233 }
234
235 void BlendedSprite::SetTexture(Texture &tex) noexcept {
236         glActiveTexture(GL_TEXTURE0);
237         tex.Bind();
238         program.Uniform(sampler_handle, GLint(0));
239 }
240
241 void BlendedSprite::SetFG(const glm::vec4 &v) noexcept {
242         program.Uniform(fg_handle, v);
243 }
244
245 void BlendedSprite::SetBG(const glm::vec4 &v) noexcept {
246         program.Uniform(bg_handle, v);
247 }
248
249
250 SkyBoxShader::SkyBoxShader()
251 : program()
252 , vp(1.0f)
253 , vp_handle(0)
254 , sampler_handle(0) {
255         program.LoadShader(
256                 GL_VERTEX_SHADER,
257                 "#version 330 core\n"
258                 "layout(location = 0) in vec3 vtx_position;\n"
259                 "uniform mat4 VP;\n"
260                 "out vec3 vtx_viewspace;\n"
261                 "void main() {\n"
262                         "gl_Position = VP * vec4(vtx_position, 1);\n"
263                         "gl_Position.z = gl_Position.w;\n"
264                         "vtx_viewspace = vtx_position;\n"
265                 "}\n"
266         );
267         program.LoadShader(
268                 GL_FRAGMENT_SHADER,
269                 "#version 330 core\n"
270                 "in vec3 vtx_viewspace;\n"
271                 "uniform samplerCube tex_sampler;\n"
272                 "out vec3 color;\n"
273                 "void main() {\n"
274                         "color = texture(tex_sampler, vtx_viewspace).rgb;\n"
275                         //"color = vec3(1,0,0);\n"
276                 "}\n"
277         );
278         program.Link();
279         if (!program.Linked()) {
280                 program.Log(std::cerr);
281                 throw std::runtime_error("link program");
282         }
283
284         vp_handle = program.UniformLocation("VP");
285         sampler_handle = program.UniformLocation("tex_sampler");
286 }
287
288
289 void SkyBoxShader::Activate() noexcept {
290         program.Use();
291 }
292
293 void SkyBoxShader::SetTexture(CubeMap &tex) noexcept {
294         glActiveTexture(GL_TEXTURE0);
295         tex.Bind();
296         program.Uniform(sampler_handle, GLint(0));
297 }
298
299 void SkyBoxShader::SetProjection(const glm::mat4 &p) noexcept {
300         projection = p;
301         vp = p * view;
302         program.Uniform(vp_handle, vp);
303 }
304
305 void SkyBoxShader::SetView(const glm::mat4 &v) noexcept {
306         view = v;
307         view[0].w = 0.0f;
308         view[1].w = 0.0f;
309         view[2].w = 0.0f;
310         view[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
311         vp = projection * view;
312         program.Uniform(vp_handle, vp);
313 }
314
315 void SkyBoxShader::SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept {
316         projection = p;
317         SetView(v);
318 }
319
320
321 PlainColor::PlainColor()
322 : program()
323 , vp(1.0f)
324 , mvp_handle(0) {
325         program.LoadShader(
326                 GL_VERTEX_SHADER,
327                 "#version 330 core\n"
328                 "layout(location = 0) in vec3 vtx_position;\n"
329                 "layout(location = 1) in vec4 vtx_color;\n"
330                 "uniform mat4 MVP;\n"
331                 "out vec4 frag_color;\n"
332                 "void main() {\n"
333                         "gl_Position = MVP * vec4(vtx_position, 1);\n"
334                         "frag_color = vtx_color;\n"
335                 "}\n"
336         );
337         program.LoadShader(
338                 GL_FRAGMENT_SHADER,
339                 "#version 330 core\n"
340                 "in vec4 frag_color;\n"
341                 "out vec4 color;\n"
342                 "void main() {\n"
343                         "color = frag_color;\n"
344                 "}\n"
345         );
346         program.Link();
347         if (!program.Linked()) {
348                 program.Log(std::cerr);
349                 throw std::runtime_error("link program");
350         }
351
352         mvp_handle = program.UniformLocation("MVP");
353 }
354
355
356 void PlainColor::Activate() noexcept {
357         program.Use();
358 }
359
360 void PlainColor::SetM(const glm::mat4 &m) noexcept {
361         program.Uniform(mvp_handle, vp * m);
362 }
363
364 void PlainColor::SetProjection(const glm::mat4 &p) noexcept {
365         projection = p;
366         vp = p * view;
367 }
368
369 void PlainColor::SetView(const glm::mat4 &v) noexcept {
370         view = v;
371         vp = projection * v;
372 }
373
374 void PlainColor::SetVP(const glm::mat4 &v, const glm::mat4 &p) noexcept {
375         projection = p;
376         view = v;
377         vp = p * v;
378 }
379
380 void PlainColor::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) noexcept {
381         SetVP(v, p);
382         SetM(m);
383 }
384
385 }
386 }