framework2
1565 строк · 51.7 Кб
1#include "ofShader.h"
2#include "ofUtils.h"
3#include "ofFileUtils.h"
4#include "ofGraphics.h"
5#include "ofGLProgrammableRenderer.h"
6#include "ofTexture.h"
7#include "ofMatrix4x4.h"
8#include "ofMatrix3x3.h"
9#include "ofParameterGroup.h"
10#include "ofParameter.h"
11#include "ofBufferObject.h"
12#include "ofShadow.h"
13#include "ofLight.h"
14#include "ofCubeMap.h"
15#ifdef TARGET_ANDROID
16#include "ofxAndroidUtils.h"
17#endif
18#include <regex>
19
20using std::unordered_map;
21using std::vector;
22using std::string;
23using std::endl;
24using std::setw;
25using std::stringstream;
26using std::ostringstream;
27
28static const string COLOR_ATTRIBUTE="color";
29static const string POSITION_ATTRIBUTE="position";
30static const string NORMAL_ATTRIBUTE="normal";
31static const string TEXCOORD_ATTRIBUTE="texcoord";
32
33static unordered_map<GLuint,int> & getShaderIds(){
34static unordered_map<GLuint,int> * ids = new unordered_map<GLuint,int>;
35return *ids;
36}
37
38static unordered_map<GLuint,int> & getProgramIds(){
39static unordered_map<GLuint,int> * ids = new unordered_map<GLuint,int>;
40return *ids;
41}
42
43//--------------------------------------------------------------
44static void retainShader(GLuint id){
45if(id==0) return;
46if(getShaderIds().find(id)!=getShaderIds().end()){
47getShaderIds()[id]++;
48}else{
49getShaderIds()[id]=1;
50}
51}
52
53//--------------------------------------------------------------
54static void releaseShader(GLuint program, GLuint id){
55if(getShaderIds().find(id)!=getShaderIds().end()){
56getShaderIds()[id]--;
57if(getShaderIds()[id]==0){
58glDetachShader(program, id);
59glDeleteShader(id);
60getShaderIds().erase(id);
61}
62}else{
63ofLogWarning("ofShader") << "releaseShader(): something's wrong here, releasing unknown shader id " << id << " from program " << program;
64glDetachShader(program, id);
65glDeleteShader(id);
66}
67}
68
69//--------------------------------------------------------------
70static void retainProgram(GLuint id){
71if(id==0) return;
72if(getProgramIds().find(id)!=getProgramIds().end()){
73getProgramIds()[id]++;
74}else{
75getProgramIds()[id]=1;
76}
77}
78
79//--------------------------------------------------------------
80static void releaseProgram(GLuint id){
81if(getProgramIds().find(id)!=getProgramIds().end()){
82getProgramIds()[id]--;
83if(getProgramIds()[id]==0){
84glDeleteProgram(id);
85getProgramIds().erase(id);
86}
87}else{
88ofLogWarning("ofShader") << "releaseProgram(): something's wrong here, releasing unknown program id " << id;
89glDeleteProgram(id);
90}
91}
92
93#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)
94//--------------------------------------------------------------
95ofShader::TransformFeedbackRangeBinding::TransformFeedbackRangeBinding(const ofBufferObject & buffer, GLuint offset, GLuint size)
96:offset(offset)
97,size(size)
98,buffer(buffer){}
99
100//--------------------------------------------------------------
101ofShader::TransformFeedbackBaseBinding::TransformFeedbackBaseBinding(const ofBufferObject & buffer)
102:buffer(buffer){}
103#endif
104
105//--------------------------------------------------------------
106ofShader::ofShader() :
107program(0),
108bLoaded(false)
109{
110}
111
112//--------------------------------------------------------------
113ofShader::~ofShader() {
114unload();
115}
116
117//--------------------------------------------------------------
118ofShader::ofShader(const ofShader & mom)
119:program(mom.program)
120,bLoaded(mom.bLoaded)
121,shaders(mom.shaders)
122,uniformsCache(mom.uniformsCache)
123,attributesBindingsCache(mom.attributesBindingsCache)
124#ifndef TARGET_OPENGLES
125,uniformBlocksCache(mom.uniformBlocksCache)
126#endif
127{
128if(mom.bLoaded){
129retainProgram(program);
130for(auto it: shaders){
131auto shader = it.second;
132retainShader(shader.id);
133}
134#ifdef TARGET_ANDROID
135ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL);
136#endif
137}
138}
139
140//--------------------------------------------------------------
141ofShader & ofShader::operator=(const ofShader & mom){
142if(this == &mom) {
143return *this;
144}
145if(bLoaded){
146unload();
147}
148program = mom.program;
149bLoaded = mom.bLoaded;
150shaders = mom.shaders;
151attributesBindingsCache = mom.attributesBindingsCache;
152uniformsCache = mom.uniformsCache;
153if(mom.bLoaded){
154retainProgram(program);
155for(auto it: shaders){
156auto shader = it.second;
157retainShader(shader.id);
158}
159#ifdef TARGET_ANDROID
160ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL);
161#endif
162}
163return *this;
164}
165
166ofShader::ofShader(ofShader && mom)
167:program(std::move(mom.program))
168,bLoaded(std::move(mom.bLoaded))
169,shaders(std::move(mom.shaders))
170,uniformsCache(std::move(mom.uniformsCache))
171,attributesBindingsCache(std::move(mom.attributesBindingsCache)){
172if(mom.bLoaded){
173#ifdef TARGET_ANDROID
174ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL);
175#endif
176}
177mom.bLoaded = false;
178}
179
180ofShader & ofShader::operator=(ofShader && mom){
181if(this == &mom) {
182return *this;
183}
184if(bLoaded){
185unload();
186}
187program = std::move(mom.program);
188bLoaded = std::move(mom.bLoaded);
189shaders = std::move(mom.shaders);
190attributesBindingsCache = std::move(mom.attributesBindingsCache);
191uniformsCache = std::move(mom.uniformsCache);
192if(mom.bLoaded){
193#ifdef TARGET_ANDROID
194ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL);
195#endif
196}
197mom.bLoaded = false;
198return *this;
199}
200
201//--------------------------------------------------------------
202bool ofShader::load(const of::filesystem::path& shaderName) {
203return load(shaderName.string() + ".vert", shaderName.string() + ".frag");
204}
205
206//--------------------------------------------------------------
207bool ofShader::load(const of::filesystem::path& vertName, const of::filesystem::path& fragName, const of::filesystem::path& geomName) {
208if(vertName.empty() == false) setupShaderFromFile(GL_VERTEX_SHADER, vertName);
209if(fragName.empty() == false) setupShaderFromFile(GL_FRAGMENT_SHADER, fragName);
210#ifndef TARGET_OPENGLES
211if(geomName.empty() == false) setupShaderFromFile(GL_GEOMETRY_SHADER_EXT, geomName);
212#endif
213if(ofIsGLProgrammableRenderer()){
214bindDefaults();
215}
216return linkProgram();
217}
218
219#if !defined(TARGET_OPENGLES) && defined(glDispatchCompute)
220//--------------------------------------------------------------
221bool ofShader::loadCompute(const of::filesystem::path& shaderName) {
222return setupShaderFromFile(GL_COMPUTE_SHADER, shaderName) && linkProgram();
223}
224#endif
225
226//--------------------------------------------------------------
227bool ofShader::setup(const ofShaderSettings & settings) {
228for (auto shader : settings.shaderFiles) {
229auto ty = shader.first;
230auto file = shader.second;
231auto shaderSource = sourceFromFile(ty, file);
232shaderSource.intDefines = settings.intDefines;
233shaderSource.floatDefines = settings.floatDefines;
234if (!setupShaderFromSource(std::move(shaderSource))) {
235return false;
236}
237}
238
239for (auto shader : settings.shaderSources) {
240auto ty = shader.first;
241auto source = shader.second;
242Source shaderSource{ty, source, settings.sourceDirectoryPath};
243shaderSource.intDefines = settings.intDefines;
244shaderSource.floatDefines = settings.floatDefines;
245if (!setupShaderFromSource(std::move(shaderSource))) {
246return false;
247}
248}
249
250if (ofIsGLProgrammableRenderer() && settings.bindDefaults) {
251bindDefaults();
252}
253
254return linkProgram();
255}
256
257#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)
258//--------------------------------------------------------------
259bool ofShader::setup(const TransformFeedbackSettings & settings) {
260for (auto shader : settings.shaderFiles) {
261auto ty = shader.first;
262auto file = shader.second;
263auto shaderSource = sourceFromFile(ty, file);
264shaderSource.intDefines = settings.intDefines;
265shaderSource.floatDefines = settings.floatDefines;
266if (!setupShaderFromSource(std::move(shaderSource))) {
267return false;
268}
269}
270
271for (auto shader : settings.shaderSources) {
272auto ty = shader.first;
273auto source = shader.second;
274Source shaderSource{ty, source, settings.sourceDirectoryPath};
275shaderSource.intDefines = settings.intDefines;
276shaderSource.floatDefines = settings.floatDefines;
277if (!setupShaderFromSource(std::move(shaderSource))) {
278return false;
279}
280}
281
282if (ofIsGLProgrammableRenderer() && settings.bindDefaults) {
283bindDefaults();
284}
285
286if (!settings.varyingsToCapture.empty()) {
287std::vector<const char*> varyings(settings.varyingsToCapture.size());
288std::transform(settings.varyingsToCapture.begin(), settings.varyingsToCapture.end(), varyings.begin(), [](const std::string & str) {
289return str.c_str();
290});
291glTransformFeedbackVaryings(getProgram(), varyings.size(), varyings.data(), settings.bufferMode);
292}
293return linkProgram();
294}
295#endif
296
297//--------------------------------------------------------------
298bool ofShader::setupShaderFromFile(GLenum type, const of::filesystem::path & filename) {
299ofBuffer buffer = ofBufferFromFile(filename);
300// we need to make absolutely sure to have an absolute path here, so that any #includes
301// within the shader files have a root directory to traverse from.
302auto absoluteFilePath = ofFilePath::getAbsolutePath(filename, true);
303auto sourceDirectoryPath = ofFilePath::getEnclosingDirectory(absoluteFilePath,false);
304if(buffer.size()) {
305return setupShaderFromSource(type, buffer.getText(), sourceDirectoryPath);
306} else {
307ofLogError("ofShader") << "setupShaderFromFile(): couldn't load " << nameForType(type) << " shader " << " from \"" << absoluteFilePath << "\"";
308return false;
309}
310}
311
312//--------------------------------------------------------------
313ofShader::Source ofShader::sourceFromFile(GLenum type, const of::filesystem::path& filename) {
314ofBuffer buffer = ofBufferFromFile(filename);
315// we need to make absolutely sure to have an absolute path here, so that any #includes
316// within the shader files have a root directory to traverse from.
317auto absoluteFilePath = ofFilePath::getAbsolutePath(filename, true);
318auto sourceDirectoryPath = ofFilePath::getEnclosingDirectory(absoluteFilePath,false);
319if(buffer.size()) {
320// return Source{type, buffer.getText(), sourceDirectoryPath.string() };
321return Source{type, buffer.getText(), sourceDirectoryPath };
322} else {
323ofLogError("ofShader") << "setupShaderFromFile(): couldn't load " << nameForType(type) << " shader " << " from \"" << absoluteFilePath << "\"";
324return Source{};
325}
326}
327
328//--------------------------------------------------------------
329// FIXME: change to of::filesystem
330bool ofShader::setupShaderFromSource(GLenum type, string source, string sourceDirectoryPath) {
331return setupShaderFromSource({type, source, sourceDirectoryPath});
332}
333
334
335//--------------------------------------------------------------
336bool ofShader::setupShaderFromSource(ofShader::Source && source){
337unload();
338
339// create program if it doesn't exist already
340checkAndCreateProgram();
341GLuint clearErrors = glGetError(); //needed for some users to clear gl errors
342if( clearErrors != GL_NO_ERROR ){
343ofLogVerbose("ofShader") << "setupShaderFromSource(): OpenGL error after checkAndCreateProgram() (probably harmless): error " << clearErrors;
344}
345
346// create shader
347GLuint shaderId = glCreateShader(source.type);
348if(shaderId == 0) {
349ofLogError("ofShader") << "setupShaderFromSource(): failed creating " << nameForType(source.type) << " shader";
350return false;
351} else {
352// if the shader object has been allocated successfully on the GPU
353// we must retain it so that it can be de-allocated again, once
354// this ofShader object has been discarded, or re-allocated.
355// we need to do this at this point in the code path, since early
356// return statements might prevent us from retaining later.
357retainShader(shaderId);
358}
359
360// look for OF_GLSL_SHADER_HEADER header placeholder
361// this will swap the glsl version based on the OpenGL version set in main.cpp
362// note this won't always work, but is handy for switching between compatible versions of GLSL based on the system
363if( ofIsStringInString(source.source, "OF_GLSL_SHADER_HEADER") ){
364ofStringReplace(source.source, "OF_GLSL_SHADER_HEADER", ofGLSLGetDefaultHeader());
365}
366
367// parse for includes
368source.expandedSource = parseForIncludes( source.source, source.directoryPath );
369
370// parse and set defines
371for (auto& define : source.intDefines) {
372const auto& name = define.first;
373const auto& value = define.second;
374std::regex re_define("#define[ \t]+" + name + "[ \t]+(([1-9][0-9]*)|(0([xX][0-9a-fA-F]+)?))");
375source.expandedSource = std::regex_replace(source.expandedSource, re_define, "#define " + name + " " + std::to_string(value));
376}
377
378for (auto& define : source.floatDefines) {
379const auto& name = define.first;
380const auto& value = define.second;
381std::regex re_define("#define[ \t]+" + name + "[ \t]+[0-9]*(\\.[0-9]*f?)?");
382source.expandedSource = std::regex_replace(source.expandedSource, re_define, "#define " + name + " " + std::to_string(value));
383}
384
385// store source code (that's the expanded source with all includes copied in)
386// we need to store this here, and before shader compilation,
387// so that any shader compilation errors can be
388// traced down to the correct shader source code line.
389shaders[source.type] = { shaderId, std::move(source) };
390auto & shader = shaders[source.type];
391
392// compile shader
393const char* sptr = shader.source.expandedSource.c_str();
394int ssize = shader.source.expandedSource.size();
395glShaderSource(shaderId, 1, &sptr, &ssize);
396glCompileShader(shaderId);
397
398// check compile status
399GLint status = GL_FALSE;
400glGetShaderiv(shaderId, GL_COMPILE_STATUS, &status);
401GLuint err = glGetError();
402if (err != GL_NO_ERROR){
403ofLogError("ofShader") << "setupShaderFromSource(): OpenGL generated error " << err << " trying to get the compile status for a " << nameForType(shader.source.type) << " shader, does your video card support this?";
404return false;
405}
406
407if(status == GL_TRUE){
408ofLogVerbose("ofShader") << "setupShaderFromSource(): " << nameForType(shader.source.type) + " shader compiled";
409#ifdef TARGET_EMSCRIPTEN
410checkShaderInfoLog(shaderId, source.type, OF_LOG_VERBOSE);
411#else
412checkShaderInfoLog(shaderId, source.type, OF_LOG_WARNING);
413#endif
414}else if (status == GL_FALSE) {
415ofLogError("ofShader") << "setupShaderFromSource(): " << nameForType(shader.source.type) + " shader failed to compile";
416checkShaderInfoLog(shaderId, source.type, OF_LOG_ERROR);
417return false;
418}
419return true;
420}
421
422/*
423* Parse for GLSL includes based on
424* https://www.opengl.org/discussion_boards/showthread.php/169209-include-in-glsl?p=1192415&viewfull=1#post1192415
425*/
426
427//--------------------------------------------------------------
428string ofShader::parseForIncludes( const string& source, const of::filesystem::path& sourceDirectoryPath) {
429vector<string> included;
430return parseForIncludes( source, included, 0, sourceDirectoryPath);
431}
432
433//--------------------------------------------------------------
434// FIXME: update to use fs::path in vector and source
435string ofShader::parseForIncludes( const string& source, vector<string>& included, int level, const of::filesystem::path& sourceDirectoryPath) {
436
437if ( level > 32 ) {
438ofLogError( "ofShader", "glsl header inclusion depth limit reached, might be caused by cyclic header inclusion" );
439return "";
440}
441
442stringstream output;
443stringstream input;
444input << source;
445
446auto match_pragma_include = [](const std::string& s_, std::string& filename_) -> bool {
447filename_ = "";
448std::istringstream s(s_);
449s >> std::ws; // eat up any leading whitespace.
450
451if (s.peek() != '#') return false;
452// -----| invariant: found '#'
453s.seekg(1, std::ios::cur); // move forward one character
454
455std::string p, i, f;
456
457// while skipping whitespace, read in tokens for: pragma, include, and filename
458s >> std::skipws >> p >> i >> f;
459
460if (p.empty())
461return false;
462else if (p == "include") {
463f = i;
464i = p;
465}
466else if (p != "pragma")
467return false;
468
469if (i.empty() || (f.size() < 2) )
470return false;
471
472if (i != "include") return false;
473
474// first and last character of filename token must match and be either
475// '<' and '>', or '"
476
477if (f[0] == '<' && f[f.size()-1] != '>') return false; //< mismatching brackets
478
479if ((f[0] == '"' || f[0] == '\'') && (f[0] != f[f.size()-1])) return false; // mismatching quotes
480
481// invariant: filename properly quoted.
482
483filename_ = f.substr(1,f.size()-2);
484
485return true;
486};
487
488// once std::regex is available across the board, use this regex in favour of the above lambda:
489// std::regex re("^\\s*#\\s*pragma\\s+include\\s+[\"<](.*)[\">].*");
490
491string line;
492while( std::getline( input, line ) ) {
493
494string include;
495
496if (!match_pragma_include(line, include)){
497output << line << endl;
498continue;
499};
500
501// --------| invariant: '#pragma include' has been requested
502
503if ( std::find( included.begin(), included.end(), include ) != included.end() ) {
504ofLogVerbose("ofShader") << include << " already included";
505continue;
506}
507
508// we store the absolute paths so as have (more) unique file identifiers.
509// FIXME: Included can be a vector of of::filesystem::path in near future
510include = ofFile(
511sourceDirectoryPath / include
512// ).getAbsolutePath().string();
513).getAbsolutePath();
514
515included.push_back( include );
516
517ofBuffer buffer = ofBufferFromFile( include );
518if ( !buffer.size() ) {
519ofLogError("ofShader") <<"Could not open glsl include file " << include;
520continue;
521}
522
523auto currentDir = ofFile(include).getEnclosingDirectory();
524output << parseForIncludes( buffer.getText(), included, level + 1, currentDir ) << endl;
525}
526
527return output.str();
528}
529
530//--------------------------------------------------------------
531string ofShader::getShaderSource(GLenum type) const{
532auto source = shaders.find(type);
533if ( source != shaders.end()) {
534return source->second.source.expandedSource;
535} else {
536ofLogError("ofShader") << "No shader source for shader of type: " << nameForType(type);
537return "";
538}
539}
540
541//--------------------------------------------------------------
542void ofShader::setGeometryInputType(GLenum type) {
543#ifndef TARGET_OPENGLES
544checkAndCreateProgram();
545glProgramParameteri(program, GL_GEOMETRY_INPUT_TYPE_EXT, type);
546#endif
547}
548
549//--------------------------------------------------------------
550void ofShader::setGeometryOutputType(GLenum type) {
551#ifndef TARGET_OPENGLES
552checkAndCreateProgram();
553glProgramParameteri(program, GL_GEOMETRY_OUTPUT_TYPE_EXT, type);
554#endif
555}
556
557//--------------------------------------------------------------
558void ofShader::setGeometryOutputCount(int count) {
559#ifndef TARGET_OPENGLES
560checkAndCreateProgram();
561glProgramParameteri(program, GL_GEOMETRY_VERTICES_OUT_EXT, count);
562#endif
563}
564
565//--------------------------------------------------------------
566int ofShader::getGeometryMaxOutputCount() const{
567#ifndef TARGET_OPENGLES
568int temp;
569glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT, &temp);
570return temp;
571#else
572return 0;
573#endif
574}
575
576//--------------------------------------------------------------
577bool ofShader::checkProgramLinkStatus() {
578GLint status;
579glGetProgramiv(program, GL_LINK_STATUS, &status);
580GLuint err = glGetError();
581if (err != GL_NO_ERROR){
582ofLogError("ofShader") << "checkProgramLinkStatus(): OpenGL generated error " << err << " trying to get the program link status, does your video card support shader programs?";
583return false;
584}
585if(status == GL_TRUE)
586ofLogVerbose("ofShader") << "checkProgramLinkStatus(): program " << program << " linked";
587else if (status == GL_FALSE) {
588ofLogError("ofShader") << "checkProgramLinkStatus(): program failed to link";
589checkProgramInfoLog();
590return false;
591}
592return true;
593}
594
595//--------------------------------------------------------------
596void ofShader::checkShaderInfoLog(GLuint shader, GLenum type, ofLogLevel logLevel) {
597GLsizei infoLength;
598glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
599if (infoLength > 1) {
600ofBuffer infoBuffer;
601infoBuffer.allocate(infoLength);
602glGetShaderInfoLog(shader, infoLength, &infoLength, infoBuffer.getData());
603ofLog(logLevel, "ofShader: %s shader reports:\n%s", nameForType(type).c_str(), infoBuffer.getText().c_str());
604#if (!defined(TARGET_LINUX) || defined(GCC_HAS_REGEX))
605if (shaders.find(type) != shaders.end()) {
606// The following regexp should match shader compiler error messages by Nvidia and ATI.
607// Unfortunately, each vendor's driver formats error messages slightly different.
608std::regex nvidia_ati("^.*[(:]{1}(\\d+)[:)]{1}.*");
609std::regex intel("^[0-9]+:([0-9]+)\\([0-9]+\\):.*$");
610std::smatch matches;
611string infoString = ofTrim(infoBuffer);
612if (std::regex_search(infoString, matches, intel) || std::regex_search(infoString, matches, nvidia_ati)){
613ofBuffer buf;
614buf.set(shaders[type].source.expandedSource);
615ofBuffer::Line line = buf.getLines().begin();
616int offendingLineNumber = ofToInt(matches[1]);
617ostringstream msg;
618msg << "ofShader: " + nameForType(type) + ", offending line " << offendingLineNumber << ":"<< endl;
619for(int i=0; line != buf.getLines().end(); line++, i++ ){
620string s = *line;
621if ( i >= offendingLineNumber -3 && i < offendingLineNumber + 2 ){
622msg << "\t" << setw(5) << (i+1) << "\t" << s << endl;
623}
624}
625ofLog(logLevel) << msg.str();
626}else{
627ofLog(logLevel) << shaders[type].source.expandedSource;
628}
629}
630#endif
631}
632}
633
634//--------------------------------------------------------------
635void ofShader::checkProgramInfoLog() {
636GLsizei infoLength;
637glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength);
638if (infoLength > 1) {
639ofBuffer infoBuffer;
640infoBuffer.allocate(infoLength);
641glGetProgramInfoLog(program, infoLength, &infoLength, infoBuffer.getData());
642// TODO: it appears that Raspberry Pi only reports shader errors whilst linking,
643// but then it becomes hard to figure out whether the fragment or the
644// vertex shader caused the error.
645// We need to find a robust way of extracing this information from
646// the log, and unfortunately can't use regex whilst gcc on RPi is assumed to
647// be < 4.9, which is the first version fully supporting this c++11 feature.
648string msg = "ofShader: program reports:\n";
649ofLogError("ofShader") << msg + infoBuffer.getText();
650#ifdef TARGET_RAPSBERRY_PI
651for(auto it: shaders){
652ofLogNotice("ofShader") << it.second.expandedSource;
653}
654#endif
655}
656}
657
658
659
660//--------------------------------------------------------------
661void ofShader::checkAndCreateProgram() {
662#ifndef TARGET_OPENGLES
663if(GL_ARB_shader_objects) {
664#else
665if(ofIsGLProgrammableRenderer()){
666#endif
667if(program == 0) {
668ofLogVerbose("ofShader") << "checkAndCreateProgram(): creating GLSL program";
669program = glCreateProgram();
670retainProgram(program);
671}
672} else {
673ofLogError("ofShader") << "sorry, it looks like you can't run 'ARB_shader_objects'";
674ofLogError("ofShader") << "please check the capabilites of your graphics card: http://www.ozone3d.net/gpu_caps_viewer";
675}
676}
677
678//--------------------------------------------------------------
679bool ofShader::linkProgram() {
680if(shaders.empty()) {
681ofLogError("ofShader") << "linkProgram(): trying to link GLSL program, but no shaders created yet";
682} else {
683checkAndCreateProgram();
684
685for(auto it: shaders){
686auto shader = it.second;
687if(shader.id>0) {
688ofLogVerbose("ofShader") << "linkProgram(): attaching " << nameForType(it.first) << " shader to program " << program;
689glAttachShader(program, shader.id);
690}
691}
692
693glLinkProgram(program);
694
695checkProgramLinkStatus();
696
697
698// Pre-cache all active uniforms
699GLint numUniforms = 0;
700glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numUniforms);
701
702GLint uniformMaxLength = 0;
703glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxLength);
704
705GLint count = -1;
706GLenum type = 0;
707GLsizei length;
708GLint location;
709vector<GLchar> uniformName(uniformMaxLength);
710for(GLint i = 0; i < numUniforms; i++) {
711glGetActiveUniform(program, i, uniformMaxLength, &length, &count, &type, uniformName.data());
712string name(uniformName.begin(), uniformName.begin()+length);
713// some drivers return uniform_name[0] for array uniforms
714// instead of the real uniform name
715location = glGetUniformLocation(program, name.c_str());
716if (location == -1) continue; // ignore uniform blocks
717
718uniformsCache[name] = location;
719auto arrayPos = name.find('[');
720if(arrayPos!=std::string::npos){
721name = name.substr(0, arrayPos);
722uniformsCache[name] = location;
723}
724}
725
726#ifndef TARGET_OPENGLES
727#ifdef GLEW_ARB_uniform_buffer_object
728if(GLEW_ARB_uniform_buffer_object) {
729// Pre-cache all active uniforms blocks
730GLint numUniformBlocks = 0;
731glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
732
733count = -1;
734type = 0;
735vector<GLchar> uniformBlockName(uniformMaxLength);
736for(GLint i = 0; i < numUniformBlocks; i++) {
737glGetActiveUniformBlockName(program, i, uniformMaxLength, &length, uniformBlockName.data() );
738string name(uniformBlockName.begin(), uniformBlockName.begin()+length);
739uniformBlocksCache[name] = glGetUniformBlockIndex(program, name.c_str());
740}
741}
742#endif
743#endif
744
745#ifdef TARGET_ANDROID
746ofAddListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL);
747#endif
748
749// bLoaded means we have loaded shaders onto the graphics card;
750// it doesn't necessarily mean that these shaders have compiled and linked successfully.
751bLoaded = true;
752}
753return bLoaded;
754}
755
756
757//--------------------------------------------------------------
758#ifdef TARGET_ANDROID
759void ofShader::unloadGL(){
760for(auto it: shaders) {
761auto shader = it.second;
762if(shader.id) {
763releaseShader(program,shader.id);
764}
765}
766
767if (program) {
768releaseProgram(program);
769program = 0;
770}
771bLoaded = false;
772ofAddListener(ofxAndroidEvents().reloadGL,this,&ofShader::reloadGL);
773}
774
775void ofShader::reloadGL(){
776auto source = shaders;
777auto bindings = attributesBindingsCache;
778shaders.clear();
779uniformsCache.clear();
780#ifndef TARGET_OPENGLES
781#ifdef GLEW_ARB_uniform_buffer_object // Core in OpenGL 3.1
782uniformBlocksCache.clear();
783#endif
784#endif
785attributesBindingsCache.clear();
786for(auto & shader: source){
787auto source = shader.second.source;
788setupShaderFromSource(std::move(shader.second.source));
789}
790for(auto binding: bindings){
791bindAttribute(binding.second, binding.first);
792}
793linkProgram();
794}
795#endif
796
797//--------------------------------------------------------------
798void ofShader::bindAttribute(GLuint location, const string & name) const{
799attributesBindingsCache[name] = location;
800glBindAttribLocation(program,location,name.c_str());
801}
802
803//--------------------------------------------------------------
804bool ofShader::bindDefaults(){
805if(shaders.empty()) {
806ofLogError("ofShader") << "bindDefaults(): trying to link GLSL program, but no shaders created yet";
807return false;
808} else {
809bindAttribute(ofShader::POSITION_ATTRIBUTE,::POSITION_ATTRIBUTE);
810bindAttribute(ofShader::COLOR_ATTRIBUTE,::COLOR_ATTRIBUTE);
811bindAttribute(ofShader::NORMAL_ATTRIBUTE,::NORMAL_ATTRIBUTE);
812bindAttribute(ofShader::TEXCOORD_ATTRIBUTE,::TEXCOORD_ATTRIBUTE);
813return true;
814}
815
816}
817
818//--------------------------------------------------------------
819void ofShader::unload() {
820if(bLoaded) {
821for(auto it: shaders) {
822auto shader = it.second;
823if(shader.id) {
824ofLogVerbose("ofShader") << "unload(): detaching and deleting " << nameForType(shader.source.type) << " shader from program " << program;
825releaseShader(program,shader.id);
826}
827}
828
829if (program) {
830releaseProgram(program);
831program = 0;
832}
833
834shaders.clear();
835uniformsCache.clear();
836#ifndef TARGET_OPENGLES
837#ifdef GLEW_ARB_uniform_buffer_object // Core in OpenGL 3.1
838uniformBlocksCache.clear();
839#endif
840#endif
841attributesBindingsCache.clear();
842#ifdef TARGET_ANDROID
843ofRemoveListener(ofxAndroidEvents().reloadGL,this,&ofShader::reloadGL);
844ofRemoveListener(ofxAndroidEvents().unloadGL,this,&ofShader::unloadGL);
845#endif
846}
847bLoaded = false;
848}
849
850//--------------------------------------------------------------
851bool ofShader::isLoaded() const{
852return bLoaded;
853}
854
855//--------------------------------------------------------------
856void ofShader::begin() const{
857ofGetGLRenderer()->bind(*this);
858}
859
860//--------------------------------------------------------------
861void ofShader::end() const{
862ofGetGLRenderer()->unbind(*this);
863}
864
865#if !defined(TARGET_OPENGLES) || defined(TARGET_EMSCRIPTEN)
866//--------------------------------------------------------------
867void ofShader::beginTransformFeedback(GLenum mode) const {
868begin();
869glEnable(GL_RASTERIZER_DISCARD);
870glBeginTransformFeedback(mode);
871}
872
873//--------------------------------------------------------------
874void ofShader::beginTransformFeedback(GLenum mode, const TransformFeedbackRangeBinding & binding) const {
875binding.buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index, binding.offset, binding.size);
876beginTransformFeedback(mode);
877}
878
879//--------------------------------------------------------------
880void ofShader::beginTransformFeedback(GLenum mode, const std::vector<TransformFeedbackRangeBinding> & bindings) const {
881for (auto & binding : bindings) {
882binding.buffer.bindRange(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index, binding.offset, binding.size);
883}
884beginTransformFeedback(mode);
885}
886
887//--------------------------------------------------------------
888void ofShader::beginTransformFeedback(GLenum mode, const TransformFeedbackBaseBinding & binding) const {
889binding.buffer.bindBase(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index);
890beginTransformFeedback(mode);
891}
892
893//--------------------------------------------------------------
894void ofShader::beginTransformFeedback(GLenum mode, const std::vector<TransformFeedbackBaseBinding> & bindings) const {
895for (auto & binding : bindings) {
896binding.buffer.bindBase(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index);
897}
898beginTransformFeedback(mode);
899}
900
901//--------------------------------------------------------------
902void ofShader::endTransformFeedback() const {
903glEndTransformFeedback();
904glDisable(GL_RASTERIZER_DISCARD);
905end();
906}
907
908//--------------------------------------------------------------
909void ofShader::endTransformFeedback(const TransformFeedbackRangeBinding & binding) const {
910binding.buffer.unbindRange(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index);
911endTransformFeedback();
912}
913
914//--------------------------------------------------------------
915void ofShader::endTransformFeedback(const std::vector<TransformFeedbackRangeBinding> & bindings) const {
916for (auto & binding : bindings) {
917binding.buffer.unbindRange(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index);
918}
919endTransformFeedback();
920}
921
922//--------------------------------------------------------------
923void ofShader::endTransformFeedback(const TransformFeedbackBaseBinding & binding) const {
924binding.buffer.unbindBase(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index);
925endTransformFeedback();
926}
927
928//--------------------------------------------------------------
929void ofShader::endTransformFeedback(const std::vector<TransformFeedbackBaseBinding> & bindings) const {
930for (auto & binding : bindings) {
931binding.buffer.unbindBase(GL_TRANSFORM_FEEDBACK_BUFFER, binding.index);
932}
933endTransformFeedback();
934}
935#endif
936
937#if !defined(TARGET_OPENGLES) && defined(glDispatchCompute)
938//--------------------------------------------------------------
939void ofShader::dispatchCompute(GLuint x, GLuint y, GLuint z) const{
940glDispatchCompute(x,y,z);
941}
942#endif
943
944//--------------------------------------------------------------
945void ofShader::setUniformTexture(const string & name, const ofBaseHasTexture& img, int textureLocation) const{
946setUniformTexture(name, img.getTexture(), textureLocation);
947}
948
949//--------------------------------------------------------------
950void ofShader::setUniformTexture(const string & name, int textureTarget, GLint textureID, int textureLocation) const{
951if(bLoaded) {
952glActiveTexture(GL_TEXTURE0 + textureLocation);
953if (!ofIsGLProgrammableRenderer()){
954glEnable(textureTarget);
955glBindTexture(textureTarget, textureID);
956glDisable(textureTarget);
957} else {
958glBindTexture(textureTarget, textureID);
959}
960setUniform1i(name, textureLocation);
961glActiveTexture(GL_TEXTURE0);
962}
963}
964
965//--------------------------------------------------------------
966void ofShader::setUniformTexture(const string & name, const ofTexture& tex, int textureLocation) const{
967if(bLoaded) {
968ofTextureData texData = tex.getTextureData();
969glActiveTexture(GL_TEXTURE0 + textureLocation);
970if (!ofIsGLProgrammableRenderer()){
971glEnable(texData.textureTarget);
972glBindTexture(texData.textureTarget, texData.textureID);
973#ifndef TARGET_OPENGLES
974if (texData.bufferId != 0) {
975glTexBuffer(GL_TEXTURE_BUFFER, texData.glInternalFormat, texData.bufferId);
976}
977#endif
978glDisable(texData.textureTarget);
979} else {
980glBindTexture(texData.textureTarget, texData.textureID);
981#ifndef TARGET_OPENGLES
982if (texData.bufferId != 0) {
983glTexBuffer(GL_TEXTURE_BUFFER, texData.glInternalFormat, texData.bufferId);
984}
985#endif
986}
987setUniform1i(name, textureLocation);
988glActiveTexture(GL_TEXTURE0);
989}
990}
991
992//--------------------------------------------------------------
993void ofShader::setUniform1i(const string & name, int v1) const{
994if(bLoaded) {
995int loc = getUniformLocation(name);
996if (loc != -1) glUniform1i(loc, v1);
997}
998}
999
1000//--------------------------------------------------------------
1001void ofShader::setUniform2i(const string & name, int v1, int v2) const{
1002if(bLoaded) {
1003int loc = getUniformLocation(name);
1004if (loc != -1) glUniform2i(loc, v1, v2);
1005}
1006}
1007
1008//--------------------------------------------------------------
1009void ofShader::setUniform3i(const string & name, int v1, int v2, int v3) const{
1010if(bLoaded) {
1011int loc = getUniformLocation(name);
1012if (loc != -1) glUniform3i(loc, v1, v2, v3);
1013}
1014}
1015
1016//--------------------------------------------------------------
1017void ofShader::setUniform4i(const string & name, int v1, int v2, int v3, int v4) const{
1018if(bLoaded) {
1019int loc = getUniformLocation(name);
1020if (loc != -1) glUniform4i(loc, v1, v2, v3, v4);
1021}
1022}
1023
1024//--------------------------------------------------------------
1025void ofShader::setUniform1f(const string & name, float v1) const{
1026if(bLoaded) {
1027int loc = getUniformLocation(name);
1028if (loc != -1) glUniform1f(loc, v1);
1029}
1030}
1031
1032//--------------------------------------------------------------
1033void ofShader::setUniform2f(const string & name, float v1, float v2) const{
1034if(bLoaded) {
1035int loc = getUniformLocation(name);
1036if (loc != -1) glUniform2f(loc, v1, v2);
1037}
1038}
1039
1040//--------------------------------------------------------------
1041void ofShader::setUniform3f(const string & name, float v1, float v2, float v3) const{
1042if(bLoaded) {
1043int loc = getUniformLocation(name);
1044if (loc != -1) glUniform3f(loc, v1, v2, v3);
1045}
1046}
1047
1048//--------------------------------------------------------------
1049void ofShader::setUniform4f(const string & name, float v1, float v2, float v3, float v4) const{
1050if(bLoaded) {
1051int loc = getUniformLocation(name);
1052if (loc != -1) glUniform4f(loc, v1, v2, v3, v4);
1053}
1054}
1055
1056
1057//--------------------------------------------------------------
1058void ofShader::setUniform2f(const string & name, const glm::vec2 & v) const{
1059setUniform2f(name,v.x,v.y);
1060}
1061
1062//--------------------------------------------------------------
1063void ofShader::setUniform3f(const string & name, const glm::vec3 & v) const{
1064setUniform3f(name,v.x,v.y,v.z);
1065}
1066
1067//--------------------------------------------------------------
1068void ofShader::setUniform4f(const string & name, const glm::vec4 & v) const{
1069setUniform4f(name,v.x,v.y,v.z,v.w);
1070}
1071
1072//--------------------------------------------------------------
1073void ofShader::setUniform4f(const string & name, const ofFloatColor & v) const{
1074setUniform4f(name,v.r,v.g,v.b,v.a);
1075}
1076
1077//--------------------------------------------------------------
1078void ofShader::setUniform1iv(const string & name, const int* v, int count) const{
1079if(bLoaded) {
1080int loc = getUniformLocation(name);
1081if (loc != -1) glUniform1iv(loc, count, v);
1082}
1083}
1084
1085//--------------------------------------------------------------
1086void ofShader::setUniform2iv(const string & name, const int* v, int count) const{
1087if(bLoaded) {
1088int loc = getUniformLocation(name);
1089if (loc != -1) glUniform2iv(loc, count, v);
1090}
1091}
1092
1093//--------------------------------------------------------------
1094void ofShader::setUniform3iv(const string & name, const int* v, int count) const{
1095if(bLoaded) {
1096int loc = getUniformLocation(name);
1097if (loc != -1) glUniform3iv(loc, count, v);
1098}
1099}
1100
1101//--------------------------------------------------------------
1102void ofShader::setUniform4iv(const string & name, const int* v, int count) const{
1103if(bLoaded) {
1104int loc = getUniformLocation(name);
1105if (loc != -1) glUniform4iv(loc, count, v);
1106}
1107}
1108
1109//--------------------------------------------------------------
1110void ofShader::setUniform1fv(const string & name, const float* v, int count) const{
1111if(bLoaded) {
1112int loc = getUniformLocation(name);
1113if (loc != -1) glUniform1fv(loc, count, v);
1114}
1115}
1116
1117//--------------------------------------------------------------
1118void ofShader::setUniform2fv(const string & name, const float* v, int count) const{
1119if(bLoaded) {
1120int loc = getUniformLocation(name);
1121if (loc != -1) glUniform2fv(loc, count, v);
1122}
1123}
1124
1125//--------------------------------------------------------------
1126void ofShader::setUniform3fv(const string & name, const float* v, int count) const{
1127if(bLoaded) {
1128int loc = getUniformLocation(name);
1129if (loc != -1) glUniform3fv(loc, count, v);
1130}
1131}
1132
1133//--------------------------------------------------------------
1134void ofShader::setUniform4fv(const string & name, const float* v, int count) const{
1135if(bLoaded) {
1136int loc = getUniformLocation(name);
1137if (loc != -1) glUniform4fv(loc, count, v);
1138}
1139}
1140
1141//--------------------------------------------------------------
1142void ofShader::setUniforms(const ofParameterGroup & parameters) const{
1143for(std::size_t i=0;i<parameters.size();i++){
1144if(parameters[i].type()==typeid(ofParameter<int>).name()){
1145setUniform1i(parameters[i].getEscapedName(),parameters[i].cast<int>());
1146}else if(parameters[i].type()==typeid(ofParameter<float>).name()){
1147setUniform1f(parameters[i].getEscapedName(),parameters[i].cast<float>());
1148}else if(parameters[i].type()==typeid(ofParameter<glm::vec2>).name()){
1149setUniform2f(parameters[i].getEscapedName(),parameters[i].cast<glm::vec2>());
1150}else if(parameters[i].type()==typeid(ofParameter<glm::vec3>).name()){
1151setUniform3f(parameters[i].getEscapedName(),parameters[i].cast<glm::vec3>());
1152}else if(parameters[i].type()==typeid(ofParameter<glm::vec4>).name()){
1153setUniform4f(parameters[i].getEscapedName(),parameters[i].cast<glm::vec4>());
1154}else if(parameters[i].type()==typeid(ofParameter<ofVec2f>).name()){
1155setUniform2f(parameters[i].getEscapedName(),parameters[i].cast<glm::vec2>());
1156}else if(parameters[i].type()==typeid(ofParameter<ofVec3f>).name()){
1157setUniform3f(parameters[i].getEscapedName(),parameters[i].cast<glm::vec3>());
1158}else if(parameters[i].type()==typeid(ofParameter<ofVec4f>).name()){
1159setUniform4f(parameters[i].getEscapedName(),parameters[i].cast<glm::vec4>());
1160}else if(parameters[i].type()==typeid(ofParameterGroup).name()){
1161setUniforms((ofParameterGroup&)parameters[i]);
1162}
1163}
1164}
1165
1166//--------------------------------------------------------------
1167void ofShader::setUniformMatrix3f(const string & name, const glm::mat3 & m, int count) const{
1168if(bLoaded) {
1169int loc = getUniformLocation(name);
1170if (loc != -1) glUniformMatrix3fv(loc, count, GL_FALSE, glm::value_ptr(m));
1171}
1172}
1173
1174//--------------------------------------------------------------
1175void ofShader::setUniformMatrix4f(const string & name, const glm::mat4 & m, int count) const{
1176if(bLoaded) {
1177int loc = getUniformLocation(name);
1178if (loc != -1) glUniformMatrix4fv(loc, count, GL_FALSE, glm::value_ptr(m));
1179}
1180}
1181
1182#ifndef TARGET_OPENGLES
1183//--------------------------------------------------------------
1184void ofShader::setAttribute1s(GLint location, short v1) const{
1185if(bLoaded)
1186glVertexAttrib1s(location, v1);
1187}
1188
1189//--------------------------------------------------------------
1190void ofShader::setAttribute2s(GLint location, short v1, short v2) const{
1191if(bLoaded)
1192glVertexAttrib2s(location, v1, v2);
1193}
1194
1195//--------------------------------------------------------------
1196void ofShader::setAttribute3s(GLint location, short v1, short v2, short v3) const{
1197if(bLoaded)
1198glVertexAttrib3s(location, v1, v2, v3);
1199}
1200
1201//--------------------------------------------------------------
1202void ofShader::setAttribute4s(GLint location, short v1, short v2, short v3, short v4) const{
1203if(bLoaded)
1204glVertexAttrib4s(location, v1, v2, v3, v4);
1205}
1206#endif
1207
1208//--------------------------------------------------------------
1209void ofShader::setAttribute1f(GLint location, float v1) const{
1210if(bLoaded)
1211glVertexAttrib1f(location, v1);
1212}
1213
1214//--------------------------------------------------------------
1215void ofShader::setAttribute2f(GLint location, float v1, float v2) const{
1216if(bLoaded)
1217glVertexAttrib2f(location, v1, v2);
1218}
1219
1220//--------------------------------------------------------------
1221void ofShader::setAttribute3f(GLint location, float v1, float v2, float v3) const{
1222if(bLoaded)
1223glVertexAttrib3f(location, v1, v2, v3);
1224}
1225
1226//--------------------------------------------------------------
1227void ofShader::setAttribute4f(GLint location, float v1, float v2, float v3, float v4) const{
1228if(bLoaded)
1229glVertexAttrib4f(location, v1, v2, v3, v4);
1230}
1231
1232//--------------------------------------------------------------
1233void ofShader::setAttribute1fv(const string & name, const float* v, GLsizei stride) const{
1234if(bLoaded){
1235GLint location = getAttributeLocation(name);
1236if (location != -1) {
1237glVertexAttribPointer(location, 1, GL_FLOAT, GL_FALSE, stride, v);
1238glEnableVertexAttribArray(location);
1239}
1240}
1241}
1242
1243//--------------------------------------------------------------
1244void ofShader::setAttribute2fv(const string & name, const float* v, GLsizei stride) const{
1245if(bLoaded){
1246GLint location = getAttributeLocation(name);
1247if (location != -1) {
1248glVertexAttribPointer(location, 2, GL_FLOAT, GL_FALSE, stride, v);
1249glEnableVertexAttribArray(location);
1250}
1251}
1252
1253}
1254
1255//--------------------------------------------------------------
1256void ofShader::setAttribute3fv(const string & name, const float* v, GLsizei stride) const{
1257if(bLoaded){
1258GLint location = getAttributeLocation(name);
1259if (location != -1) {
1260glVertexAttribPointer(location, 3, GL_FLOAT, GL_FALSE, stride, v);
1261glEnableVertexAttribArray(location);
1262}
1263}
1264}
1265
1266//--------------------------------------------------------------
1267void ofShader::setAttribute4fv(const string & name, const float* v, GLsizei stride) const{
1268if(bLoaded){
1269GLint location = getAttributeLocation(name);
1270if (location != -1) {
1271glVertexAttribPointer(location, 4, GL_FLOAT, GL_FALSE, stride, v);
1272glEnableVertexAttribArray(location);
1273}
1274}
1275}
1276
1277#ifndef TARGET_OPENGLES
1278//--------------------------------------------------------------
1279void ofShader::setAttribute1d(GLint location, double v1) const{
1280if(bLoaded)
1281glVertexAttrib1d(location, v1);
1282}
1283
1284//--------------------------------------------------------------
1285void ofShader::setAttribute2d(GLint location, double v1, double v2) const{
1286if(bLoaded)
1287glVertexAttrib2d(location, v1, v2);
1288}
1289
1290//--------------------------------------------------------------
1291void ofShader::setAttribute3d(GLint location, double v1, double v2, double v3) const{
1292if(bLoaded)
1293glVertexAttrib3d(location, v1, v2, v3);
1294}
1295
1296//--------------------------------------------------------------
1297void ofShader::setAttribute4d(GLint location, double v1, double v2, double v3, double v4) const{
1298if(bLoaded)
1299glVertexAttrib4d(location, v1, v2, v3, v4);
1300}
1301#endif
1302
1303//--------------------------------------------------------------
1304GLint ofShader::getAttributeLocation(const string & name) const{
1305return glGetAttribLocation(program, name.c_str());
1306}
1307
1308//--------------------------------------------------------------
1309GLint ofShader::getUniformLocation(const string & name) const{
1310if(!bLoaded) return -1;
1311auto it = uniformsCache.find(name);
1312if (it == uniformsCache.end()){
1313return -1;
1314} else {
1315return it->second;
1316}
1317}
1318
1319#ifndef TARGET_OPENGLES
1320#ifdef GLEW_ARB_uniform_buffer_object
1321//--------------------------------------------------------------
1322GLint ofShader::getUniformBlockIndex(const string & name) const{
1323if(!bLoaded) return -1;
1324
1325if(GLEW_ARB_uniform_buffer_object) {
1326auto it = uniformBlocksCache.find(name);
1327if (it == uniformBlocksCache.end()){
1328return -1;
1329} else {
1330return it->second;
1331}
1332} else {
1333ofLogError("ofShader::getUniformBlockIndex") << "Sorry, it looks like you can't run 'ARB_uniform_buffer_object'";
1334return -1;
1335}
1336}
1337
1338//--------------------------------------------------------------
1339GLint ofShader::getUniformBlockBinding( const string & name ) const{
1340if(!bLoaded) return -1;
1341
1342if(GLEW_ARB_uniform_buffer_object) {
1343GLint index = getUniformBlockIndex(name);
1344if (index == -1) return -1;
1345
1346GLint blockBinding;
1347glGetActiveUniformBlockiv(program, index, GL_UNIFORM_BLOCK_BINDING, &blockBinding);
1348return blockBinding;
1349} else {
1350ofLogError("ofShader::getUniformBlockBinding") << "Sorry, it looks like you can't run 'ARB_uniform_buffer_object'";
1351return -1;
1352}
1353}
1354
1355//--------------------------------------------------------------
1356void ofShader::printActiveUniformBlocks() const{
1357if(GLEW_ARB_uniform_buffer_object) {
1358GLint numUniformBlocks = 0;
1359glGetProgramiv(program, GL_ACTIVE_UNIFORM_BLOCKS, &numUniformBlocks);
1360ofLogNotice("ofShader") << numUniformBlocks << " uniform blocks";
1361
1362GLint uniformBlockMaxLength = 0;
1363glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformBlockMaxLength);
1364
1365GLchar* uniformBlockName = new GLchar[uniformBlockMaxLength];
1366stringstream line;
1367for(GLint i = 0; i < numUniformBlocks; i++) {
1368GLsizei length;
1369GLint blockBinding;
1370GLsizei blockDataSize;
1371glGetActiveUniformBlockName(program, i, uniformBlockMaxLength, &length, uniformBlockName );
1372glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_BINDING, &blockBinding );
1373glGetActiveUniformBlockiv(program, i, GL_UNIFORM_BLOCK_DATA_SIZE, &blockDataSize );
1374
1375line << " [" << i << "] ";
1376for(int j = 0; j < length; j++) {
1377line << uniformBlockName[j];
1378}
1379line << " @ index " << getUniformBlockIndex( uniformBlockName ) << ", binding point " << blockBinding << ", size " << blockDataSize << " bytes";
1380ofLogNotice("ofShader") << line.str();
1381line.str("");
1382}
1383delete [] uniformBlockName;
1384} else {
1385ofLogError("ofShader::printActiveUniformBlocks") << "Sorry, it looks like you can't run 'ARB_uniform_buffer_object'";
1386}
1387}
1388
1389
1390void ofShader::bindUniformBlock(GLuint binding, const string & name) const{
1391if(bLoaded){
1392if(GLEW_ARB_uniform_buffer_object) {
1393GLint index = getUniformBlockIndex(name);
1394if (index != -1) {
1395glUniformBlockBinding( program, index, binding );
1396}
1397} else {
1398ofLogError("ofShader::bindUniformBlock") << "Sorry, it looks like you can't run 'ARB_uniform_buffer_object'";
1399}
1400}
1401}
1402#endif
1403#endif
1404
1405//--------------------------------------------------------------
1406void ofShader::printActiveUniforms() const{
1407GLint numUniforms = 0;
1408glGetProgramiv(program, GL_ACTIVE_UNIFORMS, &numUniforms);
1409ofLogNotice("ofShader") << numUniforms << " uniforms";
1410
1411GLint uniformMaxLength = 0;
1412glGetProgramiv(program, GL_ACTIVE_UNIFORM_MAX_LENGTH, &uniformMaxLength);
1413
1414GLint count = -1;
1415GLenum type = 0;
1416GLchar* uniformName = new GLchar[uniformMaxLength];
1417for(GLint i = 0; i < numUniforms; i++) {
1418stringstream line;
1419GLsizei length;
1420GLint location;
1421glGetActiveUniform(program, i, uniformMaxLength, &length, &count, &type, uniformName);
1422location = glGetUniformLocation(program, uniformName);
1423if (location == -1) continue; // ignore uniform blocks
1424
1425line << "[" << location << "] ";
1426for(int j = 0; j < length; j++) {
1427line << uniformName[j];
1428}
1429line << " @ index " << location;
1430ofLogNotice("ofShader") << line.str();
1431}
1432delete[] uniformName;
1433}
1434
1435//--------------------------------------------------------------
1436void ofShader::printActiveAttributes() const{
1437GLint numAttributes = 0;
1438glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &numAttributes);
1439ofLogNotice("ofShader") << numAttributes << " attributes";
1440
1441GLint attributeMaxLength = 0;
1442glGetProgramiv(program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &attributeMaxLength);
1443
1444GLint count = -1;
1445GLenum type = 0;
1446GLchar* attributeName = new GLchar[attributeMaxLength];
1447stringstream line;
1448for(GLint i = 0; i < numAttributes; i++) {
1449GLsizei length;
1450glGetActiveAttrib(program, i, attributeMaxLength, &length, &count, &type, attributeName);
1451line << " [" << i << "] ";
1452for(int j = 0; j < length; j++) {
1453line << attributeName[j];
1454}
1455line << " @ index " << getAttributeLocation(attributeName);
1456ofLogNotice("ofShader") << line.str();
1457line.str("");
1458}
1459delete [] attributeName;
1460}
1461
1462//----------------------------------------
1463bool ofShader::setShadowUniforms( int textureLocation ) const {
1464if( !ofIsGLProgrammableRenderer() ) {
1465return false;
1466}
1467
1468setUniformTexture("uShadowCubeMap", ofShadow::getTextureTarget( OF_LIGHT_POINT ), ofShadow::getPointTexId(), textureLocation );
1469setUniformTexture("uShadowMapDirectional", ofShadow::getTextureTarget( OF_LIGHT_DIRECTIONAL ), ofShadow::getDirectionalTexId(), textureLocation+1 );
1470setUniformTexture("uShadowMapSpot", ofShadow::getTextureTarget( OF_LIGHT_SPOT ), ofShadow::getSpotTexId(), textureLocation+2 );
1471setUniformTexture("uShadowMapArea", ofShadow::getTextureTarget( OF_LIGHT_AREA ), ofShadow::getAreaTexId(), textureLocation+3 );
1472
1473for(size_t i=0;i<ofShadowsData().size();i++){
1474std::string idx = ofToString(i,0);
1475std::shared_ptr<ofShadow::Data> shadow = ofShadowsData()[i].lock();
1476std::string shadowAddress = "shadows["+idx+"]";
1477if(!shadow || !shadow->isEnabled || shadow->index < 0 ){
1478setUniform1f(shadowAddress+".enabled", 0 );
1479continue;
1480}
1481setUniform1f(shadowAddress+".enabled", 1 );
1482if( shadow->lightType != OF_LIGHT_POINT ) {
1483setUniformMatrix4f(shadowAddress+".shadowMatrix", shadow->shadowMatrix );
1484}
1485
1486setUniform1f(shadowAddress+".near", shadow->nearClip );
1487setUniform1f(shadowAddress+".far", shadow->farClip );
1488setUniform1f(shadowAddress+".normalBias", shadow->normalBias );
1489setUniform1f(shadowAddress+".bias", shadow->bias );
1490if( shadow->lightType != OF_LIGHT_POINT ) {
1491setUniform1f(shadowAddress+".sampleRadius", shadow->sampleRadius/(float)ofShadow::getDepthMapWidth(shadow->lightType) );
1492} else {
1493setUniform1f(shadowAddress+".sampleRadius", shadow->sampleRadius );
1494}
1495
1496setUniform3f(shadowAddress+".lightWorldPos", shadow->position );
1497setUniform1f(shadowAddress+".strength", shadow->strength );
1498setUniform3f(shadowAddress+".lightUp", shadow->up );
1499setUniform3f(shadowAddress+".lightRight", shadow->right );
1500setUniform1f(shadowAddress+".shadowType", (float)shadow->shadowType );
1501setUniform1i(shadowAddress+".texIndex", shadow->texIndex );
1502}
1503return true;
1504}
1505
1506//----------------------------------------
1507bool ofShader::setPbrEnvironmentMapUniforms( int textureLocation ) const {
1508if( !ofIsGLProgrammableRenderer() ) {
1509return false;
1510}
1511
1512std::shared_ptr<ofCubeMap::Data> cubeMapData = ofCubeMap::getActiveData();
1513if( cubeMapData ) {
1514if( cubeMapData->bIrradianceAllocated ) {
1515setUniformTexture("tex_irradianceMap", GL_TEXTURE_CUBE_MAP, cubeMapData->irradianceMapId, textureLocation );
1516}
1517if(cubeMapData->bPreFilteredMapAllocated) {
1518setUniformTexture("tex_prefilterEnvMap", GL_TEXTURE_CUBE_MAP, cubeMapData->preFilteredMapId, textureLocation+1 );
1519}
1520if( cubeMapData->settings.useLutTex && ofCubeMap::getBrdfLutTexture().isAllocated() ) {
1521setUniformTexture("tex_brdfLUT", ofCubeMap::getBrdfLutTexture(), textureLocation+2 );
1522}
1523}
1524return true;
1525}
1526
1527//--------------------------------------------------------------
1528GLuint ofShader::getProgram() const{
1529return program;
1530}
1531
1532//--------------------------------------------------------------
1533GLuint ofShader::getShader(GLenum type) const{
1534auto shader = shaders.find(type);
1535if(shader!=shaders.end()){
1536return shader->second.id;
1537}else{
1538return 0;
1539}
1540}
1541
1542//--------------------------------------------------------------
1543bool ofShader::operator==(const ofShader & other) const{
1544return other.program==program;
1545}
1546
1547//--------------------------------------------------------------
1548bool ofShader::operator!=(const ofShader & other) const{
1549return other.program!=program;
1550}
1551
1552//--------------------------------------------------------------
1553string ofShader::nameForType(GLenum type){
1554switch(type) {
1555case GL_VERTEX_SHADER: return "GL_VERTEX_SHADER";
1556case GL_FRAGMENT_SHADER: return "GL_FRAGMENT_SHADER";
1557#ifndef TARGET_OPENGLES
1558case GL_GEOMETRY_SHADER_EXT: return "GL_GEOMETRY_SHADER_EXT";
1559#ifdef glDispatchCompute
1560case GL_COMPUTE_SHADER: return "GL_COMPUTE_SHADER";
1561#endif
1562#endif
1563default: return "UNKNOWN SHADER TYPE";
1564}
1565}
1566
1567
1568