From c3eea71370eb94cff1fd96185458643fab6eb2c5 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Thu, 3 Nov 2022 19:47:46 +0000 Subject: Restructure how shaders are worked with Needs a tidy-up --- gfx/gl/glSource.cpp | 40 -------------- gfx/gl/glSource.h | 16 ------ gfx/gl/program.cpp | 35 ++++++++++++ gfx/gl/program.h | 46 ++++++++++++++++ gfx/gl/programHandle.cpp | 14 ----- gfx/gl/programHandle.h | 13 ----- gfx/gl/sceneShader.cpp | 135 ++++++++++++++++++++--------------------------- gfx/gl/sceneShader.h | 81 ++++++++++++++++++---------- gfx/gl/shader.cpp | 41 ++++++++++++++ gfx/gl/shader.h | 21 ++++++++ gfx/gl/uiShader.cpp | 31 ++++------- gfx/gl/uiShader.h | 37 ++++++++++--- 12 files changed, 297 insertions(+), 213 deletions(-) delete mode 100644 gfx/gl/glSource.cpp delete mode 100644 gfx/gl/glSource.h create mode 100644 gfx/gl/program.cpp create mode 100644 gfx/gl/program.h delete mode 100644 gfx/gl/programHandle.cpp delete mode 100644 gfx/gl/programHandle.h create mode 100644 gfx/gl/shader.cpp create mode 100644 gfx/gl/shader.h (limited to 'gfx') diff --git a/gfx/gl/glSource.cpp b/gfx/gl/glSource.cpp deleted file mode 100644 index 962d096..0000000 --- a/gfx/gl/glSource.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "glSource.h" -#include -#include -#include - -GLsource::ShaderRef -GLsource::compile() const -{ - ShaderRef id {type}; - glShaderSource(id, 1, &text, &len); - glCompileShader(id); - - CheckShaderError(id, GL_COMPILE_STATUS, false, "Error compiling shader!"); - return id; -} - -void -GLsource::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage) -{ - GLint success = 0; - - if (isProgram) { - glGetProgramiv(shader, flag, &success); - } - else { - glGetShaderiv(shader, flag, &success); - } - - if (success == GL_FALSE) { - std::array error {}; - if (isProgram) { - glGetProgramInfoLog(shader, error.size(), nullptr, error.data()); - } - else { - glGetShaderInfoLog(shader, error.size(), nullptr, error.data()); - } - - throw std::runtime_error {std::string {errorMessage} + ": '" + std::string {error.data(), error.size()} + "'"}; - } -} diff --git a/gfx/gl/glSource.h b/gfx/gl/glSource.h deleted file mode 100644 index c6b1f41..0000000 --- a/gfx/gl/glSource.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include -#include -#include - -struct GLsource { - using ShaderRef = glRef; - - const GLchar * text; - GLint len; - GLuint type; - - [[nodiscard]] ShaderRef compile() const; - static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage); -}; diff --git a/gfx/gl/program.cpp b/gfx/gl/program.cpp new file mode 100644 index 0000000..c36cc80 --- /dev/null +++ b/gfx/gl/program.cpp @@ -0,0 +1,35 @@ +#include "program.h" +#include "shader.h" +#include +#include +#include +#include + +void +Program::linkAndValidate() const +{ + glLinkProgram(m_program); + Shader::CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program"); + + glValidateProgram(m_program); + Shader::CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program"); +} + +void +Program::use() const +{ + glUseProgram(m_program); +} + +Program::UniformLocation::UniformLocation(GLuint program, const char * name) : + location {glGetUniformLocation(program, name)} +{ +} + +Program::RequiredUniformLocation::RequiredUniformLocation(GLuint program, const char * name) : + UniformLocation {program, name} +{ + if (location < 0) { + throw std::logic_error("Required uniform does not exist"); + } +} diff --git a/gfx/gl/program.h b/gfx/gl/program.h new file mode 100644 index 0000000..711a26d --- /dev/null +++ b/gfx/gl/program.h @@ -0,0 +1,46 @@ +#pragma once + +#include "shader.h" +#include +#include +#include + +class Location; + +class Program { +public: + template Program(const S &... srcs) + { + (glAttachShader(m_program, srcs), ...); + linkAndValidate(); + } + virtual ~Program() = default; + + class UniformLocation { + public: + UniformLocation(GLuint prog, const char * name); + operator auto() const + { + return location; + } + + protected: + GLint location; + }; + + class RequiredUniformLocation : public UniformLocation { + public: + RequiredUniformLocation(GLuint prog, const char * name); + }; + + operator GLuint() const + { + return m_program; + } + +protected: + void use() const; + using ProgramRef = glRef; + void linkAndValidate() const; + ProgramRef m_program; +}; diff --git a/gfx/gl/programHandle.cpp b/gfx/gl/programHandle.cpp deleted file mode 100644 index bfe06f2..0000000 --- a/gfx/gl/programHandle.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include "programHandle.h" -#include "glSource.h" - -ProgramHandleBase::ProgramHandleBase(GLuint vs, GLuint fs) : viewProjection_uniform {}, model_uniform {} -{ - glAttachShader(m_program, vs); - glAttachShader(m_program, fs); - - glLinkProgram(m_program); - GLsource::CheckShaderError(m_program, GL_LINK_STATUS, true, "Error linking shader program"); - - glValidateProgram(m_program); - GLsource::CheckShaderError(m_program, GL_VALIDATE_STATUS, true, "Invalid shader program"); -} diff --git a/gfx/gl/programHandle.h b/gfx/gl/programHandle.h deleted file mode 100644 index a2a7a2d..0000000 --- a/gfx/gl/programHandle.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -#include -#include - -class ProgramHandleBase { -public: - ProgramHandleBase(GLuint, GLuint); - using ProgramRef = glRef; - - ProgramRef m_program; - GLint viewProjection_uniform, model_uniform; -}; diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index 48c0f42..bec6553 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -1,77 +1,58 @@ -#include "sceneShader.h" -#include "gfx/gl/glSource.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -SceneShader::ProgramHandle::ProgramHandle(GLuint vs, GLuint fs) : ProgramHandleBase {vs, fs} -{ - glBindAttribLocation(m_program, 0, "position"); - glBindAttribLocation(m_program, 1, "texCoord"); - glBindAttribLocation(m_program, 2, "normal"); - - viewProjection_uniform = glGetUniformLocation(m_program, "viewProjection"); - model_uniform = glGetUniformLocation(m_program, "model"); -} - -SceneShader::SceneShader() : - programs {{{ - basicShader_vs.compile(), - basicShader_fs.compile(), - }, - { - waterShader_vs.compile(), - waterShader_fs.compile(), - }, - { - landmassShader_vs.compile(), - landmassShader_fs.compile(), - }, - { - landmassShader_vs.compile(), - basicShader_fs.compile(), - }}} -{ -} - -void -SceneShader::setView(glm::mat4 proj) const -{ - for (const auto & prog : programs) { - glUseProgram(prog.m_program); - glUniformMatrix4fv(prog.viewProjection_uniform, 1, GL_FALSE, glm::value_ptr(proj)); - } -} - -void -SceneShader::setUniform(const GLchar * uniform, glm::vec3 v) const -{ - for (const auto & prog : programs) { - if (auto loc = glGetUniformLocation(prog.m_program, uniform); loc >= 0) { - glUseProgram(prog.m_program); - glUniform3fv(loc, 1, glm::value_ptr(v)); - } - } -} - -void -SceneShader::setModel(const Location & loc, Program pid) const -{ - auto & prog = programs[static_cast(pid)]; - glUseProgram(prog.m_program); - if (prog.model_uniform >= 0) { - const auto model {glm::translate(loc.pos) * rotate_ypr(loc.rot)}; - glUniformMatrix4fv(prog.model_uniform, 1, GL_FALSE, glm::value_ptr(model)); - } -} +#include "sceneShader.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +SceneShader::SceneShader() : + landmass {landmassShader_vs, landmassShader_fs}, absolute {landmassShader_vs, basicShader_fs} +{ +} + +void +SceneShader::setView(glm::mat4 proj) const +{ + for (const auto & prog : std::array {&basic, &water, &landmass, &absolute}) { + prog->setView(proj); + } +} + +void +SceneShader::SceneProgram::setView(const glm::mat4 & viewProjection) const +{ + glUseProgram(*this); + glUniformMatrix4fv(viewProjectionLoc, 1, GL_FALSE, glm::value_ptr(viewProjection)); +} + +SceneShader::BasicProgram::BasicProgram() : SceneProgram {basicShader_vs, basicShader_fs}, modelLoc {*this, "model"} { } + +void +SceneShader::BasicProgram::setModel(Location const & location) const +{ + const auto model {glm::translate(location.pos) * rotate_ypr(location.rot)}; + glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); +} + +void +SceneShader::BasicProgram::use(Location const & location) const +{ + Program::use(); + setModel(location); +} + +SceneShader::WaterProgram::WaterProgram() : SceneProgram {waterShader_vs, waterShader_fs}, waveLoc {*this, "waves"} { } + +void +SceneShader::WaterProgram::use(float waveCycle) const +{ + Program::use(); + glm::vec3 waves {waveCycle, 0.F, 0.F}; + glUniform3fv(waveLoc, 1, glm::value_ptr(waves)); +} diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h index 61c159b..a85e55b 100644 --- a/gfx/gl/sceneShader.h +++ b/gfx/gl/sceneShader.h @@ -1,27 +1,54 @@ -#pragma once - -#include "programHandle.h" -#include -#include -#include - -class Location; - -class SceneShader { -public: - enum class Program { Basic = 0, Water = 1, LandMass = 2, StaticPos = 3 }; - - SceneShader(); - - void setView(glm::mat4 view) const; - void setModel(const Location &, Program = Program::Basic) const; - void setUniform(const GLchar *, glm::vec3 dir) const; - -private: - class ProgramHandle : public ProgramHandleBase { - public: - ProgramHandle(GLuint, GLuint); - }; - - std::array programs; -}; +#pragma once + +#include "program.h" + +class Location; + +struct SceneShader { + class SceneProgram : public Program { + public: + template + inline SceneProgram(const S &... srcs) : Program {srcs...}, viewProjectionLoc {*this, "viewProjection"} + { + } + + void setView(const glm::mat4 &) const; + + private: + RequiredUniformLocation viewProjectionLoc; + }; + + class BasicProgram : public SceneProgram { + public: + BasicProgram(); + void setModel(const Location &) const; + void use(const Location &) const; + + private: + RequiredUniformLocation modelLoc; + }; + + class AbsolutePosProgram : public SceneProgram { + public: + using Program::use; + using SceneProgram::SceneProgram; + }; + + class WaterProgram : public SceneProgram { + public: + public: + WaterProgram(); + void use(float waveCycle) const; + + private: + RequiredUniformLocation waveLoc; + }; + + SceneShader(); + + BasicProgram basic; + WaterProgram water; + AbsolutePosProgram landmass, absolute; + + void setView(glm::mat4 proj) const; +}; diff --git a/gfx/gl/shader.cpp b/gfx/gl/shader.cpp new file mode 100644 index 0000000..8b0f614 --- /dev/null +++ b/gfx/gl/shader.cpp @@ -0,0 +1,41 @@ +#include "shader.h" +#include +#include +#include + +Shader::operator GLuint() const +{ + if (!shader) { + shader.emplace(type); + glShaderSource(*shader, 1, &text, &len); + glCompileShader(*shader); + + CheckShaderError(*shader, GL_COMPILE_STATUS, false, "Error compiling shader!"); + } + return *shader; +} + +void +Shader::CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage) +{ + GLint success = 0; + + if (isProgram) { + glGetProgramiv(shader, flag, &success); + } + else { + glGetShaderiv(shader, flag, &success); + } + + if (success == GL_FALSE) { + std::array error {}; + if (isProgram) { + glGetProgramInfoLog(shader, error.size(), nullptr, error.data()); + } + else { + glGetShaderInfoLog(shader, error.size(), nullptr, error.data()); + } + + throw std::runtime_error {std::string {errorMessage} + ": '" + std::string {error.data(), error.size()} + "'"}; + } +} diff --git a/gfx/gl/shader.h b/gfx/gl/shader.h new file mode 100644 index 0000000..1a8ddef --- /dev/null +++ b/gfx/gl/shader.h @@ -0,0 +1,21 @@ +#pragma once + +#include +#include +#include +#include + +class Shader { +public: + constexpr Shader(const GLchar * text, GLint len, GLuint type) : text {text}, len {len}, type {type} { } + + operator GLuint() const; + static void CheckShaderError(GLuint shader, GLuint flag, bool isProgram, std::string_view errorMessage); + +private: + using ShaderRef = glRef; + const GLchar * text; + GLint len; + GLuint type; + mutable std::optional shader {}; +}; diff --git a/gfx/gl/uiShader.cpp b/gfx/gl/uiShader.cpp index fbcdd15..78e0064 100644 --- a/gfx/gl/uiShader.cpp +++ b/gfx/gl/uiShader.cpp @@ -1,6 +1,6 @@ #include "uiShader.h" -#include -#include +#include +#include #include #include #include @@ -8,30 +8,21 @@ #include #include -UIShader::UIShader(size_t width, size_t height) : - progDefault {uiShader_vs.compile(), uiShader_fs.compile()}, progText {uiShader_vs.compile(), - uiShaderFont_fs.compile()} +UIShader::IconProgram::IconProgram(const glm::mat4 & vp) : UIProgram {vp, uiShader_vs, uiShader_fs} { } +UIShader::TextProgram::TextProgram(const glm::mat4 & vp) : + UIProgram {vp, uiShader_vs, uiShaderFont_fs}, colorLoc {*this, "colour"} { - for (const auto prog : {&progDefault, &progText}) { - if (auto loc = glGetUniformLocation(prog->m_program, "uiProjection"); loc >= 0) { - glUseProgram(prog->m_program); - const auto uiProjection = glm::ortho(0, static_cast(width), 0, static_cast(height)); - glUniformMatrix4fv(loc, 1, GL_FALSE, glm::value_ptr(uiProjection)); - } - } } -void -UIShader::useDefault() const +UIShader::UIShader(size_t width, size_t height) : + UIShader {glm::ortho(0, static_cast(width), 0, static_cast(height))} { - glUseProgram(progDefault.m_program); } +UIShader::UIShader(const glm::mat4 & viewProjection) : icon {viewProjection}, text {viewProjection} { } void -UIShader::useText(glm::vec3 colour) const +UIShader::TextProgram::use(const glm::vec3 & colour) const { - glUseProgram(progText.m_program); - if (auto loc = glGetUniformLocation(progText.m_program, "colour"); loc >= 0) { - glUniform3fv(loc, 1, glm::value_ptr(colour)); - } + Program::use(); + glUniform3fv(colorLoc, 1, glm::value_ptr(colour)); } diff --git a/gfx/gl/uiShader.h b/gfx/gl/uiShader.h index ea5bf25..ee44af7 100644 --- a/gfx/gl/uiShader.h +++ b/gfx/gl/uiShader.h @@ -1,19 +1,44 @@ #pragma once -#include "programHandle.h" +#include "program.h" #include #include #include +#include class UIShader { public: UIShader(std::size_t width, std::size_t height); - void useDefault() const; - void useText(glm::vec3) const; private: - class UIProgramHandle : public ProgramHandleBase { - using ProgramHandleBase::ProgramHandleBase; + explicit UIShader(const glm::mat4 & viewProjection); + + class UIProgram : public Program { + public: + template UIProgram(const glm::mat4 & vp, S &&... srcs) : Program {std::forward(srcs)...} + { + RequiredUniformLocation uiProjectionLoc {*this, "uiProjection"}; + glUseProgram(*this); + glUniformMatrix4fv(uiProjectionLoc, 1, GL_FALSE, glm::value_ptr(vp)); + } + }; + + class IconProgram : public UIProgram { + public: + explicit IconProgram(const glm::mat4 & vp); + using Program::use; + }; + + class TextProgram : public UIProgram { + public: + explicit TextProgram(const glm::mat4 & vp); + void use(const glm::vec3 & colour) const; + + private: + RequiredUniformLocation colorLoc; }; - UIProgramHandle progDefault, progText; + +public: + IconProgram icon; + TextProgram text; }; -- cgit v1.2.3