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)
147 , light_direction_handle(0)
148 , light_color_handle(0) {
151 "#version 330 core\n"
152 "layout(location = 0) in vec3 vtx_position;\n"
153 "layout(location = 1) in vec3 vtx_color;\n"
154 "layout(location = 2) in vec3 vtx_normal;\n"
156 "uniform mat4 MVP;\n"
157 "out vec3 frag_color;\n"
160 "gl_Position = MVP * vec4(vtx_position, 1);\n"
161 "normal = (M * vec4(vtx_normal, 0)).xyz;\n"
162 "frag_color = vtx_color;\n"
167 "#version 330 core\n"
168 "in vec3 frag_color;\n"
170 "uniform vec3 light_direction;\n"
171 "uniform vec3 light_color;\n"
174 "vec3 ambient = vec3(0.1, 0.1, 0.1) * frag_color;\n"
175 "vec3 n = normalize(normal);\n"
176 "vec3 l = normalize(light_direction);\n"
177 "float cos_theta = clamp(dot(n, l), 0, 1);\n"
178 "color = ambient + frag_color * light_color * cos_theta;\n"
182 if (!program.Linked()) {
183 program.Log(std::cerr);
184 throw std::runtime_error("link program");
187 m_handle = program.UniformLocation("M");
188 mvp_handle = program.UniformLocation("MVP");
189 light_direction_handle = program.UniformLocation("light_direction");
190 light_color_handle = program.UniformLocation("light_color");
194 void DirectionalLighting::Activate() {
195 GLContext::EnableDepthTest();
196 GLContext::EnableBackfaceCulling();
199 glUniform3f(light_direction_handle, light_direction.x, light_direction.y, light_direction.z);
200 glUniform3f(light_color_handle, light_color.x, light_color.y, light_color.z);
203 void DirectionalLighting::SetM(const glm::mat4 &m) {
204 glm::mat4 mvp(vp * m);
205 glUniformMatrix4fv(m_handle, 1, GL_FALSE, &m[0][0]);
206 glUniformMatrix4fv(mvp_handle, 1, GL_FALSE, &mvp[0][0]);
209 void DirectionalLighting::SetVP(const glm::mat4 &v, const glm::mat4 &p) {
213 void DirectionalLighting::SetMVP(const glm::mat4 &m, const glm::mat4 &v, const glm::mat4 &p) {