#include "Shader.h" #include #include #include #include "systems/Logger.h" namespace OX { Shader::Shader(const std::string &vertexPath, const std::string &fragmentPath) { LoadFromFiles(vertexPath, fragmentPath); } bool Shader::LoadFromFiles(const std::string &vertexPath, const std::string &fragmentPath) { m_vertexPath = vertexPath; m_fragmentPath = fragmentPath; std::string vertexSrc = ReadFile(vertexPath); std::string fragmentSrc = ReadFile(fragmentPath); try { m_vertTimestamp = std::filesystem::last_write_time(vertexPath); m_fragTimestamp = std::filesystem::last_write_time(fragmentPath); } catch (...) { std::cerr << "[Shader] Warning: Could not get file timestamps.\n"; } return LoadFromSource(vertexSrc, fragmentSrc); } bool Shader::LoadFromSource(const std::string &vertexSrc, const std::string &fragmentSrc) { GLuint vertexShader = CompileShader(GL_VERTEX_SHADER, vertexSrc); GLuint fragmentShader = CompileShader(GL_FRAGMENT_SHADER, fragmentSrc); if (!vertexShader || !fragmentShader) return false; GLuint program = glCreateProgram(); glAttachShader(program, vertexShader); glAttachShader(program, fragmentShader); glLinkProgram(program); GLint success; glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { char info[512]; glGetProgramInfoLog(program, 512, nullptr, info); Logger::LogError("'%s' Linking failed: '%s'", m_name.c_str(), info); glDeleteProgram(program); return false; } if (m_programID) glDeleteProgram(m_programID); m_programID = program; m_uniformCache.clear(); glDeleteShader(vertexShader); glDeleteShader(fragmentShader); Logger::LogDebug("Shader '%s' Loaded", m_name.c_str()); return true; } void Shader::Reload() { OX_PROFILE_FUNCTION(); LoadFromFiles(m_vertexPath, m_fragmentPath); } void Shader::Use() const { glUseProgram(m_programID); } GLuint Shader::CompileShader(GLenum type, const std::string &source) { OX_PROFILE_FUNCTION(); 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 info[512]; glGetShaderInfoLog(shader, 512, nullptr, info); Logger::LogDebug("Failed to Compile Shader: '%s'", m_name.c_str()); return 0; } return shader; } void Shader::CheckHotReload() { OX_PROFILE_FUNCTION(); if (m_vertexPath.empty() || m_fragmentPath.empty()) { return; } try { OX_PROFILE_LABEL("Get Write Time"); auto vertTime = std::filesystem::last_write_time(m_vertexPath); auto fragTime = std::filesystem::last_write_time(m_fragmentPath); if (vertTime != m_vertTimestamp || fragTime != m_fragTimestamp) { std::cout << "[Shader] Reloading shader: " << m_vertexPath << " / " << m_fragmentPath << "\n"; Reload(); } } catch (const std::exception &e) { Logger::LogError("Failed to Reload Shader '%s', %s", m_name.c_str(), e.what()); } } std::string Shader::ReadFile(const std::string &path) { if (!std::filesystem::exists(path)) { std::ofstream file(path, std::ios::app); } std::ifstream file(path); std::stringstream ss; ss << file.rdbuf(); return ss.str(); } GLint Shader::GetUniformLocation(const std::string &name) { if (m_uniformCache.contains(name)) return m_uniformCache[name]; GLint location = glGetUniformLocation(m_programID, name.c_str()); m_uniformCache[name] = location; return location; } void Shader::SetInt(const std::string &name, int value) { glUniform1i(GetUniformLocation(name), value); } void Shader::SetFloat(const std::string &name, float value) { glUniform1f(GetUniformLocation(name), value); } void Shader::SetVec2(const std::string &name, const glm::vec2 &value) { glUniform2fv(GetUniformLocation(name), 1, &value[0]); } void Shader::SetVec3(const std::string &name, const glm::vec3 &value) { glUniform3fv(GetUniformLocation(name), 1, &value[0]); } void Shader::SetVec4(const std::string &name, const glm::vec4 &value) { glUniform4fv(GetUniformLocation(name), 1, &value[0]); } void Shader::SetMat4(const std::string &name, const glm::mat4 &value) { glUniformMatrix4fv(GetUniformLocation(name), 1, GL_FALSE, &value[0][0]); } void Shader::SetBool(const std::string &name, bool value) { glUniform1i(GetUniformLocation(name), (int) value); } }