--- /dev/null
+#include "shader.hpp"
+
+#include "../app/error.hpp"
+
+#include <algorithm>
+#include <memory>
+#include <GL/glew.h>
+#include <glm/gtc/type_ptr.hpp>
+
+
+namespace tacos {
+
+Shader Shader::Vertex(const GLchar *source) {
+ return Shader(GL_VERTEX_SHADER, source);
+}
+
+Shader Shader::Fragment(const GLchar *source) {
+ return Shader(GL_FRAGMENT_SHADER, source);
+}
+
+Shader::Shader(GLenum type, const GLchar *source)
+: shader(glCreateShader(type)) {
+ if (shader == 0) {
+ throw GLError("glCreateShader");
+ }
+ const GLchar *sources[] = { source };
+ glShaderSource(shader, 1, sources, nullptr);
+ glCompileShader(shader);
+ GLint compiled = GL_FALSE;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+ if (compiled != GL_TRUE) {
+ int log_length = 0, max_length = 0;
+ glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &max_length);
+ ++max_length;
+ std::unique_ptr<char[]> log(new char[max_length]);
+ glGetShaderInfoLog(shader, max_length, &log_length, log.get());
+ log[log_length] = '\0';
+ glDeleteShader(shader);
+ throw GLCompileError("glCompileShader", log.get());
+ }
+}
+
+Shader::~Shader() noexcept {
+ if (shader != 0) {
+ glDeleteShader(shader);
+ }
+}
+
+Shader::Shader(Shader &&other) noexcept
+: shader(other.shader) {
+ other.shader = 0;
+}
+
+Shader &Shader::operator =(Shader &&other) noexcept {
+ std::swap(shader, other.shader);
+ return *this;
+}
+
+
+Program::Program()
+: program(glCreateProgram()) {
+ if (program == 0) {
+ throw GLError("glCreateProgram");
+ }
+}
+
+Program::~Program() noexcept {
+ glDeleteProgram(program);
+}
+
+void Program::Attach(const Shader &shader) noexcept {
+ glAttachShader(program, shader.shader);
+}
+
+void Program::Link() {
+ glLinkProgram(program);
+ GLint linked = GL_FALSE;
+ glGetProgramiv(program, GL_LINK_STATUS, &linked);
+ if (linked != GL_TRUE) {
+ int log_length = 0, max_length = 0;
+ glGetProgramiv(program, GL_INFO_LOG_LENGTH, &max_length);
+ ++max_length;
+ std::unique_ptr<char[]> log(new char[max_length]);
+ glGetProgramInfoLog(program, max_length, &log_length, log.get());
+ log[log_length] = '\0';
+ throw GLCompileError("glLinkProgram", log.get());
+ }
+}
+
+void Program::Use() noexcept {
+ glUseProgram(program);
+}
+
+GLint Program::AttributeLocation(const GLchar *name) const noexcept {
+ return glGetAttribLocation(program, name);
+}
+
+GLint Program::UniformLocation(const GLchar *name) const noexcept {
+ return glGetUniformLocation(program, name);
+}
+
+void Program::Uniform(GLint loc, GLint val) noexcept {
+ glUniform1i(loc, val);
+}
+
+void Program::Uniform(GLint loc, float val) noexcept {
+ glUniform1f(loc, val);
+}
+
+void Program::Uniform(GLint loc, const glm::vec3 &val) noexcept {
+ glUniform3fv(loc, 1, glm::value_ptr(val));
+}
+
+void Program::Uniform(GLint loc, const glm::vec4 &val) noexcept {
+ glUniform4fv(loc, 1, glm::value_ptr(val));
+}
+
+void Program::Uniform(GLint loc, const glm::mat4 &val) noexcept {
+ glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(val));
+}
+
+}