The current ACGL implementations allows for custom shader parsing and an especially simple interface for custom pragmas.
One notable application is the Includes in shaders extension.
Class overview
Every ShaderProgramCreator and ShaderCreator has a ShaderParserFactory that is used to instantiate appropriate ShaderParser for every shader source file.
Without any modification, the default IncludingShaderParser will be used that supports the ACGLimport pragma for source file inclusion.
In principle, a ShaderParserFactory may return a different parser based on the source file. In practice, the same parser for all files is often sufficient. To make things easier, the SimpleShaderParserFactory can be used as a factory that returns a parser of type ShaderParserType for every file.
Example
This example presents a simple shader parser that reacts to "#pragma CustomCode" by replacing it with some custom text. The parser is a subclass of IncludingShaderParser and is therefore also able to use the ACGLimport pragma.
ShaderParser code: Header:
class CustomShaderParser : public IncludingShaderParser { public: /// c'tor CustomShaderParser( std::string const& _filename ) : IncludingShaderParser(_filename) { } /// Processes "#pragma CustomCode" virtual bool processPragma(std::vector const& _tokens, std::string const& _filename); }; ACGL_SMARTPOINTER_TYPEDEFS(CustomShaderParser)
Implementation:
bool CustomShaderParser::processPragma(const std::vector &_tokens, const std::string &_filename) { // (0) Check if correct pragma if ( _tokens.size() == 1 && _tokens[0] == "CustomCode" ) { // (1) - Start with lineNumber 1 int lineNumber = 1; // (2) - Register appropriate source file (using registerSourceFile(...)) int fileID = registerSourceFile("Generated Pipeline Defines"); // (3) - Initialize source content with lineDirective(lineNumber, fileID) std::string source = lineDirective(lineNumber, fileID); // (4) - Add custom source content source += "vec3 customFunction() { return vec3(0, 1, 0); }\n"; // (5) - Call addSource(...) with your source content addSource(source); // (6) - return true to indicate success return true; } // Otherwise, return base class processPragma(...) else return IncludingShaderParser::processPragma(_tokens, _filename); }
In most cases, it is sufficient to adapt point (0) and (4) in the above function.
Usage:
// create shader program creator ACGL::OpenGL::ShaderProgramCreator shader(...); ... shader setup ... // register custom shader parser factory shader.shaderParserFactory(std::make_shared >()); // create shader program using custom parser ACGL::OpenGL::SharedShaderProgram shaderProg = shader.create();