1 #include "AlphaSprite.hpp"
2 #include "CreatureSkin.hpp"
3 #include "PlainColor.hpp"
4 #include "PlanetSurface.hpp"
7 #include "SunSurface.hpp"
9 #include "ArrayTexture.hpp"
10 #include "Texture.hpp"
11 #include "../app/init.hpp"
19 #include <glm/gtc/type_ptr.hpp>
24 void gl_error(std::string msg) {
25 const GLubyte *errBegin = gluErrorString(glGetError());
26 if (errBegin && *errBegin != '\0') {
27 const GLubyte *errEnd = errBegin;
28 while (*errEnd != '\0') {
32 msg.append(errBegin, errEnd);
34 throw std::runtime_error(msg);
42 Shader::Shader(GLenum type)
43 : handle(glCreateShader(type)) {
45 gl_error("glCreateShader");
51 glDeleteShader(handle);
55 Shader::Shader(Shader &&other) noexcept
56 : handle(other.handle) {
60 Shader &Shader::operator =(Shader &&other) noexcept {
61 std::swap(handle, other.handle);
66 void Shader::Source(const GLchar *src) noexcept {
67 const GLchar* src_arr[] = { src };
68 glShaderSource(handle, 1, src_arr, nullptr);
71 void Shader::Compile() noexcept {
72 glCompileShader(handle);
75 bool Shader::Compiled() const noexcept {
76 GLint compiled = GL_FALSE;
77 glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled);
78 return compiled == GL_TRUE;
81 void Shader::Log(std::ostream &out) const {
82 int log_len = 0, max_len = 0;
83 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &max_len);
84 std::unique_ptr<char[]> log(new char[max_len]);
85 glGetShaderInfoLog(handle, max_len, &log_len, log.get());
86 out.write(log.get(), log_len);
90 void Shader::AttachToProgram(GLuint id) const noexcept {
91 glAttachShader(id, handle);
96 : handle(glCreateProgram()) {
98 gl_error("glCreateProgram");
102 Program::~Program() {
104 glDeleteProgram(handle);
109 const Shader &Program::LoadShader(GLenum type, const GLchar *src) {
110 shaders.emplace_back(type);
111 Shader &shader = shaders.back();
114 if (!shader.Compiled()) {
115 shader.Log(std::cerr);
116 throw std::runtime_error("compile shader");
122 void Program::Attach(Shader &shader) noexcept {
123 shader.AttachToProgram(handle);
126 void Program::Link() noexcept {
127 glLinkProgram(handle);
130 bool Program::Linked() const noexcept {
131 GLint linked = GL_FALSE;
132 glGetProgramiv(handle, GL_LINK_STATUS, &linked);
133 return linked == GL_TRUE;
136 void Program::Log(std::ostream &out) const {
137 int log_len = 0, max_len = 0;
138 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &max_len);
139 std::unique_ptr<char[]> log(new char[max_len]);
140 glGetProgramInfoLog(handle, max_len, &log_len, log.get());
141 out.write(log.get(), log_len);
145 GLint Program::AttributeLocation(const GLchar *name) const noexcept {
146 return glGetAttribLocation(handle, name);
149 GLint Program::AttributeLocation(const std::string &name) const noexcept {
150 return AttributeLocation(name.c_str());
153 GLint Program::UniformLocation(const GLchar *name) const noexcept {
154 return glGetUniformLocation(handle, name);
157 GLint Program::UniformLocation(const std::string &name) const noexcept {
158 return UniformLocation(name.c_str());
162 void Program::Uniform(GLint loc, GLint val) noexcept {
163 glUniform1i(loc, val);
166 void Program::Uniform(GLint loc, float val) noexcept {
167 glUniform1f(loc, val);
170 void Program::Uniform(GLint loc, const glm::vec3 &val) noexcept {
171 glUniform3fv(loc, 1, glm::value_ptr(val));
174 void Program::Uniform(GLint loc, const glm::vec4 &val) noexcept {
175 glUniform4fv(loc, 1, glm::value_ptr(val));
178 void Program::Uniform(GLint loc, const glm::mat4 &val) noexcept {
179 glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
183 constexpr int PlanetSurface::MAX_LIGHTS;
185 PlanetSurface::PlanetSurface()
189 "#version 330 core\n"
191 "layout(location = 0) in vec3 vtx_position;\n"
192 "layout(location = 1) in vec3 vtx_tex_uv;\n"
196 "uniform mat4 MVP;\n"
198 "out vec3 frag_tex_uv;\n"
199 "out vec3 vtx_viewspace;\n"
202 "gl_Position = MVP * vec4(vtx_position, 1);\n"
203 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
204 "frag_tex_uv = vtx_tex_uv;\n"
209 "#version 330 core\n"
211 "struct LightSource {\n"
217 "in vec3 vtx_viewspace;\n"
218 "in vec3 frag_tex_uv;\n"
220 "uniform sampler2DArray tex_sampler;\n"
221 "uniform vec3 normal;\n"
222 "uniform int num_lights;\n"
223 "uniform LightSource light[8];\n"
228 "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
229 "vec3 total_light = tex_color * vec3(0.01, 0.01, 0.01);\n"
230 "for (int i = 0; i < num_lights; ++i) {\n"
231 "vec3 to_light = light[i].position - vtx_viewspace;\n"
232 "float distance = length(to_light) + length(vtx_viewspace);\n"
233 "vec3 light_dir = normalize(to_light);\n"
234 "float attenuation = light[i].strength / (distance * distance);\n"
235 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
236 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
237 "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
238 "if (dot(normal, light_dir) >= 0.0) {\n"
239 "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
241 "total_light = total_light + diffuse + specular;\n"
243 "color = total_light;\n"
247 if (!prog.Linked()) {
249 throw std::runtime_error("link program");
251 m_handle = prog.UniformLocation("M");
252 mv_handle = prog.UniformLocation("MV");
253 mvp_handle = prog.UniformLocation("MVP");
254 sampler_handle = prog.UniformLocation("tex_sampler");
255 normal_handle = prog.UniformLocation("normal");
256 num_lights_handle = prog.UniformLocation("num_lights");
257 for (int i = 0; i < MAX_LIGHTS; ++i) {
258 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
259 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
260 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
264 PlanetSurface::~PlanetSurface() {
267 void PlanetSurface::Activate() noexcept {
269 glEnable(GL_DEPTH_TEST);
270 glDepthFunc(GL_LESS);
271 glEnable(GL_CULL_FACE);
275 void PlanetSurface::SetM(const glm::mat4 &mm) noexcept {
279 prog.Uniform(m_handle, m);
280 prog.Uniform(mv_handle, mv);
281 prog.Uniform(mvp_handle, mvp);
284 void PlanetSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
289 prog.Uniform(mv_handle, mv);
290 prog.Uniform(mvp_handle, mvp);
293 void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
299 prog.Uniform(m_handle, m);
300 prog.Uniform(mv_handle, mv);
301 prog.Uniform(mvp_handle, mvp);
304 void PlanetSurface::SetNormal(const glm::vec3 &n) noexcept {
305 prog.Uniform(normal_handle, n);
308 void PlanetSurface::SetTexture(ArrayTexture &tex) noexcept {
309 glActiveTexture(GL_TEXTURE0);
311 prog.Uniform(sampler_handle, GLint(0));
314 void PlanetSurface::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
315 prog.Uniform(light_handle[3 * n + 0], pos);
316 prog.Uniform(light_handle[3 * n + 1], color);
317 prog.Uniform(light_handle[3 * n + 2], strength);
320 void PlanetSurface::SetNumLights(int n) noexcept {
321 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
325 SunSurface::SunSurface()
329 "#version 330 core\n"
331 "layout(location = 0) in vec3 vtx_position;\n"
335 "uniform mat4 MVP;\n"
337 "out vec3 vtx_viewspace;\n"
340 "gl_Position = MVP * vec4(vtx_position, 1);\n"
341 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
346 "#version 330 core\n"
348 "in vec3 vtx_viewspace;\n"
350 "uniform vec3 light_color;\n"
351 "uniform float light_strength;\n"
356 "vec3 to_light = -vtx_viewspace;\n"
357 "float distance = length(to_light);\n"
358 //"vec3 light_dir = normalize(to_light);\n"
359 "float attenuation = light_strength / (distance * distance);\n"
360 "color = attenuation * light_color;\n"
364 if (!prog.Linked()) {
366 throw std::runtime_error("link program");
368 m_handle = prog.UniformLocation("M");
369 mv_handle = prog.UniformLocation("MV");
370 mvp_handle = prog.UniformLocation("MVP");
371 light_color_handle = prog.UniformLocation("light_color");
372 light_strength_handle = prog.UniformLocation("light_strength");
375 vao.BindAttributes();
376 vao.EnableAttribute(0);
377 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
378 vao.ReserveAttributes(8, GL_STATIC_DRAW);
380 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
381 attrib[0].position = glm::vec3(-1.0f, -1.0f, -1.0f);
382 attrib[1].position = glm::vec3(-1.0f, -1.0f, 1.0f);
383 attrib[2].position = glm::vec3(-1.0f, 1.0f, -1.0f);
384 attrib[3].position = glm::vec3(-1.0f, 1.0f, 1.0f);
385 attrib[4].position = glm::vec3( 1.0f, -1.0f, -1.0f);
386 attrib[5].position = glm::vec3( 1.0f, -1.0f, 1.0f);
387 attrib[6].position = glm::vec3( 1.0f, 1.0f, -1.0f);
388 attrib[7].position = glm::vec3( 1.0f, 1.0f, 1.0f);
391 vao.ReserveElements(36, GL_STATIC_DRAW);
393 auto element = vao.MapElements(GL_WRITE_ONLY);
440 SunSurface::~SunSurface() {
443 void SunSurface::Activate() noexcept {
445 glEnable(GL_DEPTH_TEST);
446 glDepthFunc(GL_LESS);
447 glEnable(GL_CULL_FACE);
451 void SunSurface::SetM(const glm::mat4 &mm) noexcept {
455 prog.Uniform(m_handle, m);
456 prog.Uniform(mv_handle, mv);
457 prog.Uniform(mvp_handle, mvp);
460 void SunSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
465 prog.Uniform(mv_handle, mv);
466 prog.Uniform(mvp_handle, mvp);
469 void SunSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
475 prog.Uniform(m_handle, m);
476 prog.Uniform(mv_handle, mv);
477 prog.Uniform(mvp_handle, mvp);
480 void SunSurface::SetLight(const glm::vec3 &color, float strength) noexcept {
481 prog.Uniform(light_color_handle, color);
482 prog.Uniform(light_strength_handle, strength);
485 void SunSurface::Draw() const noexcept {
487 vao.DrawTriangles(36);
491 constexpr int CreatureSkin::MAX_LIGHTS;
493 CreatureSkin::CreatureSkin()
497 "#version 330 core\n"
499 "layout(location = 0) in vec3 vtx_position;\n"
500 "layout(location = 1) in vec3 vtx_normal;\n"
501 "layout(location = 2) in vec3 vtx_tex_uv;\n"
505 "uniform mat4 MVP;\n"
507 "out vec3 vtx_viewspace;\n"
508 "out vec3 frag_tex_uv;\n"
512 "gl_Position = MVP * vec4(vtx_position, 1);\n"
513 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
514 "normal = normalize((MV * vec4(vtx_normal, 0)).xyz);\n"
515 "frag_tex_uv = vtx_tex_uv;\n"
520 "#version 330 core\n"
522 "struct LightSource {\n"
528 "in vec3 vtx_viewspace;\n"
529 "in vec3 frag_tex_uv;\n"
532 "uniform sampler2DArray tex_sampler;\n"
533 "uniform int num_lights;\n"
534 "uniform LightSource light[8];\n"
539 "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
540 "vec3 total_light = tex_color * vec3(0.01, 0.01, 0.01);\n"
541 "for (int i = 0; i < num_lights; ++i) {\n"
542 "vec3 to_light = light[i].position - vtx_viewspace;\n"
543 "float distance = length(to_light) + length(vtx_viewspace);\n"
544 "vec3 light_dir = normalize(to_light);\n"
545 "float attenuation = light[i].strength / (distance * distance);\n"
546 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
547 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
548 "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
549 "if (dot(normal, light_dir) >= 0.0) {\n"
550 "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
552 "total_light = total_light + diffuse + specular;\n"
554 "color = total_light;\n"
558 if (!prog.Linked()) {
560 throw std::runtime_error("link program");
562 m_handle = prog.UniformLocation("M");
563 mv_handle = prog.UniformLocation("MV");
564 mvp_handle = prog.UniformLocation("MVP");
565 sampler_handle = prog.UniformLocation("tex_sampler");
566 num_lights_handle = prog.UniformLocation("num_lights");
567 for (int i = 0; i < MAX_LIGHTS; ++i) {
568 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
569 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
570 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
574 CreatureSkin::~CreatureSkin() {
577 void CreatureSkin::Activate() noexcept {
579 glEnable(GL_DEPTH_TEST);
580 glDepthFunc(GL_LESS);
581 glEnable(GL_CULL_FACE);
585 void CreatureSkin::SetM(const glm::mat4 &mm) noexcept {
589 prog.Uniform(m_handle, m);
590 prog.Uniform(mv_handle, mv);
591 prog.Uniform(mvp_handle, mvp);
594 void CreatureSkin::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
599 prog.Uniform(mv_handle, mv);
600 prog.Uniform(mvp_handle, mvp);
603 void CreatureSkin::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
609 prog.Uniform(m_handle, m);
610 prog.Uniform(mv_handle, mv);
611 prog.Uniform(mvp_handle, mvp);
614 void CreatureSkin::SetTexture(ArrayTexture &tex) noexcept {
615 glActiveTexture(GL_TEXTURE0);
617 prog.Uniform(sampler_handle, GLint(0));
620 void CreatureSkin::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
621 prog.Uniform(light_handle[3 * n + 0], pos);
622 prog.Uniform(light_handle[3 * n + 1], color);
623 prog.Uniform(light_handle[3 * n + 2], strength);
626 void CreatureSkin::SetNumLights(int n) noexcept {
627 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
631 PlainColor::PlainColor()
635 "#version 330 core\n"
637 "layout(location = 0) in vec3 vtx_position;\n"
641 "uniform mat4 MVP;\n"
644 "gl_Position = MVP * vec4(vtx_position, 1);\n"
649 "#version 330 core\n"
651 "uniform vec3 fg_color;\n"
656 "color = fg_color;\n"
660 if (!prog.Linked()) {
662 throw std::runtime_error("link program");
664 m_handle = prog.UniformLocation("M");
665 mv_handle = prog.UniformLocation("MV");
666 mvp_handle = prog.UniformLocation("MVP");
667 fg_color_handle = prog.UniformLocation("fg_color");
670 vao.BindAttributes();
671 vao.EnableAttribute(0);
672 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
673 vao.ReserveAttributes(4, GL_STATIC_DRAW);
675 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
676 attrib[0].position = glm::vec3(-1.0f, -1.0f, 0.0f);
677 attrib[1].position = glm::vec3(-1.0f, 1.0f, 0.0f);
678 attrib[2].position = glm::vec3( 1.0f, -1.0f, 0.0f);
679 attrib[3].position = glm::vec3( 1.0f, 1.0f, 0.0f);
682 vao.ReserveElements(7, GL_STATIC_DRAW);
684 auto element = vao.MapElements(GL_WRITE_ONLY);
696 PlainColor::~PlainColor() {
699 void PlainColor::Activate() noexcept {
701 glEnable(GL_DEPTH_TEST);
702 glDepthFunc(GL_LESS);
703 glEnable(GL_CULL_FACE);
707 void PlainColor::SetM(const glm::mat4 &mm) noexcept {
711 prog.Uniform(m_handle, m);
712 prog.Uniform(mv_handle, mv);
713 prog.Uniform(mvp_handle, mvp);
716 void PlainColor::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
721 prog.Uniform(mv_handle, mv);
722 prog.Uniform(mvp_handle, mvp);
725 void PlainColor::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
731 prog.Uniform(m_handle, m);
732 prog.Uniform(mv_handle, mv);
733 prog.Uniform(mvp_handle, mvp);
736 void PlainColor::SetColor(const glm::vec3 &color) noexcept {
737 prog.Uniform(fg_color_handle, color);
740 void PlainColor::DrawRect() const noexcept {
742 vao.DrawTriangles(6);
745 void PlainColor::OutlineRect() const noexcept {
747 vao.DrawLineLoop(4, 3);
751 AlphaSprite::AlphaSprite()
755 "#version 330 core\n"
757 "layout(location = 0) in vec3 vtx_position;\n"
758 "layout(location = 1) in vec2 vtx_texture;\n"
762 "uniform mat4 MVP;\n"
764 "out vec2 frag_tex_uv;\n"
767 "gl_Position = MVP * vec4(vtx_position, 1);\n"
768 "frag_tex_uv = vtx_texture;\n"
773 "#version 330 core\n"
775 "in vec2 frag_tex_uv;\n"
777 "uniform sampler2D tex_sampler;\n"
778 "uniform vec4 fg_color;\n"
779 "uniform vec4 bg_color;\n"
784 "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
785 "vec4 factor = mix(bg_color, fg_color, tex_color.a);\n"
786 "color = vec4((tex_color * factor).rgb, factor.a);\n"
790 if (!prog.Linked()) {
792 throw std::runtime_error("link program");
794 m_handle = prog.UniformLocation("M");
795 mv_handle = prog.UniformLocation("MV");
796 mvp_handle = prog.UniformLocation("MVP");
797 sampler_handle = prog.UniformLocation("tex_sampler");
798 fg_color_handle = prog.UniformLocation("fg_color");
799 bg_color_handle = prog.UniformLocation("bg_color");
802 vao.BindAttributes();
803 vao.EnableAttribute(0);
804 vao.EnableAttribute(1);
805 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
806 vao.AttributePointer<glm::vec2>(1, false, offsetof(Attributes, texture));
807 vao.ReserveAttributes(4, GL_STATIC_DRAW);
809 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
810 attrib[0].position = glm::vec3(-1.0f, -1.0f, 0.0f);
811 attrib[0].texture = glm::vec2(0.0f, 0.0f);
812 attrib[1].position = glm::vec3(-1.0f, 1.0f, 0.0f);
813 attrib[1].texture = glm::vec2(0.0f, 1.0f);
814 attrib[2].position = glm::vec3( 1.0f, -1.0f, 0.0f);
815 attrib[2].texture = glm::vec2(1.0f, 0.0f);
816 attrib[3].position = glm::vec3( 1.0f, 1.0f, 0.0f);
817 attrib[3].texture = glm::vec2(1.0f, 1.0f);
820 vao.ReserveElements(7, GL_STATIC_DRAW);
822 auto element = vao.MapElements(GL_WRITE_ONLY);
831 AlphaSprite::~AlphaSprite() {
834 void AlphaSprite::Activate() noexcept {
836 glEnable(GL_DEPTH_TEST);
837 glDepthFunc(GL_LESS);
838 glEnable(GL_CULL_FACE);
840 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
843 void AlphaSprite::SetM(const glm::mat4 &mm) noexcept {
847 prog.Uniform(m_handle, m);
848 prog.Uniform(mv_handle, mv);
849 prog.Uniform(mvp_handle, mvp);
852 void AlphaSprite::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
857 prog.Uniform(mv_handle, mv);
858 prog.Uniform(mvp_handle, mvp);
861 void AlphaSprite::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
867 prog.Uniform(m_handle, m);
868 prog.Uniform(mv_handle, mv);
869 prog.Uniform(mvp_handle, mvp);
872 void AlphaSprite::SetTexture(Texture &tex) noexcept {
873 glActiveTexture(GL_TEXTURE0);
875 prog.Uniform(sampler_handle, GLint(0));
878 void AlphaSprite::SetFgColor(const glm::vec4 &color) noexcept {
879 prog.Uniform(fg_color_handle, color);
882 void AlphaSprite::SetBgColor(const glm::vec4 &color) noexcept {
883 prog.Uniform(bg_color_handle, color);
886 void AlphaSprite::DrawRect() const noexcept {
888 vao.DrawTriangleStrip(4);