Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
libgui: Added GLShaderBank
Bank for storing shared GL shaders and building GL programs out of them.
  • Loading branch information
skyjake committed May 16, 2013
1 parent 587a15b commit 33d240a
Show file tree
Hide file tree
Showing 4 changed files with 290 additions and 0 deletions.
1 change: 1 addition & 0 deletions doomsday/libgui/include/de/GLShaderBank
@@ -0,0 +1 @@
#include "gui/glshaderbank.h"
66 changes: 66 additions & 0 deletions doomsday/libgui/include/de/gui/glshaderbank.h
@@ -0,0 +1,66 @@
/** @file glshaderbank.h Bank containing GL shaders.
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBGUI_GLSHADERBANK_H
#define LIBGUI_GLSHADERBANK_H

#include <de/InfoBank>
#include "../GLShader"

namespace de {

class GLProgram;

/**
* Bank containing GL shaders.
*
* Shader objects are automatically shared between created programs. Programs
* can be are created based on definitions from an Info file.
*
* Shaders and programs cannot be accessed until OpenGL is ready.
*/
class GLShaderBank : public InfoBank
{
public:
GLShaderBank();

void addFromInfo(File const &file);

GLShader &shader(Path const &path, GLShader::Type type) const;

/**
* Builds a GL program using the defined shaders.
*
* @param program Program to build.
* @param path Identifier of the shader.
*
* @return Reference to @a program.
*/
GLProgram &build(GLProgram &program, Path const &path) const;

protected:
ISource *newSourceFromInfo(String const &id);
IData *loadFromSource(ISource &source);

private:
DENG2_PRIVATE(d)
};

} // namespace de

#endif // LIBGUI_GLSHADERBANK_H
3 changes: 3 additions & 0 deletions doomsday/libgui/libgui.pro
Expand Up @@ -58,6 +58,7 @@ HEADERS += \
include/de/GLBuffer \
include/de/GLProgram \
include/de/GLShader \
include/de/GLShaderBank \
include/de/GLState \
include/de/GLTarget \
include/de/GLTexture \
Expand Down Expand Up @@ -86,6 +87,7 @@ HEADERS += \
include/de/gui/glentrypoints.h \
include/de/gui/glprogram.h \
include/de/gui/glshader.h \
include/de/gui/glshaderbank.h \
include/de/gui/glstate.h \
include/de/gui/gltarget.h \
include/de/gui/gltexture.h \
Expand Down Expand Up @@ -116,6 +118,7 @@ SOURCES += \
src/glentrypoints.cpp \
src/glprogram.cpp \
src/glshader.cpp \
src/glshaderbank.cpp \
src/glstate.cpp \
src/gltarget.cpp \
src/gltexture.cpp \
Expand Down
220 changes: 220 additions & 0 deletions doomsday/libgui/src/glshaderbank.cpp
@@ -0,0 +1,220 @@
/** @file glshaderbank.cpp Bank containing GL shaders.
*
* @authors Copyright (c) 2013 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#include "de/GLShaderBank"
#include "de/GLProgram"
#include "de/GLShader"

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

#include <QMap>

namespace de {

DENG2_PIMPL(GLShaderBank)
{
struct Source : public ISource
{
/// Information about a shader source.
struct ShaderSource {
String source;
enum Type {
FilePath,
ShaderSourceText
};
Type type;

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

GLShaderBank &bank;
ShaderSource vertex;
ShaderSource fragment;

Source(GLShaderBank &b, ShaderSource const &vtx, ShaderSource const &frag)
: bank(b), vertex(vtx), fragment(frag)
{}

Time sourceModifiedAt(ShaderSource const &src) const
{
if(src.type == ShaderSource::FilePath)
{
return App::rootFolder().locate<File const>(src.source).status().modifiedAt;
}
return bank.sourceModifiedAt();
}

Time modifiedAt() const
{
Time vtxTime = sourceModifiedAt(vertex);
Time fragTime = sourceModifiedAt(fragment);
return de::max(vtxTime, fragTime);
}

GLShader *load(GLShader::Type type) const
{
ShaderSource const &src = (type == GLShader::Vertex? vertex : fragment);

if(src.type == ShaderSource::FilePath)
{
return bank.d->findShader(src.source, type);
}
// The program will hold the only ref to this shader.
return refless(new GLShader(type, src.source.toLatin1()));
}
};

struct Data : public IData
{
GLShader *vertex;
GLShader *fragment;

Data(GLShader *v, GLShader *f)
: vertex(holdRef(v)), fragment(holdRef(f)) {}
~Data() {
releaseRef(vertex);
releaseRef(fragment);
}
};

typedef QMap<String, GLShader *> Shaders; // path -> shader
Shaders shaders;

String relativeToPath;

Instance(Public *i) : Base(i)
{}

~Instance()
{
clearShaders();
}

void clearShaders()
{
// Release all of our references to the shaders.
foreach(GLShader *shader, shaders.values())
{
shader->release();
}
shaders.clear();
}

GLShader *findShader(String const &path, GLShader::Type type)
{
/// @todo Should check the modification time of the file to determine
/// if recompiling the shader is appropriate.

if(shaders.contains(path))
{
return shaders[path];
}

// We don't have this one yet, load and compile it now.
GLShader *shader = new GLShader(type, App::rootFolder().locate<ByteArrayFile const>(path));
shaders.insert(path, shader);
return shader;
}
};

GLShaderBank::GLShaderBank() : d(new Instance(this))
{}

void GLShaderBank::addFromInfo(File const &file)
{
LOG_AS("GLShaderBank");
d->relativeToPath = file.path().fileNamePath();
parse(file);
addFromInfoBlocks("shader");
}

GLShader &GLShaderBank::shader(Path const &path, GLShader::Type type) const
{
Instance::Data &i = static_cast<Instance::Data &>(data(path));

if(type == GLShader::Vertex)
{
return *i.vertex;
}
else
{
return *i.fragment;
}
}

GLProgram &GLShaderBank::build(GLProgram &program, Path const &path) const
{
Instance::Data &i = static_cast<Instance::Data &>(data(path));
program.build(i.vertex, i.fragment);
return program;
}

Bank::ISource *GLShaderBank::newSourceFromInfo(String const &id)
{
typedef Instance::Source Source;
typedef Instance::Source::ShaderSource ShaderSource;

Record const &def = info()[id];

ShaderSource vtx;
ShaderSource frag;

// Vertex shader definition.
if(def.has("path.vertex"))
{
vtx = ShaderSource(d->relativeToPath / def["path.vertex"], ShaderSource::FilePath);
}
else if(def.has("path"))
{
vtx = ShaderSource(d->relativeToPath / def["path"] + ".vsh", ShaderSource::FilePath);
}
else if(def.has("vertex"))
{
vtx = ShaderSource(def["vertex"], ShaderSource::ShaderSourceText);
}

// Fragment shader definition.
if(def.has("path.fragment"))
{
frag = ShaderSource(d->relativeToPath / def["path.fragment"], ShaderSource::FilePath);
}
else if(def.has("path"))
{
frag = ShaderSource(d->relativeToPath / def["path"] + ".fsh", ShaderSource::FilePath);
}
else if(def.has("fragment"))
{
frag = ShaderSource(def["fragment"], ShaderSource::ShaderSourceText);
}

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

Bank::IData *GLShaderBank::loadFromSource(ISource &source)
{
Instance::Source &src = static_cast<Instance::Source &>(source);

return new Instance::Data(src.load(GLShader::Vertex),
src.load(GLShader::Fragment));
}

} // namespace de

0 comments on commit 33d240a

Please sign in to comment.