1 #include "AlphaSprite.hpp"
3 #include "CreatureSkin.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>
20 #include <glm/gtx/transform.hpp>
25 void gl_error(std::string msg) {
26 const GLubyte *errBegin = gluErrorString(glGetError());
27 if (errBegin && *errBegin != '\0') {
28 const GLubyte *errEnd = errBegin;
29 while (*errEnd != '\0') {
33 msg.append(errBegin, errEnd);
35 throw std::runtime_error(msg);
43 Shader::Shader(GLenum type)
44 : handle(glCreateShader(type)) {
46 gl_error("glCreateShader");
52 glDeleteShader(handle);
56 Shader::Shader(Shader &&other) noexcept
57 : handle(other.handle) {
61 Shader &Shader::operator =(Shader &&other) noexcept {
62 std::swap(handle, other.handle);
67 void Shader::Source(const GLchar *src) noexcept {
68 const GLchar* src_arr[] = { src };
69 glShaderSource(handle, 1, src_arr, nullptr);
72 void Shader::Compile() noexcept {
73 glCompileShader(handle);
76 bool Shader::Compiled() const noexcept {
77 GLint compiled = GL_FALSE;
78 glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled);
79 return compiled == GL_TRUE;
82 void Shader::Log(std::ostream &out) const {
83 int log_len = 0, max_len = 0;
84 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &max_len);
85 std::unique_ptr<char[]> log(new char[max_len]);
86 glGetShaderInfoLog(handle, max_len, &log_len, log.get());
87 out.write(log.get(), log_len);
91 void Shader::AttachToProgram(GLuint id) const noexcept {
92 glAttachShader(id, handle);
97 : handle(glCreateProgram()) {
99 gl_error("glCreateProgram");
103 Program::~Program() {
105 glDeleteProgram(handle);
110 const Shader &Program::LoadShader(GLenum type, const GLchar *src) {
111 shaders.emplace_back(type);
112 Shader &shader = shaders.back();
115 if (!shader.Compiled()) {
116 shader.Log(std::cerr);
117 throw std::runtime_error("compile shader");
123 void Program::Attach(Shader &shader) noexcept {
124 shader.AttachToProgram(handle);
127 void Program::Link() noexcept {
128 glLinkProgram(handle);
131 bool Program::Linked() const noexcept {
132 GLint linked = GL_FALSE;
133 glGetProgramiv(handle, GL_LINK_STATUS, &linked);
134 return linked == GL_TRUE;
137 void Program::Log(std::ostream &out) const {
138 int log_len = 0, max_len = 0;
139 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &max_len);
140 std::unique_ptr<char[]> log(new char[max_len]);
141 glGetProgramInfoLog(handle, max_len, &log_len, log.get());
142 out.write(log.get(), log_len);
146 GLint Program::AttributeLocation(const GLchar *name) const noexcept {
147 return glGetAttribLocation(handle, name);
150 GLint Program::AttributeLocation(const std::string &name) const noexcept {
151 return AttributeLocation(name.c_str());
154 GLint Program::UniformLocation(const GLchar *name) const noexcept {
155 return glGetUniformLocation(handle, name);
158 GLint Program::UniformLocation(const std::string &name) const noexcept {
159 return UniformLocation(name.c_str());
163 void Program::Uniform(GLint loc, GLint val) noexcept {
164 glUniform1i(loc, val);
167 void Program::Uniform(GLint loc, float val) noexcept {
168 glUniform1f(loc, val);
171 void Program::Uniform(GLint loc, const glm::vec3 &val) noexcept {
172 glUniform3fv(loc, 1, glm::value_ptr(val));
175 void Program::Uniform(GLint loc, const glm::vec4 &val) noexcept {
176 glUniform4fv(loc, 1, glm::value_ptr(val));
179 void Program::Uniform(GLint loc, const glm::mat4 &val) noexcept {
180 glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
184 constexpr int PlanetSurface::MAX_LIGHTS;
186 PlanetSurface::PlanetSurface()
190 "#version 330 core\n"
192 "layout(location = 0) in vec3 vtx_position;\n"
193 "layout(location = 1) in vec3 vtx_tex_uv;\n"
197 "uniform mat4 MVP;\n"
199 "out vec3 frag_tex_uv;\n"
200 "out vec3 vtx_viewspace;\n"
203 "gl_Position = MVP * vec4(vtx_position, 1);\n"
204 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
205 "frag_tex_uv = vtx_tex_uv;\n"
210 "#version 330 core\n"
212 "struct LightSource {\n"
218 "in vec3 vtx_viewspace;\n"
219 "in vec3 frag_tex_uv;\n"
221 "uniform sampler2DArray tex_sampler;\n"
222 "uniform vec3 normal;\n"
223 "uniform int num_lights;\n"
224 "uniform LightSource light[8];\n"
229 "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
230 "vec3 total_light = tex_color * vec3(0.01, 0.01, 0.01);\n"
231 "for (int i = 0; i < num_lights; ++i) {\n"
232 "vec3 to_light = light[i].position - vtx_viewspace;\n"
233 "float distance = length(to_light) + length(vtx_viewspace);\n"
234 "vec3 light_dir = normalize(to_light);\n"
235 "float attenuation = light[i].strength / (distance * distance);\n"
236 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
237 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
238 "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
239 "if (dot(normal, light_dir) >= 0.0) {\n"
240 "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
242 "total_light = total_light + diffuse + specular;\n"
244 "color = total_light;\n"
248 if (!prog.Linked()) {
250 throw std::runtime_error("link program");
252 m_handle = prog.UniformLocation("M");
253 mv_handle = prog.UniformLocation("MV");
254 mvp_handle = prog.UniformLocation("MVP");
255 sampler_handle = prog.UniformLocation("tex_sampler");
256 normal_handle = prog.UniformLocation("normal");
257 num_lights_handle = prog.UniformLocation("num_lights");
258 for (int i = 0; i < MAX_LIGHTS; ++i) {
259 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
260 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
261 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
265 PlanetSurface::~PlanetSurface() {
268 void PlanetSurface::Activate() noexcept {
270 glEnable(GL_DEPTH_TEST);
271 glDepthFunc(GL_LESS);
272 glEnable(GL_CULL_FACE);
276 void PlanetSurface::SetM(const glm::mat4 &mm) noexcept {
280 prog.Uniform(m_handle, m);
281 prog.Uniform(mv_handle, mv);
282 prog.Uniform(mvp_handle, mvp);
285 void PlanetSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
290 prog.Uniform(mv_handle, mv);
291 prog.Uniform(mvp_handle, mvp);
294 void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
300 prog.Uniform(m_handle, m);
301 prog.Uniform(mv_handle, mv);
302 prog.Uniform(mvp_handle, mvp);
305 void PlanetSurface::SetNormal(const glm::vec3 &n) noexcept {
306 prog.Uniform(normal_handle, n);
309 void PlanetSurface::SetTexture(ArrayTexture &tex) noexcept {
310 glActiveTexture(GL_TEXTURE0);
312 prog.Uniform(sampler_handle, GLint(0));
315 void PlanetSurface::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
316 prog.Uniform(light_handle[3 * n + 0], pos);
317 prog.Uniform(light_handle[3 * n + 1], color);
318 prog.Uniform(light_handle[3 * n + 2], strength);
321 void PlanetSurface::SetNumLights(int n) noexcept {
322 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
326 SunSurface::SunSurface()
330 "#version 330 core\n"
332 "layout(location = 0) in vec3 vtx_position;\n"
336 "uniform mat4 MVP;\n"
338 "out vec3 vtx_viewspace;\n"
341 "gl_Position = MVP * vec4(vtx_position, 1);\n"
342 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
347 "#version 330 core\n"
349 "in vec3 vtx_viewspace;\n"
351 "uniform vec3 light_color;\n"
352 "uniform float light_strength;\n"
357 "vec3 to_light = -vtx_viewspace;\n"
358 "float distance = length(to_light);\n"
359 //"vec3 light_dir = normalize(to_light);\n"
360 "float attenuation = light_strength / (distance * distance);\n"
361 "color = attenuation * light_color;\n"
365 if (!prog.Linked()) {
367 throw std::runtime_error("link program");
369 m_handle = prog.UniformLocation("M");
370 mv_handle = prog.UniformLocation("MV");
371 mvp_handle = prog.UniformLocation("MVP");
372 light_color_handle = prog.UniformLocation("light_color");
373 light_strength_handle = prog.UniformLocation("light_strength");
376 vao.BindAttributes();
377 vao.EnableAttribute(0);
378 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
379 vao.ReserveAttributes(8, GL_STATIC_DRAW);
381 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
382 attrib[0].position = glm::vec3(-1.0f, -1.0f, -1.0f);
383 attrib[1].position = glm::vec3(-1.0f, -1.0f, 1.0f);
384 attrib[2].position = glm::vec3(-1.0f, 1.0f, -1.0f);
385 attrib[3].position = glm::vec3(-1.0f, 1.0f, 1.0f);
386 attrib[4].position = glm::vec3( 1.0f, -1.0f, -1.0f);
387 attrib[5].position = glm::vec3( 1.0f, -1.0f, 1.0f);
388 attrib[6].position = glm::vec3( 1.0f, 1.0f, -1.0f);
389 attrib[7].position = glm::vec3( 1.0f, 1.0f, 1.0f);
392 vao.ReserveElements(36, GL_STATIC_DRAW);
394 auto element = vao.MapElements(GL_WRITE_ONLY);
441 SunSurface::~SunSurface() {
444 void SunSurface::Activate() noexcept {
446 glEnable(GL_DEPTH_TEST);
447 glDepthFunc(GL_LESS);
448 glEnable(GL_CULL_FACE);
452 void SunSurface::SetM(const glm::mat4 &mm) noexcept {
456 prog.Uniform(m_handle, m);
457 prog.Uniform(mv_handle, mv);
458 prog.Uniform(mvp_handle, mvp);
461 void SunSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
466 prog.Uniform(mv_handle, mv);
467 prog.Uniform(mvp_handle, mvp);
470 void SunSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
476 prog.Uniform(m_handle, m);
477 prog.Uniform(mv_handle, mv);
478 prog.Uniform(mvp_handle, mvp);
481 void SunSurface::SetLight(const glm::vec3 &color, float strength) noexcept {
482 prog.Uniform(light_color_handle, color);
483 prog.Uniform(light_strength_handle, strength);
486 void SunSurface::Draw() const noexcept {
488 vao.DrawTriangles(36);
492 constexpr int CreatureSkin::MAX_LIGHTS;
494 CreatureSkin::CreatureSkin()
498 "#version 330 core\n"
500 "layout(location = 0) in vec3 vtx_position;\n"
501 "layout(location = 1) in vec3 vtx_normal;\n"
502 "layout(location = 2) in vec3 vtx_tex_uv;\n"
506 "uniform mat4 MVP;\n"
508 "out vec3 vtx_viewspace;\n"
509 "out vec3 frag_tex_uv;\n"
513 "gl_Position = MVP * vec4(vtx_position, 1);\n"
514 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
515 "normal = normalize((MV * vec4(vtx_normal, 0)).xyz);\n"
516 "frag_tex_uv = vtx_tex_uv;\n"
521 "#version 330 core\n"
523 "struct LightSource {\n"
529 "in vec3 vtx_viewspace;\n"
530 "in vec3 frag_tex_uv;\n"
533 "uniform sampler2DArray tex_sampler;\n"
534 "uniform int num_lights;\n"
535 "uniform LightSource light[8];\n"
540 "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
541 "vec3 total_light = tex_color * vec3(0.01, 0.01, 0.01);\n"
542 "for (int i = 0; i < num_lights; ++i) {\n"
543 "vec3 to_light = light[i].position - vtx_viewspace;\n"
544 "float distance = length(to_light) + length(vtx_viewspace);\n"
545 "vec3 light_dir = normalize(to_light);\n"
546 "float attenuation = light[i].strength / (distance * distance);\n"
547 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
548 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
549 "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
550 "if (dot(normal, light_dir) >= 0.0) {\n"
551 "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
553 "total_light = total_light + diffuse + specular;\n"
555 "color = total_light;\n"
559 if (!prog.Linked()) {
561 throw std::runtime_error("link program");
563 m_handle = prog.UniformLocation("M");
564 mv_handle = prog.UniformLocation("MV");
565 mvp_handle = prog.UniformLocation("MVP");
566 sampler_handle = prog.UniformLocation("tex_sampler");
567 num_lights_handle = prog.UniformLocation("num_lights");
568 for (int i = 0; i < MAX_LIGHTS; ++i) {
569 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
570 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
571 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
575 CreatureSkin::~CreatureSkin() {
578 void CreatureSkin::Activate() noexcept {
580 glEnable(GL_DEPTH_TEST);
581 glDepthFunc(GL_LESS);
582 glEnable(GL_CULL_FACE);
586 void CreatureSkin::SetM(const glm::mat4 &mm) noexcept {
590 prog.Uniform(m_handle, m);
591 prog.Uniform(mv_handle, mv);
592 prog.Uniform(mvp_handle, mvp);
595 void CreatureSkin::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
600 prog.Uniform(mv_handle, mv);
601 prog.Uniform(mvp_handle, mvp);
604 void CreatureSkin::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
610 prog.Uniform(m_handle, m);
611 prog.Uniform(mv_handle, mv);
612 prog.Uniform(mvp_handle, mvp);
615 void CreatureSkin::SetTexture(ArrayTexture &tex) noexcept {
616 glActiveTexture(GL_TEXTURE0);
618 prog.Uniform(sampler_handle, GLint(0));
621 void CreatureSkin::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
622 prog.Uniform(light_handle[3 * n + 0], pos);
623 prog.Uniform(light_handle[3 * n + 1], color);
624 prog.Uniform(light_handle[3 * n + 2], strength);
627 void CreatureSkin::SetNumLights(int n) noexcept {
628 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
632 AlphaSprite::AlphaSprite()
636 "#version 330 core\n"
638 "layout(location = 0) in vec3 vtx_position;\n"
639 "layout(location = 1) in vec2 vtx_texture;\n"
643 "uniform mat4 MVP;\n"
645 "out vec2 frag_tex_uv;\n"
648 "gl_Position = MVP * vec4(vtx_position, 1);\n"
649 "frag_tex_uv = vtx_texture;\n"
654 "#version 330 core\n"
656 "in vec2 frag_tex_uv;\n"
658 "uniform sampler2D tex_sampler;\n"
659 "uniform vec4 fg_color;\n"
660 "uniform vec4 bg_color;\n"
665 "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
666 "vec4 factor = mix(bg_color, fg_color, tex_color.a);\n"
667 "color = vec4((tex_color * factor).rgb, factor.a);\n"
671 if (!prog.Linked()) {
673 throw std::runtime_error("link program");
675 m_handle = prog.UniformLocation("M");
676 mv_handle = prog.UniformLocation("MV");
677 mvp_handle = prog.UniformLocation("MVP");
678 sampler_handle = prog.UniformLocation("tex_sampler");
679 fg_color_handle = prog.UniformLocation("fg_color");
680 bg_color_handle = prog.UniformLocation("bg_color");
683 vao.BindAttributes();
684 vao.EnableAttribute(0);
685 vao.EnableAttribute(1);
686 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
687 vao.AttributePointer<glm::vec2>(1, false, offsetof(Attributes, texture));
688 vao.ReserveAttributes(4, GL_STATIC_DRAW);
690 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
691 attrib[0].position = glm::vec3(-0.5f, -0.5f, 0.0f);
692 attrib[0].texture = glm::vec2(0.0f, 0.0f);
693 attrib[1].position = glm::vec3(-0.5f, 0.5f, 0.0f);
694 attrib[1].texture = glm::vec2(0.0f, 1.0f);
695 attrib[2].position = glm::vec3( 0.5f, -0.5f, 0.0f);
696 attrib[2].texture = glm::vec2(1.0f, 0.0f);
697 attrib[3].position = glm::vec3( 0.5f, 0.5f, 0.0f);
698 attrib[3].texture = glm::vec2(1.0f, 1.0f);
701 vao.ReserveElements(7, GL_STATIC_DRAW);
703 auto element = vao.MapElements(GL_WRITE_ONLY);
712 AlphaSprite::~AlphaSprite() {
715 void AlphaSprite::Activate() noexcept {
717 glEnable(GL_DEPTH_TEST);
718 glDepthFunc(GL_LESS);
719 glEnable(GL_CULL_FACE);
721 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
724 void AlphaSprite::SetM(const glm::mat4 &mm) noexcept {
728 prog.Uniform(m_handle, m);
729 prog.Uniform(mv_handle, mv);
730 prog.Uniform(mvp_handle, mvp);
733 void AlphaSprite::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
738 prog.Uniform(mv_handle, mv);
739 prog.Uniform(mvp_handle, mvp);
742 void AlphaSprite::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
748 prog.Uniform(m_handle, m);
749 prog.Uniform(mv_handle, mv);
750 prog.Uniform(mvp_handle, mvp);
753 void AlphaSprite::SetTexture(Texture &tex) noexcept {
754 glActiveTexture(GL_TEXTURE0);
756 prog.Uniform(sampler_handle, GLint(0));
759 void AlphaSprite::SetFgColor(const glm::vec4 &color) noexcept {
760 prog.Uniform(fg_color_handle, color);
763 void AlphaSprite::SetBgColor(const glm::vec4 &color) noexcept {
764 prog.Uniform(bg_color_handle, color);
767 void AlphaSprite::DrawRect() const noexcept {
769 vao.DrawTriangleStrip(4);
778 "#version 330 core\n"
780 "layout(location = 0) in vec2 vtx_position;\n"
786 // disamond rule adjust
787 //"vec3 position = vtx_position + vec3(0.5, 0.5, 0.0);\n"
788 "gl_Position = P * vec4(vtx_position, z, 1);\n"
793 "#version 330 core\n"
804 if (!prog.Linked()) {
806 throw std::runtime_error("link program");
808 p_handle = prog.UniformLocation("P");
809 z_handle = prog.UniformLocation("z");
810 c_handle = prog.UniformLocation("c");
813 vao.BindAttributes();
814 vao.EnableAttribute(0);
815 vao.AttributePointer<glm::vec2>(0, false, offsetof(Attributes, position));
816 vao.ReserveAttributes(255, GL_DYNAMIC_DRAW);
818 vao.ReserveElements(255, GL_DYNAMIC_DRAW);
825 void Canvas::Resize(float w, float h) noexcept {
826 prog.Uniform(p_handle, glm::ortho(0.0f, w, h, 0.0f, 1.0e4f, -1.0e4f));
829 void Canvas::ZIndex(float z) noexcept {
830 prog.Uniform(z_handle, -z);
833 void Canvas::SetColor(const glm::vec4 &color) noexcept {
834 prog.Uniform(c_handle, color);
837 void Canvas::Activate() noexcept {
839 glEnable(GL_DEPTH_TEST);
840 glDepthFunc(GL_LESS);
841 glEnable(GL_CULL_FACE);
843 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
846 void Canvas::DrawLine(const glm::vec2 &p1, const glm::vec2 &p2, float width) {
847 glm::vec2 d = glm::normalize(p2 - p1) * (width * 0.5f);
848 glm::vec2 n = glm::vec2(d.y, -d.x);
850 vao.BindAttributes();
852 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
853 attr[0].position = p1 - d + n;
854 attr[1].position = p1 - d - n;
855 attr[2].position = p2 + d + n;
856 attr[3].position = p2 + d - n;
860 auto elem = vao.MapElements(GL_WRITE_ONLY);
866 vao.DrawTriangleStrip(4);
870 void Canvas::DrawRect(const glm::vec2 &p1, const glm::vec2 &p2, float width) {
871 glm::vec2 min(std::min(p1.x, p2.x), std::min(p1.y, p2.y));
872 glm::vec2 max(std::max(p1.x, p2.x), std::max(p1.y, p2.y));
873 glm::vec2 dg1(min.x, max.y);
874 glm::vec2 dg2(max.x, min.y);
875 glm::vec2 d(width * 0.5f, width * 0.5f);
876 glm::vec2 n(d.y, -d.x);
878 vao.BindAttributes();
880 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
881 attr[0].position = min + d;
882 attr[1].position = min - d;
883 attr[2].position = dg1 + n;
884 attr[3].position = dg1 - n;
885 attr[4].position = max - d;
886 attr[5].position = max + d;
887 attr[6].position = dg2 - n;
888 attr[7].position = dg2 + n;
892 auto elem = vao.MapElements(GL_WRITE_ONLY);
904 vao.DrawTriangleStrip(10);
908 void Canvas::FillRect(const glm::vec2 &p1, const glm::vec2 &p2) {
909 glm::vec2 min(std::min(p1.x, p2.x), std::min(p1.y, p2.y));
910 glm::vec2 max(std::max(p1.x, p2.x), std::max(p1.y, p2.y));
911 glm::vec2 dg1(min.x, max.y);
912 glm::vec2 dg2(max.x, min.y);
914 vao.BindAttributes();
916 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
917 attr[0].position = min;
918 attr[1].position = dg1;
919 attr[2].position = dg2;
920 attr[3].position = max;
924 auto elem = vao.MapElements(GL_WRITE_ONLY);
930 vao.DrawTriangleStrip(4);