#include "CShaderGL.h" #include "CEngine.h" #include "U_Log.h" #include #include #include "GL/glew.h" #include #include "glm/glm.hpp" #include "glm/gtc/matrix_transform.hpp" #include "glm/gtx/quaternion.hpp" #include "glm/gtc/type_ptr.hpp" CShaderGL::CShaderGL() { } CShaderGL::CShaderGL(const std::string& vertex_path, const std::string& frag_path, const std::string& geom_path) { LoadFromFile(vertex_path, frag_path, geom_path); } void CShaderGL::SetProperty(const std::string& name, const std::string& value) { for (Property& prop : Properties) { if (prop.Name == name) { prop.Value = value; return; } } Properties.push_back({ name, value }); } void CShaderGL::DeleteProperty(const std::string& name) { for (int i = 0; i < Properties.size(); i++) { if (Properties.at(i).Name == name) { Properties.erase(Properties.begin() + i); return; } } } void CShaderGL::ReloadShadersProperties() { std::string vertCode = OriginalVertexShader, fragCode = OriginalFragmentShader, geomCode = OriginalGeometryShader; if (!fragCode.empty()) { usingFrag = true; } if (!geomCode.empty()) { usingGeom = true; } std::string propString; for (Property& prop : Properties) { propString += "#define " + prop.Name + " " + prop.Value + "\r\n"; } std::string toFind = "#version 430\r\n"; size_t index = vertCode.find(toFind); vertCode.insert(index + toFind.length(), propString); if (usingFrag) { std::string toFind = "#version 430\r\n"; size_t index = fragCode.find(toFind); fragCode.insert(index + toFind.length(), propString); } if (usingGeom) { std::string toFind = "#version 430\r\n"; size_t index = geomCode.find(toFind); geomCode.insert(index + toFind.length(), propString); } Compile(vertCode, fragCode, geomCode); } void CShaderGL::SetDefaultShaderProperties() { } void CShaderGL::LoadFromFile(const std::string& vertex_path, const std::string& frag_path, const std::string& geom_path) { if (!frag_path.empty()) { usingFrag = true; } if (!geom_path.empty()) { usingGeom = true; } vertPath = vertex_path; fragPath = frag_path; geomPath = geom_path; std::string vertCode, fragCode, geomCode; std::ifstream vertStream, fragStream, geomStream; std::string propString; for (Property& prop : Properties) { propString += "#define " + prop.Name + " " + prop.Value + "\r\n"; } vertStream.open(vertex_path); if (vertStream.is_open()) { std::stringstream vertStringStream; vertStringStream << vertStream.rdbuf(); vertStream.close(); vertCode = vertStringStream.str(); OriginalVertexShader = vertCode; std::string toFind = "#version 430\r\n"; size_t index = vertCode.find(toFind); vertCode.insert(index + toFind.length(), propString); if (vertex_path == "resources\\shaders\\default.vs") { std::ofstream fstr; fstr.open("vs.txt"); fstr << vertCode; fstr.close(); } } if (usingFrag) { fragStream.open(frag_path); if (fragStream.is_open()) { std::stringstream fragStringStream; fragStringStream << fragStream.rdbuf(); fragStream.close(); fragCode = fragStringStream.str(); OriginalFragmentShader = fragCode; std::string toFind = "#version 430\r\n"; size_t index = fragCode.find(toFind); fragCode.insert(index + toFind.length(), propString); if (vertex_path == "resources\\shaders\\default.vs") { std::ofstream fstr; fstr.open("fs.txt"); fstr << fragCode; fstr.close(); } } } if (usingGeom) { geomStream.open(geom_path); if (geomStream.is_open()) { std::stringstream geomStringStream; geomStringStream << geomStream.rdbuf(); geomStream.close(); geomCode = geomStringStream.str(); OriginalGeometryShader = geomCode; std::string toFind = "#version 430\r\n"; size_t index = geomCode.find(toFind); geomCode.insert(index + toFind.length(), propString); } } Compile(vertCode, fragCode, geomCode); } void CShaderGL::Compile(const std::string& vertCode, const std::string& fragCode, const std::string& geomCode) { if (Compiled) { DestructProgram(); Compiled = false; } unsigned int vertex, fragment, geometry; int success; char infoLog[512]; const char* vertcode = vertCode.c_str(); vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vertcode, NULL); glCompileShader(vertex); glGetShaderiv(vertex, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(vertex, 512, NULL, infoLog); Log::Errln("Can't compile vertex shader \"" + vertPath + "\":\n" + std::string(infoLog)); std::ofstream fstr; fstr.open("errordvs.txt"); fstr << vertCode; fstr.close(); } else { Log::Outln("Vertex shader compiled"); } if (usingFrag) { const char* fragcode = fragCode.c_str(); fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fragcode, NULL); glCompileShader(fragment); glGetShaderiv(fragment, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(fragment, 512, NULL, infoLog); Log::Errln("Can't compile fragment shader \"" + fragPath + "\":\n" + std::string(infoLog)); std::ofstream fstr; fstr.open("errordfs.txt"); fstr << fragCode; fstr.close(); } else { Log::Outln("Fragment shader compiled"); } } if (usingGeom) { const char* geomcode = geomCode.c_str(); geometry = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(geometry, 1, &geomcode, NULL); glCompileShader(geometry); glGetShaderiv(geometry, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(geometry, 512, NULL, infoLog); Log::Errln("Can't compile geometry shader \"" + geomPath + "\":\n" + std::string(infoLog)); } else { Log::Outln("Geometry shader compiled"); } } ID = glCreateProgram(); glAttachShader(ID, vertex); if (usingFrag) { glAttachShader(ID, fragment); } if (usingGeom) { glAttachShader(ID, geometry); } glLinkProgram(ID); glGetProgramiv(ID, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(ID, 512, NULL, infoLog); Log::Errln("Can't link shader:\n" + std::string(infoLog)); } else { Compiled = true; Log::Outln("Shader linked"); } glDeleteShader(vertex); if (usingFrag) { glDeleteShader(fragment); } if (usingGeom) { glDeleteShader(geometry); } } CShaderGL::~CShaderGL() { DestructProgram(); } unsigned int CShaderGL::GetShaderID() { return ID; } void CShaderGL::DestructProgram() { glDeleteProgram(ID); } void CShaderGL::Bind() { glUseProgram(ID); } void CShaderGL::UnbindAll() { glUseProgram(0); } int CShaderGL::GetUniformLocation(const std::string& name) { for (Uniform& u : Uniforms) { if (u.Name == name) { return u.Location; } } int loc = glGetUniformLocation(ID, name.c_str()); if (loc != -1) { Log::Instance() << "Found uniform \"" << name << "\"\n"; Uniforms.push_back({ name, loc }); } return loc; } int CShaderGL::GetUniformBlockLocation(const std::string& name) { for (Uniform& u : Uniforms) { if (u.Name == name) { return u.Location; } } int loc = glGetUniformBlockIndex(ID, name.c_str()); if (loc != -1) { Uniforms.push_back({ name, loc }); } return loc; } void CShaderGL::setUniform(const std::string& name, float x) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform1f(loc, x); } } void CShaderGL::setUniform(const std::string& name, int x) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform1i(loc, x); } } void CShaderGL::setUniformLegacyTextureID(const std::string& name, int x) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform1i(loc, x); } } void CShaderGL::setUniform(const std::string& name, unsigned int x) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform1ui(loc, x); } } void CShaderGL::setUniform(const std::string& name, bool x) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform1i(loc, static_cast(x)); } } void CShaderGL::setUniform(const std::string& name, const glm::vec2& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform2f(loc, v.x, v.y); } } void CShaderGL::setUniform(const std::string& name, const glm::vec3& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform3f(loc, v.x, v.y, v.z); } } void CShaderGL::setUniform(const std::string& name, const glm::vec4& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform4f(loc, v.x, v.y, v.z, v.w); } } void CShaderGL::setUniform(const std::string& name, const glm::ivec2& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform2i(loc, v.x, v.y); } } void CShaderGL::setUniform(const std::string& name, const glm::ivec3& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform3i(loc, v.x, v.y, v.z); } } void CShaderGL::setUniform(const std::string& name, const glm::ivec4& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform4i(loc, v.x, v.y, v.z, v.w); } } void CShaderGL::setUniform(const std::string& name, const glm::uvec2& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform2ui(loc, v.x, v.y); } } void CShaderGL::setUniform(const std::string& name, const glm::uvec3& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform3ui(loc, v.x, v.y, v.z); } } void CShaderGL::setUniform(const std::string& name, const glm::uvec4& v) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform4ui(loc, v.x, v.y, v.z, v.w); } } void CShaderGL::setUniform(const std::string& name, const glm::mat3& matrix) { int loc = GetUniformLocation(name); if (loc != -1) { glUniformMatrix3fv(loc, 1, GL_FALSE, glm::value_ptr(matrix)); } } void CShaderGL::setUniform(const std::string& name, const glm::mat4& matrix) { int loc = GetUniformLocation(name); if (loc != -1) { glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(matrix)); } } void CShaderGL::setTextureHandleUniform(const std::string& name, std::uint64_t handle) { int loc = GetUniformLocation(name); if (loc != -1) { glUniform2ui(loc, reinterpret_cast(&handle)[0], reinterpret_cast(&handle)[1]); } } void CShaderGL::setUniformBuffer(const std::string& name, GLuint id, GLuint binding) { int loc = GetUniformBlockLocation(name); //Game.Console.Print("loc of \"" + name + "\" is " + std::to_string(loc) + " and id is " + std::to_string(id)); if (loc != -1) { glUniformBlockBinding(ID, loc, binding); glBindBufferBase(GL_UNIFORM_BUFFER, binding, id); } } int CShaderGL::getUboLayoutSize(const std::string& name) { GLint blockSize; glGetActiveUniformBlockiv(ID, GetUniformBlockLocation(name), GL_UNIFORM_BLOCK_DATA_SIZE, &blockSize); return blockSize; } std::vector CShaderGL::getUboLayoutIndices(const std::string& name, std::vector names) { char** result = new char* [names.size()]; for (int index = 0; index < names.size(); index++) { result[index] = const_cast(names[index].c_str()); } std::vector ret = getUboLayoutIndices(name, const_cast(result), names.size()); delete[] result; return ret; } std::vector CShaderGL::getUboLayoutOffsets(const std::string& name, std::vector indices) { return getUboLayoutOffsets(name, indices.data(), indices.size()); } std::vector CShaderGL::getUboLayoutIndices(const std::string& name, const char** names, size_t count) { GLuint* indices = new GLuint[count]; glGetUniformIndices(ID, count, names, indices); std::vector ret; ret.assign(indices, indices + count); delete[] indices; return ret; } std::vector CShaderGL::getUboLayoutOffsets(const std::string& name, const GLuint* indices, size_t count) { GLint* offset = new GLint[count]; glGetActiveUniformsiv(ID, count, indices, GL_UNIFORM_OFFSET, offset); std::vector ret; ret.assign(offset, offset + count); delete[] offset; return ret; }