2016-02-07 22:32:38 +00:00
|
|
|
//
|
|
|
|
// Shader.cpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 07/02/2016.
|
|
|
|
// Copyright © 2016 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#include "Shader.hpp"
|
2016-02-08 00:21:22 +00:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
using namespace OpenGL;
|
|
|
|
|
2017-02-20 15:35:33 +00:00
|
|
|
namespace
|
|
|
|
{
|
2016-05-01 15:07:49 +00:00
|
|
|
Shader *bound_shader = nullptr;
|
|
|
|
}
|
|
|
|
|
2017-02-20 15:35:33 +00:00
|
|
|
GLuint Shader::compile_shader(const std::string &source, GLenum type)
|
2016-02-08 00:21:22 +00:00
|
|
|
{
|
|
|
|
GLuint shader = glCreateShader(type);
|
2017-02-20 15:35:33 +00:00
|
|
|
const char *c_str = source.c_str();
|
|
|
|
glShaderSource(shader, 1, &c_str, NULL);
|
2016-02-08 00:21:22 +00:00
|
|
|
glCompileShader(shader);
|
|
|
|
|
2017-02-20 15:35:33 +00:00
|
|
|
#ifdef DEBUG
|
2016-02-08 00:21:22 +00:00
|
|
|
GLint isCompiled = 0;
|
|
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
|
|
|
|
if(isCompiled == GL_FALSE)
|
|
|
|
{
|
|
|
|
GLint logLength;
|
|
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logLength);
|
2016-04-19 12:05:43 +00:00
|
|
|
if(logLength > 0) {
|
2017-02-20 15:35:33 +00:00
|
|
|
GLchar *log = new GLchar[logLength];
|
2016-02-08 00:21:22 +00:00
|
|
|
glGetShaderInfoLog(shader, logLength, &logLength, log);
|
|
|
|
printf("Compile log:\n%s\n", log);
|
2017-02-20 15:35:33 +00:00
|
|
|
delete[] log;
|
2016-02-08 00:21:22 +00:00
|
|
|
}
|
2016-04-19 12:05:43 +00:00
|
|
|
|
|
|
|
throw (type == GL_VERTEX_SHADER) ? VertexShaderCompilationError : FragmentShaderCompilationError;
|
2016-02-08 00:21:22 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return shader;
|
|
|
|
}
|
|
|
|
|
2017-02-20 15:35:33 +00:00
|
|
|
Shader::Shader(const std::string &vertex_shader, const std::string &fragment_shader, const AttributeBinding *attribute_bindings)
|
2016-02-08 00:21:22 +00:00
|
|
|
{
|
2016-11-21 03:57:45 +00:00
|
|
|
shader_program_ = glCreateProgram();
|
2016-02-08 00:21:22 +00:00
|
|
|
GLuint vertex = compile_shader(vertex_shader, GL_VERTEX_SHADER);
|
|
|
|
GLuint fragment = compile_shader(fragment_shader, GL_FRAGMENT_SHADER);
|
|
|
|
|
2016-11-21 03:57:45 +00:00
|
|
|
glAttachShader(shader_program_, vertex);
|
|
|
|
glAttachShader(shader_program_, fragment);
|
2016-04-19 11:23:15 +00:00
|
|
|
|
|
|
|
if(attribute_bindings)
|
|
|
|
{
|
|
|
|
while(attribute_bindings->name)
|
|
|
|
{
|
2016-11-21 03:57:45 +00:00
|
|
|
glBindAttribLocation(shader_program_, attribute_bindings->index, attribute_bindings->name);
|
2016-04-19 11:23:15 +00:00
|
|
|
attribute_bindings++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-21 03:57:45 +00:00
|
|
|
glLinkProgram(shader_program_);
|
2016-04-19 01:32:48 +00:00
|
|
|
|
2017-02-20 15:35:33 +00:00
|
|
|
#ifdef DEBUG
|
2016-04-19 01:32:48 +00:00
|
|
|
GLint didLink = 0;
|
2016-11-21 03:57:45 +00:00
|
|
|
glGetProgramiv(shader_program_, GL_LINK_STATUS, &didLink);
|
2016-04-19 01:32:48 +00:00
|
|
|
if(didLink == GL_FALSE)
|
|
|
|
{
|
|
|
|
GLint logLength;
|
2016-11-21 03:57:45 +00:00
|
|
|
glGetProgramiv(shader_program_, GL_INFO_LOG_LENGTH, &logLength);
|
2016-04-25 02:32:24 +00:00
|
|
|
if(logLength > 0) {
|
2017-02-20 15:35:33 +00:00
|
|
|
GLchar *log = new GLchar[logLength];
|
2016-11-21 03:57:45 +00:00
|
|
|
glGetProgramInfoLog(shader_program_, logLength, &logLength, log);
|
2016-04-19 01:32:48 +00:00
|
|
|
printf("Link log:\n%s\n", log);
|
2017-02-20 15:35:33 +00:00
|
|
|
delete[] log;
|
2016-04-19 01:32:48 +00:00
|
|
|
}
|
2016-04-19 12:05:43 +00:00
|
|
|
throw ProgramLinkageError;
|
2016-04-19 01:32:48 +00:00
|
|
|
}
|
|
|
|
#endif
|
2016-02-08 00:21:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Shader::~Shader()
|
|
|
|
{
|
2016-05-01 15:07:49 +00:00
|
|
|
if(bound_shader == this) Shader::unbind();
|
2016-11-21 03:57:45 +00:00
|
|
|
glDeleteProgram(shader_program_);
|
2016-02-08 00:21:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Shader::bind()
|
|
|
|
{
|
2016-05-01 15:07:49 +00:00
|
|
|
if(bound_shader != this)
|
|
|
|
{
|
2016-11-21 03:57:45 +00:00
|
|
|
glUseProgram(shader_program_);
|
2016-05-01 15:07:49 +00:00
|
|
|
bound_shader = this;
|
|
|
|
}
|
2016-05-14 22:06:55 +00:00
|
|
|
flush_functions();
|
2016-05-01 15:07:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Shader::unbind()
|
|
|
|
{
|
|
|
|
bound_shader = nullptr;
|
|
|
|
glUseProgram(0);
|
2016-02-08 00:21:22 +00:00
|
|
|
}
|
|
|
|
|
2016-04-19 11:23:15 +00:00
|
|
|
GLint Shader::get_attrib_location(const GLchar *name)
|
2016-02-08 00:21:22 +00:00
|
|
|
{
|
2016-11-21 03:57:45 +00:00
|
|
|
return glGetAttribLocation(shader_program_, name);
|
2016-02-08 00:21:22 +00:00
|
|
|
}
|
|
|
|
|
2016-04-19 11:23:15 +00:00
|
|
|
GLint Shader::get_uniform_location(const GLchar *name)
|
2016-02-08 00:21:22 +00:00
|
|
|
{
|
2016-11-21 03:57:45 +00:00
|
|
|
return glGetUniformLocation(shader_program_, name);
|
2016-02-08 00:21:22 +00:00
|
|
|
}
|
2016-05-10 23:11:48 +00:00
|
|
|
|
|
|
|
void Shader::enable_vertex_attribute_with_pointer(const char *name, GLint size, GLenum type, GLboolean normalised, GLsizei stride, const GLvoid *pointer, GLuint divisor)
|
|
|
|
{
|
|
|
|
GLint location = get_attrib_location(name);
|
|
|
|
glEnableVertexAttribArray((GLuint)location);
|
|
|
|
glVertexAttribPointer((GLuint)location, size, type, normalised, stride, pointer);
|
|
|
|
glVertexAttribDivisor((GLuint)location, divisor);
|
|
|
|
}
|
2016-05-14 02:08:32 +00:00
|
|
|
|
|
|
|
// The various set_uniforms...
|
2016-11-21 03:57:45 +00:00
|
|
|
#define location() glGetUniformLocation(shader_program_, name.c_str())
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLint value)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value, this] {
|
|
|
|
glUniform1i(location(), value);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLuint value)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value, this] {
|
|
|
|
glUniform1ui(location(), value);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLfloat value)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value, this] {
|
|
|
|
glUniform1f(location(), value);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLint value1, GLint value2)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, this] {
|
|
|
|
glUniform2i(location(), value1, value2);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, this] {
|
2017-01-04 03:16:52 +00:00
|
|
|
GLint location = location();
|
|
|
|
glUniform2f(location, value1, value2);
|
2016-05-14 22:06:55 +00:00
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, this] {
|
|
|
|
glUniform2ui(location(), value1, value2);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
|
|
|
|
void Shader::set_uniform(const std::string &name, GLint value1, GLint value2, GLint value3)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, value3, this] {
|
|
|
|
glUniform3i(location(), value1, value2, value3);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2, GLfloat value3)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, value3, this] {
|
|
|
|
glUniform3f(location(), value1, value2, value3);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2, GLuint value3)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, value3, this] {
|
|
|
|
glUniform3ui(location(), value1, value2, value3);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
|
|
|
|
void Shader::set_uniform(const std::string &name, GLint value1, GLint value2, GLint value3, GLint value4)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, value3, value4, this] {
|
|
|
|
glUniform4i(location(), value1, value2, value3, value4);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLfloat value1, GLfloat value2, GLfloat value3, GLfloat value4)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, value3, value4, this] {
|
|
|
|
glUniform4f(location(), value1, value2, value3, value4);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLuint value1, GLuint value2, GLuint value3, GLuint value4)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
enqueue_function([name, value1, value2, value3, value4, this] {
|
|
|
|
glUniform4ui(location(), value1, value2, value3, value4);
|
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
|
|
|
|
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLint *values)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-15 18:59:59 +00:00
|
|
|
size_t number_of_values = (size_t)count * (size_t)size;
|
|
|
|
GLint *values_copy = new GLint[number_of_values];
|
|
|
|
memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);
|
|
|
|
|
2016-05-14 22:15:10 +00:00
|
|
|
enqueue_function([name, size, count, values_copy, this] {
|
2016-05-14 22:06:55 +00:00
|
|
|
switch(size)
|
|
|
|
{
|
2016-05-14 22:15:10 +00:00
|
|
|
case 1: glUniform1iv(location(), count, values_copy); break;
|
|
|
|
case 2: glUniform2iv(location(), count, values_copy); break;
|
|
|
|
case 3: glUniform3iv(location(), count, values_copy); break;
|
|
|
|
case 4: glUniform4iv(location(), count, values_copy); break;
|
2016-05-14 22:06:55 +00:00
|
|
|
}
|
2016-05-14 22:15:10 +00:00
|
|
|
delete[] values_copy;
|
2016-05-14 22:06:55 +00:00
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLfloat *values)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-15 18:59:59 +00:00
|
|
|
size_t number_of_values = (size_t)count * (size_t)size;
|
|
|
|
GLfloat *values_copy = new GLfloat[number_of_values];
|
|
|
|
memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);
|
|
|
|
|
2016-05-14 22:15:10 +00:00
|
|
|
enqueue_function([name, size, count, values_copy, this] {
|
2016-05-14 22:06:55 +00:00
|
|
|
switch(size)
|
|
|
|
{
|
2016-05-14 22:15:10 +00:00
|
|
|
case 1: glUniform1fv(location(), count, values_copy); break;
|
|
|
|
case 2: glUniform2fv(location(), count, values_copy); break;
|
|
|
|
case 3: glUniform3fv(location(), count, values_copy); break;
|
|
|
|
case 4: glUniform4fv(location(), count, values_copy); break;
|
2016-05-14 22:06:55 +00:00
|
|
|
}
|
2016-05-14 22:15:10 +00:00
|
|
|
delete[] values_copy;
|
2016-05-14 22:06:55 +00:00
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform(const std::string &name, GLint size, GLsizei count, const GLuint *values)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-15 18:59:59 +00:00
|
|
|
size_t number_of_values = (size_t)count * (size_t)size;
|
|
|
|
GLuint *values_copy = new GLuint[number_of_values];
|
|
|
|
memcpy(values_copy, values, sizeof(*values) * (size_t)number_of_values);
|
|
|
|
|
2016-05-14 22:15:10 +00:00
|
|
|
enqueue_function([name, size, count, values_copy, this] {
|
2016-05-14 22:06:55 +00:00
|
|
|
switch(size)
|
|
|
|
{
|
2016-05-14 22:15:10 +00:00
|
|
|
case 1: glUniform1uiv(location(), count, values_copy); break;
|
|
|
|
case 2: glUniform2uiv(location(), count, values_copy); break;
|
|
|
|
case 3: glUniform3uiv(location(), count, values_copy); break;
|
|
|
|
case 4: glUniform4uiv(location(), count, values_copy); break;
|
2016-05-14 22:06:55 +00:00
|
|
|
}
|
2016-05-14 22:15:10 +00:00
|
|
|
delete[] values_copy;
|
2016-05-14 22:06:55 +00:00
|
|
|
});
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform_matrix(const std::string &name, GLint size, bool transpose, const GLfloat *values)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
|
|
|
set_uniform_matrix(name, size, 1, transpose, values);
|
|
|
|
}
|
|
|
|
|
2016-05-14 22:06:55 +00:00
|
|
|
void Shader::set_uniform_matrix(const std::string &name, GLint size, GLsizei count, bool transpose, const GLfloat *values)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-15 18:59:59 +00:00
|
|
|
size_t number_of_values = (size_t)count * (size_t)size * (size_t)size;
|
|
|
|
GLfloat *values_copy = new GLfloat[number_of_values];
|
|
|
|
memcpy(values_copy, values, sizeof(*values) * number_of_values);
|
|
|
|
|
2016-05-14 22:15:10 +00:00
|
|
|
enqueue_function([name, size, count, transpose, values_copy, this] {
|
|
|
|
GLboolean glTranspose = transpose ? GL_TRUE : GL_FALSE;
|
2016-05-14 22:06:55 +00:00
|
|
|
switch(size)
|
|
|
|
{
|
2016-05-14 22:15:10 +00:00
|
|
|
case 2: glUniformMatrix2fv(location(), count, glTranspose, values_copy); break;
|
|
|
|
case 3: glUniformMatrix3fv(location(), count, glTranspose, values_copy); break;
|
|
|
|
case 4: glUniformMatrix4fv(location(), count, glTranspose, values_copy); break;
|
2016-05-14 22:06:55 +00:00
|
|
|
}
|
2016-05-14 22:15:10 +00:00
|
|
|
delete[] values_copy;
|
2016-05-14 22:06:55 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void Shader::enqueue_function(std::function<void(void)> function)
|
|
|
|
{
|
2017-02-20 02:45:28 +00:00
|
|
|
std::lock_guard<std::mutex> function_guard(function_mutex_);
|
2016-11-21 03:57:45 +00:00
|
|
|
enqueued_functions_.push_back(function);
|
2016-05-14 22:06:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Shader::flush_functions()
|
|
|
|
{
|
2017-02-20 02:45:28 +00:00
|
|
|
std::lock_guard<std::mutex> function_guard(function_mutex_);
|
2016-11-21 03:57:45 +00:00
|
|
|
for(std::function<void(void)> function : enqueued_functions_)
|
2016-05-14 02:08:32 +00:00
|
|
|
{
|
2016-05-14 22:06:55 +00:00
|
|
|
function();
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|
2016-11-21 03:57:45 +00:00
|
|
|
enqueued_functions_.clear();
|
2016-05-14 02:08:32 +00:00
|
|
|
}
|