#include #include #include #include #include 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); E2D_LOG_INFO("Compiling vertex shader..."); // 编译顶点着色器 GLuint vs = compileShader(GL_VERTEX_SHADER, processedVS); if (vs == 0) { E2D_LOG_ERROR("Vertex shader compilation failed"); return false; } E2D_LOG_INFO("Compiling fragment shader..."); // 编译片段着色器 GLuint fs = compileShader(GL_FRAGMENT_SHADER, processedFS); if (fs == 0) { E2D_LOG_ERROR("Fragment shader compilation failed"); glDeleteShader(vs); return false; } E2D_LOG_INFO("Linking shader program..."); // 链接程序 if (!linkProgram(vs, fs)) { E2D_LOG_ERROR("Shader program linking failed"); glDeleteShader(vs); glDeleteShader(fs); return false; } // 清理着色器对象 glDeleteShader(vs); glDeleteShader(fs); E2D_LOG_INFO("Shader program created successfully, program ID: {}", program_); 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); // 调试:输出设置成功的uniform static int logCount = 0; if (logCount < 3) { E2D_LOG_INFO("Set uniform '{}' at location {}", name, location); logCount++; } } else { // 调试:输出未找到的uniform static bool loggedOnce = false; if (!loggedOnce) { E2D_LOG_WARN("Uniform '{}' not found in shader", name); loggedOnce = true; } } } 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