Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
glfShaderProgram.cpp
1 /*
2  This file is part of the BIAS library (Basic ImageAlgorithmS).
3 
4  Copyright (C) 2008, 2009 (see file CONTACT for details)
5  Multimediale Systeme der Informationsverarbeitung
6  Institut fuer Informatik
7  Christian-Albrechts-Universitaet Kiel
8 
9 
10  BIAS is free software; you can redistribute it and/or modify
11  it under the terms of the GNU Lesser General Public License as published by
12  the Free Software Foundation; either version 2.1 of the License, or
13  (at your option) any later version.
14 
15  BIAS is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  GNU Lesser General Public License for more details.
19 
20  You should have received a copy of the GNU Lesser General Public License
21  along with BIAS; if not, write to the Free Software
22  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23  */
24 
25 #include "glfShaderProgram.hh"
26 #include "glfUniformNotFoundException.hh"
27 
28 
29 using namespace BIAS;
30 using namespace std;
31 
33 {
34  id_ = 0;
35 }
36 
38 {
39  if (id_ != 0)
40  {
41 
42  for (unsigned int i = 0; i < shaders_attached_as_object_.size(); i++)
43  {
44  glDetachShader(id_, shaders_attached_as_object_[i]);
45  }
46 
47  // all shaders attached from source are internaly attached as object
48  // so glDetachShader was already called
49  for (unsigned int i = 0; i < shaders_attached_from_source_.size(); i++)
50  {
51  delete shaders_attached_from_source_[i];
52  }
53 
54  shaders_attached_as_object_.clear();
55  shaders_attached_from_source_.clear();
56 
57  glDeleteProgram(id_);
58  }
59 }
60 
61 
63 glfShaderProgram::operator=(const glfShaderProgram& b)
64 {
65  return (*this);
66 }
67 
69 {}
70 
72 
73 {
74  if (id_ == 0)
75  {
76  id_ = glCreateProgram();
77  }
78 
79  GLF_THROW_ON_OPENGL_ERROR;
80 }
81 
82 void
84 {
85  BIASASSERT(id_ != 0);
86 
87  GLF_THROW_ON_OPENGL_ERROR;
88 
89  if(glIsProgram(id_)==GL_FALSE) {
90  GLF_THROW_EXCEPTION("not a valid program id!");
91  }
92 
93  if(glIsShader(shader.GetShaderID())==GL_FALSE) {
94  GLF_THROW_EXCEPTION("not a valid shader id!");
95  }
96 
97  GLsizei count;
98  GLuint shaders[50];
99  glGetAttachedShaders(id_, 50, &count, shaders);
100  bool alreadyAttached=false;
101  for (int i=0; i<count; i++) {
102  alreadyAttached = alreadyAttached || (shaders[i]==shader.GetShaderID());
103  }
104 
105  if(!alreadyAttached)
106  glAttachShader(id_, shader.GetShaderID());
107 
108 
109  GLF_THROW_ON_OPENGL_ERROR;
110  shaders_attached_as_object_.push_back(shader.GetShaderID());
111 
112  GLF_THROW_ON_OPENGL_ERROR;
113 }
114 
115 void
117  const std::string& sourceCode)
118 {
119  glfShader* shader = new glfShader();
120  shader->Create(type, sourceCode);
121 
122  shaders_attached_from_source_.push_back(shader);
123  AttachShader(*shader);
124 
125 }
126 
127 void
128 glfShaderProgram::AttachShaderFromFile(GLenum type, const std::string& fileName)
129 {
130  glfShader* shader = new glfShader();
131  shader->CreateFromFile(type, fileName);
132  shaders_attached_from_source_.push_back(shader);
133  AttachShader(*shader);
134 }
135 
136 void
138 {
139  BIASASSERT(id_ != 0);
140 
141  glLinkProgram(id_);
142 
143  GLint linkSuccess;
144  glGetProgramiv(id_, GL_LINK_STATUS, &linkSuccess);
145  if (linkSuccess == GL_FALSE)
146  {
147  GLF_THROW_EXCEPTION("Failed to link shader program: "
148  << endl << GetInfoLog());
149  }
150 
151  GLF_THROW_ON_OPENGL_ERROR;
152 }
153 
154 string
156 {
157  BIASASSERT(id_ != 0);
158 
159  GLint logLength = 0;
160  glGetProgramiv(id_, GL_INFO_LOG_LENGTH, &logLength);
161  char* infoLog = new char[logLength];
162  glGetProgramInfoLog(id_, logLength, NULL, infoLog);
163  std::string out = infoLog;
164  delete[] infoLog;
165 
166  GLF_THROW_ON_OPENGL_ERROR;
167 
168  return out;
169 }
170 
171 void
172 glfShaderProgram::SetUniform(const std::string& varName, bool value)
173 {
174  Bind();
175  GLboolean glValue = (value) ? GL_TRUE : GL_FALSE;
176  try{
177  GLint loc = GetUniformLocation_(varName);
178  glUniform1i(loc, glValue);
179  }
180  catch(glfException& e) {
181  std::cout << "Error: " << e.GetMessageString() << std::endl;
182  return;
183  }
184 
185  GLF_THROW_ON_OPENGL_ERROR_INFO(varName);
186 }
187 
188 
189 void
190 glfShaderProgram::SetUniform(const std::string& varName, float value)
191 {
192  Bind();
193  try{
194  GLint loc = GetUniformLocation_(varName);
195  glUniform1f(loc, value);
196  }
197  catch(glfException& e) {
198  std::cout << "Error: " << e.GetMessageString() << std::endl;
199  return;
200  }
201 
202  GLF_THROW_ON_OPENGL_ERROR_INFO(varName);
203 }
204 
205 void
206 glfShaderProgram::SetUniform(const std::string& varName, double value)
207 {
208  SetUniform(varName, (float) value);
209 }
210 
211 void
212 glfShaderProgram::SetUniform(const std::string& varName, int value)
213 {
214  Bind();
215  try{
216  GLint loc = GetUniformLocation_(varName);
217  glUniform1i(loc, value);
218  }
219  catch(glfException& e) {
220  std::cout << "Error: " << e.GetMessageString() << std::endl;
221  return;
222  }
223 
224  GLF_THROW_ON_OPENGL_ERROR_INFO(varName);
225 }
226 
227 void
228 glfShaderProgram::SetUniform(const std::string& varName, int count, int *value)
229 {
230  Bind();
231  try{
232  GLint loc = GetUniformLocation_(varName);
233  glUniform1iv(loc, count, value);
234  }
235  catch(glfException& e) {
236  std::cout << "Error: " << e.GetMessageString() << std::endl;
237  return;
238  }
239 
240  GLF_THROW_ON_OPENGL_ERROR_INFO(varName);
241 }
242 
243 void glfShaderProgram::SetUniform(const std::string& varName, int count, float *value) {
244  Bind();
245  try {
246  GLint loc = GetUniformLocation_(varName);
247  glUniform1fv(loc, count, value);
248  }
249  catch (glfException& e) {
250  std::cout << "Error: " << e.GetMessageString() << std::endl;
251  return;
252  }
253 
254  GLF_THROW_ON_OPENGL_ERROR_INFO(varName);
255 }
256 
257 void
258 glfShaderProgram::SetUniform(const std::string& varName,
259  const BIAS::Vector<float>& v)
260 {
261  Bind();
262 
263  GLint loc = GetUniformLocation_(varName);
264  switch (v.GetNumElements())
265  {
266  case 1:
267  glUniform1fv(loc, 1, v.GetData());
268  break;
269  case 2:
270  glUniform2fv(loc, 1, v.GetData());
271  break;
272  case 3:
273  glUniform3fv(loc, 1, v.GetData());
274  break;
275  case 4:
276  glUniform4fv(loc, 1, v.GetData());
277  break;
278  default:
279  GLF_THROW_EXCEPTION("Invalid vector size "<<v.GetNumElements()<< " for uniform "<<varName)
280  ;
281  break;
282  }
283 
284  GLF_THROW_ON_OPENGL_ERROR;
285 }
286 
287 void
288 glfShaderProgram::SetUniform(const std::string& varName, const BIAS::Vector<
289  double>& v)
290 {
291  Vector<float> vf(v.GetNumElements());
292  for (int i = 0; i < v.GetNumElements(); i++)
293  {
294  vf[i] = (float) v[i];
295  }
296  SetUniform(varName, vf);
297 }
298 
299 void
300 glfShaderProgram::SetUniform(const std::string& varName,
301  const BIAS::Vector<int>& v)
302 {
303  Bind();
304  try{
305  GLint loc = GetUniformLocation_(varName);
306 
307  switch (v.GetNumElements())
308  {
309  case 1:
310  glUniform1iv(loc, 1, v.GetData());
311  break;
312  case 2:
313  glUniform2iv(loc, 1, v.GetData());
314  break;
315  case 3:
316  glUniform3iv(loc, 1, v.GetData());
317  break;
318  case 4:
319  glUniform4iv(loc, 1, v.GetData());
320  break;
321  default:
322  GLF_THROW_EXCEPTION("Invalid vector size for uniform")
323  ;
324  break;
325  }
326  }
327  catch(glfException& e) {
328  std::cout << "Error: " << e.GetMessageString() << std::endl;
329  return;
330  }
331  GLF_THROW_ON_OPENGL_ERROR;
332 }
333 
334 void
335 glfShaderProgram::SetUniform(const std::string& varName,
336  const BIAS::Matrix<float>& md)
337 {
339  Bind();
340  try{
341  GLint loc = GetUniformLocation_(varName);
342  switch (m.GetRows())
343  {
344  case 2:
345  switch (m.GetCols())
346  {
347  case 2:
348  glUniformMatrix2fv(loc, 1, GL_FALSE, m.GetData());
349  break;
350  //case 3: glUniformMatrix2x3fv(loc, 1, GL_FALSE, m.GetData()); break;
351  //case 4: glUniformMatrix2x4fv(loc, 1, GL_FALSE, m.GetData()); break;
352  default:
353  GLF_THROW_EXCEPTION("Invalid number of columns for uniform matrix")
354  ;
355  break;
356  }
357  break;
358  case 3:
359  switch (m.GetCols())
360  {
361  //case 2: glUniformMatrix3x2fv(loc, 1, GL_FALSE, m.GetData()); break;
362  case 3:
363  glUniformMatrix3fv(loc, 1, GL_FALSE, m.GetData());
364  break;
365  //case 4: glUniformMatrix3x4fv(loc, 1, GL_FALSE, m.GetData()); break;
366  default:
367  GLF_THROW_EXCEPTION("Invalid number of columns for uniform matrix")
368  ;
369  break;
370  }
371  break;
372  case 4:
373  switch (m.GetCols())
374  {
375  //case 2: glUniformMatrix4x2fv(loc, 1, GL_FALSE, m.GetData()); break;
376  //case 3: glUniformMatrix4x3fv(loc, 1, GL_FALSE, m.GetData()); break;
377  case 4:
378  glUniformMatrix4fv(loc, 1, GL_FALSE, m.GetData());
379  break;
380  default:
381  GLF_THROW_EXCEPTION("Invalid number of columns for uniform matrix")
382  ;
383  break;
384  }
385  break;
386  default:
387  GLF_THROW_EXCEPTION("Invalid number of rows for uniform matrix")
388  ;
389  break;
390  }
391  }
392  catch(glfException& e) {
393  std::cout << "Error: " << e.GetMessageString() << std::endl;
394  return;
395  }
396  GLF_THROW_ON_OPENGL_ERROR;
397 }
398 
399 void
400 glfShaderProgram::SetUniform(const std::string& varName, const BIAS::Matrix<
401  double>& m)
402 {
403  Matrix<float> mf(m.GetRows(), m.GetCols());
404  for (unsigned int i = 1; i <= m.GetRows(); i++)
405  {
406  for (unsigned int j = 1; j <= m.GetCols(); j++)
407  {
408  mf(i, j) = (float) m(i, j);
409  }
410  }
411  SetUniform(varName, mf);
412 }
413 
414 void
415 glfShaderProgram::SetUniform(const std::string& varName, const glfMatrix& m)
416 {
417  Bind();
418  try{
419  GLint loc = GetUniformLocation_(varName);
420  glUniformMatrix4fv(loc, 1, GL_FALSE, m.GetArray());
421  }
422  catch(glfException& e) {
423  std::cout << "Error: " << e.GetMessageString() << std::endl;
424  return;
425  }
426 
427 }
428 
429 void
431 {
432  BIASASSERT(id_ != 0);
433  glUseProgram(id_);
434 }
435 
436 bool
437 glfShaderProgram::IsSamplerType_(GLenum type) {
438  bool isSampler = false;
439  switch(type) {
440  case GL_SAMPLER_1D :
441  case GL_SAMPLER_2D :
442  case GL_SAMPLER_3D :
443  case GL_SAMPLER_CUBE :
444  case GL_SAMPLER_1D_SHADOW :
445  case GL_SAMPLER_2D_SHADOW :
446  isSampler = true;
447  break;
448  default :
449  BIASWARN("Sampler Type List is incomplete!");
450  isSampler = false;
451  break;
452  }
453  return isSampler;
454 }
455 
456 void
458 {
459  BIASASSERT(id_ != 0);
460  GLint numActiveUniforms;
461  glGetProgramiv(id_, GL_ACTIVE_UNIFORMS, &numActiveUniforms);
462  GLF_THROW_ON_OPENGL_ERROR_DEBUG;
463  //cout<<"num active uniforms = "<<numActiveUniforms<<endl;
464  GLint assignTU = 0;
465  GLenum uniformType;
466  const int bufSize = 50;
467  char name[bufSize];
468  GLsizei length;
469  GLint uniformSize;
470  for(int i=0; i<numActiveUniforms; i++) {
471  glGetActiveUniform(id_, i, bufSize, &length, &uniformSize, &uniformType, name);
472  if(IsSamplerType_(uniformType)) {
473  // cout<<"assigning TU "<<assignTU<<" to "<<name<<endl;
474  SetUniform(name, assignTU++);
475  }
476  }
477  GLF_THROW_ON_OPENGL_ERROR;
478 }
479 
480 GLint
481 glfShaderProgram::GetUniformLocation_(const std::string& varName)
482 {
483  BIASASSERT(id_ != 0);
484  GLint loc = glGetUniformLocation(id_, varName.c_str());
485  if(loc == -1) {
486  std::stringstream msg;
487  msg << "no active uniform named "
488  <<varName
489  <<"! Check: 1. Is Program Linked?, 2. Typo?, 3. Correct shader?";
490  // throw glfUniformNotFoundException(__FILE__, __LINE__, msg.str(), varName);
491 // BIASWARN(msg.str()<<endl);
492  }
493  return loc;
494 }
495 
496 GLint
497 glfShaderProgram::GetUniformLocation(const std::string& varName)
498 {
499  BIASASSERT(id_ != 0);
500  GLint loc = glGetUniformLocation(id_, varName.c_str());
501  if(loc == -1) {
502  std::stringstream msg;
503  msg << "no active uniform named "
504  <<varName
505  <<"! Check: 1. Is Program Linked?, 2. Typo?, 3. Correct shader?";
506  throw glfUniformNotFoundException(__FILE__, __LINE__, msg.str(), varName);
507  }
508  return loc;
509 }
510 
511 
512 int
514 {
515  GLint TUs = 0;
516 
517  glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &TUs);
518 
519  return static_cast<GLint> (TUs);
520 }
521 
522 #ifdef GL_VERSION_3_0
523 void
524 glfShaderProgram::BindAttribLocation(GLuint indexSlot, const std::string& VertexAttributeName)
525 {
526  BIASASSERT(id_ != 0);
527  glBindAttribLocation(id_, indexSlot, VertexAttributeName.c_str());
528 }
529 #endif
530 
static int GetMaxCombinedTextureUnits()
void AttachShaderFromSource(GLenum type, const std::string &sourceCode)
Attaches a shader to the program, without the need to create an instance of the glfShader class...
void Create()
Creates the shader program.
void SetUniform(const std::string &varName, float value)
std::string GetInfoLog() const
Returns the info log containing information about the linking of the shader program.
void Link()
Links the attached shaders.
void AttachShader(const glfShader &shader)
Attaches a shader to the program.
Matrix< T > Transpose() const
transpose function, storing data destination matrix
Definition: Matrix.hh:823
void CreateFromFile(GLenum type, const std::string &fileName)
Creates the shader from GLSL source code loaded from a file.
Definition: glfShader.cpp:94
void Create(GLenum type)
Creates the shader without the GLSL source code, use other Create() methods to upload source afterwar...
Definition: glfShader.cpp:55
GLint GetUniformLocation(const std::string &varName)
Exception class used for run-time errors in the OpenGLFramework.
Definition: glfException.hh:79
GLuint GetShaderID() const
Returns the OpenGL id of the shader.
Definition: glfShader.cpp:127
const std::string & GetMessageString() const
Returns the description of the error including the file name and line number where the error occured...
void Bind() const
Binds the shader program.
A shader program composed of several shaders.
A GLSL vertex shader or fragment shader, which must be linked in a shader program.
Definition: glfShader.hh:39
unsigned int GetRows() const
Definition: Matrix.hh:202
int GetNumElements() const
conformance interface JW
Definition: Vector.hh:147
T * GetData()
get the pointer to the data array of the matrix (for faster direct memeory access) ...
Definition: Matrix.hh:185
Class is thrown when a uniform is set but was not set active by the gl compiler.
unsigned int GetCols() const
Definition: Matrix.hh:204
T * GetData() const
get the pointer to the data array of the vector (for faster direct memory access) ...
Definition: Vector.hh:219
void AutoSetSamplerUniforms()
Finds all sampler uniforms and automatically assigns them texture unit indices.
matrix class with arbitrary size, indexing is row major.
A 4x4 matrix in native OpenGL format.
Definition: glfMatrix.hh:41
void AttachShaderFromFile(GLenum type, const std::string &fileName)
Attaches a shader to the program, without the need to create an instance of the glfShader class...
const GLfloat * GetArray() const
Definition: glfMatrix.hh:171