25 #include <string_view>
32 gl_program_id = glCreateProgram();
37 throw std::runtime_error(
"Unable to create OpenGL shader program");
47 glDeleteProgram(gl_program_id);
52 if (attached_objects.find(&
object) != attached_objects.end())
54 throw std::runtime_error(
"OpenGL shader object already attached to the shader program");
59 if (glIsProgram(gl_program_id) != GL_TRUE)
61 throw std::runtime_error(
"Invalid OpenGL shader program");
63 if (glIsShader(
object.gl_shader_id) != GL_TRUE)
65 throw std::runtime_error(
"Invalid OpenGL shader object");
69 glAttachShader(gl_program_id,
object.gl_shader_id);
72 attached_objects.insert(&
object);
78 if (attached_objects.find(&
object) == attached_objects.end())
80 throw std::runtime_error(
"Shader object is not attached to the shader program.");
85 if (glIsProgram(gl_program_id) != GL_TRUE)
87 throw std::runtime_error(
"Invalid OpenGL shader program");
89 if (glIsShader(
object.gl_shader_id) != GL_TRUE)
91 throw std::runtime_error(
"Invalid OpenGL shader object");
95 glDetachShader(gl_program_id,
object.gl_shader_id);
98 attached_objects.erase(&
object);
104 while (!attached_objects.empty())
106 detach(**attached_objects.begin());
114 variable_map.clear();
117 if (glIsProgram(gl_program_id) != GL_TRUE)
119 throw std::runtime_error(
"Invalid OpenGL shader program");
123 glLinkProgram(gl_program_id);
126 GLint gl_link_status;
127 glGetProgramiv(gl_program_id, GL_LINK_STATUS, &gl_link_status);
128 m_linked = (gl_link_status == GL_TRUE);
139 GLint gl_info_log_length;
140 glGetProgramiv(gl_program_id, GL_INFO_LOG_LENGTH, &gl_info_log_length);
142 if (gl_info_log_length > 0)
145 info_log.resize(gl_info_log_length);
148 glGetProgramInfoLog(gl_program_id, gl_info_log_length, &gl_info_log_length, info_log.data());
158 void shader_program::load_variables()
160 variable_map.clear();
163 GLint max_uniform_name_length = 0;
164 glGetProgramiv(gl_program_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_uniform_name_length);
167 std::string uniform_name(
static_cast<std::size_t
>(max_uniform_name_length),
'\0');
170 GLint active_uniform_count = 0;
171 glGetProgramiv(gl_program_id, GL_ACTIVE_UNIFORMS, &active_uniform_count);
174 GLint texture_index = 0;
177 for (GLint uniform_index = 0; uniform_index < active_uniform_count; ++uniform_index)
180 GLsizei uniform_name_length;
183 glGetActiveUniform(gl_program_id,
static_cast<GLuint
>(uniform_index),
static_cast<GLsizei
>(max_uniform_name_length), &uniform_name_length, &uniform_size, &uniform_type, uniform_name.data());
186 const GLint uniform_location = glGetUniformLocation(gl_program_id, uniform_name.c_str());
187 if (uniform_location == -1)
189 throw std::runtime_error(
"Unable to get shader uniform location");
193 std::size_t uniform_base_name_length =
static_cast<std::size_t
>(uniform_name_length);
194 if (std::size_t i = std::string_view(uniform_name.c_str(), uniform_name_length).find_first_of(
"["); i != std::string::npos)
196 uniform_base_name_length = i;
200 const hash::fnv1a32_t variable_key = hash::fnv1a32<char>({uniform_name.c_str(), uniform_base_name_length});
203 const std::size_t variable_size =
static_cast<std::size_t
>(uniform_size);
206 std::unique_ptr<const gl::shader_variable>
variable;
207 switch (uniform_type)
210 variable = std::make_unique<const gl_shader_bool>(variable_size, uniform_location);
213 variable = std::make_unique<const gl_shader_bvec2>(variable_size, uniform_location);
216 variable = std::make_unique<const gl_shader_bvec3>(variable_size, uniform_location);
219 variable = std::make_unique<const gl_shader_bvec4>(variable_size, uniform_location);
223 variable = std::make_unique<const gl_shader_int>(variable_size, uniform_location);
226 variable = std::make_unique<const gl_shader_ivec2>(variable_size, uniform_location);
229 variable = std::make_unique<const gl_shader_ivec3>(variable_size, uniform_location);
232 variable = std::make_unique<const gl_shader_ivec4>(variable_size, uniform_location);
235 case GL_UNSIGNED_INT:
236 variable = std::make_unique<const gl_shader_uint>(variable_size, uniform_location);
238 case GL_UNSIGNED_INT_VEC2:
239 variable = std::make_unique<const gl_shader_uvec2>(variable_size, uniform_location);
241 case GL_UNSIGNED_INT_VEC3:
242 variable = std::make_unique<const gl_shader_uvec3>(variable_size, uniform_location);
244 case GL_UNSIGNED_INT_VEC4:
245 variable = std::make_unique<const gl_shader_uvec4>(variable_size, uniform_location);
249 variable = std::make_unique<const gl_shader_float>(variable_size, uniform_location);
252 variable = std::make_unique<const gl_shader_fvec2>(variable_size, uniform_location);
255 variable = std::make_unique<const gl_shader_fvec3>(variable_size, uniform_location);
258 variable = std::make_unique<const gl_shader_fvec4>(variable_size, uniform_location);
262 variable = std::make_unique<const gl_shader_fmat2>(variable_size, uniform_location);
265 variable = std::make_unique<const gl_shader_fmat3>(variable_size, uniform_location);
268 variable = std::make_unique<const gl_shader_fmat4>(variable_size, uniform_location);
272 case GL_SAMPLER_1D_SHADOW:
273 variable = std::make_unique<const gl_shader_texture_1d>(variable_size, uniform_location, texture_index);
274 texture_index += uniform_size;
278 case GL_SAMPLER_2D_SHADOW:
279 variable = std::make_unique<const gl_shader_texture_2d>(variable_size, uniform_location, texture_index);
280 texture_index += uniform_size;
284 variable = std::make_unique<const gl_shader_texture_3d>(variable_size, uniform_location, texture_index);
285 texture_index += uniform_size;
288 case GL_SAMPLER_CUBE:
289 variable = std::make_unique<const gl_shader_texture_cube>(variable_size, uniform_location, texture_index);
290 texture_index += uniform_size;
294 throw std::runtime_error(
"Unsupported to shader uniform type");
299 variable_map.emplace(variable_key, std::move(
variable));
Shader object which can be compiled and linked to a shader program.
shader_program()
Creates an empty shader program.
const shader_variable * variable(hash::fnv1a32_t key) const
Returns a pointer to an active shader variable with the given name, or nullptr if not found.
void attach(const shader_object &object)
Attaches a shader object to the shader program.
bool link()
Links all attached shader objects to create an executable shader program.
~shader_program()
Destroys a shader program.
void detach_all()
Detaches all shader objects from the shader program.
void detach(const shader_object &object)
Detaches a shader object from the shader program.
Graphics library interface.
32-bit FNV-1a hash value.