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"
197 "layout(location = 3) in float vtx_shiny;\n"
198 "layout(location = 4) in float vtx_glossy;\n"
199 "layout(location = 5) in float vtx_metallic;\n"
203 "uniform mat4 MVP;\n"
205 "out vec3 vtx_viewspace;\n"
206 "out vec3 nrm_viewspace;\n"
207 "out vec3 frag_tex_uv;\n"
208 "out float frag_shiny;\n"
209 "out float frag_glossy;\n"
210 "out float frag_metallic;\n"
213 "gl_Position = MVP * vec4(vtx_position, 1.0);\n"
214 "vtx_viewspace = (MV * vec4(vtx_position, 1.0)).xyz;\n"
215 "nrm_viewspace = (MV * vec4(vtx_position, 0.0)).xyz;\n"
216 "frag_tex_uv = vtx_tex_uv;\n"
217 "frag_shiny = vtx_shiny;\n"
218 "frag_glossy = vtx_glossy;\n"
219 "frag_metallic = vtx_metallic;\n"
224 "#version 330 core\n"
226 "struct LightSource {\n"
232 "in vec3 vtx_viewspace;\n"
233 "in vec3 nrm_viewspace;\n"
234 "in vec3 frag_tex_uv;\n"
235 "in float frag_shiny;\n"
236 "in float frag_glossy;\n"
237 "in float frag_metallic;\n"
239 "uniform sampler2DArray tex_sampler;\n"
240 "uniform vec3 ambient;\n"
241 "uniform int num_lights;\n"
242 "uniform LightSource light[8];\n"
247 "vec3 normal = normalize(nrm_viewspace);\n"
248 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
249 "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
250 "vec3 spec_color = mix(vec3(frag_glossy), tex_color, frag_metallic);\n"
251 "vec3 total_light = tex_color * ambient;\n"
252 "for (int i = 0; i < num_lights; ++i) {\n"
253 "vec3 to_light = light[i].position - vtx_viewspace;\n"
254 "float distance = length(to_light) + length(vtx_viewspace);\n"
255 "vec3 light_dir = normalize(to_light);\n"
256 "float attenuation = light[i].strength / (distance * distance);\n"
257 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
258 "vec3 specular = attenuation * light[i].color"
259 " * mix(spec_color, vec3(1.0), pow(1.0 - max(0.0, dot(normalize(light_dir + view_dir), view_dir)), 5.0))"
260 " * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), frag_shiny);\n"
261 "total_light = total_light + diffuse + specular;\n"
263 "color = total_light;\n"
267 if (!prog.Linked()) {
269 throw std::runtime_error("link program");
271 m_handle = prog.UniformLocation("M");
272 mv_handle = prog.UniformLocation("MV");
273 mvp_handle = prog.UniformLocation("MVP");
274 sampler_handle = prog.UniformLocation("tex_sampler");
275 ambient_handle = prog.UniformLocation("ambient");
276 num_lights_handle = prog.UniformLocation("num_lights");
277 for (int i = 0; i < MAX_LIGHTS; ++i) {
278 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
279 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
280 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
284 PlanetSurface::~PlanetSurface() {
287 void PlanetSurface::Activate() noexcept {
289 glEnable(GL_DEPTH_TEST);
290 glDepthFunc(GL_LESS);
291 glEnable(GL_CULL_FACE);
295 void PlanetSurface::SetM(const glm::mat4 &mm) noexcept {
299 prog.Uniform(m_handle, m);
300 prog.Uniform(mv_handle, mv);
301 prog.Uniform(mvp_handle, mvp);
304 void PlanetSurface::SetV(const glm::mat4 &vv) noexcept {
308 prog.Uniform(mv_handle, mv);
309 prog.Uniform(mvp_handle, mvp);
312 void PlanetSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
317 prog.Uniform(mv_handle, mv);
318 prog.Uniform(mvp_handle, mvp);
321 void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
327 prog.Uniform(m_handle, m);
328 prog.Uniform(mv_handle, mv);
329 prog.Uniform(mvp_handle, mvp);
332 void PlanetSurface::SetTexture(ArrayTexture &tex) noexcept {
333 glActiveTexture(GL_TEXTURE0);
335 prog.Uniform(sampler_handle, GLint(0));
338 void PlanetSurface::SetAmbient(const glm::vec3 &a) noexcept {
339 prog.Uniform(ambient_handle, a);
342 void PlanetSurface::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
343 prog.Uniform(light_handle[3 * n + 0], pos);
344 prog.Uniform(light_handle[3 * n + 1], color);
345 prog.Uniform(light_handle[3 * n + 2], strength);
348 void PlanetSurface::SetNumLights(int n) noexcept {
349 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
360 "#version 330 core\n"
362 "layout(location = 0) in vec3 vtx_position;\n"
366 "out vec3 vtx_viewspace;\n"
369 "gl_Position = VP * vec4(vtx_position, 1.0);\n"
370 "gl_Position.z = gl_Position.w;\n"
371 "vtx_viewspace = vtx_position;\n"
376 "#version 330 core\n"
378 "in vec3 vtx_viewspace;\n"
380 "uniform samplerCube tex_sampler;\n"
385 "color = texture(tex_sampler, vtx_viewspace).rgb;\n"
389 if (!prog.Linked()) {
391 throw std::runtime_error("link program");
393 vp_handle = prog.UniformLocation("VP");
394 sampler_handle = prog.UniformLocation("tex_sampler");
397 vao.BindAttributes();
398 vao.EnableAttribute(0);
399 vao.AttributePointer<glm::vec3>(0, false, 0);
400 vao.ReserveAttributes(8, GL_STATIC_DRAW);
402 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
403 attrib[0] = glm::vec3(-1.0f, -1.0f, -1.0f);
404 attrib[1] = glm::vec3(-1.0f, -1.0f, 1.0f);
405 attrib[2] = glm::vec3(-1.0f, 1.0f, -1.0f);
406 attrib[3] = glm::vec3(-1.0f, 1.0f, 1.0f);
407 attrib[4] = glm::vec3( 1.0f, -1.0f, -1.0f);
408 attrib[5] = glm::vec3( 1.0f, -1.0f, 1.0f);
409 attrib[6] = glm::vec3( 1.0f, 1.0f, -1.0f);
410 attrib[7] = glm::vec3( 1.0f, 1.0f, 1.0f);
413 vao.ReserveElements(14, GL_STATIC_DRAW);
415 auto element = vao.MapElements(GL_WRITE_ONLY);
437 void SkyBox::Activate() noexcept {
439 glEnable(GL_DEPTH_TEST);
440 glDepthFunc(GL_LEQUAL);
441 glDisable(GL_CULL_FACE);
445 void SkyBox::SetV(const glm::mat4 &vv) noexcept {
450 v[3] = glm::vec4(0.0f, 0.0f, 0.0f, 1.0f);
452 prog.Uniform(vp_handle, vp);
455 void SkyBox::SetP(const glm::mat4 &pp) noexcept {
458 prog.Uniform(vp_handle, vp);
461 void SkyBox::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
466 void SkyBox::SetTexture(CubeMap &cm) noexcept {
467 glActiveTexture(GL_TEXTURE0);
469 prog.Uniform(sampler_handle, GLint(0));
472 void SkyBox::Draw() const noexcept {
474 vao.DrawTriangleStrip(14);
478 SunSurface::SunSurface()
482 "#version 330 core\n"
484 "layout(location = 0) in vec3 vtx_position;\n"
488 "uniform mat4 MVP;\n"
490 "out vec3 vtx_viewspace;\n"
493 "gl_Position = MVP * vec4(vtx_position, 1);\n"
494 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
499 "#version 330 core\n"
501 "in vec3 vtx_viewspace;\n"
503 "uniform vec3 light_color;\n"
504 "uniform float light_strength;\n"
509 "vec3 to_light = -vtx_viewspace;\n"
510 "float distance = length(to_light);\n"
511 //"vec3 light_dir = normalize(to_light);\n"
512 "float attenuation = light_strength / (distance * distance);\n"
513 "color = attenuation * light_color;\n"
517 if (!prog.Linked()) {
519 throw std::runtime_error("link program");
521 m_handle = prog.UniformLocation("M");
522 mv_handle = prog.UniformLocation("MV");
523 mvp_handle = prog.UniformLocation("MVP");
524 light_color_handle = prog.UniformLocation("light_color");
525 light_strength_handle = prog.UniformLocation("light_strength");
527 // "resolution" of sphere
528 constexpr int size = 10;
531 vao.BindAttributes();
532 vao.EnableAttribute(0);
533 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
534 vao.ReserveAttributes(4 * 6 * size * size, GL_STATIC_DRAW);
536 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
538 constexpr float radius = float(size) * 0.5f;
540 for (int surface = 0; surface < 3; ++surface) {
541 for (int y = 0; y < size; ++y) {
542 for (int x = 0; x < size; ++x, ++index) {
544 pos[0][(surface + 0) % 3] = float(x + 0) - radius;
545 pos[0][(surface + 1) % 3] = float(y + 0) - radius;
546 pos[0][(surface + 2) % 3] = radius;
547 pos[1][(surface + 0) % 3] = float(x + 0) - radius;
548 pos[1][(surface + 1) % 3] = float(y + 1) - radius;
549 pos[1][(surface + 2) % 3] = radius;
550 pos[2][(surface + 0) % 3] = float(x + 1) - radius;
551 pos[2][(surface + 1) % 3] = float(y + 0) - radius;
552 pos[2][(surface + 2) % 3] = radius;
553 pos[3][(surface + 0) % 3] = float(x + 1) - radius;
554 pos[3][(surface + 1) % 3] = float(y + 1) - radius;
555 pos[3][(surface + 2) % 3] = radius;
556 attrib[4 * index + 0].position = glm::normalize(pos[0]);
557 attrib[4 * index + 1].position = glm::normalize(pos[1]);
558 attrib[4 * index + 2].position = glm::normalize(pos[2]);
559 attrib[4 * index + 3].position = glm::normalize(pos[3]);
563 for (int surface = 3; surface < 6; ++surface) {
564 for (int y = 0; y < size; ++y) {
565 for (int x = 0; x < size; ++x, ++index) {
567 pos[0][(surface + 0) % 3] = float(x + 0) - radius;
568 pos[0][(surface + 1) % 3] = float(y + 0) - radius;
569 pos[0][(surface + 2) % 3] = radius;
570 pos[1][(surface + 0) % 3] = float(x + 0) - radius;
571 pos[1][(surface + 1) % 3] = float(y + 1) - radius;
572 pos[1][(surface + 2) % 3] = radius;
573 pos[2][(surface + 0) % 3] = float(x + 1) - radius;
574 pos[2][(surface + 1) % 3] = float(y + 0) - radius;
575 pos[2][(surface + 2) % 3] = radius;
576 pos[3][(surface + 0) % 3] = float(x + 1) - radius;
577 pos[3][(surface + 1) % 3] = float(y + 1) - radius;
578 pos[3][(surface + 2) % 3] = radius;
579 attrib[4 * index + 0].position = glm::normalize(pos[0]) * -1.0f;
580 attrib[4 * index + 1].position = glm::normalize(pos[1]) * -1.0f;
581 attrib[4 * index + 2].position = glm::normalize(pos[2]) * -1.0f;
582 attrib[4 * index + 3].position = glm::normalize(pos[3]) * -1.0f;
588 vao.ReserveElements(6 * 6 * size * size, GL_STATIC_DRAW);
590 auto element = vao.MapElements(GL_WRITE_ONLY);
592 for (int surface = 0; surface < 3; ++surface) {
593 for (int y = 0; y < size; ++y) {
594 for (int x = 0; x < size; ++x, ++index) {
595 element[6 * index + 0] = 4 * index + 0;
596 element[6 * index + 1] = 4 * index + 2;
597 element[6 * index + 2] = 4 * index + 1;
598 element[6 * index + 3] = 4 * index + 1;
599 element[6 * index + 4] = 4 * index + 2;
600 element[6 * index + 5] = 4 * index + 3;
604 for (int surface = 3; surface < 6; ++surface) {
605 for (int y = 0; y < size; ++y) {
606 for (int x = 0; x < size; ++x, ++index) {
607 element[6 * index + 0] = 4 * index + 0;
608 element[6 * index + 1] = 4 * index + 1;
609 element[6 * index + 2] = 4 * index + 2;
610 element[6 * index + 3] = 4 * index + 2;
611 element[6 * index + 4] = 4 * index + 1;
612 element[6 * index + 5] = 4 * index + 3;
620 SunSurface::~SunSurface() {
623 void SunSurface::Activate() noexcept {
625 glEnable(GL_DEPTH_TEST);
626 glDepthFunc(GL_LESS);
627 glEnable(GL_CULL_FACE);
631 void SunSurface::SetM(const glm::mat4 &mm) noexcept {
635 prog.Uniform(m_handle, m);
636 prog.Uniform(mv_handle, mv);
637 prog.Uniform(mvp_handle, mvp);
640 void SunSurface::SetV(const glm::mat4 &vv) noexcept {
644 prog.Uniform(mv_handle, mv);
645 prog.Uniform(mvp_handle, mvp);
648 void SunSurface::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
653 prog.Uniform(mv_handle, mv);
654 prog.Uniform(mvp_handle, mvp);
657 void SunSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
663 prog.Uniform(m_handle, m);
664 prog.Uniform(mv_handle, mv);
665 prog.Uniform(mvp_handle, mvp);
668 void SunSurface::SetLight(const glm::vec3 &color, float strength) noexcept {
669 prog.Uniform(light_color_handle, color);
670 prog.Uniform(light_strength_handle, strength);
673 void SunSurface::Draw() const noexcept {
674 constexpr int size = 10;
676 vao.DrawTriangles(6 * 6 * size * size);
680 constexpr int CreatureSkin::MAX_LIGHTS;
682 CreatureSkin::CreatureSkin()
686 "#version 330 core\n"
688 "layout(location = 0) in vec3 vtx_position;\n"
689 "layout(location = 1) in vec3 vtx_normal;\n"
690 "layout(location = 2) in vec3 vtx_tex_uv;\n"
694 "uniform mat4 MVP;\n"
696 "out vec3 vtx_viewspace;\n"
697 "out vec3 frag_tex_uv;\n"
701 "gl_Position = MVP * vec4(vtx_position, 1);\n"
702 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
703 "normal = normalize((MV * vec4(vtx_normal, 0)).xyz);\n"
704 "frag_tex_uv = vtx_tex_uv;\n"
709 "#version 330 core\n"
711 "struct LightSource {\n"
717 "in vec3 vtx_viewspace;\n"
718 "in vec3 frag_tex_uv;\n"
721 "uniform vec3 base_color;\n"
722 "uniform vec4 highlight_color;\n"
723 "uniform sampler2DArray tex_sampler;\n"
724 "uniform vec3 ambient;\n"
725 "uniform int num_lights;\n"
726 "uniform LightSource light[8];\n"
731 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
732 "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
733 "vec3 mat_color = mix(base_color, highlight_color.rgb, tex_color.r * tex_color.a * highlight_color.a);\n"
734 "vec3 spec_color = vec3(0.5);\n"
735 "vec3 total_light = mat_color * ambient;\n"
736 "for (int i = 0; i < num_lights; ++i) {\n"
737 "vec3 to_light = light[i].position - vtx_viewspace;\n"
738 "float distance = length(to_light) + length(vtx_viewspace);\n"
739 "vec3 light_dir = normalize(to_light);\n"
740 "float attenuation = light[i].strength / (distance * distance);\n"
741 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * mat_color;\n"
742 "vec3 specular = attenuation * light[i].color"
743 " * mix(spec_color, vec3(1.0), pow(1.0 - max(0.0, dot(normalize(light_dir + view_dir), view_dir)), 5.0))"
744 " * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 5.0);\n"
745 "total_light = total_light + diffuse + specular;\n"
747 "color = total_light;\n"
751 if (!prog.Linked()) {
753 throw std::runtime_error("link program");
755 m_handle = prog.UniformLocation("M");
756 mv_handle = prog.UniformLocation("MV");
757 mvp_handle = prog.UniformLocation("MVP");
758 base_color_handle = prog.UniformLocation("base_color");
759 highlight_color_handle = prog.UniformLocation("highlight_color");
760 sampler_handle = prog.UniformLocation("tex_sampler");
761 ambient_handle = prog.UniformLocation("ambient");
762 num_lights_handle = prog.UniformLocation("num_lights");
763 for (int i = 0; i < MAX_LIGHTS; ++i) {
764 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
765 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
766 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
770 CreatureSkin::~CreatureSkin() {
773 void CreatureSkin::Activate() noexcept {
775 glEnable(GL_DEPTH_TEST);
776 glDepthFunc(GL_LESS);
777 glEnable(GL_CULL_FACE);
781 void CreatureSkin::SetM(const glm::mat4 &mm) noexcept {
785 prog.Uniform(m_handle, m);
786 prog.Uniform(mv_handle, mv);
787 prog.Uniform(mvp_handle, mvp);
790 void CreatureSkin::SetV(const glm::mat4 &vv) noexcept {
794 prog.Uniform(mv_handle, mv);
795 prog.Uniform(mvp_handle, mvp);
798 void CreatureSkin::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
803 prog.Uniform(mv_handle, mv);
804 prog.Uniform(mvp_handle, mvp);
807 void CreatureSkin::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
813 prog.Uniform(m_handle, m);
814 prog.Uniform(mv_handle, mv);
815 prog.Uniform(mvp_handle, mvp);
818 void CreatureSkin::SetBaseColor(const glm::vec3 &c) noexcept {
819 prog.Uniform(base_color_handle, c);
822 void CreatureSkin::SetHighlightColor(const glm::vec4 &c) noexcept {
823 prog.Uniform(highlight_color_handle, c);
826 void CreatureSkin::SetTexture(ArrayTexture &tex) noexcept {
827 glActiveTexture(GL_TEXTURE0);
829 prog.Uniform(sampler_handle, GLint(0));
832 void CreatureSkin::SetAmbient(const glm::vec3 &a) noexcept {
833 prog.Uniform(ambient_handle, a);
836 void CreatureSkin::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
837 prog.Uniform(light_handle[3 * n + 0], pos);
838 prog.Uniform(light_handle[3 * n + 1], color);
839 prog.Uniform(light_handle[3 * n + 2], strength);
842 void CreatureSkin::SetNumLights(int n) noexcept {
843 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
847 AlphaSprite::AlphaSprite()
851 "#version 330 core\n"
853 "layout(location = 0) in vec3 vtx_position;\n"
854 "layout(location = 1) in vec2 vtx_texture;\n"
858 "uniform mat4 MVP;\n"
860 "out vec2 frag_tex_uv;\n"
863 "gl_Position = MVP * vec4(vtx_position, 1);\n"
864 "frag_tex_uv = vtx_texture;\n"
869 "#version 330 core\n"
871 "in vec2 frag_tex_uv;\n"
873 "uniform sampler2D tex_sampler;\n"
874 "uniform vec4 fg_color;\n"
875 "uniform vec4 bg_color;\n"
880 "vec4 tex_color = texture(tex_sampler, frag_tex_uv);\n"
881 "vec4 factor = mix(bg_color, fg_color, tex_color.a);\n"
882 "color = vec4((tex_color * factor).rgb, factor.a);\n"
886 if (!prog.Linked()) {
888 throw std::runtime_error("link program");
890 m_handle = prog.UniformLocation("M");
891 mv_handle = prog.UniformLocation("MV");
892 mvp_handle = prog.UniformLocation("MVP");
893 sampler_handle = prog.UniformLocation("tex_sampler");
894 fg_color_handle = prog.UniformLocation("fg_color");
895 bg_color_handle = prog.UniformLocation("bg_color");
898 vao.BindAttributes();
899 vao.EnableAttribute(0);
900 vao.EnableAttribute(1);
901 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
902 vao.AttributePointer<glm::vec2>(1, false, offsetof(Attributes, texture));
903 vao.ReserveAttributes(4, GL_STATIC_DRAW);
905 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
906 attrib[0].position = glm::vec3(-0.5f, -0.5f, 0.0f);
907 attrib[0].texture = glm::vec2(0.0f, 0.0f);
908 attrib[1].position = glm::vec3(-0.5f, 0.5f, 0.0f);
909 attrib[1].texture = glm::vec2(0.0f, 1.0f);
910 attrib[2].position = glm::vec3( 0.5f, -0.5f, 0.0f);
911 attrib[2].texture = glm::vec2(1.0f, 0.0f);
912 attrib[3].position = glm::vec3( 0.5f, 0.5f, 0.0f);
913 attrib[3].texture = glm::vec2(1.0f, 1.0f);
916 vao.ReserveElements(7, GL_STATIC_DRAW);
918 auto element = vao.MapElements(GL_WRITE_ONLY);
927 AlphaSprite::~AlphaSprite() {
930 void AlphaSprite::Activate() noexcept {
932 glEnable(GL_DEPTH_TEST);
933 glDepthFunc(GL_LESS);
934 glEnable(GL_CULL_FACE);
936 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
939 void AlphaSprite::SetM(const glm::mat4 &mm) noexcept {
943 prog.Uniform(m_handle, m);
944 prog.Uniform(mv_handle, mv);
945 prog.Uniform(mvp_handle, mvp);
948 void AlphaSprite::SetVP(const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
953 prog.Uniform(mv_handle, mv);
954 prog.Uniform(mvp_handle, mvp);
957 void AlphaSprite::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
963 prog.Uniform(m_handle, m);
964 prog.Uniform(mv_handle, mv);
965 prog.Uniform(mvp_handle, mvp);
968 void AlphaSprite::SetTexture(Texture &tex) noexcept {
969 glActiveTexture(GL_TEXTURE0);
971 prog.Uniform(sampler_handle, GLint(0));
974 void AlphaSprite::SetFgColor(const glm::vec4 &color) noexcept {
975 prog.Uniform(fg_color_handle, color);
978 void AlphaSprite::SetBgColor(const glm::vec4 &color) noexcept {
979 prog.Uniform(bg_color_handle, color);
982 void AlphaSprite::DrawRect() const noexcept {
984 vao.DrawTriangleStrip(4);
993 "#version 330 core\n"
995 "layout(location = 0) in vec2 vtx_position;\n"
1001 // disamond rule adjust
1002 //"vec3 position = vtx_position + vec3(0.5, 0.5, 0.0);\n"
1003 "gl_Position = P * vec4(vtx_position, z, 1);\n"
1008 "#version 330 core\n"
1019 if (!prog.Linked()) {
1020 prog.Log(std::cerr);
1021 throw std::runtime_error("link program");
1023 p_handle = prog.UniformLocation("P");
1024 z_handle = prog.UniformLocation("z");
1025 c_handle = prog.UniformLocation("c");
1028 vao.BindAttributes();
1029 vao.EnableAttribute(0);
1030 vao.AttributePointer<glm::vec2>(0, false, offsetof(Attributes, position));
1031 vao.ReserveAttributes(255, GL_DYNAMIC_DRAW);
1033 vao.ReserveElements(255, GL_DYNAMIC_DRAW);
1040 void Canvas::Resize(float w, float h) noexcept {
1041 prog.Uniform(p_handle, glm::ortho(0.0f, w, h, 0.0f, 1.0e4f, -1.0e4f));
1044 void Canvas::ZIndex(float z) noexcept {
1045 prog.Uniform(z_handle, -z);
1048 void Canvas::SetColor(const glm::vec4 &color) noexcept {
1049 prog.Uniform(c_handle, color);
1052 void Canvas::Activate() noexcept {
1054 glEnable(GL_DEPTH_TEST);
1055 glDepthFunc(GL_LESS);
1056 glEnable(GL_CULL_FACE);
1058 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1061 void Canvas::DrawLine(const glm::vec2 &p1, const glm::vec2 &p2, float width) {
1062 glm::vec2 d = glm::normalize(p2 - p1) * (width * 0.5f);
1063 glm::vec2 n = glm::vec2(d.y, -d.x);
1065 vao.BindAttributes();
1067 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
1068 attr[0].position = p1 - d + n;
1069 attr[1].position = p1 - d - n;
1070 attr[2].position = p2 + d + n;
1071 attr[3].position = p2 + d - n;
1075 auto elem = vao.MapElements(GL_WRITE_ONLY);
1081 vao.DrawTriangleStrip(4);
1085 void Canvas::DrawRect(const glm::vec2 &p1, const glm::vec2 &p2, float width) {
1086 glm::vec2 min(std::min(p1.x, p2.x), std::min(p1.y, p2.y));
1087 glm::vec2 max(std::max(p1.x, p2.x), std::max(p1.y, p2.y));
1088 glm::vec2 dg1(min.x, max.y);
1089 glm::vec2 dg2(max.x, min.y);
1090 glm::vec2 d(width * 0.5f, width * 0.5f);
1091 glm::vec2 n(d.y, -d.x);
1093 vao.BindAttributes();
1095 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
1096 attr[0].position = min + d;
1097 attr[1].position = min - d;
1098 attr[2].position = dg1 + n;
1099 attr[3].position = dg1 - n;
1100 attr[4].position = max - d;
1101 attr[5].position = max + d;
1102 attr[6].position = dg2 - n;
1103 attr[7].position = dg2 + n;
1107 auto elem = vao.MapElements(GL_WRITE_ONLY);
1119 vao.DrawTriangleStrip(10);
1123 void Canvas::FillRect(const glm::vec2 &p1, const glm::vec2 &p2) {
1124 glm::vec2 min(std::min(p1.x, p2.x), std::min(p1.y, p2.y));
1125 glm::vec2 max(std::max(p1.x, p2.x), std::max(p1.y, p2.y));
1126 glm::vec2 dg1(min.x, max.y);
1127 glm::vec2 dg2(max.x, min.y);
1129 vao.BindAttributes();
1131 auto attr = vao.MapAttributes(GL_WRITE_ONLY);
1132 attr[0].position = min;
1133 attr[1].position = dg1;
1134 attr[2].position = dg2;
1135 attr[3].position = max;
1139 auto elem = vao.MapElements(GL_WRITE_ONLY);
1145 vao.DrawTriangleStrip(4);