15 void gl_error(std::string msg) {
16 const GLubyte *errBegin = gluErrorString(glGetError());
17 if (errBegin && *errBegin != '\0') {
18 const GLubyte *errEnd = errBegin;
19 while (*errEnd != '\0') {
23 msg.append(errBegin, errEnd);
25 throw std::runtime_error(msg);
32 Shader::Shader(GLenum type)
33 : handle(glCreateShader(type)) {
35 gl_error("glCreateShader");
41 glDeleteShader(handle);
45 Shader::Shader(Shader &&other)
46 : handle(other.handle) {
50 Shader &Shader::operator =(Shader &&other) {
51 std::swap(handle, other.handle);
56 void Shader::Source(const GLchar *src) {
57 const GLchar* src_arr[] = { src };
58 glShaderSource(handle, 1, src_arr, nullptr);
61 void Shader::Compile() {
62 glCompileShader(handle);
65 bool Shader::Compiled() const {
66 GLint compiled = GL_FALSE;
67 glGetShaderiv(handle, GL_COMPILE_STATUS, &compiled);
68 return compiled == GL_TRUE;
71 void Shader::Log(std::ostream &out) const {
72 int log_len = 0, max_len = 0;
73 glGetShaderiv(handle, GL_INFO_LOG_LENGTH, &max_len);
74 std::unique_ptr<char[]> log(new char[max_len]);
75 glGetShaderInfoLog(handle, max_len, &log_len, log.get());
76 out.write(log.get(), log_len);
80 void Shader::AttachToProgram(GLuint id) const {
81 glAttachShader(id, handle);
86 : handle(glCreateProgram()) {
88 gl_error("glCreateProgram");
94 glDeleteProgram(handle);
99 const Shader &Program::LoadShader(GLenum type, const GLchar *src) {
100 shaders.emplace_back(type);
101 Shader &shader = shaders.back();
104 if (!shader.Compiled()) {
105 shader.Log(std::cerr);
106 throw std::runtime_error("compile shader");
112 void Program::Attach(Shader &shader) {
113 shader.AttachToProgram(handle);
116 void Program::Link() {
117 glLinkProgram(handle);
120 bool Program::Linked() const {
121 GLint linked = GL_FALSE;
122 glGetProgramiv(handle, GL_LINK_STATUS, &linked);
123 return linked == GL_TRUE;
126 void Program::Log(std::ostream &out) const {
127 int log_len = 0, max_len = 0;
128 glGetProgramiv(handle, GL_INFO_LOG_LENGTH, &max_len);
129 std::unique_ptr<char[]> log(new char[max_len]);
130 glGetProgramInfoLog(handle, max_len, &log_len, log.get());
131 out.write(log.get(), log_len);
135 GLint Program::UniformLocation(const GLchar *name) const {
136 return glGetUniformLocation(handle, name);
140 DirectionalLighting::DirectionalLighting()
142 , light_direction(1.0f, 3.0f, 2.0f)
143 , light_color(0.9f, 0.9f, 0.9f)
148 , light_direction_handle(0)
149 , light_color_handle(0)
150 , fog_density_handle(0) {
153 "#version 330 core\n"
154 "layout(location = 0) in vec3 vtx_position;\n"
155 "layout(location = 1) in vec3 vtx_color;\n"
156 "layout(location = 2) in vec3 vtx_normal;\n"
159 "uniform mat4 MVP;\n"
160 "out vec3 frag_color;\n"
161 "out vec3 vtx_viewspace;\n"
164 "gl_Position = MVP * vec4(vtx_position, 1);\n"
165 "vtx_viewspace = (MV * vec4(vtx_position, 1)).xyz;\n"
166 "normal = (M * vec4(vtx_normal, 0)).xyz;\n"
167 "frag_color = vtx_color;\n"
172 "#version 330 core\n"
173 "in vec3 frag_color;\n"
174 "in vec3 vtx_viewspace;\n"
176 "uniform vec3 light_direction;\n"
177 "uniform vec3 light_color;\n"
178 "uniform float fog_density;\n"
181 "vec3 ambient = vec3(0.1, 0.1, 0.1) * frag_color;\n"
182 // this should be the same as the clear color, otherwise looks really weird
183 "vec3 fog_color = vec3(0, 0, 0);\n"
184 "float e = 2.718281828;\n"
185 "vec3 n = normalize(normal);\n"
186 "vec3 l = normalize(light_direction);\n"
187 "float cos_theta = clamp(dot(n, l), 0, 1);\n"
188 "vec3 reflect_color = ambient + frag_color * light_color * cos_theta;\n"
189 "float value = pow(e, -pow(fog_density * length(vtx_viewspace), 5));"
190 "color = mix(fog_color, reflect_color, value);\n"
194 if (!program.Linked()) {
195 program.Log(std::cerr);
196 throw std::runtime_error("link program");
199 m_handle = program.UniformLocation("M");
200 mv_handle = program.UniformLocation("MV");
201 mvp_handle = program.UniformLocation("MVP");
202 light_direction_handle = program.UniformLocation("light_direction");
203 light_color_handle = program.UniformLocation("light_color");
204 fog_density_handle = program.UniformLocation("fog_density");
208 void DirectionalLighting::Activate() {
209 GLContext::EnableDepthTest();
210 GLContext::EnableBackfaceCulling();
213 glUniform3f(light_direction_handle, light_direction.x, light_direction.y, light_direction.z);
214 glUniform3f(light_color_handle, light_color.x, light_color.y, light_color.z);
217 void DirectionalLighting::SetM(const glm::mat4 &m) {
218 glm::mat4 mv(view * m);
219 glm::mat4 mvp(vp * m);
220 glUniformMatrix4fv(m_handle, 1, GL_FALSE, &m[0][0]);
221 glUniformMatrix4fv(mv_handle, 1, GL_FALSE, &mv[0][0]);
222 glUniformMatrix4fv(mvp_handle, 1, GL_FALSE, &mvp[0][0]);
225 void DirectionalLighting::SetLightDirection(const glm::vec3 &dir) {
226 light_direction = -dir;
227 glUniform3f(light_direction_handle, light_direction.x, light_direction.y, light_direction.z);
230 void DirectionalLighting::SetFogDensity(float f) {
232 glUniform1f(fog_density_handle, fog_density);
235 void DirectionalLighting::SetProjection(const glm::mat4 &p) {
240 void DirectionalLighting::SetView(const glm::mat4 &v) {
245 void DirectionalLighting::SetVP(const glm::mat4 &v, const glm::mat4 &p) {
251 void DirectionalLighting::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) {