mirror of
				https://github.com/ciphervance/supercell-wx.git
				synced 2025-11-04 15:10:08 +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
 |