Skip to content

Commit

Permalink
libgui|GLShaderBank: Including common shader sources
Browse files Browse the repository at this point in the history
'include.vertex' and 'include.fragment' in a shader definition are
now used to specify additional paths to common shader sources that
should be included in the primary sources of the shader.

Both include keys are expected to be specified as arrays of paths
to text files.
  • Loading branch information
skyjake committed Mar 26, 2014
1 parent 27b0659 commit bcaeaf9
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 16 deletions.
13 changes: 13 additions & 0 deletions doomsday/libgui/include/de/gui/glshader.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <de/Error>
#include <de/Counted>
#include <de/Asset>
#include <de/Block>
#include <de/IByteArray>

#include "libgui.h"
Expand Down Expand Up @@ -64,6 +65,18 @@ class LIBGUI_PUBLIC GLShader : public Counted, public Asset

void recompile();

/**
* Prefixes a piece of shader source code to another shader source. This takes
* into account that certain elements must remain at the beginning of the source
* (#version).
*
* @param source Main source where prefixing is done.
* @param prefix Source to prefix in the beginning of @a source.
*
* @return The resulting combination.
*/
static Block prefixToSource(Block const &source, Block const &prefix);

private:
DENG2_PRIVATE(d)
};
Expand Down
30 changes: 18 additions & 12 deletions doomsday/libgui/src/glshader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,23 @@ void GLShader::clear()
d->release();
}

Block GLShader::prefixToSource(Block const &source, Block const &prefix)
{
Block src = source;
int versionPos = src.indexOf("#version ");
if(versionPos >= 0)
{
// Append prefix after version.
int pos = src.indexOf('\n', versionPos);
src.insert(pos + 1, prefix);
}
else
{
src = prefix + src;
}
return src;
}

void GLShader::compile(Type shaderType, IByteArray const &source)
{
#ifndef LIBGUI_GLES2
Expand All @@ -126,18 +143,7 @@ void GLShader::compile(Type shaderType, IByteArray const &source)

// Prepare the shader source. This would be the time to substitute any
// remaining symbols in the shader source.
Block src = source;
int versionPos = src.indexOf("#version ");
if(versionPos >= 0)
{
// Append prefix after version.
int pos = src.indexOf('\n', versionPos);
src.insert(pos + 1, prefix);
}
else
{
src = prefix + src;
}
Block src = prefixToSource(source, prefix);
src.append('\0');

char const *srcPtr = src.constData();
Expand Down
45 changes: 41 additions & 4 deletions doomsday/libgui/src/glshaderbank.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

#include <de/App>
#include <de/ScriptedInfo>
#include <de/ArrayValue>
#include <de/ByteArrayFile>
#include <de/math.h>

Expand All @@ -34,16 +35,36 @@ DENG2_PIMPL(GLShaderBank)
struct Source : public ISource
{
/// Information about a shader source.
struct ShaderSource {
struct ShaderSource
{
String source;
enum Type {
enum Type
{
FilePath,
ShaderSourceText
};
Type type;

ShaderSource(String const &str = "", Type t = ShaderSourceText)
: source(str), type(t) {}
: source(str), type(t) {}

void convertToSourceText()
{
if(type == FilePath)
{
source = String::fromLatin1(Block(App::rootFolder().locate<File const>(source)));
type = ShaderSourceText;
}
}

void insertFromFile(String const &path)
{
convertToSourceText();
source += "\n";
Block combo = GLShader::prefixToSource(source.toLatin1(),
Block(App::rootFolder().locate<File const>(path)));
source = String::fromLatin1(combo);
}
};

GLShaderBank &bank;
Expand All @@ -56,7 +77,7 @@ DENG2_PIMPL(GLShaderBank)

Time sourceModifiedAt(ShaderSource const &src) const
{
if(src.type == ShaderSource::FilePath)
if(src.type == ShaderSource::FilePath && !src.source.isEmpty())
{
return App::rootFolder().locate<File const>(src.source).status().modifiedAt;
}
Expand Down Expand Up @@ -206,6 +227,22 @@ Bank::ISource *GLShaderBank::newSourceFromInfo(String const &id)
frag = ShaderSource(d->relativeToPath / def["path"] + ".fsh", ShaderSource::FilePath);
}

// Additional shaders to append to the main source.
if(def.has("include.vertex"))
{
DENG2_FOR_EACH_CONST(ArrayValue::Elements, i, def["include.vertex"].value().as<ArrayValue>().elements())
{
vtx.insertFromFile(d->relativeToPath / (*i)->asText());
}
}
if(def.has("include.fragment"))
{
DENG2_FOR_EACH_CONST(ArrayValue::Elements, i, def["include.fragment"].value().as<ArrayValue>().elements())
{
frag.insertFromFile(d->relativeToPath / (*i)->asText());
}
}

return new Source(*this, vtx, frag);
}

Expand Down

0 comments on commit bcaeaf9

Please sign in to comment.