171 lines
3.8 KiB
C++
171 lines
3.8 KiB
C++
/*
|
|
* =====================================================================================
|
|
*
|
|
* Filename: Shader.cpp
|
|
*
|
|
* Description:
|
|
*
|
|
* Created: 15/12/2014 16:30:34
|
|
*
|
|
* Author: Quentin Bazin, <quent42340@gmail.com>
|
|
*
|
|
* =====================================================================================
|
|
*/
|
|
#include <iostream>
|
|
#include <fstream>
|
|
|
|
#define GLM_FORCE_RADIANS
|
|
#include <glm/gtc/type_ptr.hpp>
|
|
|
|
#include "Exception.hpp"
|
|
#include "Shader.hpp"
|
|
|
|
Shader::Shader(const std::string &vertexFilename, const std::string &fragmentFilename) {
|
|
loadFromFile(vertexFilename, fragmentFilename);
|
|
}
|
|
|
|
Shader::~Shader() {
|
|
while(m_vertexShaders.size() != 0) {
|
|
glDeleteShader(m_vertexShaders.back());
|
|
m_vertexShaders.pop_back();
|
|
}
|
|
|
|
while(m_fragmentShaders.size() != 0) {
|
|
glDeleteShader(m_fragmentShaders.back());
|
|
m_fragmentShaders.pop_back();
|
|
}
|
|
|
|
glDeleteProgram(m_program);
|
|
}
|
|
|
|
void Shader::loadFromFile(const std::string &vertexFilename, const std::string &fragmentFilename) {
|
|
createProgram();
|
|
|
|
addShader(GL_VERTEX_SHADER, vertexFilename);
|
|
addShader(GL_FRAGMENT_SHADER, fragmentFilename);
|
|
|
|
linkProgram();
|
|
}
|
|
|
|
void Shader::createProgram() {
|
|
m_program = glCreateProgram();
|
|
}
|
|
|
|
void Shader::linkProgram() {
|
|
glLinkProgram(m_program);
|
|
|
|
GLint linkOK = GL_FALSE;
|
|
glGetProgramiv(m_program, GL_LINK_STATUS, &linkOK);
|
|
if(!linkOK){
|
|
GLint errorSize = 0;
|
|
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &errorSize);
|
|
|
|
char *errorMsg = new char[errorSize + 1];
|
|
|
|
glGetProgramInfoLog(m_program, errorSize, &errorSize, errorMsg);
|
|
errorMsg[errorSize] = '\0';
|
|
|
|
std::string error = std::string(errorMsg);
|
|
|
|
delete[] errorMsg;
|
|
glDeleteProgram(m_program);
|
|
|
|
throw EXCEPTION("Program", m_program, "link failed:", error);
|
|
}
|
|
}
|
|
|
|
void Shader::addShader(GLenum type, const std::string &filename) {
|
|
GLuint shader = glCreateShader(type);
|
|
|
|
if(type == GL_VERTEX_SHADER) {
|
|
m_vertexShaders.push_back(shader);
|
|
} else {
|
|
m_fragmentShaders.push_back(shader);
|
|
}
|
|
|
|
std::ifstream file(filename);
|
|
if(!file) {
|
|
glDeleteShader(shader);
|
|
|
|
throw EXCEPTION("Failed to open", filename);
|
|
}
|
|
|
|
std::string line;
|
|
std::string sourceCode;
|
|
|
|
while(getline(file, line)) sourceCode += line + '\n';
|
|
file.close();
|
|
|
|
const GLchar *sourceCodeString = sourceCode.c_str();
|
|
|
|
glShaderSource(shader, 1, &sourceCodeString, nullptr);
|
|
|
|
glCompileShader(shader);
|
|
|
|
GLint compileOK = GL_FALSE;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileOK);
|
|
if(!compileOK) {
|
|
GLint errorSize = 0;
|
|
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &errorSize);
|
|
|
|
char *errorMsg = new char[errorSize + 1];
|
|
|
|
glGetShaderInfoLog(shader, errorSize, &errorSize, errorMsg);
|
|
errorMsg[errorSize] = '\0';
|
|
|
|
std::string error = std::string(errorMsg);
|
|
|
|
delete[] errorMsg;
|
|
glDeleteShader(shader);
|
|
|
|
throw EXCEPTION("Shader", filename, "compilation failed:", error);
|
|
}
|
|
|
|
glAttachShader(m_program, shader);
|
|
}
|
|
|
|
GLint Shader::attrib(const std::string &name) const {
|
|
GLint attrib = glGetAttribLocation(m_program, name.c_str());
|
|
|
|
if(attrib == -1) {
|
|
DEBUG("Could not bind attribute:", name);
|
|
}
|
|
|
|
return attrib;
|
|
}
|
|
|
|
GLint Shader::uniform(const std::string &name) const {
|
|
GLint uniform = glGetUniformLocation(m_program, name.c_str());
|
|
|
|
if(uniform == -1) {
|
|
DEBUG("Could not bind uniform:", name);
|
|
}
|
|
|
|
return uniform;
|
|
}
|
|
|
|
void Shader::enableVertexAttribArray(const std::string &name) const {
|
|
glEnableVertexAttribArray(attrib(name));
|
|
}
|
|
|
|
void Shader::disableVertexAttribArray(const std::string &name) const {
|
|
glDisableVertexAttribArray(attrib(name));
|
|
}
|
|
|
|
void Shader::setUniform(const std::string &name, int n) const {
|
|
glUniform1i(uniform(name), n);
|
|
}
|
|
|
|
void Shader::setUniform(const std::string &name, const glm::mat4 &matrix) const {
|
|
glUniformMatrix4fv(uniform(name), 1, GL_FALSE, glm::value_ptr(matrix));
|
|
}
|
|
|
|
void Shader::bind(const Shader *shader) {
|
|
if(shader) {
|
|
glUseProgram(shader->m_program);
|
|
} else {
|
|
glUseProgram(0);
|
|
}
|
|
}
|
|
|