/**********************************************************************
* *
* cgt - CAMP Graphics Toolbox, Copyright (C) 2012-2014 *
* Chair for Computer Aided Medical Procedures *
* Technische Universitaet Muenchen, Germany. *
* *
* *
* forked from tgt - Tiny Graphics Toolbox, Copyright (C) 2006-2011 *
* Visualization and Computer Graphics Group, Department of *
* Computer Science, University of Muenster, Germany. *
* *
* *
* This file is part of the cgt library. This library is free *
* software; you can redistribute it and/or modify it under the terms *
* of the GNU Lesser General Public License version 2.1 as published *
* by the Free Software Foundation. *
* *
* This library 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 Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License in the file "LICENSE.txt" along with this library. *
* If not, see . *
* *
**********************************************************************/
#ifndef CGT_SHADERMANAGER_H
#define CGT_SHADERMANAGER_H
#include
#include
#include
#include "cgt/exception.h"
#include "cgt/manager.h"
#include "cgt/matrix.h"
#include "cgt/cgt_gl.h"
#include "cgt/types.h"
#include "cgt/singleton.h"
#include "cgt/vector.h"
namespace cgt {
/**
* Type of a shader object, can be vertex, fragment or geometry shader
*
* #include statements are allowed.
*
* Geometry shaders can be controled using directives in shader source.
* Accepted directives:
* GL_GEOMETRY_INPUT_TYPE_EXT(GL_POINTS | GL_LINES | GL_LINES_ADJACENCY_EXT | GL_TRIANGLES | GL_TRIANGLES_ADJACENCY_EXT)
* GL_GEOMETRY_OUTPUT_TYPE_EXT(GL_POINTS | GL_LINE_STRIP | GL_TRIANGLE_STRIP)
* GL_GEOMETRY_VERTICES_OUT_EXT()
* No newline or space allowed between each pair of brackets.
*
* Example geometry shader header:
* #version 120
* #extension GL_EXT_geometry_shader4 : enable
* //GL_GEOMETRY_INPUT_TYPE_EXT(GL_LINES)
* //GL_GEOMETRY_OUTPUT_TYPE_EXT(GL_LINE_STRIP)
* //GL_GEOMETRY_VERTICES_OUT_EXT(42)
* [...]
*/
class CGT_API ShaderObject {
public:
friend class Shader;
friend class ShaderPreprocessor;
enum ShaderType {
VERTEX_SHADER = GL_VERTEX_SHADER,
FRAGMENT_SHADER = GL_FRAGMENT_SHADER,
GEOMETRY_SHADER = GL_GEOMETRY_SHADER_EXT
};
// Helper for resolving line number when includes are used in shader files
struct LineInfo {
LineInfo(int n, std::string s, int sn)
: lineNumber_(n), filename_(s), sourceLineNumber_(sn) {}
int lineNumber_; //< line number in preprocessed file
std::string filename_; //< filename of included file
int sourceLineNumber_; //< line number in included file (needed when it itself
//< includes another file)
};
/**
* Creates a shader object of the specified type
*/
ShaderObject(const std::string& filename, ShaderType type = VERTEX_SHADER);
/**
* Deletes the shader and source
*/
~ShaderObject();
/**
* Loads the shader source from the specified file.
*
* @throw Exception if loading failed.
*/
void loadSourceFromFile(const std::string& filename)
throw (Exception);
bool compileShader();
bool isCompiled() const { return isCompiled_; }
std::string getCompilerLog() const;
bool rebuildFromFile();
/**
* Use h as header for shadersource (copies h)
*/
void setHeader(const std::string& h);
void setCustomGlslVersion(const std::string& version) {
customGlslVersion_ = version;
}
ShaderType getType() { return shaderType_; }
void setSource(std::string source) {
source_ = source;
unparsedSource_ = source;
}
const std::string getSource() { return unparsedSource_; }
/**
* Set geometry shader input type. For this change to take effect call setDirectives() and
* re-link already linked shaders. Currently only GL_POINTS, GL_LINES,
* GL_LINES_ADJACENCY_EXT, GL_TRIANGLES or GL_TRIANGLES_ADJACENCY_EXT can be used.
*/
void setInputType(GLint inputType) { inputType_ = inputType; }
GLint getInputType() const { return inputType_; }
/**
* Set geometry shader output type. For this change to take effect call setDirectives() and
* re-link already linked shaders. Currently only GL_POINTS, GL_LINE_STRIP or
* GL_TRIANGLE_STRIP can be used.
*/
void setOutputType(GLint outputType) { outputType_ = outputType; }
GLint getOuputType() const { return outputType_; }
/**
* Set maximum number of primitives a geometry shader can create.
* For this change to take effect call setDirectives()
* re-link already linked shaders. Limited by GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT.
*/
void setVerticesOut(GLint verticesOut) { verticesOut_ = verticesOut; }
GLint getVerticesOut() const { return verticesOut_; }
protected:
void uploadSource();
std::string filename_;
ShaderType shaderType_;
GLuint id_;
std::string source_;
std::string unparsedSource_;
std::string header_;
std::string customGlslVersion_; ///< Optional custom GLSL version, will override global GLSL version if set
bool isCompiled_;
GLint inputType_;
GLint outputType_;
GLint verticesOut_;
std::vector lineTracker_; ///< keeps track of line numbers when includes are used
static const std::string loggerCat_;
};
//------------------------------------------------------------------------------
/**
* Represents an OpenGL shader program, consisting of linked ShaderObjects.
*
* @note Convenient loading of shaders from file is provided by ShaderManager.
*/
class CGT_API Shader {
friend class ShaderManager;
public:
/**
* Guard to enable ignoring uniform location errors and ensuring to disable it again upon destruction.
*/
struct IgnoreUniformLocationErrorGuard {
public:
/**
* Creates a new IgnoreUniformLocationErrorGuard for the given shader.
* Sets the shader's ignoreError_ to true.
* \param shader Shader to enable ignoring uniform location errors.
*/
IgnoreUniformLocationErrorGuard(cgt::Shader* shader)
: _shader(shader)
, _stateToRestore(shader->getIgnoreUniformLocationError())
{
_shader->setIgnoreUniformLocationError(true);
};
/**
* Destructor, restores the shader's original ignoreError_ state.
*/
~IgnoreUniformLocationErrorGuard() {
_shader->setIgnoreUniformLocationError(_stateToRestore);
}
private:
cgt::Shader* _shader; ///< Shader to modify
bool _stateToRestore; ///< Original state
};
Shader();
/**
* Detaches all shader objects, deletes them an disposes all textures
*/
~Shader();
/**
* Attach shader object to Shader
*/
void attachObject(ShaderObject* obj);
void detachObject(ShaderObject* obj);
void detachObjectsByType(ShaderObject::ShaderType type);
/**
* Link all shader objects to one shader.
* Will re-link already linked shaders.
* @return true for success
*/
bool linkProgram();
bool rebuild();
bool rebuildFromFile();
void setHeaders(const std::string& customHeader);
void bindFragDataLocation(GLuint colorNumber, std::string name);
GLint getID() {return id_;};
/**
* Activates the shader
*/
void activate();
static void activate(GLint id);
static void deactivate();
static GLint getCurrentProgram();
/**
* Returns whether the Shader is currently activated
*/
bool isActivated();
bool isLinked() { return isLinked_; }
std::string getLinkerLog() const;
// Subroutines
bool selectSubroutine(ShaderObject::ShaderType type, const std::string& subroutineName);
//
// Uniform stuff
//
/**
* Returns uniform location, or -1 on failure
*/
GLint getUniformLocation(const std::string& name);
void setIgnoreUniformLocationError(bool ignoreError);
bool getIgnoreUniformLocationError();
// Floats
bool setUniform(const std::string& name, GLfloat value);
bool setUniform(const std::string& name, GLfloat v1, GLfloat v2);
bool setUniform(const std::string& name, GLfloat v1, GLfloat v2, GLfloat v3);
bool setUniform(const std::string& name, GLfloat v1, GLfloat v2, GLfloat v3, GLfloat v4);
bool setUniform(const std::string& name, GLfloat* v, int count);
// Integers
bool setUniform(const std::string& name, GLint value);
bool setUniform(const std::string& name, GLint v1, GLint v2);
bool setUniform(const std::string& name, GLint v1, GLint v2, GLint v3);
bool setUniform(const std::string& name, GLint v1, GLint v2, GLint v3, GLint v4);
bool setUniform(const std::string& name, GLint* v, int count);
// Unsigned Integers
bool setUniform(const std::string& name, GLuint value);
bool setUniform(const std::string& name, GLuint v1, GLuint v2);
bool setUniform(const std::string& name, GLuint v1, GLuint v2, GLuint v3);
bool setUniform(const std::string& name, GLuint v1, GLuint v2, GLuint v3, GLuint v4);
bool setUniform(const std::string& name, GLuint* v, int count);
// Booleans
bool setUniform(const std::string& name, bool value);
bool setUniform(const std::string& name, bool v1, bool v2);
bool setUniform(const std::string& name, bool v1, bool v2, bool v3);
bool setUniform(const std::string& name, bool v1, bool v2, bool v3, bool v4);
bool setUniform(const std::string& name, GLboolean* v, int count);
// Vectors
bool setUniform(const std::string& name, const Vector2f& value);
bool setUniform(const std::string& name, Vector2f* vectors, GLsizei count = 1);
bool setUniform(const std::string& name, const Vector3f& value);
bool setUniform(const std::string& name, Vector3f* vectors, GLsizei count = 1);
bool setUniform(const std::string& name, const Vector4f& value);
bool setUniform(const std::string& name, Vector4f* vectors, GLsizei count = 1);
bool setUniform(const std::string& name, const ivec2& value);
bool setUniform(const std::string& name, ivec2* vectors, GLsizei count = 1);
bool setUniform(const std::string& name, const ivec3& value);
bool setUniform(const std::string& name, ivec3* vectors, GLsizei count = 1);
bool setUniform(const std::string& name, const ivec4& value);
bool setUniform(const std::string& name, ivec4* vectors, GLsizei count = 1);
// Note: Matrix is transposed by OpenGL
bool setUniform(const std::string& name, const Matrix2f& value, bool transpose = false);
bool setUniform(const std::string& name, const Matrix3f& value, bool transpose = false);
bool setUniform(const std::string& name, const Matrix4f& value, bool transpose = false);
// No location lookup
//
// Floats
static void setUniform(GLint l, GLfloat value);
static void setUniform(GLint l, GLfloat v1, GLfloat v2);
static void setUniform(GLint l, GLfloat v1, GLfloat v2, GLfloat v3);
static void setUniform(GLint l, GLfloat v1, GLfloat v2, GLfloat v3, GLfloat v4);
// Integers
static void setUniform(GLint l, GLint value);
static void setUniform(GLint l, GLint v1, GLint v2);
static void setUniform(GLint l, GLint v1, GLint v2, GLint v3);
static void setUniform(GLint l, GLint v1, GLint v2, GLint v3, GLint v4);
// Vectors
static void setUniform(GLint l, const Vector2f& value);
static void setUniform(GLint l, const Vector3f& value);
static void setUniform(GLint l, const Vector4f& value);
static void setUniform(GLint l, const ivec2& value);
static void setUniform(GLint l, const ivec3& value);
static void setUniform(GLint l, const ivec4& value);
static void setUniform(GLint l, const Matrix2f& value, bool transpose = false);
static void setUniform(GLint l, const Matrix3f& value, bool transpose = false);
static void setUniform(GLint l, const Matrix4f& value, bool transpose = false);
// Attributes
//
// 1 component
static void setAttribute(GLint index, GLfloat v1);
static void setAttribute(GLint index, GLshort v1);
static void setAttribute(GLint index, GLdouble v1);
// 2 components
static void setAttribute(GLint index, GLfloat v1, GLfloat v2);
static void setAttribute(GLint index, GLshort v1, GLshort v2);
static void setAttribute(GLint index, GLdouble v1, GLdouble v2);
// 3 components
static void setAttribute(GLint index, GLfloat v1, GLfloat v2, GLfloat v3);
static void setAttribute(GLint index, GLshort v1, GLshort v2, GLshort v3);
static void setAttribute(GLint index, GLdouble v1, GLdouble v2, GLdouble v3);
// 4 components
static void setAttribute(GLint index, GLfloat v1, GLfloat v2, GLfloat v3, GLfloat v4);
static void setAttribute(GLint index, GLshort v1, GLshort v2, GLshort v3, GLshort v4);
static void setAttribute(GLint index, GLdouble v1, GLdouble v2, GLdouble v3, GLdouble v4);
// For vectors
static void setAttribute(GLint index, const Vector2f& v);
static void setAttribute(GLint index, const Vector3f& v);
static void setAttribute(GLint index, const Vector4f& v);
static void setAttribute(GLint index, const Vector2d& v);
static void setAttribute(GLint index, const Vector3d& v);
static void setAttribute(GLint index, const Vector4d& v);
static void setAttribute(GLint index, const Vector2& v);
static void setAttribute(GLint index, const Vector3& v);
static void setAttribute(GLint index, const Vector4& v);
static void setAttribute(GLint index, const Vector4& v);
static void setAttribute(GLint index, const Vector4& v);
static void setAttribute(GLint index, const Vector4& v);
static void setAttribute(GLint index, const Vector4& v);
static void setAttribute(GLint index, const Vector4& v);
// Attribute locations
// ATTENTION: This method was deliberately deactivated, since it was not working as expected
// with AMD GPUs.
// void setAttributeLocation(GLuint index, const std::string& name);
GLint getAttributeLocation(const std::string& name);
// Normalized attributes
static void setNormalizedAttribute(GLint index, GLubyte v1, GLubyte v2, GLubyte v3, GLubyte v4);
static void setNormalizedAttribute(GLint index, const Vector4& v);
static void setNormalizedAttribute(GLint index, const Vector4& v);
static void setNormalizedAttribute(GLint index, const Vector4& v);
// Unsigned version
static void setNormalizedAttribute(GLint index, const Vector4& v);
static void setNormalizedAttribute(GLint index, const Vector4& v);
static void setNormalizedAttribute(GLint index, const Vector4& v);
protected:
/**
* Load filename.vert and filename.frag (vertex and fragment shader) and link shader.
*
* @param customHeader Header to be put in front of the shader source.
*
* @throw Exception if loading failed
*/
void load(const std::string& filename, const std::string& customHeader = "")
throw (Exception);
/**
* Load vertex shader \p vertFilename, geometry shader \p geomFilename,
* fragment shader \p fragFilename.
*
* @param customHeader header to be put in front of the shader source
*
* @throw Exception if loading failed
*/
void loadSeparate(const std::string& vertFilename, const std::string& geomFilename,
const std::string& fragFilename, const std::string& customHeader = "", const std::string& customGlslVersion = "")
throw (Exception);
typedef std::list ShaderObjects;
ShaderObjects objects_;
GLuint id_;
bool isLinked_;
bool ignoreError_;
static const std::string loggerCat_;
};
//------------------------------------------------------------------------------
class ShaderManager;
#ifdef DLL_TEMPLATE_INST
template class CGT_API Singleton;
#endif
#ifdef DLL_TEMPLATE_INST
template class CGT_API ResourceManager;
#endif
/**
* Loads shaders from the file system, managing a shader search path.
*
* @see ResourceManager
*/
class CGT_API ShaderManager : public ResourceManager, public Singleton {
public:
ShaderManager();
/**
* Load given shaders from file and link them.
* Empty file names will be ignored (not loaded and linked). You have to pass the complete
* file names, inclusive file extensions (".vert", ".geom", frag").
*
* \param vertFilename Vertex shader file name
* \param fragFilename Fragment shader file name
* \param customHeader Custom header to add to all shaders (may be empty)
* \throw Exception if loading failed.
* \return The newly created shader.
*/
Shader* load(const std::string& vertFilename, const std::string& fragFilename,
const std::string& customHeader)
throw (Exception);
/**
* Load given shaders from file and link them.
* Empty file names will be ignored (not loaded and linked). You have to pass the complete
* file names, inclusive file extensions (".vert", ".geom", frag").
*
* \param vertFilename Vertex shader file name
* \param geomFilename Geometry shader file name (leave empty to disable geometry shader)
* \param fragFilename Fragment shader file name
* \param customHeader Custom header to add to all shaders (may be empty)
* \throw Exception if loading failed.
* \return The newly created shader.
*/
Shader* load(const std::string& vertFilename, const std::string& geomFilename, const std::string& fragFilename,
const std::string& customHeader)
throw(Exception);
/**
* Load given shaders from file and link them.
* Empty file names will be ignored (not loaded and linked). You have to pass the complete
* file names, inclusive file extensions (".vert", ".geom", frag").
*
* \param vertFilename Vertex shader file name
* \param geomFilename Geometry shader file name (leave empty to disable geometry shader)
* \param fragFilename Fragment shader file name
* \param customHeader Custom header to add to all shaders (may be empty)
* \param customGlslVersion Custom GLSL version for all shaders (leave empty to use default GLSL version from ShaderManager).
* \throw Exception if loading failed.
* \return The newly created shader.
*/
Shader* loadWithCustomGlslVersion(const std::string& vertFilename, const std::string& geomFilename, const std::string& fragFilename,
const std::string& customHeader, const std::string& customGlslVersion)
throw(Exception);
bool rebuildAllShadersFromFile();
/**
* Sets the global header that will be added to all shaders to \a header.
* \param header The new global header that will be added to all shaders.
*/
void setGlobalHeader(const std::string& header) {
globalHeader_ = header;
}
/**
* Gets the global header that will be added to all shaders.
* \return globalHeader_
*/
const std::string& getGlobalHeader() const {
return globalHeader_;
}
/**
* Sets the default GLSL version string, will be added to the '#version' pragma
* at the beginning of each shader.
* \param version Default GLSL version string.
*/
void setDefaultGlslVersion(const std::string& version) {
defaultGlslVersion_ = version;
}
/**
* Gets the default GLSL version string, will be added to the '#version' pragma
* at the beginning of each shader.
*/
const std::string& getDefaultGlslVersion() const {
return defaultGlslVersion_;
}
protected:
std::string defaultGlslVersion_; ///< Default GLSL version string, will be added to the '#version' pragma at the beginning of each shader
std::string globalHeader_; ///< Global header that will be added to all shaders.
static const std::string loggerCat_;
};
/**
* Parses #include statements and geometry shader settings
*/
class ShaderPreprocessor {
public:
enum Mode {
MODE_NONE = 0,
MODE_INCLUDE = 1,
MODE_GEOMETRY = 2
};
ShaderPreprocessor(ShaderObject* obj, Mode mode = Mode(MODE_INCLUDE | MODE_GEOMETRY));
// Returns the parsed result
std::string getResult() const;
GLint getGeomShaderInputType() const;
GLint getGeomShaderOutputType() const;
GLint getGeomShaderVerticesOut() const;
protected:
void parse();
void parsePart(const std::string& input, const std::string& name = "");
void outputComment(const std::string& comment, const std::string& type = "INFO");
/**
* Scan for geometry shader directives in shader source.
*
* Accepted directives:
* GL_GEOMETRY_INPUT_TYPE_EXT(GL_POINTS | GL_LINES | GL_LINES_ADJACENCY_EXT | GL_TRIANGLES | GL_TRIANGLES_ADJACENCY_EXT)
* GL_GEOMETRY_OUTPUT_TYPE_EXT(GL_POINTS | GL_LINE_STRIP | GL_TRIANGLE_STRIP)
* GL_GEOMETRY_VERTICES_OUT_EXT()
* No newline or space allowed between each pair of brackets.
*
* Example geometry shader header:
* #version 120
* #extension GL_EXT_geometry_shader4 : enable
*
* //GL_GEOMETRY_INPUT_TYPE_EXT(GL_LINES)
* //GL_GEOMETRY_OUTPUT_TYPE_EXT(GL_LINE_STRIP)
* //GL_GEOMETRY_VERTICES_OUT_EXT(42)
* [...]
*/
bool scanGeomShaderDirectives();
std::string getGeomShaderDirective(const std::string& d);
ShaderObject* shd_;
std::vector& lineTracker_; ///< keeps track of line numbers when includes are used
std::set includedFilenames_; ///< list of all filenames that have already been included (to avoid double inclusion)
int activeLine_;
std::ostringstream result_;
GLint inputType_;
GLint outputType_;
GLint verticesOut_;
static const std::string loggerCat_;
};
} // namespace cgt
#define ShdrMgr cgt::Singleton::getRef()
#endif //CGT_SHADERMANAGER_H