1 #include "AlphaSprite.hpp"
3 #include "CreatureSkin.hpp"
4 #include "PlanetSurface.hpp"
8 #include "SunSurface.hpp"
10 #include "ArrayTexture.hpp"
11 #include "CubeMap.hpp"
12 #include "Texture.hpp"
13 #include "../app/init.hpp"
21 #include <glm/gtc/type_ptr.hpp>
22 #include <glm/gtx/transform.hpp>
27 void gl_error(std::string msg) {
28 const GLubyte *errBegin = gluErrorString(glGetError());
29 if (errBegin && *errBegin != '\0') {
30 const GLubyte *errEnd = errBegin;
31 while (*errEnd != '\0') {
35 msg.append(errBegin, errEnd);
37 throw std::runtime_error(msg);
45 Shader::Shader(GLenum type)
46 : handle(glCreateShader(type)) {
48 gl_error("glCreateShader");
54 glDeleteShader(handle);
58 Shader::Shader(Shader &&other) noexcept
59 : handle(other.handle) {
63 Shader &Shader::operator =(Shader &&other) noexcept {
64 std::swap(handle, other.handle);
69 void Shader::Source(const GLchar *src) noexcept {
70 const GLchar* src_arr[] = { src };
71 glShaderSource(handle, 1, src_arr, nullptr);
74 void Shader::Compile() noexcept {
75 glCompileShader(handle);
78 bool Shader::Compiled() const noexcept {
79 GLint compiled = GL_FALSE;
80 glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled);
81 return compiled == GL_TRUE;
84 void Shader::Log(std::ostream &out) const {
85 int log_len = 0, max_len = 0;
86 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &max_len);
87 std::unique_ptr<char[]> log(new char[max_len]);
88 glGetShaderInfoLog(handle, max_len, &log_len, log.get());
89 out.write(log.get(), log_len);
93 void Shader::AttachToProgram(GLuint id) const noexcept {
94 glAttachShader(id, handle);
99 : handle(glCreateProgram()) {
101 gl_error("glCreateProgram");
105 Program::~Program() {
107 glDeleteProgram(handle);
112 const Shader &Program::LoadShader(GLenum type, const GLchar *src) {
113 shaders.emplace_back(type);
114 Shader &shader = shaders.back();
117 if (!shader.Compiled()) {
118 shader.Log(std::cerr);
119 throw std::runtime_error("compile shader");
125 void Program::Attach(Shader &shader) noexcept {
126 shader.AttachToProgram(handle);
129 void Program::Link() noexcept {
130 glLinkProgram(handle);
133 bool Program::Linked() const noexcept {
134 GLint linked = GL_FALSE;
135 glGetProgramiv(handle, GL_LINK_STATUS, &linked);
136 return linked == GL_TRUE;
139 void Program::Log(std::ostream &out) const {
140 int log_len = 0, max_len = 0;
141 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &max_len);
142 std::unique_ptr<char[]> log(new char[max_len]);
143 glGetProgramInfoLog(handle, max_len, &log_len, log.get());
144 out.write(log.get(), log_len);
148 GLint Program::AttributeLocation(const GLchar *name) const noexcept {
149 return glGetAttribLocation(handle, name);
152 GLint Program::AttributeLocation(const std::string &name) const noexcept {
153 return AttributeLocation(name.c_str());
156 GLint Program::UniformLocation(const GLchar *name) const noexcept {
157 return glGetUniformLocation(handle, name);
160 GLint Program::UniformLocation(const std::string &name) const noexcept {
161 return UniformLocation(name.c_str());
165 void Program::Uniform(GLint loc, GLint val) noexcept {
166 glUniform1i(loc, val);
169 void Program::Uniform(GLint loc, float val) noexcept {
170 glUniform1f(loc, val);
173 void Program::Uniform(GLint loc, const glm::vec3 &val) noexcept {
174 glUniform3fv(loc, 1, glm::value_ptr(val));
177 void Program::Uniform(GLint loc, const glm::vec4 &val) noexcept {
178 glUniform4fv(loc, 1, glm::value_ptr(val));
181 void Program::Uniform(GLint loc, const glm::mat4 &val) noexcept {
182 glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
186 constexpr int PlanetSurface::MAX_LIGHTS;
188 PlanetSurface::PlanetSurface()
192 "#version 330 core\n"
194 "layout(location = 0) in vec3 vtx_position;\n"
195 "layout(location = 1) in vec3 vtx_normal;\n"
196 "layout(location = 2) in vec3 vtx_tex_uv;\n"
200 "uniform mat4 MVP;\n"
202 "out vec3 vtx_viewspace;\n"
203 "out vec3 nrm_viewspace;\n"
204 "out vec3 frag_tex_uv;\n"
207 "gl_Position = MVP * vec4(vtx_position, 1.0);\n"
208 "vtx_viewspace = (MV * vec4(vtx_position, 1.0)).xyz;\n"
209 "nrm_viewspace = (MV * vec4(vtx_position, 0.0)).xyz;\n"
210 "frag_tex_uv = vtx_tex_uv;\n"
215 "#version 330 core\n"
217 "struct LightSource {\n"
223 "in vec3 vtx_viewspace;\n"
224 "in vec3 nrm_viewspace;\n"
225 "in vec3 frag_tex_uv;\n"
227 "uniform sampler2DArray tex_sampler;\n"
228 "uniform int num_lights;\n"
229 "uniform LightSource light[8];\n"
234 "vec3 normal = normalize(nrm_viewspace);\n"
235 "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
236 "vec3 total_light = tex_color * vec3(0.1, 0.1, 0.1);\n"
237 "for (int i = 0; i < num_lights; ++i) {\n"
238 "vec3 to_light = light[i].position - vtx_viewspace;\n"
239 "float distance = length(to_light) + length(vtx_viewspace);\n"
240 "vec3 light_dir = normalize(to_light);\n"
241 "float attenuation = light[i].strength / (distance * distance);\n"
242 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
243 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
244 "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
245 "if (dot(normal, light_dir) >= 0.0) {\n"
246 "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
248 "total_light = total_light + diffuse + specular;\n"
250 "color = total_light;\n"
254 if (!prog.Linked()) {
256 throw std::runtime_error("link program");
258 m_handle = prog.UniformLocation("M");
259 mv_handle = prog.UniformLocation("MV");
260 mvp_handle = prog.UniformLocation("MVP");
261 sampler_handle = prog.UniformLocation("tex_sampler");
262 num_lights_handle = prog.UniformLocation("num_lights");
263 for (int i = 0; i < MAX_LIGHTS; ++i) {
264 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
265 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
266 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
270 PlanetSurface::~PlanetSurface() {
273 void PlanetSurface::Activate() noexcept {
275 glEnable(GL_DEPTH_TEST);
276 glDepthFunc(GL_LESS);
277 glEnable(GL_CULL_FACE);
281 void PlanetSurface::SetM(const glm::mat4 &mm) noexcept {
285 prog.Uniform(m_handle, m);
286 prog.Uniform(mv_handle, mv);
287 prog.Uniform(mvp_handle, mvp);
290 void PlanetSurface::SetV(const glm::mat4 &vv) noexcept {
294 prog.Uniform(mv_handle, mv);
295 prog.Uniform(mvp_handle, mvp);
298 void PlanetSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
303 prog.Uniform(mv_handle, mv);
304 prog.Uniform(mvp_handle, mvp);
307 void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
313 prog.Uniform(m_handle, m);
314 prog.Uniform(mv_handle, mv);
315 prog.Uniform(mvp_handle, mvp);
318 void PlanetSurface::SetTexture(ArrayTexture &tex) noexcept {
319 glActiveTexture(GL_TEXTURE0);
321 prog.Uniform(sampler_handle, GLint(0));
324 void PlanetSurface::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
325 prog.Uniform(light_handle[3 * n + 0], pos);
326 prog.Uniform(light_handle[3 * n + 1], color);
327 prog.Uniform(light_handle[3 * n + 2], strength);
330 void PlanetSurface::SetNumLights(int n) noexcept {
331 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
342 "#version 330 core\n"
344 "layout(location = 0) in vec3 vtx_position;\n"
348 "out vec3 vtx_viewspace;\n"
351 "gl_Position = VP * vec4(vtx_position, 1.0);\n"
352 "gl_Position.z = gl_Position.w;\n"
353 "vtx_viewspace = vtx_position;\n"
358 "#version 330 core\n"
360 "in vec3 vtx_viewspace;\n"
362 "uniform samplerCube tex_sampler;\n"
367 "color = texture(tex_sampler, vtx_viewspace).rgb;\n"
371 if (!prog.Linked()) {
373 throw std::runtime_error("link program");
375 vp_handle = prog.UniformLocation("VP");
376 sampler_handle = prog.UniformLocation("tex_sampler");
379 vao.BindAttributes();
380 vao.EnableAttribute(0);
381 vao.AttributePointer<glm::vec3>(0, false, 0);
382 vao.ReserveAttributes(8, GL_STATIC_DRAW);
384 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
385 attrib[0] = glm::vec3(-1.0f, -1.0f, -1.0f);
386 attrib[1] = glm::vec3(-1.0f, -1.0f, 1.0f);
387 attrib[2] = glm::vec3(-1.0f, 1.0f, -1.0f);
388 attrib[3] = glm::vec3(-1.0f, 1.0f, 1.0f);
389 attrib[4] = glm::vec3( 1.0f, -1.0f, -1.0f);
390 attrib[5] = glm::vec3( 1.0f, -1.0f, 1.0f);
391 attrib[6] = glm::vec3( 1.0f, 1.0f, -1.0f);
392 attrib[7] = glm::vec3( 1.0f, 1.0f, 1.0f);
395 vao.ReserveElements(14, GL_STATIC_DRAW);
397 auto element = vao.MapElements(GL_WRITE_ONLY);
419 void SkyBox::Activate() noexcept {
421 glEnable(GL_DEPTH_TEST);
422 glDepthFunc(GL_LEQUAL);
423 glDisable(GL_CULL_FACE);
427 void SkyBox::SetV(const glm::mat4 &vv) noexcept {
432 v[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
434 prog.Uniform(vp_handle, vp);
437 void SkyBox::SetP(const glm::mat4 &pp) noexcept {
440 prog.Uniform(vp_handle, vp);
443 void SkyBox::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
448 void SkyBox::SetTexture(CubeMap &cm) noexcept {
449 glActiveTexture(GL_TEXTURE0);
451 prog.Uniform(sampler_handle, GLint(0));
454 void SkyBox::Draw() const noexcept {
456 vao.DrawTriangleStrip(14);
460 SunSurface::SunSurface()
464 "#version 330 core\n"
466 "layout(location = 0) in vec3 vtx_position;\n"
470 "uniform mat4 MVP;\n"
472 "out vec3 vtx_viewspace;\n"
475 "gl_Position = MVP * vec4(vtx_position, 1);\n"
476 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
481 "#version 330 core\n"
483 "in vec3 vtx_viewspace;\n"
485 "uniform vec3 light_color;\n"
486 "uniform float light_strength;\n"
491 "vec3 to_light = -vtx_viewspace;\n"
492 "float distance = length(to_light);\n"
493 //"vec3 light_dir = normalize(to_light);\n"
494 "float attenuation = light_strength / (distance * distance);\n"
495 "color = attenuation * light_color;\n"
499 if (!prog.Linked()) {
501 throw std::runtime_error("link program");
503 m_handle = prog.UniformLocation("M");
504 mv_handle = prog.UniformLocation("MV");
505 mvp_handle = prog.UniformLocation("MVP");
506 light_color_handle = prog.UniformLocation("light_color");
507 light_strength_handle = prog.UniformLocation("light_strength");
509 // "resolution" of sphere
510 constexpr int size = 10;
513 vao.BindAttributes();
514 vao.EnableAttribute(0);
515 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
516 vao.ReserveAttributes(4 * 6 * size * size, GL_STATIC_DRAW);
518 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
520 constexpr float radius = float(size) * 0.5f;
522 for (int surface = 0; surface < 3; ++surface) {
523 for (int y = 0; y < size; ++y) {
524 for (int x = 0; x < size; ++x, ++index) {
526 pos[0][(surface + 0) % 3] = float(x + 0) - radius;
527 pos[0][(surface + 1) % 3] = float(y + 0) - radius;
528 pos[0][(surface + 2) % 3] = radius;
529 pos[1][(surface + 0) % 3] = float(x + 0) - radius;
530 pos[1][(surface + 1) % 3] = float(y + 1) - radius;
531 pos[1][(surface + 2) % 3] = radius;
532 pos[2][(surface + 0) % 3] = float(x + 1) - radius;
533 pos[2][(surface + 1) % 3] = float(y + 0) - radius;
534 pos[2][(surface + 2) % 3] = radius;
535 pos[3][(surface + 0) % 3] = float(x + 1) - radius;
536 pos[3][(surface + 1) % 3] = float(y + 1) - radius;
537 pos[3][(surface + 2) % 3] = radius;
538 attrib[4 * index + 0].position = glm::normalize(pos[0]);
539 attrib[4 * index + 1].position = glm::normalize(pos[1]);
540 attrib[4 * index + 2].position = glm::normalize(pos[2]);
541 attrib[4 * index + 3].position = glm::normalize(pos[3]);
545 for (int surface = 3; surface < 6; ++surface) {
546 for (int y = 0; y < size; ++y) {
547 for (int x = 0; x < size; ++x, ++index) {
549 pos[0][(surface + 0) % 3] = float(x + 0) - radius;
550 pos[0][(surface + 1) % 3] = float(y + 0) - radius;
551 pos[0][(surface + 2) % 3] = radius;
552 pos[1][(surface + 0) % 3] = float(x + 0) - radius;
553 pos[1][(surface + 1) % 3] = float(y + 1) - radius;
554 pos[1][(surface + 2) % 3] = radius;
555 pos[2][(surface + 0) % 3] = float(x + 1) - radius;
556 pos[2][(surface + 1) % 3] = float(y + 0) - radius;
557 pos[2][(surface + 2) % 3] = radius;
558 pos[3][(surface + 0) % 3] = float(x + 1) - radius;
559 pos[3][(surface + 1) % 3] = float(y + 1) - radius;
560 pos[3][(surface + 2) % 3] = radius;
561 attrib[4 * index + 0].position = glm::normalize(pos[0]) * -1.0f;
562 attrib[4 * index + 1].position = glm::normalize(pos[1]) * -1.0f;
563 attrib[4 * index + 2].position = glm::normalize(pos[2]) * -1.0f;
564 attrib[4 * index + 3].position = glm::normalize(pos[3]) * -1.0f;
570 vao.ReserveElements(6 * 6 * size * size, GL_STATIC_DRAW);
572 auto element = vao.MapElements(GL_WRITE_ONLY);
574 for (int surface = 0; surface < 3; ++surface) {
575 for (int y = 0; y < size; ++y) {
576 for (int x = 0; x < size; ++x, ++index) {
577 element[6 * index + 0] = 4 * index + 0;
578 element[6 * index + 1] = 4 * index + 2;
579 element[6 * index + 2] = 4 * index + 1;
580 element[6 * index + 3] = 4 * index + 1;
581 element[6 * index + 4] = 4 * index + 2;
582 element[6 * index + 5] = 4 * index + 3;
586 for (int surface = 3; surface < 6; ++surface) {
587 for (int y = 0; y < size; ++y) {
588 for (int x = 0; x < size; ++x, ++index) {
589 element[6 * index + 0] = 4 * index + 0;
590 element[6 * index + 1] = 4 * index + 1;
591 element[6 * index + 2] = 4 * index + 2;
592 element[6 * index + 3] = 4 * index + 2;
593 element[6 * index + 4] = 4 * index + 1;
594 element[6 * index + 5] = 4 * index + 3;
602 SunSurface::~SunSurface() {
605 void SunSurface::Activate() noexcept {
607 glEnable(GL_DEPTH_TEST);
608 glDepthFunc(GL_LESS);
609 glEnable(GL_CULL_FACE);
613 void SunSurface::SetM(const glm::mat4 &mm) noexcept {
617 prog.Uniform(m_handle, m);
618 prog.Uniform(mv_handle, mv);
619 prog.Uniform(mvp_handle, mvp);
622 void SunSurface::SetV(const glm::mat4 &vv) noexcept {
626 prog.Uniform(mv_handle, mv);
627 prog.Uniform(mvp_handle, mvp);
630 void SunSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
635 prog.Uniform(mv_handle, mv);
636 prog.Uniform(mvp_handle, mvp);
639 void SunSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
645 prog.Uniform(m_handle, m);
646 prog.Uniform(mv_handle, mv);
647 prog.Uniform(mvp_handle, mvp);
650 void SunSurface::SetLight(const glm::vec3 &color, float strength) noexcept {
651 prog.Uniform(light_color_handle, color);
652 prog.Uniform(light_strength_handle, strength);
655 void SunSurface::Draw() const noexcept {
656 constexpr int size = 10;
658 vao.DrawTriangles(6 * 6 * size * size);
662 constexpr int CreatureSkin::MAX_LIGHTS;
664 CreatureSkin::CreatureSkin()
668 "#version 330 core\n"
670 "layout(location = 0) in vec3 vtx_position;\n"
671 "layout(location = 1) in vec3 vtx_normal;\n"
672 "layout(location = 2) in vec3 vtx_tex_uv;\n"
676 "uniform mat4 MVP;\n"
678 "out vec3 vtx_viewspace;\n"
679 "out vec3 frag_tex_uv;\n"
683 "gl_Position = MVP * vec4(vtx_position, 1);\n"
684 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
685 "normal = normalize((MV * vec4(vtx_normal, 0)).xyz);\n"
686 "frag_tex_uv = vtx_tex_uv;\n"
691 "#version 330 core\n"
693 "struct LightSource {\n"
699 "in vec3 vtx_viewspace;\n"
700 "in vec3 frag_tex_uv;\n"
703 "uniform vec3 base_color;\n"
704 "uniform vec4 highlight_color;\n"
705 "uniform sampler2DArray tex_sampler;\n"
706 "uniform int num_lights;\n"
707 "uniform LightSource light[8];\n"
712 "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
713 "vec3 mat_color = mix(base_color, highlight_color.rgb, tex_color.r * tex_color.a * highlight_color.a);\n"
714 "vec3 total_light = mat_color * vec3(0.1, 0.1, 0.1);\n"
715 "for (int i = 0; i < num_lights; ++i) {\n"
716 "vec3 to_light = light[i].position - vtx_viewspace;\n"
717 "float distance = length(to_light) + length(vtx_viewspace);\n"
718 "vec3 light_dir = normalize(to_light);\n"
719 "float attenuation = light[i].strength / (distance * distance);\n"
720 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * mat_color;\n"
721 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
722 "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
723 "if (dot(normal, light_dir) >= 0.0) {\n"
724 "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
726 "total_light = total_light + diffuse + specular;\n"
728 "color = total_light;\n"
732 if (!prog.Linked()) {
734 throw std::runtime_error("link program");
736 m_handle = prog.UniformLocation("M");
737 mv_handle = prog.UniformLocation("MV");
738 mvp_handle = prog.UniformLocation("MVP");
739 base_color_handle = prog.UniformLocation("base_color");
740 highlight_color_handle = prog.UniformLocation("highlight_color");
741 sampler_handle = prog.UniformLocation("tex_sampler");
742 num_lights_handle = prog.UniformLocation("num_lights");
743 for (int i = 0; i < MAX_LIGHTS; ++i) {
744 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
745 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
746 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
750 CreatureSkin::~CreatureSkin() {
753 void CreatureSkin::Activate() noexcept {
755 glEnable(GL_DEPTH_TEST);
756 glDepthFunc(GL_LESS);
757 glEnable(GL_CULL_FACE);
761 void CreatureSkin::SetM(const glm::mat4 &mm) noexcept {
765 prog.Uniform(m_handle, m);
766 prog.Uniform(mv_handle, mv);
767 prog.Uniform(mvp_handle, mvp);
770 void CreatureSkin::SetV(const glm::mat4 &vv) noexcept {
774 prog.Uniform(mv_handle, mv);
775 prog.Uniform(mvp_handle, mvp);
778 void CreatureSkin::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
783 prog.Uniform(mv_handle, mv);
784 prog.Uniform(mvp_handle, mvp);
787 void CreatureSkin::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
793 prog.Uniform(m_handle, m);
794 prog.Uniform(mv_handle, mv);
795 prog.Uniform(mvp_handle, mvp);
798 void CreatureSkin::SetBaseColor(const glm::vec3 &c) noexcept {
799 prog.Uniform(base_color_handle, c);
802 void CreatureSkin::SetHighlightColor(const glm::vec4 &c) noexcept {
803 prog.Uniform(highlight_color_handle, c);
806 void CreatureSkin::SetTexture(ArrayTexture &tex) noexcept {
807 glActiveTexture(GL_TEXTURE0);
809 prog.Uniform(sampler_handle, GLint(0));
812 void CreatureSkin::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
813 prog.Uniform(light_handle[3 * n + 0], pos);
814 prog.Uniform(light_handle[3 * n + 1], color);
815 prog.Uniform(light_handle[3 * n + 2], strength);
818 void CreatureSkin::SetNumLights(int n) noexcept {
819 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
823 AlphaSprite::AlphaSprite()
827 "#version 330 core\n"
829 "layout(location = 0) in vec3 vtx_position;\n"
830 "layout(location = 1) in vec2 vtx_texture;\n"
834 "uniform mat4 MVP;\n"
836 "out vec2 frag_tex_uv;\n"
839 "gl_Position = MVP * vec4(vtx_position, 1);\n"
840 "frag_tex_uv = vtx_texture;\n"
845 "#version 330 core\n"
847 "in vec2 frag_tex_uv;\n"
849 "uniform sampler2D tex_sampler;\n"
850 "uniform vec4 fg_color;\n"
851 "uniform vec4 bg_color;\n"
856 "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
857 "vec4 factor = mix(bg_color, fg_color, tex_color.a);\n"
858 "color = vec4((tex_color * factor).rgb, factor.a);\n"
862 if (!prog.Linked()) {
864 throw std::runtime_error("link program");
866 m_handle = prog.UniformLocation("M");
867 mv_handle = prog.UniformLocation("MV");
868 mvp_handle = prog.UniformLocation("MVP");
869 sampler_handle = prog.UniformLocation("tex_sampler");
870 fg_color_handle = prog.UniformLocation("fg_color");
871 bg_color_handle = prog.UniformLocation("bg_color");
874 vao.BindAttributes();
875 vao.EnableAttribute(0);
876 vao.EnableAttribute(1);
877 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
878 vao.AttributePointer<glm::vec2>(1, false, offsetof(Attributes, texture));
879 vao.ReserveAttributes(4, GL_STATIC_DRAW);
881 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
882 attrib[0].position = glm::vec3(-0.5f, -0.5f, 0.0f);
883 attrib[0].texture = glm::vec2(0.0f, 0.0f);
884 attrib[1].position = glm::vec3(-0.5f, 0.5f, 0.0f);
885 attrib[1].texture = glm::vec2(0.0f, 1.0f);
886 attrib[2].position = glm::vec3( 0.5f, -0.5f, 0.0f);
887 attrib[2].texture = glm::vec2(1.0f, 0.0f);
888 attrib[3].position = glm::vec3( 0.5f, 0.5f, 0.0f);
889 attrib[3].texture = glm::vec2(1.0f, 1.0f);
892 vao.ReserveElements(7, GL_STATIC_DRAW);
894 auto element = vao.MapElements(GL_WRITE_ONLY);
903 AlphaSprite::~AlphaSprite() {
906 void AlphaSprite::Activate() noexcept {
908 glEnable(GL_DEPTH_TEST);
909 glDepthFunc(GL_LESS);
910 glEnable(GL_CULL_FACE);
912 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
915 void AlphaSprite::SetM(const glm::mat4 &mm) noexcept {
919 prog.Uniform(m_handle, m);
920 prog.Uniform(mv_handle, mv);
921 prog.Uniform(mvp_handle, mvp);
924 void AlphaSprite::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
929 prog.Uniform(mv_handle, mv);
930 prog.Uniform(mvp_handle, mvp);
933 void AlphaSprite::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
939 prog.Uniform(m_handle, m);
940 prog.Uniform(mv_handle, mv);
941 prog.Uniform(mvp_handle, mvp);
944 void AlphaSprite::SetTexture(Texture &tex) noexcept {
945 glActiveTexture(GL_TEXTURE0);
947 prog.Uniform(sampler_handle, GLint(0));
950 void AlphaSprite::SetFgColor(const glm::vec4 &color) noexcept {
951 prog.Uniform(fg_color_handle, color);
954 void AlphaSprite::SetBgColor(const glm::vec4 &color) noexcept {
955 prog.Uniform(bg_color_handle, color);
958 void AlphaSprite::DrawRect() const noexcept {
960 vao.DrawTriangleStrip(4);
969 "#version 330 core\n"
971 "layout(location = 0) in vec2 vtx_position;\n"
977 // disamond rule adjust
978 //"vec3 position = vtx_position + vec3(0.5, 0.5, 0.0);\n"
979 "gl_Position = P * vec4(vtx_position, z, 1);\n"
984 "#version 330 core\n"
995 if (!prog.Linked()) {
997 throw std::runtime_error("link program");
999 p_handle = prog.UniformLocation("P");
1000 z_handle = prog.UniformLocation("z");
1001 c_handle = prog.UniformLocation("c");
1004 vao.BindAttributes();
1005 vao.EnableAttribute(0);
1006 vao.AttributePointer<glm::vec2>(0, false, offsetof(Attributes, position));
1007 vao.ReserveAttributes(255, GL_DYNAMIC_DRAW);
1009 vao.ReserveElements(255, GL_DYNAMIC_DRAW);
1016 void Canvas::Resize(float w, float h) noexcept {
1017 prog.Uniform(p_handle, glm::ortho(0.0f, w, h, 0.0f, 1.0e4f, -1.0e4f));
1020 void Canvas::ZIndex(float z) noexcept {
1021 prog.Uniform(z_handle, -z);
1024 void Canvas::SetColor(const glm::vec4 &color) noexcept {
1025 prog.Uniform(c_handle, color);
1028 void Canvas::Activate() noexcept {
1030 glEnable(GL_DEPTH_TEST);
1031 glDepthFunc(GL_LESS);
1032 glEnable(GL_CULL_FACE);
1034 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1037 void Canvas::DrawLine(const glm::vec2 &p1, const glm::vec2 &p2, float width) {
1038 glm::vec2 d = glm::normalize(p2 - p1) * (width * 0.5f);
1039 glm::vec2 n = glm::vec2(d.y, -d.x);
1041 vao.BindAttributes();
1043 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
1044 attr[0].position = p1 - d + n;
1045 attr[1].position = p1 - d - n;
1046 attr[2].position = p2 + d + n;
1047 attr[3].position = p2 + d - n;
1051 auto elem = vao.MapElements(GL_WRITE_ONLY);
1057 vao.DrawTriangleStrip(4);
1061 void Canvas::DrawRect(const glm::vec2 &p1, const glm::vec2 &p2, float width) {
1062 glm::vec2 min(std::min(p1.x, p2.x), std::min(p1.y, p2.y));
1063 glm::vec2 max(std::max(p1.x, p2.x), std::max(p1.y, p2.y));
1064 glm::vec2 dg1(min.x, max.y);
1065 glm::vec2 dg2(max.x, min.y);
1066 glm::vec2 d(width * 0.5f, width * 0.5f);
1067 glm::vec2 n(d.y, -d.x);
1069 vao.BindAttributes();
1071 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
1072 attr[0].position = min + d;
1073 attr[1].position = min - d;
1074 attr[2].position = dg1 + n;
1075 attr[3].position = dg1 - n;
1076 attr[4].position = max - d;
1077 attr[5].position = max + d;
1078 attr[6].position = dg2 - n;
1079 attr[7].position = dg2 + n;
1083 auto elem = vao.MapElements(GL_WRITE_ONLY);
1095 vao.DrawTriangleStrip(10);
1099 void Canvas::FillRect(const glm::vec2 &p1, const glm::vec2 &p2) {
1100 glm::vec2 min(std::min(p1.x, p2.x), std::min(p1.y, p2.y));
1101 glm::vec2 max(std::max(p1.x, p2.x), std::max(p1.y, p2.y));
1102 glm::vec2 dg1(min.x, max.y);
1103 glm::vec2 dg2(max.x, min.y);
1105 vao.BindAttributes();
1107 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
1108 attr[0].position = min;
1109 attr[1].position = dg1;
1110 attr[2].position = dg2;
1111 attr[3].position = max;
1115 auto elem = vao.MapElements(GL_WRITE_ONLY);
1121 vao.DrawTriangleStrip(4);