Basic Image AlgorithmS Library  2.8.0
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
ShaderProgramPool.cpp
1 /*
2  * ShaderProgramPool.cpp
3  *
4  * Created on: Mar 6, 2009
5  * Author: africk
6  */
7 
8 #include "ShaderProgramPool.hh"
9 #include <Base/Common/FileHandling.hh>
10 #include <Base/Math/Vector.hh>
11 #include <Utils/IOUtils.hh>
12 #include <algorithm>
13 
14 using namespace std;
15 using namespace BIAS;
16 
17 ShaderProgramPool::ShaderProgramPool()
18 {
19  all_program_linked_ = false;
20 
21 }
22 
23 ShaderProgramPool::~ShaderProgramPool()
24 {
25  ClearAll();
26 }
27 
28 void
29 ShaderProgramPool::ClearAll()
30 {
31  all_program_linked_ = false;
32 
33  program_map_t::iterator program_iter = program_map_.begin();
34 
35  for (; program_iter != program_map_.end(); program_iter++)
36  {
37  glfShaderProgram* programP = GetShaderProgram_(program_iter->second);
38 
39  map<string, shader_map_t>::iterator shader_iter = shaders_.begin();
40  for (; shader_iter != shaders_.end(); shader_iter++)
41  {
42  shader_map_t& shader_map = shader_iter->second;
43  shader_map_t::iterator iter = shader_map.begin();
44  for (; iter != shader_map.end(); iter++)
45  {
46  delete GetShader_(iter->second);
47  }
48  }
49  shaders_.clear();
50 
51  delete programP;
52  }
53 
54  program_map_.clear();
55  validitlyLinked_.clear();
56 }
57 
58 //###############################################################
59 
60 /**
61  * adds an empty shader program identified through the shader_program_name to the pool
62  * @author frick
63  */
64 void
65 ShaderProgramPool::AddShaderProgram(const string& shader_program_name)
66 {
67  glfShaderProgram* programP = new glfShaderProgram();
68 
69  //try to insert
70  pair<program_map_t::iterator, bool> result = program_map_.insert(make_pair(
71  shader_program_name, make_pair(programP, uniforms_map_t())));
72  if (result.second)
73  {
74  programP->Create();
75  validitlyLinked_[shader_program_name] = false;
76  }
77  else
78  {
79  delete programP;
80  GLF_THROW_EXCEPTION("program name :" << shader_program_name
81  << " already exists !" << endl);
82  }
83  all_program_linked_ = false;
84 }
85 
86 /**
87  * adds a fragment shader with shader_name and shader_source to the program with shader_program_name
88  * the program with the given name must exist
89  * @author frick
90  */
91 void
92 ShaderProgramPool::AddFragmentShader(const string& shader_source,
93  const string& shader_name, const string& shader_program_name)
94 {
95  AddShader_(GL_FRAGMENT_SHADER,shader_source, shader_name, shader_program_name);
96  all_program_linked_ = false;
97 }
98 
99 /**
100  * adds a vertex shader with shader_name and shader_source to the program with shader_program_name
101  * the program with the given name must exist
102  * @author frick
103  */
104 void
105 ShaderProgramPool::AddVertexShader(const string& shader_source,
106  const string& shader_name, const string& shader_program_name)
107 {
108  AddShader_(GL_VERTEX_SHADER,shader_source, shader_name, shader_program_name);
109  all_program_linked_ = false;
110 }
111 
112 void
113 ShaderProgramPool::AddFragmentShaderFromFile(const string& path_to_shader,
114  const string& shader_name, const string& shader_program_name)
115 {
116  string shader_source;
117  LoadShaderFromFile_(path_to_shader, shader_source);
118  AddFragmentShader(shader_source, shader_name, shader_program_name);
119 }
120 
121 void
122 ShaderProgramPool::AddVertexShaderFromFile(const string& path_to_shader,
123  const string& shader_name, const string& shader_program_name)
124 {
125  string shader_source;
126  LoadShaderFromFile_(path_to_shader, shader_source);
127  AddVertexShader(shader_source, shader_name, shader_program_name);
128 }
129 
130 /**
131  * removes the shader program from program pool; deletes all attached shaders
132  */
133 void
134 ShaderProgramPool::RemoveShaderProgram(const string& shader_program_name)
135 {
136  glfShaderProgram* programP = GetShaderProgram(shader_program_name);
137  if (programP != NULL)
138  {
139  program_map_.erase(shader_program_name);
140  validitlyLinked_.erase(shader_program_name);
141  map<string, shader_map_t>::iterator shader_iter = shaders_.find(
142  shader_program_name);
143  if (shader_iter != shaders_.end())
144  {
145  shader_map_t& shader_map = shader_iter->second;
146  shader_map_t::iterator iter = shader_map.begin();
147  for (; iter != shader_map.end(); iter++)
148  {
149  delete GetShader_(iter->second);
150  }
151 
152  shader_map.clear();
153  shaders_.erase(shader_iter);
154  }
155 
156  delete programP;
157  }
158 }
159 
160 /**
161  * returns the program pointer or null if the program with shader_program_name does not exist
162  * @author frick
163  */
165 ShaderProgramPool::GetShaderProgram(const string& shader_program_name)
166 {
167  program_data_t* program_dataP = GetShaderProgramData_(shader_program_name);
168  if (program_dataP != NULL)
169  {
170  return program_dataP->first;
171  }
172  else
173  {
174  return NULL;
175  }
176 }
177 
178 void
179 ShaderProgramPool::BindShaderProgram(const string& shader_program_name)
180 {
181  glfShaderProgram* programP = GetShaderProgram(shader_program_name);
182  if (programP != NULL)
183  {
184  programP->Bind();
185  }
186 }
187 
188 bool
189 ShaderProgramPool::IsLinked()
190 {
191  return all_program_linked_;
192 }
193 
194 void
195 ShaderProgramPool::LinkAll()
196 {
197  if (!all_program_linked_)
198  {
199  program_map_t::iterator iter = program_map_.begin();
200  for (; iter != program_map_.end(); iter++)
201  {
202  program_data_t& program_data = iter->second;
203  //link only when required
204  if (!validitlyLinked_[iter->first])
205  {
206  (program_data.first)->Link();
207  validitlyLinked_[iter->first] = true;
208  }
209  }
210 
211  all_program_linked_ = true;
212  }
213 }
214 
215 void
216 ShaderProgramPool::GetShaderNames(const string& shader_program_name, vector<
217  string>& shader_names)
218 {
219  shader_map_t* shaders_mapP = GetShadersMap_(shader_program_name);
220  if (shaders_mapP != NULL)
221  {
222  shader_map_t::iterator iter = shaders_mapP->begin();
223  for (; iter != shaders_mapP->end(); iter++)
224  {
225  shader_names.push_back(iter->first);
226  }
227  }
228 }
229 
230 string
231 ShaderProgramPool::GetUniformType(const string& shader_program_name,
232  const string& varName)
233 {
234  string result = "";
235  uniforms_map_t* uniforms_mapP = GetUniformMap_(shader_program_name);
236  if (uniforms_mapP == NULL)
237  {
238  GLF_THROW_EXCEPTION("program name :" << shader_program_name
239  << " does not exist !" << endl);
240  }
241  else
242  {
243  uniforms_map_t::iterator iter = uniforms_mapP->begin();
244  for (; iter != uniforms_mapP->end(); iter++)
245  {
246  list<string>& variable_list = iter->second;
247  list<string>::iterator var_iter = find(variable_list.begin(),
248  variable_list.end(), varName);
249  if (var_iter != variable_list.end())
250  {
251  return iter->first;
252  }
253  }
254  }
255 
256  return result;
257 }
258 
259 template<class StorageType>
260  void
261  ShaderProgramPool::SetUniformArray(const std::string& shader_program_name,
262  const std::string& varName, StorageType value, int arg_number)
263  {
264  if (all_program_linked_)
265  {
266  program_data_t* program_dataP = GetShaderProgramData_(
267  shader_program_name);
268  if (program_dataP == NULL)
269  {
270  GLF_THROW_EXCEPTION("program name :" << shader_program_name
271  << " does not exist !" << endl);
272  }
273  else
274  {
275  uniforms_map_t* uniforms_mapP = GetUniformMap_(*program_dataP);
276  uniforms_map_t::iterator iter;
277  if (typeid(StorageType) == typeid(int*))
278  {
279  iter = uniforms_mapP->find("int_array");
280  }
281  else
282  {
283  GLF_THROW_EXCEPTION("SetUniform() is not implemented for type (" << typeid(StorageType).name() << ")"<<endl);
284  }
285 
286  if (iter != uniforms_mapP->end())
287  {
288  list<string>& uniforms = iter->second;
289  list<string>::iterator uniform_iter = find(uniforms.begin(),
290  uniforms.end(), varName);
291  if (uniform_iter != uniforms.end())
292  {
293  glfShaderProgram* programP = program_dataP->first;
294  // cout << varName << endl;
295  // cout << arg_number << endl;
296  // cout << programP->GetProgramId() << endl;
297  // cout << programP->GetInfoLog() << endl;
298  programP->SetUniform(varName, arg_number, value);
299 
300  }
301  else
302  {
303  GLF_THROW_EXCEPTION("no uniform variable with name (" << varName << ") and type (" << typeid(StorageType).name()
304  << ") exists in shader program : " << shader_program_name << endl);
305  }
306  }
307  else
308  {
309  GLF_THROW_EXCEPTION("no uniform variable with name (" << varName << ") and type (" << typeid(StorageType).name()
310  << ") exists in shader program : " << shader_program_name << endl);
311  }
312  }
313  }
314  else
315  {
316  GLF_THROW_EXCEPTION("all programs must be linked to set uniform variable, call LinkAll() first ! " << endl);
317  }
318  }
319 
320 template<class StorageType>
321  void
322  ShaderProgramPool::SetUniform(const std::string& shader_program_name,
323  const std::string& varName, StorageType value)
324  {
325  // cout<<"trying to set uniform "<<varName<<" with value "<<value<<" to program "<<shader_program_name<<endl;
326  if (all_program_linked_)
327  {
328  program_data_t* program_dataP = GetShaderProgramData_(
329  shader_program_name);
330  if (program_dataP == NULL)
331  {
332  GLF_THROW_EXCEPTION("program name :" << shader_program_name
333  << " does not exist !" << endl);
334  }
335  else
336  {
337  uniforms_map_t* uniforms_mapP = GetUniformMap_(*program_dataP);
338  uniforms_map_t::iterator iter;
339  if (typeid(StorageType) == typeid(bool))
340  {
341  iter = uniforms_mapP->find("bool");
342  }
343  else
344  {
345 
346  if (typeid(StorageType) == typeid(int))
347  {
348  iter = uniforms_mapP->find("int");
349  }
350  else
351  {
352  if (typeid(StorageType) == typeid(float)
353  || typeid(StorageType) == typeid(double))
354  {
355  iter = uniforms_mapP->find("float");
356  }
357  else
358  {
359 
360  if (typeid(StorageType) == typeid(const Vector<float>&)
361  || typeid(StorageType)
362  == typeid(const Vector<float>&))
363  {
364  iter = uniforms_mapP->find("vec");
365  }
366  else
367  {
368  GLF_THROW_EXCEPTION("SetUniform() is not implemented for type (" << typeid(StorageType).name() << ")"<<endl);
369  }
370  }
371 
372  }
373  }
374  //----------------------
375  if (iter != uniforms_mapP->end())
376  {
377  list<string>& uniforms = iter->second;
378  list<string>::iterator uniform_iter = find(uniforms.begin(),
379  uniforms.end(), varName);
380  if (uniform_iter != uniforms.end())
381  {
382  glfShaderProgram* programP = program_dataP->first;
383  programP->SetUniform(varName, value);
384  }
385  else
386  {
387  iter = uniforms_mapP->find("sampler2D");
388  if (iter != uniforms_mapP->end())
389  {
390  list<string> & uniforms = iter->second;
391  list<string>::iterator uniform_iter = find(
392  uniforms.begin(), uniforms.end(), varName);
393  if (uniform_iter != uniforms.end())
394  {
395  glfShaderProgram* programP = program_dataP->first;
396  programP->SetUniform(varName, value);
397  }
398  else
399  {
400  GLF_THROW_EXCEPTION("no uniform variable with name (" << varName << ") and type (" << typeid(StorageType).name()
401  << ") exists in shader program : " << shader_program_name << endl);
402  }
403  }
404  else
405  {
406  GLF_THROW_EXCEPTION("no uniform variable with name (" << varName << ") and type (" << typeid(StorageType).name()
407  << ") exists in shader program : " << shader_program_name << endl);
408  }
409  }
410  }
411  else
412  {
413  if (typeid(StorageType) == typeid(int))
414  {
415  iter = uniforms_mapP->find("sampler2D");
416  if (iter != uniforms_mapP->end())
417  {
418  list<string>& uniforms = iter->second;
419  list<string>::iterator uniform_iter = find(
420  uniforms.begin(), uniforms.end(), varName);
421  if (uniform_iter != uniforms.end())
422  {
423  glfShaderProgram* programP = program_dataP->first;
424  programP->SetUniform(varName, value);
425  }
426  else
427  {
428  cout << "no uniform variable with name (" << varName << ") and type (" << typeid(StorageType).name()
429  << ") exists in shader program : " << shader_program_name << endl;
430  GLF_THROW_EXCEPTION("no uniform variable with name (" << varName << ") and type (" << typeid(StorageType).name()
431  << ") exists in shader program : " << shader_program_name << endl);
432  }
433  }
434  else
435  {
436  GLF_THROW_EXCEPTION("no uniform variable with name (" << varName << ") and type (" << typeid(StorageType).name()
437  << ") exists in shader program : " << shader_program_name << endl);
438  }
439  }
440  else
441  {
442  GLF_THROW_EXCEPTION("no uniform variable with type (" << typeid(StorageType).name()
443  << ") exists in shader program : " << shader_program_name << endl);
444  }
445  }
446  }
447  }
448  else
449  {
450  GLF_THROW_EXCEPTION("all programs must be linked to set uniform variable, call LinkAll() first ! " << endl);
451  }
452  }
453 
454 //###############################################################
455 
457 ShaderProgramPool::GetShaderProgramData_(const string& shader_program_name)
458 {
459  program_map_t::iterator iter = program_map_.find(shader_program_name);
460  if (iter != program_map_.end())
461  {
462  return &(iter->second);
463  }
464  else
465  {
466  return NULL;
467  }
468 }
469 
470 void
471 ShaderProgramPool::AddShader_(GLenum type, const string& shader_source,
472  const string& shader_name, const string& shader_program_name)
473 {
474  program_data_t* program_dataP = GetShaderProgramData_(shader_program_name);
475  if (program_dataP == NULL)
476  {
477  GLF_THROW_EXCEPTION("program with name:" << shader_program_name
478  << " does not exist !" << endl);
479  }
480  else
481  {
482  glfShader* shaderP = GetShader_(shader_program_name, shader_name);
483  if (shaderP == NULL)
484  {
485 
486  glfShaderProgram* programP = program_dataP->first;
487  shaderP = new glfShader();
488  shaderP->Create(type, shader_source);
489  //try {
490  programP->AttachShader(*shaderP);
491  //} catch(...) {
492  // cout<<"OHOH!\n";
493  // exit(1);
494  //}
495  // shader_map_t tmp;
496  shader_map_t& shader_map = (shaders_.insert(make_pair(
497  shader_program_name, shader_map_t())).first)->second;
498  shader_map[shader_name] = make_pair(shaderP, shader_source);
499  AddUniformDataFromSource_(*program_dataP, shader_source);
500 
501  }
502  else
503  {
504  GLF_THROW_EXCEPTION("shader with name:" << shader_name
505  << " already exists !" << endl);
506  }
507  }
508 }
509 
511 ShaderProgramPool::GetShadersMap_(const std::string& shader_program_name)
512 {
513  map<string, shader_map_t>::iterator iter = shaders_.find(shader_program_name);
514  if (iter != shaders_.end())
515  {
516  return &(iter->second);
517  }
518  else
519  {
520  return NULL;
521  }
522 }
523 
525 ShaderProgramPool::GetShaderData_(ShaderProgramPool::shader_map_t& shader_map,
526  const std::string& shader_name)
527 {
528  shader_map_t::iterator iter = shader_map.find(shader_name);
529  if (iter != shader_map.end())
530  {
531  return &(iter->second);
532  }
533  else
534  {
535  return NULL;
536  }
537 }
538 
540 ShaderProgramPool::GetUniformMap_(program_data_t& program_data)
541 {
542  return &((program_data).second);
543 }
544 
546 ShaderProgramPool::GetUniformMap_(const std::string& shader_program_name)
547 {
548  program_map_t::iterator iter = program_map_.find(shader_program_name);
549  if (iter != program_map_.end())
550  {
551  return GetUniformMap_(iter->second);
552  }
553  else
554  {
555  return NULL;
556  }
557 }
558 
559 string*
560 ShaderProgramPool::GetShaderSource_(shader_data_t& shader_data)
561 {
562  return &(shader_data.second);
563 }
564 
565 glfShader*
566 ShaderProgramPool::GetShader_(shader_data_t& shader_data)
567 {
568  return shader_data.first;
569 }
570 
571 glfShader*
572 ShaderProgramPool::GetShader_(const string& shader_program_name,
573  const string& shader_name)
574 {
575  shader_map_t* shader_mapP = GetShadersMap_(shader_program_name);
576  if (shader_mapP != NULL)
577  {
578  shader_data_t* shader_dataP = GetShaderData_(*(shader_mapP), shader_name);
579  if (shader_dataP != NULL)
580  {
581  return GetShader_(*shader_dataP);
582  }
583  else
584  {
585  return NULL;
586  }
587  }
588  else
589  {
590  return NULL;
591  }
592 }
593 
594 void
595 ShaderProgramPool::AddUniformDataFromSource_(program_data_t& program_data,
596  string shader_source)
597 {
598  //Remove all commentaries, which do not follow the expected grammer here.
599  shader_source = RemoveCommentariesFromSource_(shader_source);
600 
601  string::size_type loc = shader_source.find("uniform ", 0);
602  // IOUtils::PrintWithLineNumbers(shader_source);
603  while (loc != string::npos)
604  {
605  string::size_type pos = shader_source.find(';', loc);
606  if (pos == string::npos)
607  {
608  IOUtils::PrintWithLineNumbers(shader_source);
609  BIASERR("; missing " <<endl);
610  BIASABORT;
611  }
612 
613  string::size_type length = pos - loc;
614  char* data = new char[length + 1];
615  shader_source.copy(data, length, loc);
616  data[length] = '\0';
617 
618  // data type is by default no array
619  bool array = false;
620  //check if data type is an array (search after '[')
621  for (int i = length; i >= 0; i--)
622  {
623  if (data[i] == '[' || data[i] == ']')
624  {
625  array = true;
626  }
627  }
628 
629  vector<string> str_v(3);
630  unsigned int index = 0;
631  char* tokenP;
632  tokenP = strtok(data, " = [");
633  while (tokenP != NULL)
634  {
635  if (index >= str_v.size())
636  {
637  break;
638  }
639  else
640  {
641  str_v[index] = string(tokenP);
642  }
643  tokenP = strtok(NULL, " = [");
644  index++;
645  }
646 
647  if (index < str_v.size() - 1)
648  {
649  IOUtils::PrintWithLineNumbers(shader_source);
650  BIASERR("error parsing uniforms !"<<endl);
651  BIASABORT;
652  }
653 
654  delete data;
655 
656  if (array)
657  {
658  AddUniformVariable_(program_data, str_v[1] + "_array", str_v[2]);
659  }
660  else
661  {
662  // cout<<"adding uniform "<<str_v[2]<<" of type "<<str_v[1]<<endl;
663  AddUniformVariable_(program_data, str_v[1], str_v[2]);
664  }
665  loc = shader_source.find("uniform", pos);
666  }
667 }
668 
669 void
670 ShaderProgramPool::AddUniformVariable_(program_data_t& program_data,
671  const string& type, const string& name)
672 {
673  uniforms_map_t& uniform_map = *(GetUniformMap_(program_data));
674 
675  string::size_type loc = type.find("vec");
676  if (loc != string::npos)
677  {
678  uniform_map[string("vec")].push_back(name);
679  }
680  else
681  {
682  uniform_map[type].push_back(name);
683  }
684 
685 }
686 
687 void
688 ShaderProgramPool::LoadShaderFromFile_(const string& shader_path,
689  string& shader_source)
690 {
691  ifstream ifs(shader_path.c_str());
692  if (!ifs)
693  {
694  GLF_THROW_EXCEPTION("Failed to load shader source file: " << shader_path);
695  }
696 
697  while (!ifs.eof())
698  {
699  string line;
700  getline(ifs, line);
701  shader_source += line + "\r\n";
702  }
703 }
704 
706 ShaderProgramPool::GetShaderProgram_(
707  ShaderProgramPool::program_data_t& program_data)
708 {
709  return program_data.first;
710 }
711 
712 string
713 ShaderProgramPool::RemoveCommentariesFromSource_(const string& source)
714 {
715  string copyString = source;
716  string::size_type pos = 0;
717  while (pos != string::npos)
718  {
719  pos = copyString.find("//");
720  if (pos != string::npos)
721  {
722  string::size_type new_pos = copyString.find('\n',pos);
723  copyString.erase(pos, new_pos - pos + 1);
724  }
725  }
726 
727  return copyString;
728 }
729 
730 //#################################################
731 template void BIASOpenGLFramework_EXPORT
732 ShaderProgramPool::SetUniform<int>(const string& shader_program_name,
733  const string& varName, int value);
734 template void BIASOpenGLFramework_EXPORT
735 ShaderProgramPool::SetUniform<bool>(const string& shader_program_name,
736  const string& varName, bool value);
737 template void BIASOpenGLFramework_EXPORT
738 ShaderProgramPool::SetUniform<float>(const string& shader_program_name,
739  const string& varName, float value);
740 template void BIASOpenGLFramework_EXPORT
741 ShaderProgramPool::SetUniform<double>(const string& shader_program_name,
742  const string& varName, double value);
743 template void BIASOpenGLFramework_EXPORT
744 ShaderProgramPool::SetUniform<Vector<float> >(
745  const string& shader_program_name, const string& varName,
746  Vector<float> value);
747 
748 //#################################################
749 template void BIASOpenGLFramework_EXPORT
750 ShaderProgramPool::SetUniformArray<int*>(const string& shader_program_name,
751  const string& varName, int* value, int arg_number);
void Create()
Creates the shader program.
void SetUniform(const std::string &varName, float value)
void AttachShader(const glfShader &shader)
Attaches a shader to the program.
std::map< std::string, std::list< std::string > > uniforms_map_t
void Create(GLenum type)
Creates the shader without the GLSL source code, use other Create() methods to upload source afterwar...
Definition: glfShader.cpp:55
std::pair< glfShaderProgram *, uniforms_map_t > program_data_t
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
std::pair< glfShader *, std::string > shader_data_t
std::map< std::string, shader_data_t > shader_map_t