Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
ACGL
acgl
Commits
82115120
Commit
82115120
authored
Jul 16, 2013
by
Philip Trettner
Browse files
shader parser refactoring
parent
c606506d
Changes
9
Hide whitespace changes
Inline
Side-by-side
include/ACGL/OpenGL/Creator/ShaderCreator.hh
View file @
82115120
...
...
@@ -35,7 +35,7 @@ public:
ShaderCreator
(
const
std
::
string
&
_filename
)
:
Resource
::
SingleFileBasedCreator
<
Shader
>
(
_filename
,
Base
::
Settings
::
the
()
->
getFullShaderPath
()),
mType
(
GL_INVALID_ENUM
),
mShaderParserFactory
(
std
::
make_shared
<
ShaderParserFactory
>
())
mShaderParserFactory
(
std
::
make_shared
<
Simple
ShaderParserFactory
<
IncludingShaderParser
>
>
())
{}
virtual
~
ShaderCreator
()
{}
...
...
@@ -52,7 +52,8 @@ public:
//
/// Sets the shader parser factory
inline
ShaderCreator
&
shaderParserFacoty
(
SharedShaderParserFactory
const
&
_factory
)
{
mShaderParserFactory
=
_factory
;
return
*
this
;
}
/// For more detailed documentation, see ShaderParser.hh
inline
ShaderCreator
&
shaderParserFactory
(
SharedShaderParserFactory
const
&
_factory
)
{
mShaderParserFactory
=
_factory
;
return
*
this
;
}
// ===================================================================================================== \/
// ============================================================================================ OVERRIDE \/
...
...
include/ACGL/OpenGL/Creator/ShaderParser.hh
0 → 100644
View file @
82115120
/***********************************************************************
* Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#pragma once
#include <vector>
#include <string>
#include <ACGL/ACGL.hh>
#include <ACGL/Base/Macros.hh>
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
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
)
public:
ShaderParser
(
const
std
::
string
&
_filename
);
virtual
~
ShaderParser
()
{
}
std
::
vector
<
std
::
string
>
getSources
()
const
{
return
mSources
;
}
std
::
string
getFileNamesPrintable
()
const
;
//! the imported sources don't count the original file!
unsigned
int
getNumberOfImportedFiles
()
const
{
return
mSourceFileNames
.
size
()
-
1
;
}
//! 0 == original file
std
::
string
getFileName
(
unsigned
int
i
)
const
{
return
mSourceFileNames
[
i
];
}
/**
* @brief checks if a given Sourcefile name exists
* @param _filename filename to check
* @return true, iff mSourceFileNames contains _filename
*/
bool
existsSourcefile
(
std
::
string
const
&
_filename
);
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" })
* @param _filename name of the current source file (changes for different includes, does not reflect custom file names)
*
* Override this function to implement custom pragma handling (no need to call base function)
*
* Recommended behavior:
* - Check if pragma is valid, otherwise call base::processPragma
* - 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
* - Return true
*/
virtual
bool
processPragma
(
std
::
vector
<
std
::
string
>
const
&
_tokens
,
std
::
string
const
&
_filename
);
/**
* @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:
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
unsigned
int
mMaxVersion
;
};
ACGL_SMARTPOINTER_TYPEDEFS
(
ShaderParser
)
/**
* @brief A ShaderParser that recognizes shader includes
*
* e.g.
* #pragma ACGLimport "matrices.glsl"
*/
class
IncludingShaderParser
:
public
ShaderParser
{
public:
/// c'tor
IncludingShaderParser
(
std
::
string
const
&
_filename
);
/**
* Processes "#pragma ACGLimport filename"
*/
virtual
bool
processPragma
(
std
::
vector
<
std
::
string
>
const
&
_tokens
,
std
::
string
const
&
_filename
);
};
ACGL_SMARTPOINTER_TYPEDEFS
(
IncludingShaderParser
)
}
// OpenGL
}
// ACGL
include/ACGL/OpenGL/Creator/ShaderParserFactory.hh
View file @
82115120
...
...
@@ -24,6 +24,8 @@ namespace OpenGL{
* @brief Factory for shader parser
*
* This can be used in in the shader program creator to create post-processes for shader
*
* For more detailed documentation, see ShaderParser.hh
*/
class
ShaderParserFactory
{
...
...
@@ -41,9 +43,26 @@ public:
* Returns the a default shader parse that is able to include other shader
* Override this function to create your own functionality
*/
virtual
SharedShaderParser
createParser
(
std
::
string
const
&
_filename
);
virtual
SharedShaderParser
createParser
(
std
::
string
const
&
_filename
)
=
0
;
};
ACGL_SMARTPOINTER_TYPEDEFS
(
ShaderParserFactory
)
/**
* @brief A simple templated shader parser factory
*
* calls std::make_shared<ShaderParserT>(_filename), so make sure that the (string const&)-c'tor is publicly accessible
*/
template
<
typename
ShaderParserT
>
class
SimpleShaderParserFactory
:
public
ShaderParserFactory
{
public:
/// see parent
virtual
SharedShaderParser
createParser
(
std
::
string
const
&
_filename
)
{
return
std
::
make_shared
<
ShaderParserT
>
(
_filename
);
}
};
}
// OpenGL
}
// ACGL
include/ACGL/OpenGL/Creator/ShaderProgramCreator.hh
View file @
82115120
...
...
@@ -45,7 +45,7 @@ public:
mAttributeLocations
(
new
LocationMappings
),
mFragmentDataLocations
(
new
LocationMappings
),
mUniformBufferLocations
(
new
LocationMappings
),
mShaderParserFactory
(
std
::
make_shared
<
ShaderParserFactory
>
())
mShaderParserFactory
(
std
::
make_shared
<
Simple
ShaderParserFactory
<
IncludingShaderParser
>
>
())
{
// the base path is only needed for updating the time stamps, as the shaders itself get loaded via ShaderCreators
// which itself will add the base path! (read: mFileNames will _NOT_ store the base path!)
...
...
@@ -76,7 +76,8 @@ public:
//
/// Sets the shader parser factory
inline
ShaderProgramCreator
&
shaderParserFacoty
(
SharedShaderParserFactory
const
&
_factory
)
{
mShaderParserFactory
=
_factory
;
return
*
this
;
}
/// For more detailed documentation, see ShaderParser.hh
inline
ShaderProgramCreator
&
shaderParserFactory
(
SharedShaderParserFactory
const
&
_factory
)
{
mShaderParserFactory
=
_factory
;
return
*
this
;
}
//
// Adding files:
...
...
include/ACGL/OpenGL/Objects/Shader.hh
View file @
82115120
...
...
@@ -14,6 +14,8 @@
*
* So normally you want to work with ShaderPrograms instead of Shaders (switch Programs,
* set uniforms etc).
*
* Custimizing shader parsing is done via custom ShaderParser classes, see Creator/ShaderParser.hh
*/
#include <vector>
...
...
@@ -24,93 +26,11 @@
#include <ACGL/Base/Macros.hh>
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Tools.hh>
#include <ACGL/OpenGL/Creator/ShaderParser.hh>
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
)
public:
ShaderParser
(
const
std
::
string
&
_filename
);
virtual
~
ShaderParser
()
{
}
std
::
vector
<
std
::
string
>
getSources
()
const
{
return
mSources
;
}
std
::
string
getFileNamesPrintable
()
const
;
//! the imported sources don't count the original file!
unsigned
int
getNumberOfImportedFiles
()
const
{
return
mSourceFileNames
.
size
()
-
1
;
}
//! 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:
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
unsigned
int
mMaxVersion
;
};
ACGL_SMARTPOINTER_TYPEDEFS
(
ShaderParser
)
class
Shader
{
ACGL_NOT_COPYABLE
(
Shader
)
...
...
src/ACGL/OpenGL/Creator/ShaderParser.cc
0 → 100644
View file @
82115120
/***********************************************************************
* Copyright 2011-2012 Computer Graphics Group RWTH Aachen University. *
* All rights reserved. *
* Distributed under the terms of the MIT License (see LICENSE.TXT). *
**********************************************************************/
#include <ACGL/OpenGL/Creator/ShaderParser.hh>
#include <ACGL/OpenGL/Tools.hh>
#include <ACGL/Utils/StringHelpers.hh>
#include <iostream>
#include <fstream>
#include <algorithm>
using
namespace
ACGL
::
Utils
;
using
namespace
ACGL
::
OpenGL
;
ShaderParser
::
ShaderParser
(
const
std
::
string
&
_filename
)
{
mMaxVersion
=
110
;
mSources
.
push_back
(
"#version 330
\n
"
);
std
::
string
path
,
file
;
StringHelpers
::
splitLastFileOrFolder
(
_filename
,
path
,
file
);
//readin( "./"+path+"/"+file );
readin
(
_filename
);
if
(
mMaxVersion
>
110
)
{
mSources
[
0
]
=
"#version "
+
StringHelpers
::
toString
(
mMaxVersion
)
+
"
\n
"
;
}
}
bool
ShaderParser
::
lineContainsVersion
(
const
std
::
string
&
line
,
unsigned
int
&
version
)
{
std
::
vector
<
std
::
string
>
token
=
StringHelpers
::
split
(
line
,
' '
);
if
(
token
.
size
()
>=
2
&&
token
[
0
]
==
"#version"
)
{
version
=
StringHelpers
::
to
<
unsigned
int
>
(
token
[
1
]);
//debug() << "string " << line << " -> version " << version << std::endl;
return
true
;
}
return
false
;
}
bool
ShaderParser
::
lineContainsImport
(
const
std
::
string
&
line
,
std
::
string
&
filename
)
{
std
::
vector
<
std
::
string
>
token
=
StringHelpers
::
split
(
line
,
' '
);
if
(
token
.
size
()
>=
3
&&
token
[
0
]
==
"#pragma"
&&
token
[
1
]
==
"ACGLimport"
)
{
if
(
token
[
2
].
size
()
>=
2
)
{
size_t
startName
=
line
.
find
(
'"'
,
0
);
if
(
startName
==
std
::
string
::
npos
)
return
false
;
size_t
endName
=
line
.
find
(
'"'
,
startName
+
1
);
if
(
endName
==
std
::
string
::
npos
)
return
false
;
filename
=
line
.
substr
(
startName
+
1
,
endName
-
startName
-
1
);
// remove the ""
//debug() << "string " << line << " -> import " << filename << std::endl;
return
true
;
}
}
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
;
for
(
size_t
i
=
0
;
i
<
mSourceFileNames
.
size
();
++
i
)
{
rString
+=
" "
+
StringHelpers
::
toString
<
unsigned
int
>
(
i
+
1
)
+
" "
+
mSourceFileNames
[
i
]
+
"
\n
"
;
}
return
rString
;
}
bool
ShaderParser
::
existsSourcefile
(
const
std
::
string
&
_filename
)
{
return
std
::
find
(
mSourceFileNames
.
begin
(),
mSourceFileNames
.
end
(),
_filename
)
!=
mSourceFileNames
.
end
();
}
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
"
;
}
bool
ShaderParser
::
processPragma
(
std
::
vector
<
std
::
string
>
const
&
,
std
::
string
const
&
)
{
return
false
;
}
void
ShaderParser
::
readin
(
const
std
::
string
&
_filename
)
{
std
::
string
line
=
""
;
std
::
ifstream
fileStream
(
_filename
.
c_str
(),
std
::
ifstream
::
in
);
unsigned
int
lineNumber
=
1
;
unsigned
int
fileNumber
=
registerSourceFile
(
_filename
);
// define the file and line number to get correct errors from the shader compiler:
std
::
string
fileContent
=
lineDirective
(
lineNumber
,
fileNumber
);
//debug() << "parse file " << _filename << std::endl;
if
(
fileStream
.
is_open
())
{
while
(
fileStream
.
good
())
{
std
::
getline
(
fileStream
,
line
);
unsigned
int
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
(
lineContainsPragma
(
line
,
pragmaToken
)
)
{
// push what we have till now:
addSource
(
fileContent
);
// let subclasses process their own pragmas
if
(
!
processPragma
(
pragmaToken
,
_filename
)
)
addSource
(
line
+
"
\n
"
);
// pragma not accepted? print it instead
// continue with a fresh chunk of source
lineNumber
++
;
fileContent
=
lineDirective
(
lineNumber
,
fileNumber
);
}
else
{
fileContent
+=
line
+
"
\n
"
;
lineNumber
++
;
}
}
fileStream
.
close
();
}
else
{
error
()
<<
"Failed to open file: "
<<
_filename
<<
std
::
endl
;
return
;
}
//debug() << "file: " << fileContent << std::endl;
addSource
(
fileContent
);
}
IncludingShaderParser
::
IncludingShaderParser
(
const
std
::
string
&
_filename
)
:
ShaderParser
(
_filename
)
{
}
bool
IncludingShaderParser
::
processPragma
(
const
std
::
vector
<
std
::
string
>
&
_tokens
,
const
std
::
string
&
_filename
)
{
if
(
_tokens
.
size
()
==
2
&&
_tokens
[
0
]
==
"ACGLimport"
)
{
std
::
string
fileToImport
(
_tokens
[
1
]);
// strip '"' or '<' also allows mix of them, but not recommended
// currently no difference in behavior
size_t
startName
=
fileToImport
.
find
(
'"'
,
0
);
if
(
startName
==
std
::
string
::
npos
)
startName
=
fileToImport
.
find
(
'<'
,
0
);
if
(
startName
==
std
::
string
::
npos
)
return
false
;
size_t
endName
=
fileToImport
.
find
(
'"'
,
startName
+
1
);
if
(
endName
==
std
::
string
::
npos
)
endName
=
fileToImport
.
find
(
'>'
,
startName
+
1
);
if
(
endName
==
std
::
string
::
npos
)
return
false
;
fileToImport
=
fileToImport
.
substr
(
startName
+
1
,
endName
-
startName
-
1
);
// remove the ""
// 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
]
==
'/'
)
fileToImport
=
fileToImport
.
substr
(
2
,
fileToImport
.
size
()
-
2
);
std
::
string
path
,
file
;
StringHelpers
::
splitLastFileOrFolder
(
_filename
,
path
,
file
);
fileToImport
=
path
+
"/"
+
fileToImport
;
}
// "#pragma once"-behavior
if
(
!
existsSourcefile
(
fileToImport
)
)
readin
(
fileToImport
);
// actual include
// success
return
true
;
}
else
return
ShaderParser
::
processPragma
(
_tokens
,
_filename
);
}
src/ACGL/OpenGL/Creator/ShaderParserFactory.cc
View file @
82115120
...
...
@@ -13,7 +13,8 @@ using namespace ACGL::Utils;
using
namespace
ACGL
::
Base
;
using
namespace
ACGL
::
OpenGL
;
SharedShaderParser
ShaderParserFactory
::
createParser
(
const
std
::
string
&
_filename
)
{
return
std
::
make_shared
<
ShaderParser
>
(
_filename
);
namespace
ACGL
{
namespace
OpenGL
{
}
}
src/ACGL/OpenGL/Creator/ShaderProgramCreator.cc
View file @
82115120
...
...
@@ -83,7 +83,7 @@ SharedShaderProgram ShaderProgramCreator::create()
// attach shader
if
(
mShaderType
[
i
]
!=
GL_INVALID_VALUE
)
{
ConstSharedShader
shader
=
ShaderFileManager
::
the
()
->
get
(
ShaderCreator
(
mFileNames
[
i
]
).
type
(
mShaderType
[
i
]
).
shaderParserFac
o
ty
(
mShaderParserFactory
)
);
ConstSharedShader
shader
=
ShaderFileManager
::
the
()
->
get
(
ShaderCreator
(
mFileNames
[
i
]
).
type
(
mShaderType
[
i
]
).
shaderParserFact
or
y
(
mShaderParserFactory
)
);
if
(
shader
)
{
shaderProgram
->
attachShader
(
shader
);
}
else
{
...
...
src/ACGL/OpenGL/Objects/Shader.cc
View file @
82115120
...
...
@@ -169,185 +169,3 @@ void Shader::getCompileLog( std::string &_log, bool &_wasErrorLog ) const
_log
=
""
;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
ShaderParser
::
ShaderParser
(
const
std
::
string
&
_filename
)
{
mMaxVersion
=
110
;
mSources
.
push_back
(
"#version 330
\n
"
);
std
::
string
path
,
file
;
StringHelpers
::
splitLastFileOrFolder
(
_filename
,
path
,
file
);
//readin( "./"+path+"/"+file );
readin
(
_filename
);
if
(
mMaxVersion
>
110
)
{
mSources
[
0
]
=
"#version "
+
StringHelpers
::
toString
(
mMaxVersion
)
+
"
\n
"
;
}
}
bool
ShaderParser
::
lineContainsVersion
(
const
std
::
string
&
line
,
unsigned
int
&
version
)
{
std
::
vector
<
std
::
string
>
token
=
StringHelpers
::
split
(
line
,
' '
);
if
(
token
.
size
()
>=
2
&&
token
[
0
]
==
"#version"
)
{
version
=
StringHelpers
::
to
<
unsigned
int
>
(
token
[
1
]);
//debug() << "string " << line << " -> version " << version << std::endl;
return
true
;
}
return
false
;
}
bool
ShaderParser
::
lineContainsImport
(
const
std
::
string
&
line
,
std
::
string
&
filename
)
{
std
::
vector
<
std
::
string
>
token
=
StringHelpers
::
split
(
line
,
' '
);
if
(
token
.
size
()
>=
3
&&
token
[
0
]
==
"#pragma"
&&
token
[
1
]
==
"ACGLimport"
)
{
if
(
token
[
2
].
size
()
>=
2
)
{
size_t
startName
=
line
.
find
(
'"'
,
0
);