//-------------------------------------------------------------- bool ofShader::setupShaderFromSource(GLenum type, string source, string sourceDirectoryPath) { unload(); // create program if it doesn't exist already checkAndCreateProgram(); GLuint clearErrors = glGetError(); //needed for some users to clear gl errors if( clearErrors != GL_NO_ERROR ) { ofLogVerbose("ofShader") << "setupShaderFromSource(): OpenGL error after checkAndCreateProgram() (probably harmless): error " << clearErrors; } // create shader GLuint shader = glCreateShader(type); if(shader == 0) { ofLogError("ofShader") << "setupShaderFromSource(): failed creating " << nameForType(type) << " shader"; return false; } // parse for includes string src = parseForIncludes( source , sourceDirectoryPath); // store source code (that's the expanded source with all includes copied in) shaderSource[type] = src; // compile shader const char* sptr = src.c_str(); int ssize = src.size(); glShaderSource(shader, 1, &sptr, &ssize); glCompileShader(shader); // check compile status GLint status = GL_FALSE; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); GLuint err = glGetError(); if (err != GL_NO_ERROR) { ofLogError("ofShader") << "setupShaderFromSource(): OpenGL generated error " << err << " trying to get the compile status for a " << nameForType(type) << " shader, does your video card support this?"; return false; } if(status == GL_TRUE) { ofLogVerbose("ofShader") << "setupShaderFromSource(): " << nameForType(type) + " shader compiled"; #ifdef TARGET_EMSCRIPTEN checkShaderInfoLog(shader, type, OF_LOG_VERBOSE); #else checkShaderInfoLog(shader, type, OF_LOG_WARNING); #endif } else if (status == GL_FALSE) { ofLogError("ofShader") << "setupShaderFromSource(): " << nameForType(type) + " shader failed to compile"; checkShaderInfoLog(shader, type, OF_LOG_ERROR); return false; } shaders[type] = shader; retainShader(shader); return true; }
string ofShader::parseForIncludes( const string& source, vector<string>& included, int level, const string& sourceDirectoryPath) { if ( level > 32 ) { ofLogError( "ofShader", "glsl header inclusion depth limit reached, might be caused by cyclic header inclusion" ); return ""; } stringstream output; stringstream input; input << source; Poco::RegularExpression re("^\\s*#\\s*pragma\\s+include\\s+[\"<](.*)[\">].*"); Poco::RegularExpression::MatchVec matches; string line; while( std::getline( input, line ) ) { if ( re.match( line, 0, matches ) < 2 ) { output << line << endl; continue; } string include = line.substr(matches[1].offset, matches[1].length); if ( std::find( included.begin(), included.end(), include ) != included.end() ) { ofLogVerbose("ofShader") << include << " already included"; continue; } // we store the absolute paths so as have (more) unique file identifiers. include = ofFile(sourceDirectoryPath + include).getAbsolutePath(); included.push_back( include ); ofBuffer buffer = ofBufferFromFile( include ); if ( !buffer.size() ) { ofLogError("ofShader") <<"Could not open glsl include file " << include; continue; } string currentDir = ofFile(include).getEnclosingDirectory(); output << parseForIncludes( buffer.getText(), included, level + 1, currentDir ) << endl; } return output.str(); }
string ofShader::parseForIncludes( const string& source, const string& sourceDirectoryPath) { vector<string> included; return parseForIncludes( source, included, 0, sourceDirectoryPath); }