Commit 1903dc9b authored by Philip Trettner's avatar Philip Trettner
Browse files

Made shader parser extendable

parent 3db02023
......@@ -28,6 +28,12 @@
namespace ACGL{
namespace OpenGL{
/**
* @brief ShaderParser for processing shader source code
*
* Subclass this and provide alternative ShaderParserFactories to Creators in order to implement custom shader processing
* Override processPragma in order to create custom pragma handling
*/
class ShaderParser
{
ACGL_NOT_COPYABLE(ShaderParser)
......@@ -45,10 +51,59 @@ public:
//! 0 == original file
std::string getFileName( unsigned int i ) const { return mSourceFileNames[i]; }
protected:
/**
* @brief registers a new SourceFile
* @param _name name of the file (may be an actual filename or a name that indicates automatic generation)
* @return an ID that is to be used in #line statements and getFileName-Index.
*/
int registerSourceFile(std::string const& _name);
/**
* @brief adds a chunk of source to the shader
* @param _source source string
*
* Does not have to correspond to files
*/
void addSource(std::string const& _source);
/**
* @brief constructs a line directive
* @param _lineNumber line number (starts at 1)
* @param _fileID file ID (usually from registerSourceFile)
* @return a string with the format "#line lineNr fileID\n"
*/
std::string lineDirective(int _lineNumber, int _fileID) const;
/**
* @brief processes a custom Pragma directive
* @param _tokens vector of tokens after #pragma (e.g. "#pragma myPragma 5" results in _tokens = { "myPragma", "5" })
*
* Override this function to implement custom pragma handling (no need to call base function)
*
* Recommended behavior:
* - Check if pragma is valid
* - Start with lineNumber 1
* - Register appropriate source file (using registerSourceFile(...))
* - Initialize source content with lineDirective(lineNumber, fileID)
* - Add custom source content
* - Call addSource(...) with your source content
*/
virtual void processPragma(std::vector<std::string> const& _tokens) { }
/**
* @brief reads in a source file from file system
* @param _filename filename of the source file
*
* Override this function to implement custom file reading functionality
*/
virtual void readin( const std::string &_filename );
private:
void readin( const std::string &_filename );
bool lineContainsVersion( const std::string &line, unsigned int &version);
bool lineContainsImport( const std::string &line, std::string &filename);
bool lineContainsPragma( const std::string &line, std::vector<std::string> &pragmaToken);
std::vector< std::string > mSources;
std::vector< std::string > mSourceFileNames; // holds at least one filename
......
......@@ -224,6 +224,20 @@ bool ShaderParser::lineContainsImport( const std::string &line, std::string &fil
return false;
}
bool ShaderParser::lineContainsPragma(const std::string &line, std::vector<std::string> &pragmaToken)
{
std::vector< std::string > token = StringHelpers::split( line, ' ' );
if (token.size() >= 2 && token[0] == "#pragma")
{
pragmaToken.clear();
pragmaToken.insert(pragmaToken.begin(), token.begin() + 1, token.end());
return true;
}
return false;
}
std::string ShaderParser::getFileNamesPrintable() const
{
std::string rString;
......@@ -233,6 +247,22 @@ std::string ShaderParser::getFileNamesPrintable() const
return rString;
}
int ShaderParser::registerSourceFile(const std::string &_name)
{
mSourceFileNames.push_back(_name);
return mSourceFileNames.size();
}
void ShaderParser::addSource(const std::string &_source)
{
mSources.push_back(_source);
}
std::string ShaderParser::lineDirective(int _lineNumber, int _fileID) const
{
return "#line "+StringHelpers::toString(_lineNumber)+" "+StringHelpers::toString(_fileID)+"\n";
}
void ShaderParser::readin( const std::string &_filename )
{
std::string line = "";
......@@ -240,11 +270,10 @@ void ShaderParser::readin( const std::string &_filename )
std::ifstream fileStream(_filename.c_str(), std::ifstream::in);
unsigned int lineNumber = 1;
mSourceFileNames.push_back( _filename );
unsigned int fileNumber = mSourceFileNames.size();
unsigned int fileNumber = registerSourceFile(_filename);
// define the file and line number to get correct errors from the shader compiler:
std::string fileContent = "#line "+StringHelpers::toString(lineNumber)+" "+StringHelpers::toString(fileNumber)+"\n";
std::string fileContent = lineDirective(lineNumber, fileNumber);
//debug() << "parse file " << _filename << std::endl;
......@@ -256,37 +285,56 @@ void ShaderParser::readin( const std::string &_filename )
unsigned int version;
std::string fileToImport;
if ( lineContainsVersion(line, version) ) {
std::vector<std::string> pragmaToken;
if ( lineContainsVersion(line, version) )
{
mMaxVersion = std::max( version, mMaxVersion );
fileContent += "\n"; // remove the #version but keep a newline
lineNumber++;
} else if ( lineContainsImport(line, fileToImport ) ) {
}
else if ( lineContainsImport(line, fileToImport ) )
{
// handle import
if (fileToImport[0] != '/') {
// it's a relative path:
// remove "./" in case this was given explicitly:
if(fileToImport.size() > 2 && fileToImport[0] == '.' && fileToImport[1] == '/') {
if(fileToImport.size() > 2 && fileToImport[0] == '.' && fileToImport[1] == '/')
fileToImport = fileToImport.substr(2, fileToImport.size()-2);
}
std::string path, file;
StringHelpers::splitLastFileOrFolder( _filename, path, file );
fileToImport = path+"/"+fileToImport;
}
if ( std::find(mSourceFileNames.begin(), mSourceFileNames.end(), fileToImport) == mSourceFileNames.end()) {
if ( std::find(mSourceFileNames.begin(), mSourceFileNames.end(), fileToImport) == mSourceFileNames.end())
{
// not imported yet:
// push what we have till now:
mSources.push_back( fileContent );
addSource( fileContent );
readin( fileToImport );
lineNumber++;
fileContent = "#line "+StringHelpers::toString(lineNumber)+" "+StringHelpers::toString(fileNumber)+"\n";
} else {
fileContent = lineDirective(lineNumber, fileNumber);
}
else
{
// ignore:
lineNumber++;
fileContent += "\n";
}
} else {
}
else if ( lineContainsPragma(line, pragmaToken) )
{
// push what we have till now:
addSource( fileContent );
// let subclasses process their own pragmas
processPragma(pragmaToken);
// continue with a fresh chunk of source
lineNumber++;
fileContent = lineDirective(lineNumber, fileNumber);
}
else
{
fileContent += line + "\n";
lineNumber++;
}
......@@ -301,5 +349,5 @@ void ShaderParser::readin( const std::string &_filename )
//debug() << "file: " << fileContent << std::endl;
mSources.push_back( fileContent );
addSource( fileContent );
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment