GLS  1.0.0
GL Stuff - A library aimed at reducing the boilerplate OpenGL code you always have to write.
program.hpp
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #pragma once
6 
7 #include <gls/headercheck.hpp>
8 #include <gls/errorcheck.hpp>
9 #include <gls/objects/object.hpp>
10 #include <gls/objects/shader.hpp>
11 #include <initializer_list>
12 #include <vector>
13 #include <memory>
14 #include <tuple>
15 #include <unordered_map>
16 #include <cassert>
17 
18 #if !defined( NDEBUG )
19  #if !defined( GLS_ERROR_STREAM )
20  #include <iostream>
21  #define GLS_ERROR_STREAM std::cerr
22  #endif
23 #endif
24 
25 namespace gls {
26 
27 namespace priv {
28  void create_program( GLsizei, GLuint* name ) { *name = glCreateProgram(); }
29  void delete_program( GLsizei, const GLuint* name ) { glDeleteProgram( *name ); }
30 }
31 
36 class program {
37 public:
44  GLuint name() const {
45  return m_object.name();
46  }
47 
69  template<typename... Shaders>
70  bool link( Shaders&&... shaders ) {
71  attach_all( shaders... );
72 
73  check_gl_error( glLinkProgram( name() ) );
74 
75  detach_all( shaders... );
76 
77  auto link_status = GL_FALSE;
78  check_gl_error( glGetProgramiv( name(), GL_LINK_STATUS, &link_status ) );
79 
80 #if !defined( NDEBUG )
81  auto info_log = get_info_log();
82 
83  if( !info_log.empty() ) {
84  GLS_ERROR_STREAM << std::move( info_log );
85  }
86 #endif
87 
88  auto result = ( link_status == GL_TRUE );
89 
90  if( result ) {
91  introspect();
92  }
93 
94  return result;
95  }
96 
108  std::string get_info_log() const {
109  auto info_log_length = GLint();
110  check_gl_error( glGetProgramiv( name(), GL_INFO_LOG_LENGTH, &info_log_length ) );
111 
112  if( !info_log_length ) {
113  return std::string();
114  }
115 
116  auto info_log = std::vector<GLchar>( static_cast<std::size_t>( info_log_length ), 0 );
117  check_gl_error( glGetProgramInfoLog( name(), info_log_length, nullptr, info_log.data() ) );
118 
119  return std::string( info_log.data() );
120  }
121 
129  void use() {
130  check_gl_error( glUseProgram( name() ) );
131  }
132 
139  static void unuse() {
140  check_gl_error( glUseProgram( 0 ) );
141  }
142 
154  GLint get_attribute_location( const std::string& attribute_name ) const {
155  const auto iter = m_attribute_map.find( attribute_name );
156 
157  if( iter == std::end( m_attribute_map ) ) {
158  return -1;
159  }
160 
161  return std::get<0>( iter->second );
162  }
163 
173  GLenum get_attribute_type( const std::string& attribute_name ) const {
174  const auto iter = m_attribute_map.find( attribute_name );
175 
176  if( iter == std::end( m_attribute_map ) ) {
177  return 0u;
178  }
179 
180  return std::get<1>( iter->second );
181  }
182 
192  GLint get_attribute_size( const std::string& attribute_name ) const {
193  const auto iter = m_attribute_map.find( attribute_name );
194 
195  if( iter == std::end( m_attribute_map ) ) {
196  return 0;
197  }
198 
199  return std::get<2>( iter->second );
200  }
201 
213  GLint get_uniform_location( const std::string& uniform_name ) const {
214  const auto iter = m_uniform_map.find( uniform_name );
215 
216  if( iter == std::end( m_uniform_map ) ) {
217  return -1;
218  }
219 
220  return std::get<0>( iter->second );
221  }
222 
232  GLenum get_uniform_type( const std::string& uniform_name ) const {
233  const auto iter = m_uniform_map.find( uniform_name );
234 
235  if( iter == std::end( m_uniform_map ) ) {
236  return 0u;
237  }
238 
239  return std::get<1>( iter->second );
240  }
241 
251  GLint get_uniform_size( const std::string& uniform_name ) const {
252  const auto iter = m_uniform_map.find( uniform_name );
253 
254  if( iter == std::end( m_uniform_map ) ) {
255  return 0;
256  }
257 
258  return std::get<2>( iter->second );
259  }
260 
272  GLuint get_uniform_block_index( const std::string& uniform_block_name ) const {
273  const auto iter = m_uniform_block_map.find( uniform_block_name );
274 
275  if( iter == std::end( m_uniform_block_map ) ) {
276  return GL_INVALID_INDEX;
277  }
278 
279  return std::get<0>( iter->second );
280  }
281 
292  GLint get_uniform_block_size( const std::string& uniform_block_name ) const {
293  const auto iter = m_uniform_block_map.find( uniform_block_name );
294 
295  if( iter == std::end( m_uniform_block_map ) ) {
296  return 0;
297  }
298 
299  return std::get<1>( iter->second );
300  }
301 
303  template<typename T>
304  void uniform( const std::string& uniform_name, T v0 ) = delete;
306 
316  void uniform( const std::string& uniform_name, GLfloat v0 ) { use(); check_gl_error( glUniform1f( get_uniform_location( uniform_name ), v0 ) ); unuse(); };
317 
327  void uniform( const std::string& uniform_name, GLint v0 ) { use(); check_gl_error( glUniform1i( get_uniform_location( uniform_name ), v0 ) ); unuse(); };
328 
338  void uniform( const std::string& uniform_name, GLuint v0 ) { use(); check_gl_error( glUniform1ui( get_uniform_location( uniform_name ), v0 ) ); unuse(); };
339 
341  template<typename T>
342  void uniform( const std::string& uniform_name, T v0, T v1 ) = delete;
344 
355  void uniform( const std::string& uniform_name, GLfloat v0, GLfloat v1 ) { use(); check_gl_error( glUniform2f( get_uniform_location( uniform_name ), v0, v1 ) ); unuse(); };
356 
367  void uniform( const std::string& uniform_name, GLint v0, GLint v1 ) { use(); check_gl_error( glUniform2i( get_uniform_location( uniform_name ), v0, v1 ) ); unuse(); };
368 
379  void uniform( const std::string& uniform_name, GLuint v0, GLuint v1 ) { use(); check_gl_error( glUniform2ui( get_uniform_location( uniform_name ), v0, v1 ) ); unuse(); };
380 
382  template<typename T>
383  void uniform( const std::string& uniform_name, T v0, T v1, T v2 ) = delete;
385 
397  void uniform( const std::string& uniform_name, GLfloat v0, GLfloat v1, GLfloat v2 ) { use(); check_gl_error( glUniform3f( get_uniform_location( uniform_name ), v0, v1, v2 ) ); unuse(); };
398 
410  void uniform( const std::string& uniform_name, GLint v0, GLint v1, GLint v2 ) { use(); check_gl_error( glUniform3i( get_uniform_location( uniform_name ), v0, v1, v2 ) ); unuse(); };
411 
423  void uniform( const std::string& uniform_name, GLuint v0, GLuint v1, GLuint v2 ) { use(); check_gl_error( glUniform3ui( get_uniform_location( uniform_name ), v0, v1, v2 ) ); unuse(); };
424 
426  template<typename T>
427  void uniform( const std::string& uniform_name, T v0, T v1, T v2, T v3 ) = delete;
429 
442  void uniform( const std::string& uniform_name, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3 ) { use(); check_gl_error( glUniform4f( get_uniform_location( uniform_name ), v0, v1, v2, v3 ) ); unuse(); };
443 
456  void uniform( const std::string& uniform_name, GLint v0, GLint v1, GLint v2, GLint v3 ) { use(); check_gl_error( glUniform4i( get_uniform_location( uniform_name ), v0, v1, v2, v3 ) ); unuse(); };
457 
470  void uniform( const std::string& uniform_name, GLuint v0, GLuint v1, GLuint v2, GLuint v3 ) { use(); check_gl_error( glUniform4ui( get_uniform_location( uniform_name ), v0, v1, v2, v3 ) ); unuse(); };
471 
483  void uniform1( const std::string& uniform_name, GLsizei count, const GLfloat* value ) { use(); check_gl_error( glUniform1fv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
484 
496  void uniform1( const std::string& uniform_name, GLsizei count, const GLint* value ) { use(); check_gl_error( glUniform1iv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
497 
509  void uniform1( const std::string& uniform_name, GLsizei count, const GLuint* value ) { use(); check_gl_error( glUniform1uiv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
510 
522  void uniform2( const std::string& uniform_name, GLsizei count, const GLfloat* value ) { use(); check_gl_error( glUniform2fv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
523 
535  void uniform2( const std::string& uniform_name, GLsizei count, const GLint* value ) { use(); check_gl_error( glUniform2iv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
536 
548  void uniform2( const std::string& uniform_name, GLsizei count, const GLuint* value ) { use(); check_gl_error( glUniform2uiv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
549 
561  void uniform3( const std::string& uniform_name, GLsizei count, const GLfloat* value ) { use(); check_gl_error( glUniform3fv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
562 
574  void uniform3( const std::string& uniform_name, GLsizei count, const GLint* value ) { use(); check_gl_error( glUniform3iv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
575 
587  void uniform3( const std::string& uniform_name, GLsizei count, const GLuint* value ) { use(); check_gl_error( glUniform3uiv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
588 
600  void uniform4( const std::string& uniform_name, GLsizei count, const GLfloat* value ) { use(); check_gl_error( glUniform4fv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
601 
613  void uniform4( const std::string& uniform_name, GLsizei count, const GLint* value ) { use(); check_gl_error( glUniform4iv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
614 
626  void uniform4( const std::string& uniform_name, GLsizei count, const GLuint* value ) { use(); check_gl_error( glUniform4uiv( get_uniform_location( uniform_name ), count, value ) ); unuse(); };
627 
640  void uniform_matrix2( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix2fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
641 
654  void uniform_matrix3( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix3fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
655 
668  void uniform_matrix4( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix4fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
669 
682  void uniform_matrix2x3( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix2x3fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
683 
696  void uniform_matrix3x2( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix3x2fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
697 
710  void uniform_matrix2x4( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix2x4fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
711 
724  void uniform_matrix4x2( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix4x2fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
725 
738  void uniform_matrix3x4( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix3x4fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
739 
752  void uniform_matrix4x3( const std::string& uniform_name, GLsizei count, GLboolean transpose, const GLfloat* value ) { use(); check_gl_error( glUniformMatrix4x3fv( get_uniform_location( uniform_name ), count, transpose, value ) ); unuse(); };
753 
754 private:
756  struct pass {
757  template<typename ...T>
758  pass( T... ) {
759  }
760  };
762 
763  template<typename... Args>
764  void attach_all( Args&&... args ) {
765  pass( ( attach( args ), 1 )... );
766  }
767 
768  template<GLenum ShaderType>
769  void attach( const shader<ShaderType>& shader_object ) {
770  check_gl_error( glAttachShader( name(), shader_object.name() ) );
771  }
772 
773  template<typename... Args>
774  void detach_all( Args&&... args ) {
775  pass( ( detach( args ), 1 )... );
776  }
777 
778  template<GLenum ShaderType>
779  void detach( const shader<ShaderType>& shader_object ) {
780  check_gl_error( glDetachShader( name(), shader_object.name() ) );
781  }
782 
783  void introspect() {
784  // Attributes
785  {
786  m_attribute_map.clear();
787 
788  auto active_attributes = GLint();
789  check_gl_error( glGetProgramiv( name(), GL_ACTIVE_ATTRIBUTES, &active_attributes ) );
790 
791  auto active_attribute_max_length = GLint();
792  check_gl_error( glGetProgramiv( name(), GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &active_attribute_max_length ) );
793 
794  auto attribute_name = std::vector<GLchar>( static_cast<std::size_t>( active_attribute_max_length ), 0 );
795 
796  for( GLuint index = 0; index < static_cast<GLuint>( active_attributes ); ++index ) {
797  auto attribute_type = GLenum();
798  auto attribute_size = GLint();
799 
800  check_gl_error( glGetActiveAttrib( name(), index, active_attribute_max_length, nullptr, &attribute_size, &attribute_type, attribute_name.data() ) );
801 
802  auto attribute_location = GLint();
803 
804  attribute_location = check_gl_error( glGetAttribLocation( name(), attribute_name.data() ) );
805 
806  assert( attribute_location >= 0 );
807 
808  m_attribute_map.emplace( std::string( attribute_name.data() ), std::make_tuple( attribute_location, attribute_type, attribute_size ) );
809  }
810  }
811 
812  // Uniforms
813  {
814  m_uniform_map.clear();
815 
816  auto active_uniforms = GLint();
817  check_gl_error( glGetProgramiv( name(), GL_ACTIVE_UNIFORMS, &active_uniforms ) );
818 
819  auto active_uniform_max_length = GLint();
820  check_gl_error( glGetProgramiv( name(), GL_ACTIVE_UNIFORM_MAX_LENGTH, &active_uniform_max_length ) );
821 
822  auto uniform_name = std::vector<GLchar>( static_cast<std::size_t>( active_uniform_max_length ), 0 );
823 
824  for( GLuint index = 0; index < static_cast<GLuint>( active_uniforms ); ++index ) {
825  auto uniform_type = GLint();
826  auto uniform_size = GLint();
827 
828  check_gl_error( glGetActiveUniformName( name(), index, active_uniform_max_length, nullptr, uniform_name.data() ) );
829  check_gl_error( glGetActiveUniformsiv( name(), 1, &index, GL_UNIFORM_TYPE, &uniform_type ) );
830  check_gl_error( glGetActiveUniformsiv( name(), 1, &index, GL_UNIFORM_SIZE, &uniform_size ) );
831 
832  auto uniform_location = GLint();
833 
834  uniform_location = check_gl_error( glGetUniformLocation( name(), uniform_name.data() ) );
835 
836  assert( uniform_location >= 0 );
837 
838  m_uniform_map.emplace( std::string( uniform_name.data() ), std::make_tuple( uniform_location, static_cast<GLenum>( uniform_type ), uniform_size ) );
839  }
840  }
841 
842  // Uniform blocks
843  {
844  m_uniform_block_map.clear();
845 
846  auto active_uniform_blocks = GLint();
847  check_gl_error( glGetProgramiv( name(), GL_ACTIVE_UNIFORM_BLOCKS, &active_uniform_blocks ) );
848 
849  auto active_uniform_block_max_name_length = GLint();
850  check_gl_error( glGetProgramiv( name(), GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH, &active_uniform_block_max_name_length ) );
851 
852  auto uniform_block_name = std::vector<GLchar>( static_cast<std::size_t>( active_uniform_block_max_name_length ), 0 );
853 
854  for( GLuint index = 0; index < static_cast<GLuint>( active_uniform_blocks ); ++index ) {
855  auto uniform_block_size = GLint();
856 
857  check_gl_error( glGetActiveUniformBlockName( name(), index, active_uniform_block_max_name_length, nullptr, uniform_block_name.data() ) );
858  check_gl_error( glGetActiveUniformBlockiv( name(), index, GL_UNIFORM_BLOCK_DATA_SIZE, &uniform_block_size ) );
859 
860  m_uniform_block_map.emplace( std::string( uniform_block_name.data() ), std::make_tuple( index, uniform_block_size ) );
861  }
862  }
863  }
864 
865  object<priv::create_program, priv::delete_program> m_object;
866  std::unordered_map<std::string, std::tuple<GLint, GLenum, GLint>> m_attribute_map;
867  std::unordered_map<std::string, std::tuple<GLint, GLenum, GLint>> m_uniform_map;
868  std::unordered_map<std::string, std::tuple<GLuint, GLint>> m_uniform_block_map;
869 };
870 
871 }
872 
GLint get_uniform_block_size(const std::string &uniform_block_name) const
Get the size of a uniform block.
Definition: program.hpp:292
void uniform_matrix3x4(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 3x4 uniform matrix values.
Definition: program.hpp:738
static void unuse()
No longer use a program.
Definition: program.hpp:139
GLint get_attribute_location(const std::string &attribute_name) const
Get the location of an attribute.
Definition: program.hpp:154
void uniform(const std::string &uniform_name, GLint v0)
Set a 1-component uniform value.
Definition: program.hpp:327
void uniform(const std::string &uniform_name, GLfloat v0)
Set a 1-component uniform value.
Definition: program.hpp:316
void uniform3(const std::string &uniform_name, GLsizei count, const GLfloat *value)
Set an array of 3-component uniform values.
Definition: program.hpp:561
GLint get_uniform_size(const std::string &uniform_name) const
Get the size of a uniform.
Definition: program.hpp:251
Class encapsulating an OpenGL program object.
Definition: program.hpp:36
void uniform(const std::string &uniform_name, GLuint v0)
Set a 1-component uniform value.
Definition: program.hpp:338
void uniform(const std::string &uniform_name, GLfloat v0, GLfloat v1)
Set a 2-component uniform value.
Definition: program.hpp:355
void uniform3(const std::string &uniform_name, GLsizei count, const GLuint *value)
Set an array of 3-component uniform values.
Definition: program.hpp:587
void uniform_matrix3(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 3x3 uniform matrix values.
Definition: program.hpp:654
void uniform(const std::string &uniform_name, GLuint v0, GLuint v1, GLuint v2, GLuint v3)
Set a 4-component uniform value.
Definition: program.hpp:470
void uniform(const std::string &uniform_name, GLint v0, GLint v1, GLint v2, GLint v3)
Set a 4-component uniform value.
Definition: program.hpp:456
void uniform4(const std::string &uniform_name, GLsizei count, const GLuint *value)
Set an array of 4-component uniform values.
Definition: program.hpp:626
void uniform3(const std::string &uniform_name, GLsizei count, const GLint *value)
Set an array of 3-component uniform values.
Definition: program.hpp:574
void uniform(const std::string &uniform_name, GLuint v0, GLuint v1, GLuint v2)
Set a 3-component uniform value.
Definition: program.hpp:423
void uniform(const std::string &uniform_name, GLuint v0, GLuint v1)
Set a 2-component uniform value.
Definition: program.hpp:379
void uniform_matrix2x3(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 2x3 uniform matrix values.
Definition: program.hpp:682
void uniform_matrix4x2(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 4x2 uniform matrix values.
Definition: program.hpp:724
std::string get_info_log() const
Get the link information log.
Definition: program.hpp:108
void uniform_matrix4(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 4x4 uniform matrix values.
Definition: program.hpp:668
void uniform(const std::string &uniform_name, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
Set a 4-component uniform value.
Definition: program.hpp:442
void uniform_matrix3x2(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 3x2 uniform matrix values.
Definition: program.hpp:696
void uniform_matrix2x4(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 2x4 uniform matrix values.
Definition: program.hpp:710
void uniform(const std::string &uniform_name, GLfloat v0, GLfloat v1, GLfloat v2)
Set a 3-component uniform value.
Definition: program.hpp:397
void uniform(const std::string &uniform_name, GLint v0, GLint v1)
Set a 2-component uniform value.
Definition: program.hpp:367
GLenum get_uniform_type(const std::string &uniform_name) const
Get the type of a uniform.
Definition: program.hpp:232
void uniform4(const std::string &uniform_name, GLsizei count, const GLint *value)
Set an array of 4-component uniform values.
Definition: program.hpp:613
void uniform1(const std::string &uniform_name, GLsizei count, const GLfloat *value)
Set an array of 1-component uniform values.
Definition: program.hpp:483
void uniform2(const std::string &uniform_name, GLsizei count, const GLfloat *value)
Set an array of 2-component uniform values.
Definition: program.hpp:522
void uniform1(const std::string &uniform_name, GLsizei count, const GLuint *value)
Set an array of 1-component uniform values.
Definition: program.hpp:509
void uniform_matrix2(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 2x2 uniform matrix values.
Definition: program.hpp:640
void uniform_matrix4x3(const std::string &uniform_name, GLsizei count, GLboolean transpose, const GLfloat *value)
Set an array of 4x3 uniform matrix values.
Definition: program.hpp:752
void uniform(const std::string &uniform_name, GLint v0, GLint v1, GLint v2)
Set a 3-component uniform value.
Definition: program.hpp:410
void use()
Use this program.
Definition: program.hpp:129
GLint get_uniform_location(const std::string &uniform_name) const
Get the location of a uniform.
Definition: program.hpp:213
GLenum get_attribute_type(const std::string &attribute_name) const
Get the type of an attribute.
Definition: program.hpp:173
GLuint get_uniform_block_index(const std::string &uniform_block_name) const
Get the index of a uniform block.
Definition: program.hpp:272
void uniform1(const std::string &uniform_name, GLsizei count, const GLint *value)
Set an array of 1-component uniform values.
Definition: program.hpp:496
void uniform2(const std::string &uniform_name, GLsizei count, const GLint *value)
Set an array of 2-component uniform values.
Definition: program.hpp:535
Definition: buffer.hpp:12
GLint get_attribute_size(const std::string &attribute_name) const
Get the size of an attribute.
Definition: program.hpp:192
void uniform4(const std::string &uniform_name, GLsizei count, const GLfloat *value)
Set an array of 4-component uniform values.
Definition: program.hpp:600
void uniform2(const std::string &uniform_name, GLsizei count, const GLuint *value)
Set an array of 2-component uniform values.
Definition: program.hpp:548
GLuint name() const
Retrieve the OpenGL name of this program.
Definition: program.hpp:44
bool link(Shaders &&...shaders)
Link a set of compiled shaders into this program.
Definition: program.hpp:70