You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
4.1 KiB
163 lines
4.1 KiB
3 years ago
|
#include <climits> // UINT_MAX
|
||
|
#include <cstdio> // printf
|
||
|
#include <fstream> // ifstream
|
||
|
#include <iostream> // ios
|
||
|
#include <memory> // make_unique
|
||
|
|
||
|
#include <glad/glad.h>
|
||
|
#include <glm/gtc/type_ptr.hpp> // glm::value_ptr
|
||
|
|
||
|
#include "shader.h"
|
||
|
|
||
|
Shader::Shader(const std::string &vertexSource, const std::string &fragmentSource) :
|
||
|
m_program(0)
|
||
|
{
|
||
|
std::string vertex = readFile(vertexSource);
|
||
|
std::string fragment = readFile(fragmentSource);
|
||
|
|
||
|
unsigned int vertexShader = compileShader(GL_VERTEX_SHADER, vertex.c_str());
|
||
|
unsigned int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragment.c_str());
|
||
|
if (vertexShader != UINT_MAX && fragmentShader != UINT_MAX) {
|
||
|
m_program = linkShader(vertexShader, fragmentShader);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Shader::~Shader()
|
||
|
{
|
||
|
if (m_program > 0) {
|
||
|
glDeleteProgram(m_program);
|
||
|
m_program = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// -----------------------------------------
|
||
|
|
||
|
std::string Shader::readFile(const std::string &path) const
|
||
|
{
|
||
|
// Create input stream object and open file
|
||
|
std::ifstream file;
|
||
|
file.open(path.c_str(), std::ifstream::in);
|
||
|
|
||
|
// Check if file exists
|
||
|
if (!file.is_open()) {
|
||
|
printf("Shader::readFile::FAILED\n%s\n", path.c_str());
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
// Get length of the file
|
||
|
file.seekg(0, std::ios::end);
|
||
|
unsigned int length = file.tellg();
|
||
|
file.seekg(0, std::ios::beg);
|
||
|
|
||
|
// Allocate memory filled with zeros
|
||
|
auto buffer = std::make_unique<char[]>(length + 1);
|
||
|
|
||
|
file.read(buffer.get(), length);
|
||
|
file.close();
|
||
|
|
||
|
// Create string from the buffer
|
||
|
std::string result = std::string(buffer.get(), length + 1);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
unsigned int Shader::compileShader(unsigned int type, const char *source) const
|
||
|
{
|
||
|
// Create new shader
|
||
|
unsigned int shader;
|
||
|
shader = glCreateShader(type);
|
||
|
// Attach shader source to shader object
|
||
|
glShaderSource(shader, 1, &source, nullptr);
|
||
|
// Compile shader
|
||
|
glCompileShader(shader);
|
||
|
// Check compilation status
|
||
|
if (checkStatus(shader)) {
|
||
|
return shader;
|
||
|
}
|
||
|
|
||
|
// On fail
|
||
|
glDeleteShader(shader);
|
||
|
return UINT_MAX;
|
||
|
}
|
||
|
|
||
|
unsigned int Shader::linkShader(unsigned int vertex, unsigned int fragment) const
|
||
|
{
|
||
|
// Create new shader program
|
||
|
unsigned int shaderProgram;
|
||
|
shaderProgram = glCreateProgram();
|
||
|
// Attach both shaders to the shader program
|
||
|
glAttachShader(shaderProgram, vertex);
|
||
|
glAttachShader(shaderProgram, fragment);
|
||
|
// Setup vertex attributes
|
||
|
glBindAttribLocation(shaderProgram, 0, "aPos");
|
||
|
// Link the shaders
|
||
|
glLinkProgram(shaderProgram);
|
||
|
// Clear resources
|
||
|
glDeleteShader(vertex);
|
||
|
glDeleteShader(fragment);
|
||
|
// Check linking status
|
||
|
if (checkStatus(shaderProgram, true)) {
|
||
|
return shaderProgram;
|
||
|
}
|
||
|
|
||
|
// On fail
|
||
|
glDeleteProgram(shaderProgram);
|
||
|
return UINT_MAX;
|
||
|
}
|
||
|
|
||
|
int Shader::checkStatus(unsigned int check, bool isProgram) const
|
||
|
{
|
||
|
int success;
|
||
|
char infoLog[INFO_LOG_SIZE];
|
||
|
|
||
|
// Check shader or program
|
||
|
!isProgram
|
||
|
? glGetShaderiv(check, GL_COMPILE_STATUS, &success)
|
||
|
: glGetProgramiv(check, GL_LINK_STATUS, &success);
|
||
|
|
||
|
if (!success) {
|
||
|
// Check shader or program
|
||
|
!isProgram
|
||
|
? glGetShaderInfoLog(check, INFO_LOG_SIZE, nullptr, infoLog)
|
||
|
: glGetProgramInfoLog(check, INFO_LOG_SIZE, nullptr, infoLog);
|
||
|
printf("Shader::checkStatus::FAILED\n%s\n", infoLog);
|
||
|
}
|
||
|
|
||
|
return success;
|
||
|
}
|
||
|
|
||
|
void Shader::use() const
|
||
|
{
|
||
|
glUseProgram(m_program);
|
||
|
}
|
||
|
|
||
|
void Shader::setFloat(const std::string &name, float f1, float f2, float f3, float f4) const
|
||
|
{
|
||
|
// Set uniform vec4 data
|
||
|
glUniform4f(glGetUniformLocation(m_program, name.c_str()), f1, f2, f3, f4);
|
||
|
}
|
||
|
|
||
|
void Shader::setFloat(const std::string &name, glm::vec3 v) const {
|
||
|
// Set uniform vec3 data
|
||
|
glUniform3f(glGetUniformLocation(m_program, name.c_str()), v.x, v.y, v.z);
|
||
|
}
|
||
|
|
||
|
void Shader::setFloat(const std::string &name, glm::vec4 v) const {
|
||
|
// Set uniform vec4 data
|
||
|
glUniform4f(glGetUniformLocation(m_program, name.c_str()), v.x, v.y, v.z, v.w);
|
||
|
// glUniform4fv(glGetUniformLocation(m_program, name.c_str()), 1, glm::value_ptr(v));
|
||
|
}
|
||
|
|
||
|
void Shader::setFloat(const std::string &name, glm::mat4 m) const {
|
||
|
// Set uniform mat4 data
|
||
|
glUniformMatrix4fv(glGetUniformLocation(m_program, name.c_str()),
|
||
|
1, GL_FALSE, glm::value_ptr(m));
|
||
|
}
|
||
|
|
||
|
// -----------------------------------------
|
||
|
|
||
|
unsigned int Shader::program() const
|
||
|
{
|
||
|
return m_program;
|
||
|
}
|