154 lines
3.4 KiB
C++
154 lines
3.4 KiB
C++
#include "shader.h"
|
|
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <vector>
|
|
|
|
#include "../lib/glew/GL/glew.h"
|
|
#include "../lib/glfw/glfw3.h"
|
|
|
|
#include "logger.h"
|
|
#include "vertex.h"
|
|
|
|
Shader::Shader(const std::string& vertexPath, const std::string& fragmentPath)
|
|
{
|
|
const uint32_t vshader = compile_shader(GL_VERTEX_SHADER, vertexPath);
|
|
const uint32_t fshader =
|
|
compile_shader(GL_FRAGMENT_SHADER, fragmentPath);
|
|
|
|
if (vshader == 0 || fshader == 0) {
|
|
program_id_ = 0;
|
|
return;
|
|
}
|
|
|
|
program_id_ = glCreateProgram();
|
|
glAttachShader(program_id_, vshader);
|
|
glAttachShader(program_id_, fshader);
|
|
glLinkProgram(program_id_);
|
|
|
|
// Error handling
|
|
int ret;
|
|
glGetProgramiv(program_id_, GL_LINK_STATUS, &ret);
|
|
if (ret == GL_FALSE) {
|
|
char buffer[1024];
|
|
glGetProgramInfoLog(program_id_, sizeof(buffer), nullptr,
|
|
buffer);
|
|
error_ = buffer;
|
|
glDeleteProgram(program_id_);
|
|
program_id_ = 0;
|
|
}
|
|
|
|
glDeleteShader(vshader);
|
|
glDeleteShader(fshader);
|
|
}
|
|
|
|
void Shader::use() const
|
|
{
|
|
if (program_id_ != 0)
|
|
glUseProgram(program_id_);
|
|
}
|
|
|
|
void Shader::setup_attribs() const
|
|
{
|
|
int loc = glGetAttribLocation(program_id_, "vpos");
|
|
if (loc != -1) {
|
|
glEnableVertexAttribArray(loc);
|
|
glVertexAttribPointer(
|
|
loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
|
reinterpret_cast<const void*>(offsetof(Vertex, position)));
|
|
}
|
|
|
|
loc = glGetAttribLocation(program_id_, "vcolor");
|
|
if (loc != -1) {
|
|
glEnableVertexAttribArray(loc);
|
|
glVertexAttribPointer(
|
|
loc, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex),
|
|
reinterpret_cast<const void*>(offsetof(Vertex, color)));
|
|
}
|
|
}
|
|
|
|
int Shader::uniform_location(const char* key) const
|
|
{
|
|
return glGetUniformLocation(program_id_, key);
|
|
}
|
|
|
|
void Shader::set_int(int loc, int value)
|
|
{
|
|
if (loc != -1)
|
|
glUniform1i(loc, value);
|
|
}
|
|
|
|
void Shader::set_float(int loc, float value)
|
|
{
|
|
if (loc != -1)
|
|
glUniform1f(loc, value);
|
|
}
|
|
|
|
void Shader::set_vec3(int loc, const glm::vec3& value)
|
|
{
|
|
if (loc != -1)
|
|
glUniform3fv(loc, 1, &value[0]);
|
|
}
|
|
|
|
void Shader::set_vec4(int loc, const glm::vec4& value)
|
|
{
|
|
if (loc != -1)
|
|
glUniform4fv(loc, 1, &value[0]);
|
|
}
|
|
|
|
void Shader::set_mat4(int loc, const glm::mat4& value)
|
|
{
|
|
if (loc != -1)
|
|
glUniformMatrix4fv(loc, 1, GL_FALSE, &value[0][0]);
|
|
}
|
|
|
|
std::string Shader::read_shader_file(const std::string& filename)
|
|
{
|
|
std::ifstream file(filename);
|
|
if (!file) {
|
|
error_ = "Failed to open shader file: " + filename;
|
|
Logger::error(sstr("Failed to open shader file: ", filename));
|
|
return std::string{0};
|
|
}
|
|
|
|
std::stringstream buffer;
|
|
buffer << file.rdbuf();
|
|
return buffer.str();
|
|
}
|
|
|
|
uint32_t Shader::compile_shader(uint32_t type, const std::string& source_path)
|
|
{
|
|
const char* shader_type_name =
|
|
(type == GL_VERTEX_SHADER) ? "vertex" : "fragment";
|
|
|
|
std::string source = read_shader_file(source_path);
|
|
if (source.empty())
|
|
return 0;
|
|
|
|
Logger::info(
|
|
sstr("Compiling ", shader_type_name, " shader: ", source_path));
|
|
|
|
const uint32_t shader = glCreateShader(type);
|
|
const char* shader_code = source.c_str();
|
|
|
|
glShaderSource(shader, 1, &shader_code, nullptr);
|
|
glCompileShader(shader);
|
|
|
|
// Error handling
|
|
int ret;
|
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &ret);
|
|
if (ret == GL_FALSE) {
|
|
char buffer[1024];
|
|
glGetShaderInfoLog(shader, sizeof(buffer), nullptr, buffer);
|
|
error_ = buffer;
|
|
Logger::error(
|
|
sstr("Shader compilation failed (", shader_type_name, "): ",
|
|
buffer));
|
|
glDeleteShader(shader);
|
|
return 0;
|
|
}
|
|
|
|
Logger::info(sstr(shader_type_name, " shader compiled successfully"));
|
|
return shader;
|
|
}
|