#include #include #include #include namespace easy2d { GLShader::GLShader() : programID_(0) { } GLShader::~GLShader() { if (programID_ != 0) { glDeleteProgram(programID_); } } bool GLShader::compileFromSource(const char* vertexSource, const char* fragmentSource) { GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexSource); if (vertexShader == 0) return false; GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentSource); if (fragmentShader == 0) { glDeleteShader(vertexShader); return false; } programID_ = glCreateProgram(); glAttachShader(programID_, vertexShader); glAttachShader(programID_, fragmentShader); glLinkProgram(programID_); GLint success; glGetProgramiv(programID_, GL_LINK_STATUS, &success); if (!success) { char infoLog[512]; glGetProgramInfoLog(programID_, 512, nullptr, infoLog); E2D_LOG_ERROR("Shader program linking failed: {}", infoLog); glDeleteProgram(programID_); programID_ = 0; } glDeleteShader(vertexShader); glDeleteShader(fragmentShader); return success == GL_TRUE; } bool GLShader::compileFromFile(const std::string& vertexPath, const std::string& fragmentPath) { std::ifstream vShaderFile(vertexPath); std::ifstream fShaderFile(fragmentPath); if (!vShaderFile.is_open() || !fShaderFile.is_open()) { E2D_LOG_ERROR("Failed to open shader files: {}, {}", vertexPath, fragmentPath); return false; } std::stringstream vShaderStream, fShaderStream; vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); return compileFromSource(vShaderStream.str().c_str(), fShaderStream.str().c_str()); } void GLShader::bind() const { glUseProgram(programID_); } void GLShader::unbind() const { glUseProgram(0); } void GLShader::setBool(const std::string& name, bool value) { glUniform1i(getUniformLocation(name), value ? 1 : 0); } void GLShader::setInt(const std::string& name, int value) { glUniform1i(getUniformLocation(name), value); } void GLShader::setFloat(const std::string& name, float value) { glUniform1f(getUniformLocation(name), value); } void GLShader::setVec2(const std::string& name, const glm::vec2& value) { glUniform2fv(getUniformLocation(name), 1, &value[0]); } void GLShader::setVec3(const std::string& name, const glm::vec3& value) { glUniform3fv(getUniformLocation(name), 1, &value[0]); } void GLShader::setVec4(const std::string& name, const glm::vec4& value) { glUniform4fv(getUniformLocation(name), 1, &value[0]); } void GLShader::setMat4(const std::string& name, const glm::mat4& value) { glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, &value[0][0]); } GLuint GLShader::compileShader(GLenum type, const char* source) { GLuint shader = glCreateShader(type); glShaderSource(shader, 1, &source, nullptr); glCompileShader(shader); GLint success; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { char infoLog[512]; glGetShaderInfoLog(shader, 512, nullptr, infoLog); E2D_LOG_ERROR("Shader compilation failed: {}", infoLog); glDeleteShader(shader); return 0; } return shader; } GLint GLShader::getUniformLocation(const std::string& name) { auto it = uniformCache_.find(name); if (it != uniformCache_.end()) { return it->second; } GLint location = glGetUniformLocation(programID_, name.c_str()); uniformCache_[name] = location; return location; } } // namespace easy2d