Extra2D/src/renderer/shader.cpp

218 lines
5.6 KiB
C++
Raw Normal View History

#include <renderer/shader.h>
#include <utils/logger.h>
#include <glad/glad.h>
#include <fstream>
#include <sstream>
namespace extra2d {
Shader::Shader() = default;
Shader::~Shader() {
if (program_ != 0) {
glDeleteProgram(program_);
program_ = 0;
}
}
bool Shader::loadFromFile(const std::string& vsPath, const std::string& fsPath) {
// 读取顶点着色器
std::ifstream vsFile(vsPath);
if (!vsFile.is_open()) {
E2D_LOG_ERROR("Failed to open vertex shader: {}", vsPath);
return false;
}
std::stringstream vsStream;
vsStream << vsFile.rdbuf();
std::string vsSource = vsStream.str();
// 读取片段着色器
std::ifstream fsFile(fsPath);
if (!fsFile.is_open()) {
E2D_LOG_ERROR("Failed to open fragment shader: {}", fsPath);
return false;
}
std::stringstream fsStream;
fsStream << fsFile.rdbuf();
std::string fsSource = fsStream.str();
return loadFromSource(vsSource, fsSource);
}
bool Shader::loadFromSource(const std::string& vsSource, const std::string& fsSource) {
// 删除旧程序
if (program_ != 0) {
glDeleteProgram(program_);
program_ = 0;
}
uniformCache_.clear();
// 处理源码(添加版本声明)
std::string processedVS = addVersionIfNeeded(vsSource, GL_VERTEX_SHADER);
std::string processedFS = addVersionIfNeeded(fsSource, GL_FRAGMENT_SHADER);
// 编译顶点着色器
GLuint vs = compileShader(GL_VERTEX_SHADER, processedVS);
if (vs == 0) {
return false;
}
// 编译片段着色器
GLuint fs = compileShader(GL_FRAGMENT_SHADER, processedFS);
if (fs == 0) {
glDeleteShader(vs);
return false;
}
// 链接程序
if (!linkProgram(vs, fs)) {
glDeleteShader(vs);
glDeleteShader(fs);
return false;
}
// 清理着色器对象
glDeleteShader(vs);
glDeleteShader(fs);
E2D_LOG_DEBUG("Shader program created successfully");
return true;
}
void Shader::bind() const {
if (program_ != 0) {
glUseProgram(program_);
}
}
void Shader::unbind() const {
glUseProgram(0);
}
void Shader::setUniformBlock(const std::string& name, uint32_t binding) {
if (program_ == 0) return;
GLuint index = glGetUniformBlockIndex(program_, name.c_str());
if (index != GL_INVALID_INDEX) {
glUniformBlockBinding(program_, index, binding);
}
}
void Shader::setInt(const std::string& name, int value) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniform1i(location, value);
}
}
void Shader::setFloat(const std::string& name, float value) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniform1f(location, value);
}
}
void Shader::setVec2(const std::string& name, float x, float y) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniform2f(location, x, y);
}
}
void Shader::setVec4(const std::string& name, float x, float y, float z, float w) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniform4f(location, x, y, z, w);
}
}
void Shader::setMat4(const std::string& name, const float* value) {
GLint location = getUniformLocation(name);
if (location != -1) {
glUniformMatrix4fv(location, 1, GL_FALSE, value);
}
}
GLuint Shader::compileShader(GLenum type, const std::string& source) {
GLuint shader = glCreateShader(type);
const char* src = source.c_str();
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
// 检查编译状态
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
char infoLog[512];
glGetShaderInfoLog(shader, 512, nullptr, infoLog);
const char* typeStr = (type == GL_VERTEX_SHADER) ? "vertex" : "fragment";
E2D_LOG_ERROR("{} shader compilation failed: {}", typeStr, infoLog);
glDeleteShader(shader);
return 0;
}
return shader;
}
bool Shader::linkProgram(GLuint vertexShader, GLuint fragmentShader) {
program_ = glCreateProgram();
glAttachShader(program_, vertexShader);
glAttachShader(program_, fragmentShader);
glLinkProgram(program_);
// 检查链接状态
GLint success;
glGetProgramiv(program_, GL_LINK_STATUS, &success);
if (!success) {
char infoLog[512];
glGetProgramInfoLog(program_, 512, nullptr, infoLog);
E2D_LOG_ERROR("Shader program linking failed: {}", infoLog);
glDeleteProgram(program_);
program_ = 0;
return false;
}
return true;
}
GLint Shader::getUniformLocation(const std::string& name) {
if (program_ == 0) return -1;
// 检查缓存
auto it = uniformCache_.find(name);
if (it != uniformCache_.end()) {
return it->second;
}
// 查询 uniform 位置
GLint location = glGetUniformLocation(program_, name.c_str());
uniformCache_[name] = location;
return location;
}
std::string Shader::addVersionIfNeeded(const std::string& source, GLenum type) {
// 如果已经包含版本声明,直接返回
if (source.find("#version") != std::string::npos) {
return source;
}
// 添加 OpenGL ES 3.2 版本声明
std::string result = "#version 320 es\n";
// 片段着色器需要添加精度声明
if (type == GL_FRAGMENT_SHADER) {
result += "precision mediump float;\n";
}
result += source;
return result;
}
} // namespace extra2d