mirror of
https://github.com/ciphervance/supercell-wx.git
synced 2025-10-30 22:30:06 +00:00
183 lines
4.3 KiB
C++
183 lines
4.3 KiB
C++
#include <scwx/qt/gl/shader_program.hpp>
|
|
#include <scwx/util/logger.hpp>
|
|
|
|
#include <QFile>
|
|
|
|
namespace scwx
|
|
{
|
|
namespace qt
|
|
{
|
|
namespace gl
|
|
{
|
|
|
|
static const std::string logPrefix_ = "scwx::qt::gl::shader_program";
|
|
static const auto logger_ = scwx::util::Logger::Create(logPrefix_);
|
|
|
|
static constexpr GLsizei kInfoLogBufSize = 512;
|
|
|
|
static const std::unordered_map<GLenum, std::string> kShaderNames_ {
|
|
{GL_VERTEX_SHADER, "vertex"},
|
|
{GL_GEOMETRY_SHADER, "geometry"},
|
|
{GL_FRAGMENT_SHADER, "fragment"}};
|
|
|
|
class ShaderProgram::Impl
|
|
{
|
|
public:
|
|
explicit Impl(OpenGLFunctions& gl) : gl_(gl), id_ {GL_INVALID_INDEX}
|
|
{
|
|
// Create shader program
|
|
id_ = gl_.glCreateProgram();
|
|
}
|
|
|
|
~Impl()
|
|
{
|
|
// Delete shader program
|
|
gl_.glDeleteProgram(id_);
|
|
}
|
|
|
|
static std::string ShaderName(GLenum type);
|
|
|
|
OpenGLFunctions& gl_;
|
|
|
|
GLuint id_;
|
|
};
|
|
|
|
ShaderProgram::ShaderProgram(OpenGLFunctions& gl) :
|
|
p(std::make_unique<Impl>(gl))
|
|
{
|
|
}
|
|
ShaderProgram::~ShaderProgram() = default;
|
|
|
|
ShaderProgram::ShaderProgram(ShaderProgram&&) noexcept = default;
|
|
ShaderProgram& ShaderProgram::operator=(ShaderProgram&&) noexcept = default;
|
|
|
|
GLuint ShaderProgram::id() const
|
|
{
|
|
return p->id_;
|
|
}
|
|
|
|
GLint ShaderProgram::GetUniformLocation(const std::string& name)
|
|
{
|
|
GLint location = p->gl_.glGetUniformLocation(p->id_, name.c_str());
|
|
if (location == -1)
|
|
{
|
|
logger_->warn("Could not find {}", name);
|
|
}
|
|
return location;
|
|
}
|
|
|
|
std::string ShaderProgram::Impl::ShaderName(GLenum type)
|
|
{
|
|
auto it = kShaderNames_.find(type);
|
|
if (it != kShaderNames_.cend())
|
|
{
|
|
return it->second;
|
|
}
|
|
return fmt::format("{:#06x}", type);
|
|
}
|
|
|
|
bool ShaderProgram::Load(const std::string& vertexPath,
|
|
const std::string& fragmentPath)
|
|
{
|
|
return Load({{GL_VERTEX_SHADER, vertexPath}, //
|
|
{GL_FRAGMENT_SHADER, fragmentPath}});
|
|
}
|
|
|
|
bool ShaderProgram::Load(
|
|
std::initializer_list<std::pair<GLenum, std::string>> shaders)
|
|
{
|
|
logger_->debug("Load()");
|
|
|
|
OpenGLFunctions& gl = p->gl_;
|
|
|
|
GLint glSuccess;
|
|
bool success = true;
|
|
char infoLog[kInfoLogBufSize];
|
|
GLsizei logLength;
|
|
|
|
std::vector<GLuint> shaderIds {};
|
|
|
|
for (auto& shader : shaders)
|
|
{
|
|
logger_->debug("Loading {} shader: {}",
|
|
Impl::ShaderName(shader.first),
|
|
shader.second);
|
|
|
|
QFile file(shader.second.c_str());
|
|
file.open(QIODevice::ReadOnly | QIODevice::Text);
|
|
|
|
if (!file.isOpen())
|
|
{
|
|
logger_->error("Could not load shader");
|
|
success = false;
|
|
break;
|
|
}
|
|
|
|
QTextStream shaderStream(&file);
|
|
shaderStream.setEncoding(QStringConverter::Utf8);
|
|
|
|
std::string shaderSource = shaderStream.readAll().toStdString();
|
|
const char* shaderSourceC = shaderSource.c_str();
|
|
|
|
// Create a shader
|
|
GLuint shaderId = gl.glCreateShader(shader.first);
|
|
shaderIds.push_back(shaderId);
|
|
|
|
// Attach the shader source code and compile the shader
|
|
gl.glShaderSource(shaderId, 1, &shaderSourceC, NULL);
|
|
gl.glCompileShader(shaderId);
|
|
|
|
// Check for errors
|
|
gl.glGetShaderiv(shaderId, GL_COMPILE_STATUS, &glSuccess);
|
|
gl.glGetShaderInfoLog(shaderId, kInfoLogBufSize, &logLength, infoLog);
|
|
if (!glSuccess)
|
|
{
|
|
logger_->error("Shader compilation failed: {}", infoLog);
|
|
success = false;
|
|
break;
|
|
}
|
|
else if (logLength > 0)
|
|
{
|
|
logger_->error("Shader compiled with warnings: {}", infoLog);
|
|
}
|
|
}
|
|
|
|
if (success)
|
|
{
|
|
for (auto& shaderId : shaderIds)
|
|
{
|
|
gl.glAttachShader(p->id_, shaderId);
|
|
}
|
|
gl.glLinkProgram(p->id_);
|
|
|
|
// Check for errors
|
|
gl.glGetProgramiv(p->id_, GL_LINK_STATUS, &glSuccess);
|
|
gl.glGetProgramInfoLog(p->id_, kInfoLogBufSize, &logLength, infoLog);
|
|
if (!glSuccess)
|
|
{
|
|
logger_->error("Shader program link failed: {}", infoLog);
|
|
success = false;
|
|
}
|
|
else if (logLength > 0)
|
|
{
|
|
logger_->error("Shader program linked with warnings: {}", infoLog);
|
|
}
|
|
}
|
|
|
|
// Delete shaders
|
|
for (auto& shaderId : shaderIds)
|
|
{
|
|
gl.glDeleteShader(shaderId);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
void ShaderProgram::Use() const
|
|
{
|
|
p->gl_.glUseProgram(p->id_);
|
|
}
|
|
|
|
} // namespace gl
|
|
} // namespace qt
|
|
} // namespace scwx
|