Files
utad-3d/src/shader.cpp
2025-10-13 17:30:05 +02:00

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;
}