Improves asset management by adding a shutdown procedure that safely terminates the asset scanning thread. This prevents crashes and ensures a clean exit. Enhances shader management by introducing shader naming and improved error logging. This makes debugging easier. Also renames the sprite shader. Fixes a minor bug related to sprite drawing position. Adds Git mappings for submodules.
183 lines
5.1 KiB
C++
183 lines
5.1 KiB
C++
#include "Shader.h"
|
|
#include <fstream>
|
|
#include <sstream>
|
|
#include <iostream>
|
|
#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);
|
|
}
|
|
}
|