Commit a8e35743 authored by Christopher Tenter's avatar Christopher Tenter

loadable shader mods refs #2308

git-svn-id: http://www.openflipper.org/svnrepo/OpenFlipper/branches/Free@19953 383ad7c9-94d9-4d36-a494-682f7c89f535
parent 3ee18ce4
......@@ -50,6 +50,8 @@
#include <QFileInfo>
#include <QDir>
#include <QTextStream>
#include <QDateTime>
#include <QHash>
namespace ACG
{
......@@ -495,6 +497,15 @@ bool ShaderGenerator::hasDefine(QString _define) const
return true;
}
// also check raw io blocks
for (QStringList::const_iterator it = rawIO_.constBegin(); it != rawIO_.constEnd(); ++it)
{
QString trimmedRef = it->trimmed();
if (trimmedRef.startsWith(trimmedDef))
return true;
}
return false;
}
......@@ -591,6 +602,10 @@ void ShaderGenerator::buildShaderCode(QStringList* _pMainCode, const QStringList
}
// add raw IO code block
code_.append(rawIO_);
// main function
foreach(it, (*_pMainCode))
code_.push_back(it);
......@@ -917,8 +932,10 @@ ShaderProgGenerator::~ShaderProgGenerator(void)
void ShaderProgGenerator::loadStringListFromFile(QString _fileName, QStringList* _out)
bool ShaderProgGenerator::loadStringListFromFile(QString _fileName, QStringList* _out)
{
bool success = false;
QString absFilename = getAbsFilePath(_fileName);
......@@ -937,6 +954,8 @@ void ShaderProgGenerator::loadStringListFromFile(QString _fileName, QStringList*
QString szLine = filestream.readLine();
_out->push_back(szLine.trimmed());
}
success = true;
}
file.close();
......@@ -944,6 +963,7 @@ void ShaderProgGenerator::loadStringListFromFile(QString _fileName, QStringList*
else
std::cout << "error: " << file.errorString().toStdString() << " -> \"" << absFilename.toStdString() << "\"" << std::endl;
return success;
}
......@@ -2223,6 +2243,219 @@ ShaderModifier::ShaderModifier( void )
ShaderModifier::~ShaderModifier( void )
{}
class ShaderModifierFile : public ShaderModifier
{
public:
ShaderModifierFile()
: version_(0)
{}
virtual ~ShaderModifierFile()
{}
void modifyVertexIO(ShaderGenerator* _shader) { modifyIO(0, _shader); }
void modifyTessControlIO(ShaderGenerator* _shader) { modifyIO(1, _shader); }
void modifyTessEvalIO(ShaderGenerator* _shader) { modifyIO(2, _shader); }
void modifyGeometryIO(ShaderGenerator* _shader) { modifyIO(3, _shader); }
void modifyFragmentIO(ShaderGenerator* _shader) { modifyIO(4, _shader); }
void modifyVertexBeginCode(QStringList* _code) { _code->append(vertexBeginCode_); }
void modifyVertexEndCode(QStringList* _code) { _code->append(vertexEndCode_); }
void modifyFragmentBeginCode(QStringList* _code) { _code->append(fragmentBeginCode_); }
void modifyFragmentEndCode(QStringList* _code) { _code->append(fragmentEndCode_); }
const QString& filename() const {return filename_;}
const QDateTime& filetime() const {return filetime_;}
void filetime(const QDateTime& _newtime) {filetime_ = _newtime;}
void clear()
{
version_ = 0;
for (int i = 0; i < 5; ++i)
io_[i].clear();
vertexBeginCode_.clear();
vertexEndCode_.clear();
fragmentBeginCode_.clear();
fragmentEndCode_.clear();
}
static ShaderModifierFile* loadFromFile(QString _filename)
{
ShaderModifierFile* res = 0;
// get timestamp
QString absFilename = ShaderProgGenerator::getAbsFilePath(_filename);
QDateTime lastmod = QFileInfo(absFilename).lastModified();
// check cache
QHash<QString, ShaderModifierFile>::iterator cacheEntry = fileCache_.find(_filename);
bool reload = false;
bool firstLoad = false;
if (cacheEntry != fileCache_.end())
{
// fetch from cache
res = &cacheEntry.value();
if (lastmod != res->filetime())
{
res->clear();
reload = true;
}
}
else
{
// load new modifier
reload = true;
firstLoad = true;
}
if (reload)
{
QStringList lines;
if (ShaderProgGenerator::loadStringListFromFile(_filename, &lines))
{
// new cache entry
if (firstLoad)
res = &fileCache_[_filename];
res->loadBlocks(lines);
res->filetime(lastmod);
// also register to generator
if (firstLoad)
ShaderProgGenerator::registerModifier(res);
}
}
return res;
}
private:
void loadBlocks(const QStringList& _lines)
{
static const char* markers [] =
{
"VertexIO:",
"TessControlIO:",
"TessEvalIO:",
"GeometryIO:",
"FragmentIO:",
"VertexBeginCode:",
"VertexEndCode:",
"FragmentBeginCode:",
"FragmentEndCode:"
};
const int numMarkers = sizeof(markers) / sizeof(markers[0]);
QStringList* blockTargets [] =
{
io_ + 0,
io_ + 1,
io_ + 2,
io_ + 3,
io_ + 4,
&vertexBeginCode_,
&vertexEndCode_,
&fragmentBeginCode_,
&fragmentEndCode_
};
assert(sizeof(blockTargets) / sizeof(blockTargets[0]) == numMarkers);
// current block in file, points to one of io_[idx], vertexBeginCode_, ...
QStringList* curBlock_ = 0;
int curLine = 0;
for (QStringList::const_iterator it = _lines.begin(); it != _lines.end(); ++it, ++curLine)
{
if (it->isEmpty())
continue;
// read glsl version
if (version_ <= 0 && it->startsWith("#version "))
{
const int offset = strlen("#version ");
version_ = atoi(it->toLatin1().data() + offset);
}
else
{
// read code blocks
bool blockMarker = false;
for (int i = 0; i < numMarkers && !blockMarker; ++i)
{
if ( it->startsWith(markers[i]) )
{
// new block start
curBlock_ = blockTargets[i];
blockMarker = true;
}
}
if (!blockMarker)
{
if (curBlock_) // code belongs to some block
curBlock_->push_back(*it);
else // wrong file structure
std::cerr << "ShaderModifierFile::loadBlocks - line belongs to unknown block in file " << filename_.toLatin1().data() << " at line " << curLine << std::endl;
}
}
}
}
void modifyIO(int _stage, ShaderGenerator* _shader)
{
if (version_ > 0)
_shader->setGLSLVersion(version_);
_shader->addRawIOBlock(io_[_stage]);
}
private:
QString filename_;
QDateTime filetime_;
// glsl version
int version_;
// io mods
QStringList io_[5];
// code mods
QStringList vertexBeginCode_,
vertexEndCode_,
fragmentBeginCode_,
fragmentEndCode_;
// loaded modifiers
static QHash<QString, ShaderModifierFile> fileCache_;
};
QHash<QString, ShaderModifierFile> ShaderModifierFile::fileCache_;
ShaderModifier* ShaderModifier::loadFromFile(QString _filename)
{
return ShaderModifierFile::loadFromFile(_filename);
}
//=============================================================================
......
......@@ -508,6 +508,23 @@ public:
*/
void addLayout(QString _layout);
/** \brief Add a raw glsl IO code block
*
* This code block is inserted between the generated IO block and the main function.
*
* Example:
* \code
* in vec3 someInput;
* out vec3 outSomeOutput;
* uniform vec3 paramA;
* #define USE_METHOD_X
* #include "imports.h"
* ..
* \endcode
*/
void addRawIOBlock(QStringList _codeBlock) {rawIO_.append(_codeBlock);}
/** \brief Add a light description to shader:
*/
void addLight(int lightIndex_, ShaderGenLightType _light);
......@@ -610,6 +627,9 @@ private:
QStringList genDefines_;
QStringList layouts_;
/// io block as glsl code
QStringList rawIO_;
/// inputs of shader are arrays (tess-control, tess-eval, geometry)
bool inputArrays_;
......@@ -845,6 +865,16 @@ public:
*/
unsigned int getID() {return modifierID_;}
/** \brief Load a modifier from file
*
* The returned modifier should not be deleted manually.
* @param _filename absolute or relative (from shaderdir) file name
* @return pointer to shader modifier, 0 if loading failed
*/
static ShaderModifier* loadFromFile(QString _filename);
// operator unsigned int() const {return modifierID_;}
operator std::vector<unsigned int>() const {return std::vector<unsigned int>(1,modifierID_);}
......@@ -983,6 +1013,18 @@ public:
*/
void generateShaders();
/** \brief Load a text file as string list
@param _fileName relative (from shader dir) or absolute file name
@param _out lines from text file
@return true on success, false otherwise
*/
static bool loadStringListFromFile(QString _fileName, QStringList* _out);
/** \brief Convert a filename to an absolute filename
@param _fileName relative (from shader dir) or absolute file name
*/
static QString getAbsFilePath(QString _fileName);
private:
/** \brief Loads external shader templates
......@@ -1027,9 +1069,6 @@ private:
/// returns path to _strFileName without last slash
static QString getPathName(QString _strFileName);
/// returns clean absolute file path to _strFileName including filename
static QString getAbsFilePath(QString _strFileName);
/// checks if _str is an include directive
/// eventually imports the included file to the specified generator
int checkForIncludes(QString _str, ShaderGenerator* _gen, QString _includePath);
......@@ -1044,8 +1083,6 @@ private:
static void loadLightingFunctions();
static void loadStringListFromFile(QString _fileName, QStringList* _out);
ShaderGenerator* vertex_;
ShaderGenerator* tessControl_;
ShaderGenerator* tessEval_;
......
Markdown is supported
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