1 #include "PlanetSurface.hpp"
4 #include "SunSurface.hpp"
6 #include "ArrayTexture.hpp"
7 #include "../app/init.hpp"
15 #include <glm/gtc/type_ptr.hpp>
20 void gl_error(std::string msg) {
21 const GLubyte *errBegin = gluErrorString(glGetError());
22 if (errBegin && *errBegin != '\0') {
23 const GLubyte *errEnd = errBegin;
24 while (*errEnd != '\0') {
28 msg.append(errBegin, errEnd);
30 throw std::runtime_error(msg);
38 Shader::Shader(GLenum type)
39 : handle(glCreateShader(type)) {
41 gl_error("glCreateShader");
47 glDeleteShader(handle);
51 Shader::Shader(Shader &&other) noexcept
52 : handle(other.handle) {
56 Shader &Shader::operator =(Shader &&other) noexcept {
57 std::swap(handle, other.handle);
62 void Shader::Source(const GLchar *src) noexcept {
63 const GLchar* src_arr[] = { src };
64 glShaderSource(handle, 1, src_arr, nullptr);
67 void Shader::Compile() noexcept {
68 glCompileShader(handle);
71 bool Shader::Compiled() const noexcept {
72 GLint compiled = GL_FALSE;
73 glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled);
74 return compiled == GL_TRUE;
77 void Shader::Log(std::ostream &out) const {
78 int log_len = 0, max_len = 0;
79 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &max_len);
80 std::unique_ptr<char[]> log(new char[max_len]);
81 glGetShaderInfoLog(handle, max_len, &log_len, log.get());
82 out.write(log.get(), log_len);
86 void Shader::AttachToProgram(GLuint id) const noexcept {
87 glAttachShader(id, handle);
92 : handle(glCreateProgram()) {
94 gl_error("glCreateProgram");
100 glDeleteProgram(handle);
105 const Shader &Program::LoadShader(GLenum type, const GLchar *src) {
106 shaders.emplace_back(type);
107 Shader &shader = shaders.back();
110 if (!shader.Compiled()) {
111 shader.Log(std::cerr);
112 throw std::runtime_error("compile shader");
118 void Program::Attach(Shader &shader) noexcept {
119 shader.AttachToProgram(handle);
122 void Program::Link() noexcept {
123 glLinkProgram(handle);
126 bool Program::Linked() const noexcept {
127 GLint linked = GL_FALSE;
128 glGetProgramiv(handle, GL_LINK_STATUS, &linked);
129 return linked == GL_TRUE;
132 void Program::Log(std::ostream &out) const {
133 int log_len = 0, max_len = 0;
134 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &max_len);
135 std::unique_ptr<char[]> log(new char[max_len]);
136 glGetProgramInfoLog(handle, max_len, &log_len, log.get());
137 out.write(log.get(), log_len);
141 GLint Program::AttributeLocation(const GLchar *name) const noexcept {
142 return glGetAttribLocation(handle, name);
145 GLint Program::AttributeLocation(const std::string &name) const noexcept {
146 return AttributeLocation(name.c_str());
149 GLint Program::UniformLocation(const GLchar *name) const noexcept {
150 return glGetUniformLocation(handle, name);
153 GLint Program::UniformLocation(const std::string &name) const noexcept {
154 return UniformLocation(name.c_str());
158 void Program::Uniform(GLint loc, GLint val) noexcept {
159 glUniform1i(loc, val);
162 void Program::Uniform(GLint loc, float val) noexcept {
163 glUniform1f(loc, val);
166 void Program::Uniform(GLint loc, const glm::vec3 &val) noexcept {
167 glUniform3fv(loc, 1, glm::value_ptr(val));
170 void Program::Uniform(GLint loc, const glm::vec4 &val) noexcept {
171 glUniform4fv(loc, 1, glm::value_ptr(val));
174 void Program::Uniform(GLint loc, const glm::mat4 &val) noexcept {
175 glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
179 constexpr int PlanetSurface::MAX_LIGHTS;
181 PlanetSurface::PlanetSurface()
185 "#version 330 core\n"
187 "layout(location = 0) in vec3 vtx_position;\n"
188 "layout(location = 1) in vec3 vtx_tex_uv;\n"
192 "uniform mat4 MVP;\n"
194 "out vec3 frag_tex_uv;\n"
195 "out vec3 vtx_viewspace;\n"
198 "gl_Position = MVP * vec4(vtx_position, 1);\n"
199 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
200 "frag_tex_uv = vtx_tex_uv;\n"
205 "#version 330 core\n"
207 "struct LightSource {\n"
213 "in vec3 vtx_viewspace;\n"
214 "in vec3 frag_tex_uv;\n"
216 "uniform sampler2DArray tex_sampler;\n"
217 "uniform vec3 normal;\n"
218 "uniform int num_lights;\n"
219 "uniform LightSource light[8];\n"
224 "vec3 tex_color = texture(tex_sampler, frag_tex_uv).rgb;\n"
225 "vec3 total_light = tex_color * vec3(0.01, 0.01, 0.01);\n"
226 "for (int i = 0; i < num_lights; ++i) {\n"
227 "vec3 to_light = light[i].position - vtx_viewspace;\n"
228 "float distance = length(to_light) + length(vtx_viewspace);\n"
229 "vec3 light_dir = normalize(to_light);\n"
230 "float attenuation = light[i].strength / (distance * distance);\n"
231 "vec3 diffuse = attenuation * max(0.0, dot(normal, light_dir)) * light[i].color * tex_color;\n"
232 "vec3 view_dir = vec3(0.0, 0.0, 1.0);\n"
233 "vec3 specular = vec3(0.0, 0.0, 0.0);\n"
234 "if (dot(normal, light_dir) >= 0.0) {\n"
235 "attenuation * light[i].color * pow(max(0.0, dot(reflect(-light_dir, normal), view_dir)), 25.0);\n"
237 "total_light = total_light + diffuse + specular;\n"
239 "color = total_light;\n"
243 if (!prog.Linked()) {
245 throw std::runtime_error("link program");
247 m_handle = prog.UniformLocation("M");
248 mv_handle = prog.UniformLocation("MV");
249 mvp_handle = prog.UniformLocation("MVP");
250 sampler_handle = prog.UniformLocation("tex_sampler");
251 normal_handle = prog.UniformLocation("normal");
252 num_lights_handle = prog.UniformLocation("num_lights");
253 for (int i = 0; i < MAX_LIGHTS; ++i) {
254 light_handle[3 * i + 0] = prog.UniformLocation("light[" + std::to_string(i) + "].position");
255 light_handle[3 * i + 1] = prog.UniformLocation("light[" + std::to_string(i) + "].color");
256 light_handle[3 * i + 2] = prog.UniformLocation("light[" + std::to_string(i) + "].strength");
260 PlanetSurface::~PlanetSurface() {
263 void PlanetSurface::Activate() noexcept {
265 glEnable(GL_DEPTH_TEST);
266 glDepthFunc(GL_LESS);
267 glEnable(GL_CULL_FACE);
271 void PlanetSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
277 prog.Uniform(m_handle, m);
278 prog.Uniform(mv_handle, mv);
279 prog.Uniform(mvp_handle, mvp);
282 void PlanetSurface::SetNormal(const glm::vec3 &n) noexcept {
283 prog.Uniform(normal_handle, n);
286 void PlanetSurface::SetTexture(ArrayTexture &tex) noexcept {
287 glActiveTexture(GL_TEXTURE0);
289 prog.Uniform(sampler_handle, GLint(0));
292 void PlanetSurface::SetLight(int n, const glm::vec3 &pos, const glm::vec3 &color, float strength) noexcept {
293 prog.Uniform(light_handle[3 * n + 0], pos);
294 prog.Uniform(light_handle[3 * n + 1], color);
295 prog.Uniform(light_handle[3 * n + 2], strength);
298 void PlanetSurface::SetNumLights(int n) noexcept {
299 prog.Uniform(num_lights_handle, std::min(MAX_LIGHTS, n));
303 SunSurface::SunSurface()
307 "#version 330 core\n"
309 "layout(location = 0) in vec3 vtx_position;\n"
313 "uniform mat4 MVP;\n"
315 "out vec3 vtx_viewspace;\n"
318 "gl_Position = MVP * vec4(vtx_position, 1);\n"
319 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
324 "#version 330 core\n"
326 "in vec3 vtx_viewspace;\n"
328 "uniform vec3 light_color;\n"
329 "uniform float light_strength;\n"
334 "vec3 to_light = -vtx_viewspace;\n"
335 "float distance = length(to_light);\n"
336 //"vec3 light_dir = normalize(to_light);\n"
337 "float attenuation = light_strength / (distance * distance);\n"
338 "color = attenuation * light_color;\n"
342 if (!prog.Linked()) {
344 throw std::runtime_error("link program");
346 m_handle = prog.UniformLocation("M");
347 mv_handle = prog.UniformLocation("MV");
348 mvp_handle = prog.UniformLocation("MVP");
349 light_color_handle = prog.UniformLocation("light_color");
350 light_strength_handle = prog.UniformLocation("light_strength");
353 vao.BindAttributes();
354 vao.EnableAttribute(0);
355 vao.AttributePointer<glm::vec3>(0, false, offsetof(Attributes, position));
356 vao.ReserveAttributes(8, GL_STATIC_DRAW);
358 auto attrib = vao.MapAttributes(GL_WRITE_ONLY);
359 attrib[0].position = glm::vec3(-1.0f, -1.0f, -1.0f);
360 attrib[1].position = glm::vec3(-1.0f, -1.0f, 1.0f);
361 attrib[2].position = glm::vec3(-1.0f, 1.0f, -1.0f);
362 attrib[3].position = glm::vec3(-1.0f, 1.0f, 1.0f);
363 attrib[4].position = glm::vec3( 1.0f, -1.0f, -1.0f);
364 attrib[5].position = glm::vec3( 1.0f, -1.0f, 1.0f);
365 attrib[6].position = glm::vec3( 1.0f, 1.0f, -1.0f);
366 attrib[7].position = glm::vec3( 1.0f, 1.0f, 1.0f);
369 vao.ReserveElements(36, GL_STATIC_DRAW);
371 auto element = vao.MapElements(GL_WRITE_ONLY);
418 SunSurface::~SunSurface() {
421 void SunSurface::Activate() noexcept {
423 glEnable(GL_DEPTH_TEST);
424 glDepthFunc(GL_LESS);
425 glEnable(GL_CULL_FACE);
429 void SunSurface::SetMVP(const glm::mat4 &mm, const glm::mat4 &vv, const glm::mat4 &pp) noexcept {
435 prog.Uniform(m_handle, m);
436 prog.Uniform(mv_handle, mv);
437 prog.Uniform(mvp_handle, mvp);
440 void SunSurface::SetLight(const glm::vec3 &color, float strength) noexcept {
441 prog.Uniform(light_color_handle, color);
442 prog.Uniform(light_strength_handle, strength);
445 void SunSurface::Draw() const noexcept {
447 vao.DrawTriangles(36);