GlProgram.cpp
Go to the documentation of this file.
1 #include "GlProgram.hpp"
2 #include "GlError.hpp"
4 #include <ivorium_config.hpp>
5 
6 namespace iv
7 {
8 
10  _program_id( 0 ),
11  _linked( false ),
12  _vertex_id( 0 ),
13  _fragment_id( 0 )
14 {
15 }
16 
17 void GlProgram::CreateProgram( ClientMarker const * logger )
18 {
19  if( this->_program_id )
20  this->DestroyProgram( logger );
21 
22  this->_program_id = glCreateProgram();
23 
24  if( this->_program_id == 0 )
25  logger->warning( SRC_INFO, "OpenGL program not created." );
26 
27  //
28  GlError_Check( logger, SRC_INFO );
29 }
30 
31 void GlProgram::PositionAttributeName( ClientMarker const * logger, const char * name )
32 {
33  #if IV_ENABLE_TRANSFORM_FEEDBACK
34  glTransformFeedbackVaryings( this->_program_id, 1, &name, GL_INTERLEAVED_ATTRIBS );
35  GlError_Check( logger, SRC_INFO );
36  #endif
37 }
38 
39 void GlProgram::Load_VertexShader( ClientMarker const * logger, std::istream & in )
40 {
41  if( !this->_program_id )
42  this->CreateProgram( logger );
43 
44  if( this->_linked )
45  {
46  logger->log( SRC_INFO, Defs::Log::Warning, "Program is already linked." );
47  return;
48  }
49 
50  if( this->_vertex_id )
51  {
52  logger->log( SRC_INFO, Defs::Log::Warning, "Vertex shader already exists in this program, skipping." );
53  return;
54  }
55 
56  // read shader source to buffer
57  std::string source;
58  while( !in.eof() )
59  {
60  constexpr size_t bufcap = 256;
61  char buf[ bufcap ];
62  in.read( buf, bufcap );
63  source.append( buf, in.gcount() );
64  }
65 
66  char const * src_dta = source.c_str();
67  int const src_len = source.size();
68 
69  // create shader
70  this->_vertex_id = glCreateShader( GL_VERTEX_SHADER );
71 
72  // load source
73  glShaderSource( this->_vertex_id, 1, &src_dta, &src_len );
74 
75  // compile
76  glCompileShader( this->_vertex_id );
77 
78  // check errors
79  GLint compiled;
80  glGetShaderiv( this->_vertex_id, GL_COMPILE_STATUS, &compiled );
81  if( compiled == GL_FALSE )
82  {
83  logger->log( SRC_INFO, Defs::Log::Warning, "Vertex shader compilation error: "+GlProgram::ExtractShaderInfoLog( this->_vertex_id ) );
84  glDeleteShader( this->_vertex_id );
85  this->_vertex_id = 0;
86  }
87 
88  // attach to program
89  glAttachShader( this->_program_id, this->_vertex_id );
90 
91  //
92  GlError_Check( logger, SRC_INFO );
93 }
94 
95 void GlProgram::Load_FragmentShader( ClientMarker const * logger, std::istream & in )
96 {
97  if( !this->_program_id )
98  this->CreateProgram( logger );
99 
100  if( this->_linked )
101  {
102  logger->log( SRC_INFO, Defs::Log::Warning, "Program is already linked." );
103  return;
104  }
105 
106  if( this->_fragment_id )
107  {
108  logger->log( SRC_INFO, Defs::Log::Warning, "Fragment shader already exists in this program, skipping." );
109  return;
110  }
111 
112  // read shader source to buffer
113  std::string source;
114  while( !in.eof() )
115  {
116  constexpr size_t bufcap = 256;
117  char buf[ bufcap ];
118  in.read( buf, bufcap );
119  source.append( buf, in.gcount() );
120  }
121 
122  char const * src_dta = source.c_str();
123  int const src_len = source.size();
124 
125  // create shader
126  this->_fragment_id = glCreateShader( GL_FRAGMENT_SHADER );
127 
128  // load source
129  glShaderSource( this->_fragment_id, 1, &src_dta, &src_len );
130 
131  // compile
132  glCompileShader( this->_fragment_id );
133 
134  // check errors
135  GLint compiled;
136  glGetShaderiv( this->_fragment_id, GL_COMPILE_STATUS, &compiled );
137  if( compiled == GL_FALSE )
138  {
139  logger->log( SRC_INFO, Defs::Log::Warning, "Fragment shader compilation error: \n"+GlProgram::ExtractShaderInfoLog( this->_fragment_id ) );
140  glDeleteShader( this->_fragment_id );
141  this->_fragment_id = 0;
142  }
143 
144  // attach to program
145  glAttachShader( this->_program_id, this->_fragment_id );
146 
147  //
148  GlError_Check( logger, SRC_INFO );
149 }
150 
151 void GlProgram::BindAttribute( ClientMarker const * logger, GLuint location, const char * attrib_name )
152 {
153  if( !this->_program_id )
154  {
155  logger->log( SRC_INFO, Defs::Log::Warning, "Program not created." );
156  return;
157  }
158 
159  if( this->_linked )
160  {
161  logger->log( SRC_INFO, Defs::Log::Warning, "Program is already linked." );
162  return;
163  }
164 
165  glBindAttribLocation( this->_program_id, location, attrib_name );
166 
167  //
168  GlError_Check( logger, SRC_INFO );
169 }
170 
171 void GlProgram::LinkProgram( ClientMarker const * logger )
172 {
173  if( !this->_program_id )
174  {
175  logger->log( SRC_INFO, Defs::Log::Warning, "No program to link." );
176  return;
177  }
178 
179  if( this->_linked )
180  return;
181 
182  // link
183  glLinkProgram( this->_program_id );
184 
185  // check errors
186  GLint linked;
187  glGetProgramiv( this->_program_id, GL_LINK_STATUS, &linked );
188  if( linked == GL_FALSE )
189  {
190  logger->log( SRC_INFO, Defs::Log::Warning, "Shader program link error: "+GlProgram::ExtractProgramInfoLog( this->_program_id ) );
191 
192  glDeleteProgram( this->_program_id );
193  this->_program_id = 0;
194  this->_linked = false;
195 
196  if( this->_vertex_id )
197  glDeleteShader( this->_vertex_id ),
198  this->_vertex_id = 0;
199 
200  if( this->_fragment_id )
201  glDeleteShader( this->_fragment_id ),
202  this->_fragment_id = 0;
203  }
204 
205  // clean shaders
206  if( this->_vertex_id )
207  glDetachShader( this->_program_id, this->_vertex_id ),
208  glDeleteShader( this->_vertex_id ),
209  this->_vertex_id = 0;
210 
211  if( this->_fragment_id )
212  glDetachShader( this->_program_id, this->_fragment_id ),
213  glDeleteShader( this->_fragment_id ),
214  this->_fragment_id = 0;
215 
216  // set variables
217  this->_linked = true;
218 
219  //
220  GlError_Check( logger, SRC_INFO );
221 }
222 
224 {
225  if( !this->_program_id )
226  return;
227 
228  if( this->_vertex_id )
229  glDetachShader( this->_program_id, this->_vertex_id ),
230  glDeleteShader( this->_vertex_id ),
231  this->_vertex_id = 0;
232 
233  if( this->_fragment_id )
234  glDetachShader( this->_program_id, this->_fragment_id ),
235  glDeleteShader( this->_fragment_id ),
236  this->_fragment_id = 0;
237 
238  glDeleteProgram( this->_program_id );
239  this->_program_id = 0;
240  this->_linked = false;
241 
242  //
243  GlError_Check( logger, SRC_INFO );
244 }
245 
246 void GlProgram::DropProgram( ClientMarker const * logger )
247 {
248  this->_vertex_id = 0;
249  this->_fragment_id = 0;
250  this->_program_id = 0;
251  this->_linked = false;
252 }
253 
254 std::string GlProgram::ExtractShaderInfoLog( GLuint shader )
255 {
256  GLint msg_len;
257  glGetShaderiv( shader, GL_INFO_LOG_LENGTH, &msg_len );
258  GLchar * msg = new GLchar[ msg_len ];
259  glGetShaderInfoLog( shader, msg_len, nullptr, msg );
260  std::string message( msg, msg_len );
261  delete [] msg;
262  return message;
263 }
264 
265 std::string GlProgram::ExtractProgramInfoLog( GLuint program )
266 {
267  GLint msg_len;
268  glGetProgramiv( program, GL_INFO_LOG_LENGTH, &msg_len );
269  GLchar * msg = new GLchar[ msg_len ];
270  glGetProgramInfoLog( program, msg_len, nullptr, msg );
271  std::string message( msg );
272  delete [] msg;
273  return message;
274 }
275 
276 GLuint GlProgram::program_id() const
277 {
278  if( this->_program_id && this->_linked )
279  return this->_program_id;
280  else
281  return 0;
282 }
283 
284 GLint GlProgram::GetUniformLocation( const char * name ) const
285 {
286  auto result = glGetUniformLocation( this->_program_id, name );
287  //GlError_Check( wt, SRC_INFO );
288  return result;
289 }
290 
291 }