Skip to main content

OpenGLShader.ixx File

OpenGL implementation of shader program management. More...

Included Headers

#include <glad/gl.h> #include <format> #include <stdexcept> #include <string> #include <helios/helios_config.h> #include <helios.rendering.shader.UniformValueMap> #include <helios.ext.opengl.rendering.shader.OpenGLUniformLocationMap> #include <helios.rendering.shader.UniformSemantics> #include <helios.util.io.StringFileReader> #include <helios.rendering.shader.Shader>

Namespaces Index

namespacehelios
namespaceext

Platform-specific extensions and backend implementations. More...

namespaceopengl

OpenGL-specific implementations. More...

namespacerendering

OpenGL rendering implementations. More...

namespaceshader

OpenGL shader implementations. More...

Classes Index

classOpenGLShader

An OpenGL-specific implementation of a Shader program, consisting of a vertex and a fragment shader. More...

Description

OpenGL implementation of shader program management.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file OpenGLShader.ixx
3 * @brief OpenGL implementation of shader program management.
4 */
5module;
6
7#include <glad/gl.h>
8#include <format>
9#include <stdexcept>
10#include <string>
11#include <helios/helios_config.h>
12
13export module helios.ext.opengl.rendering.shader.OpenGLShader;
14
15import helios.rendering.shader.Shader;
16
17import helios.util.io.StringFileReader;
18import helios.ext.opengl.rendering.shader.OpenGLUniformLocationMap;
19import helios.rendering.shader.UniformSemantics;
20import helios.rendering.shader.UniformValueMap;
21
22
24
25 /**
26 * @brief An OpenGL-specific implementation of a Shader program,
27 * consisting of a vertex and a fragment shader.
28 *
29 * This class manages the lifecycle of the Shaders. Source files are
30 * getting loaded via a StringFileReader and immediately compiled after loading.
31 * Any occupied memory for source-files and file-paths to the shader is being cleared
32 * once compilation succeeded and are not guaranteed to persist the compilation process.
33 */
35
36 private:
37 /**
38 * @brief Source of the shader. Not guaranteed to be persisted
39 * once compilation was successful.
40 */
41 std::string vertexShaderSource_;
42
43
44 /**
45 * @brief Source of the shader. Not guaranteed to be persisted
46 * once compilation was successful.
47 */
48 std::string fragmentShaderSource_;
49
50 /**
51 * @brief Loads the specified vertex and fragment shader.
52 *
53 * @return true if loading succeeded, otherwise false.
54 *
55 * @throws if loading the specified files failed.
56 */
57 void load(
58 const std::string& vertexShaderPath,
59 const std::string& fragmentShaderPath,
60 const helios::util::io::StringFileReader& stringFileReader
61 ) {
62 logger_.info(std::format("Loading shader from {0}, {1}", vertexShaderPath, fragmentShaderPath));
63 if (!stringFileReader.readInto(fragmentShaderPath, fragmentShaderSource_) ||
64 !stringFileReader.readInto(vertexShaderPath, vertexShaderSource_)) {
65 logger_.error("Could not load shader");
66 throw std::runtime_error("Could not load shader");
67 }
68 }
69
70
71 /**
72 * @brief Compiles the vertex and fragment shader represented by this instance.
73 *
74 * @return true if compilation succeeded, otherwise false.
75 *
76 * @throws if compilation failed.
77 */
78 void compile() {
79 if (progId_ != 0) {
80 logger_.warn("Shader already compiled");
81 return;
82 }
83
84 const GLchar* vertexSrc = vertexShaderSource_.c_str();
85 const GLchar* fragmentSrc = fragmentShaderSource_.c_str();
86
87 const unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
88 glShaderSource(vertexShader, 1, &vertexSrc, nullptr);
89 glCompileShader(vertexShader);
90
91 const unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
92 glShaderSource(fragmentShader, 1, &fragmentSrc, nullptr);
93 glCompileShader(fragmentShader);
94
95
96 int success;
97 char infoLog[512];
98 glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
99
100 if (!success) {
101 glGetShaderInfoLog(vertexShader, 512, nullptr, infoLog);
102
103 logger_.error("VERTEX::COMPILATION_FAILED " + static_cast<std::string>(infoLog));
104 throw std::runtime_error("Vertex Shader Compilation failed.");
105 }
106
107 glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
108 if (!success) {
109 glGetShaderInfoLog(fragmentShader, 512, nullptr, infoLog);
110 logger_.error("SHADER::FRAGMENT::COMPILATION_FAILED " + static_cast<std::string>(infoLog));
111 throw std::runtime_error("Fragment Shader Compilation failed.");
112 }
113
114 progId_ = glCreateProgram();
115
116 glAttachShader(progId_, vertexShader);
117 glAttachShader(progId_, fragmentShader);
118 glLinkProgram(progId_);
119
120 glGetProgramiv(progId_, GL_LINK_STATUS, &success);
121 if (!success) {
122 glGetProgramInfoLog(progId_, 512, nullptr, infoLog);
123 logger_.error("PROGRAM_LINKING_FAILED " + static_cast<std::string>(infoLog));
124 throw std::runtime_error("Program linking failed.");
125 }
126
127 glDeleteShader(vertexShader);
128 glDeleteShader(fragmentShader);
129
130 vertexShaderSource_.clear();
131 vertexShaderSource_.shrink_to_fit();
132 fragmentShaderSource_.clear();
133 fragmentShaderSource_.shrink_to_fit();
134
135 logger_.info("Shader loaded and linked");
136 }
137
138
139 protected:
140 /**
141 * @brief The program id as assigned by the underlying rendering backend.
142 */
143 unsigned int progId_ = 0;
144
145 /**
146 * @brief A unique pointer to the OpenGLUniformLocationMap this shader uses.
147 */
148 std::unique_ptr<const OpenGLUniformLocationMap> uniformLocationMap_ = nullptr;
149
150 public:
151 /**
152 * @brief Rule of three.
153 * @see https://wikis.khronos.org/opengl/Common_Mistakes#RAII_and_hidden_destructor_calls
154 * @see https://en.cppreference.com/w/cpp/language/rule_of_three.html
155 *
156 * Prevent copying.
157 */
158 OpenGLShader(const OpenGLShader&)=delete;
160
161
162 /**
163 * @brief Creates and initializes this OpenGLShader.
164 * An instance of this class is guaranteed to have a progId_ != 0,
165 * hence shader-files where successfully loaded and compiled, ready to be used.
166 *
167 * @param vertexShaderPath The path to the vertex shader.
168 * @param fragmentShaderPath The path to the fragment shader.
169 * @param stringFileReader The StringFileReader used for loading the shader source files.
170 *
171 * @throws if creating this shader failed.
172 */
174 const std::string& vertexShaderPath,
175 const std::string& fragmentShaderPath,
176 const helios::util::io::StringFileReader& stringFileReader
177 ) {
178 try {
179 load(vertexShaderPath, fragmentShaderPath, stringFileReader);
180 compile();
181 } catch (std::runtime_error& e) {
182 logger_.error("Could not initialize shader");
183 throw std::runtime_error("Could not initialize shader");
184 }
185 }
186
187
188 /**
189 * @brief Activates this OpenGLShader for subsequent draw calls.
190 * This implementation calls `glUseProgram` with the `progId_` received after
191 * compilation.
192 *
193 * @see https://registry.khronos.org/OpenGL-Refpages/gl4/html/glUseProgram.xhtml
194 */
195 void use() const noexcept override {
196 if (!progId_) {
197 logger_.error("Cannot use shader, progId_ is invalid");
198 }
199 glUseProgram(progId_);
200 }
201
202 /**
203 * @brief Deletes the program object upon destruction of this instance.
204 *
205 * @see https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteProgram.xhtml
206 */
207 ~OpenGLShader() override {
208 if (progId_ != 0) {
209 glDeleteProgram(progId_);
210 }
211 }
212
213 /**
214 * @brief Sets the OpenGLUniformLocationMap for this OpenGLShader.
215 * Ownership is transferred to this instance.
216 *
217 * @param uniformLocationMap The OpenGLUniformMap providing the mappings for the uniforms
218 * of the underlying GLSL shader.
219 */
221 std::unique_ptr<const OpenGLUniformLocationMap> uniformLocationMap) noexcept {
222 uniformLocationMap_ = std::move(uniformLocationMap);
223 }
224
225 /**
226 * @brief Returns the uniform location for the uniform represented by the specified
227 * UniformSemantics.
228 *
229 * @param uniformSemantics The `UniformSemantics` identifier.
230 *
231 * @return The integer representing the uniform variable location in the shader, or
232 * -1 if no location map was registered with this shader or if the uniform with the
233 * specified semantics was not found.
234 */
235 [[nodiscard]] int uniformLocation(
236 helios::rendering::shader::UniformSemantics uniformSemantics) const noexcept {
238 return uniformLocationMap_->get(uniformSemantics);
239 }
240
241 return -1;
242 }
243
244 /**
245 * @copydoc helios::rendering::shader::Shader::applyUniformValues()
246 */
248 const helios::rendering::shader::UniformValueMap& uniformValueMap) const noexcept override {
249
250 if (const auto viewMatrixUniform = uniformLocation(helios::rendering::shader::UniformSemantics::ViewMatrix); viewMatrixUniform != -1) {
251 if (const auto* mat4f_ptr = uniformValueMap.mat4f_ptr(helios::rendering::shader::UniformSemantics::ViewMatrix)) {
252 glUniformMatrix4fv(viewMatrixUniform, 1, false, mat4f_ptr);
253 }
254 }
255
256 if (const auto projectionMatrixUniform = uniformLocation(helios::rendering::shader::UniformSemantics::ProjectionMatrix); projectionMatrixUniform != -1) {
257 if (const auto* mat4f_ptr = uniformValueMap.mat4f_ptr(helios::rendering::shader::UniformSemantics::ProjectionMatrix)) {
258 glUniformMatrix4fv(projectionMatrixUniform, 1, false, mat4f_ptr);
259 }
260 }
261
262 if (const auto modelMatrixUniform = uniformLocation(helios::rendering::shader::UniformSemantics::ModelMatrix); modelMatrixUniform != -1) {
263 if (const auto* mat4f_ptr = uniformValueMap.mat4f_ptr(helios::rendering::shader::UniformSemantics::ModelMatrix)) {
264 glUniformMatrix4fv(modelMatrixUniform, 1, false, mat4f_ptr);
265 }
266 }
267 if (const auto materialBaseColorUniform = uniformLocation(helios::rendering::shader::UniformSemantics::MaterialBaseColor); materialBaseColorUniform != -1) {
268 if (const auto* vec4f_ptr = uniformValueMap.vec4f_ptr(helios::rendering::shader::UniformSemantics::MaterialBaseColor)) {
269 glUniform4fv(materialBaseColorUniform, 1, vec4f_ptr);
270 }
271 }
272
273 // texture
274 if (const auto textColorUniform = uniformLocation(helios::rendering::shader::UniformSemantics::TextColor); textColorUniform != -1) {
275 if (const auto* vec4f_ptr = uniformValueMap.vec4f_ptr(helios::rendering::shader::UniformSemantics::TextColor)) {
276 glUniform4fv(textColorUniform, 1, vec4f_ptr);
277 }
278 }
279 if (const auto textTextureUniform = uniformLocation(helios::rendering::shader::UniformSemantics::TextTexture); textTextureUniform != -1) {
280 if (const auto* int_ptr = uniformValueMap.int_ptr(helios::rendering::shader::UniformSemantics::TextTexture)) {
281 glUniform1i(textTextureUniform, *int_ptr);
282 }
283 }
284 }
285
286 };
287}

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.