#define GLFW_INCLUDE_NONE #include "XCEngine/RHI/OpenGL/OpenGLShader.h" #include #include #include #include #include namespace XCEngine { namespace RHI { OpenGLShader::OpenGLShader() : m_program(0) { } OpenGLShader::~OpenGLShader() { Shutdown(); } bool OpenGLShader::CompileFromFile(const char* vertexPath, const char* fragmentPath) { std::string vertexCode, fragmentCode; std::ifstream vShaderFile(vertexPath), fShaderFile(fragmentPath); if (!vShaderFile.is_open() || !fShaderFile.is_open()) { return false; } std::stringstream vShaderStream, fShaderStream; vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); vShaderFile.close(); fShaderFile.close(); vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); return Compile(vertexCode.c_str(), fragmentCode.c_str()); } bool OpenGLShader::CompileFromFile(const char* vertexPath, const char* fragmentPath, const char* geometryPath) { std::string vertexCode, fragmentCode, geometryCode; std::ifstream vShaderFile(vertexPath), fShaderFile(fragmentPath), gShaderFile(geometryPath); if (!vShaderFile.is_open() || !fShaderFile.is_open() || !gShaderFile.is_open()) { return false; } std::stringstream vShaderStream, fShaderStream, gShaderStream; vShaderStream << vShaderFile.rdbuf(); fShaderStream << fShaderFile.rdbuf(); gShaderStream << gShaderFile.rdbuf(); vShaderFile.close(); fShaderFile.close(); gShaderFile.close(); vertexCode = vShaderStream.str(); fragmentCode = fShaderStream.str(); geometryCode = gShaderStream.str(); return Compile(vertexCode.c_str(), fragmentCode.c_str(), geometryCode.c_str()); } bool OpenGLShader::Compile(const char* vertexSource, const char* fragmentSource) { unsigned int vertex, fragment; vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vertexSource, nullptr); glCompileShader(vertex); if (!CheckCompileErrors(vertex, "VERTEX")) { return false; } fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fragmentSource, nullptr); glCompileShader(fragment); if (!CheckCompileErrors(fragment, "FRAGMENT")) { return false; } m_program = glCreateProgram(); glAttachShader(m_program, vertex); glAttachShader(m_program, fragment); glLinkProgram(m_program); if (!CheckLinkErrors(m_program)) { return false; } glDeleteShader(vertex); glDeleteShader(fragment); return true; } bool OpenGLShader::Compile(const char* vertexSource, const char* fragmentSource, const char* geometrySource) { unsigned int vertex, fragment, geometry; vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex, 1, &vertexSource, nullptr); glCompileShader(vertex); if (!CheckCompileErrors(vertex, "VERTEX")) { return false; } fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment, 1, &fragmentSource, nullptr); glCompileShader(fragment); if (!CheckCompileErrors(fragment, "FRAGMENT")) { return false; } geometry = glCreateShader(GL_GEOMETRY_SHADER); glShaderSource(geometry, 1, &geometrySource, nullptr); glCompileShader(geometry); if (!CheckCompileErrors(geometry, "GEOMETRY")) { return false; } m_program = glCreateProgram(); glAttachShader(m_program, vertex); glAttachShader(m_program, fragment); glAttachShader(m_program, geometry); glLinkProgram(m_program); if (!CheckLinkErrors(m_program)) { return false; } glDeleteShader(vertex); glDeleteShader(fragment); glDeleteShader(geometry); return true; } bool OpenGLShader::CompileCompute(const char* computeSource) { unsigned int compute = glCreateShader(GL_COMPUTE_SHADER); glShaderSource(compute, 1, &computeSource, nullptr); glCompileShader(compute); if (!CheckCompileErrors(compute, "COMPUTE")) { return false; } m_program = glCreateProgram(); glAttachShader(m_program, compute); glLinkProgram(m_program); if (!CheckLinkErrors(m_program)) { return false; } glDeleteShader(compute); return true; } bool OpenGLShader::Compile(const char* source, ShaderType type) { unsigned int shader = 0; switch (type) { case ShaderType::Vertex: shader = glCreateShader(GL_VERTEX_SHADER); break; case ShaderType::Fragment: shader = glCreateShader(GL_FRAGMENT_SHADER); break; case ShaderType::Geometry: shader = glCreateShader(GL_GEOMETRY_SHADER); break; case ShaderType::Compute: shader = glCreateShader(GL_COMPUTE_SHADER); break; case ShaderType::TessControl: shader = glCreateShader(GL_TESS_CONTROL_SHADER); break; case ShaderType::TessEvaluation: shader = glCreateShader(GL_TESS_EVALUATION_SHADER); break; default: return false; } glShaderSource(shader, 1, &source, nullptr); glCompileShader(shader); const char* typeName[] = { "VERTEX", "FRAGMENT", "GEOMETRY", "COMPUTE", "TESS_CONTROL", "TESS_EVALUATION" }; if (!CheckCompileErrors(shader, typeName[(int)type])) { return false; } if (m_program == 0) { m_program = glCreateProgram(); } glAttachShader(m_program, shader); glLinkProgram(m_program); if (!CheckLinkErrors(m_program)) { return false; } glDeleteShader(shader); return true; } void OpenGLShader::Shutdown() { if (m_program) { glDeleteProgram(m_program); m_program = 0; } } void OpenGLShader::Use() const { glUseProgram(m_program); } void OpenGLShader::Unbind() { glUseProgram(0); } void OpenGLShader::SetInt(const char* name, int value) { glUniform1i(glGetUniformLocation(m_program, name), value); } void OpenGLShader::SetIntArray(const char* name, const int* values, unsigned int count) { glUniform1iv(glGetUniformLocation(m_program, name), count, values); } void OpenGLShader::SetFloat(const char* name, float value) { glUniform1f(glGetUniformLocation(m_program, name), value); } void OpenGLShader::SetFloatArray(const char* name, const float* values, unsigned int count) { glUniform1fv(glGetUniformLocation(m_program, name), count, values); } void OpenGLShader::SetVec3(const char* name, float x, float y, float z) { glUniform3f(glGetUniformLocation(m_program, name), x, y, z); } void OpenGLShader::SetVec3(const char* name, const float* values) { glUniform3fv(glGetUniformLocation(m_program, name), 1, values); } void OpenGLShader::SetVec4(const char* name, float x, float y, float z, float w) { glUniform4f(glGetUniformLocation(m_program, name), x, y, z, w); } void OpenGLShader::SetVec4(const char* name, const float* values) { glUniform4fv(glGetUniformLocation(m_program, name), 1, values); } void OpenGLShader::SetMat2(const char* name, const float* value) { glUniformMatrix2fv(glGetUniformLocation(m_program, name), 1, GL_FALSE, value); } void OpenGLShader::SetMat3(const char* name, const float* value) { glUniformMatrix3fv(glGetUniformLocation(m_program, name), 1, GL_FALSE, value); } void OpenGLShader::SetMat4(const char* name, const float* value) { glUniformMatrix4fv(glGetUniformLocation(m_program, name), 1, GL_FALSE, value); } void OpenGLShader::SetMat4Array(const char* name, const float* values, unsigned int count) { glUniformMatrix4fv(glGetUniformLocation(m_program, name), count, GL_FALSE, values); } int OpenGLShader::GetUniformLocation(const char* name) const { return glGetUniformLocation(m_program, name); } bool OpenGLShader::CheckCompileErrors(unsigned int shader, const char* type) { int success; char infoLog[1024]; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if (!success) { glGetShaderInfoLog(shader, 1024, nullptr, infoLog); std::cout << "ERROR::SHADER_COMPILATION_ERROR: " << type << "\n" << infoLog << std::endl; return false; } return true; } bool OpenGLShader::CheckLinkErrors(unsigned int program) { int success; char infoLog[1024]; glGetProgramiv(program, GL_LINK_STATUS, &success); if (!success) { glGetProgramInfoLog(program, 1024, nullptr, infoLog); std::cout << "ERROR::PROGRAM_LINKING_ERROR\n" << infoLog << std::endl; return false; } return true; } } // namespace RHI } // namespace XCEngine