ShaderProgram.hh 19.9 KB
Newer Older
Robert Menzel's avatar
Robert Menzel committed
1 2 3 4 5
////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2011, Computer Graphics Group RWTH Aachen University         //
// All rights reserved.                                                       //
////////////////////////////////////////////////////////////////////////////////

6 7
#ifndef ACGL_OPENGL_OBJECTS_SHADERPROGRAM_HH
#define ACGL_OPENGL_OBJECTS_SHADERPROGRAM_HH
Robert Menzel's avatar
Robert Menzel committed
8

Robert Menzel's avatar
Robert Menzel committed
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
/*
 * A ShaderProgram is a wrapper around an OpenGL Program: A combination of Shaders
 * that are linked together to controll the programmable pipeline stages.
 *
 * A ShaderProgram is still quite low-level and just wraps the OpenGL object itself.
 *
 * One note on uniforms:
 * There are basically four ways to set uniform values here:
 *
 * setUniform(        GLint       _location, VALUE );
 * setUniform(        std::string _location, VALUE );
 * setProgramUniform( GLint       _location, VALUE );
 * setProgramUniform( std::string _location, VALUE );
 *
 * The versions with a std::string as a location are easy to use, just provide the name
 * the uniform is called in the shaderfile. But it will have to query the uniform location
 * each call and thus is inefficient! It would be faster to query the location once using
 * getUniformLocation( std::string ); and use the returned value in combination with the
 * set*Uniform( GLint, ...) versions.
 *
 * Both are provided as setUniform and setProgramUniform:
 * In order for setUniform(...) to work as intendet the ShaderProgram has to be active ( use() ),
 * setProgramUniform(...) does not have this limitation and is based on direct state access
 * (via an extension or a basic simulation of the extension).
 * Use setProgramUniform if you can't know which program is in use right now, setUniform should
 * be prefered for performance critical parts of your app.
 *
 * In short: setProgramUniform( std::string _location, VALUE ); is the most error proof option
 *           and good for testing out new stuff
 *           setUniform( GLint _location, VALUE ); is best for performance critical code thats
 *           well tested
 *
 */

Robert Menzel's avatar
Robert Menzel committed
43 44
#include <ACGL/ACGL.hh>

45
#include <ACGL/Base/Macros.hh>
Robert Menzel's avatar
Robert Menzel committed
46 47 48
#include <ACGL/OpenGL/GL.hh>
#include <ACGL/OpenGL/Objects/Shader.hh>
#include <ACGL/OpenGL/Objects/Texture.hh>
49
#include <ACGL/Math/Math.hh>
Robert Menzel's avatar
Robert Menzel committed
50 51

#include <vector>
Robert Menzel's avatar
Robert Menzel committed
52
#include <tr1/memory>
Robert Menzel's avatar
Robert Menzel committed
53 54

namespace ACGL{
Robert Menzel's avatar
Robert Menzel committed
55
namespace OpenGL{
Robert Menzel's avatar
Robert Menzel committed
56 57 58

class ShaderProgram
{
59
    ACGL_NOT_COPYABLE(ShaderProgram)
60

Robert Menzel's avatar
Robert Menzel committed
61 62 63 64
    // ===================================================================================================== \/
    // ============================================================================================ TYPEDEFS \/
    // ===================================================================================================== \/
public:
65
    typedef std::vector< ConstSharedShader > ConstSharedShaderVec;
Robert Menzel's avatar
Robert Menzel committed
66 67 68 69 70 71

    // ========================================================================================================= \/
    // ============================================================================================ CONSTRUCTORS \/
    // ========================================================================================================= \/
public:
    ShaderProgram(void)
72
    :   mObjectName(0),
Robert Menzel's avatar
Robert Menzel committed
73 74
        mShaders()
    {
75
        mObjectName = glCreateProgram();
Robert Menzel's avatar
Robert Menzel committed
76 77 78 79 80
    }

    virtual ~ShaderProgram(void)
    {
        // "DeleteProgram will silently ignore the value zero." - GL Spec
81
        glDeleteProgram(mObjectName);
Robert Menzel's avatar
Robert Menzel committed
82 83 84 85 86 87
    }

    // ==================================================================================================== \/
    // ============================================================================================ GETTERS \/
    // ==================================================================================================== \/
public:
88 89 90
    inline       GLuint                operator()   (void) const { return mObjectName; }
    inline       GLuint                getObjectName(void) const { return mObjectName; }
    inline const ConstSharedShaderVec& getShaders   (void) const { return mShaders;    }
Robert Menzel's avatar
Robert Menzel committed
91 92 93 94 95

    // ===================================================================================================== \/
    // ============================================================================================ WRAPPERS \/
    // ===================================================================================================== \/
public:
96
    inline GLint getUniformLocation      (const std::string& _nameInShader) const { return glGetUniformLocation (mObjectName, _nameInShader.c_str()); }
Robert Menzel's avatar
Robert Menzel committed
97
#if (ACGL_OPENGL_VERSION >= 30)
98 99 100 101
    inline GLint getAttributeLocation    (const std::string& _nameInShader) const { return glGetAttribLocation  (mObjectName, _nameInShader.c_str()); }
    inline GLint getFragmentDataLocation (const std::string& _nameInShader) const { return glGetFragDataLocation(mObjectName, _nameInShader.c_str()); }
    inline void bindAttributeLocation    (const std::string& _nameInShader, GLuint _location) const { glBindAttribLocation   (mObjectName, _location, _nameInShader.c_str()); }
    inline void bindFragmentDataLocation (const std::string& _nameInShader, GLuint _location) const { glBindFragDataLocation (mObjectName, _location, _nameInShader.c_str()); }
102
#endif // OpenGL >= 3.0
103
    inline void use(void) const { glUseProgram(mObjectName); }
Robert Menzel's avatar
Robert Menzel committed
104

105
    inline void attachShader(const ConstSharedShader& _shader)
Robert Menzel's avatar
Robert Menzel committed
106 107
    {
        mShaders.push_back(_shader);
108
        glAttachShader( mObjectName, _shader->getObjectName() );
Robert Menzel's avatar
Robert Menzel committed
109 110 111 112
    }

    bool link (void) const;

Robert Menzel's avatar
Robert Menzel committed
113

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
    // ===================================================================================================== \/
    // ============================================================================================ UNIFORMS \/
    // ===================================================================================================== \/

    // int by location
    inline void setUniform (GLint _location, GLint _v)             const { glUniform1i (_location, _v); }
    inline void setUniform (GLint _location, const glm::ivec2& _v) const { glUniform2iv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::ivec3& _v) const { glUniform3iv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::ivec4& _v) const { glUniform4iv(_location, 1, glm::value_ptr(_v)); }

    // int DSA by location
    inline void setProgramUniform (GLint _location, GLint _v)             const { glProgramUniform1i (mObjectName, _location, _v); }
    inline void setProgramUniform (GLint _location, const glm::ivec2& _v) const { glProgramUniform2iv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::ivec3& _v) const { glProgramUniform3iv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::ivec4& _v) const { glProgramUniform4iv(mObjectName, _location, 1, glm::value_ptr(_v)); }
129

130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
#if (ACGL_OPENGL_VERSION >= 30)
    // unsigned int by location
    inline void setUniform (GLint _location, GLuint _v)            const { glUniform1ui (_location, _v); }
    inline void setUniform (GLint _location, const glm::uvec2& _v) const { glUniform2uiv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::uvec3& _v) const { glUniform3uiv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::uvec4& _v) const { glUniform4uiv(_location, 1, glm::value_ptr(_v)); }

    // unsigned int DSA by location
    inline void setProgramUniform (GLint _location, GLuint _v)            const { glProgramUniform1ui (mObjectName, _location, _v); }
    inline void setProgramUniform (GLint _location, const glm::uvec2& _v) const { glProgramUniform2uiv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::uvec3& _v) const { glProgramUniform3uiv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::uvec4& _v) const { glProgramUniform4uiv(mObjectName, _location, 1, glm::value_ptr(_v)); }
#endif // OpenGL >= 3.0

    // float by location
    inline void setUniform (GLint _location, GLfloat _v)          const { glUniform1f (_location, _v); }
Robert Menzel's avatar
Robert Menzel committed
146 147 148
    inline void setUniform (GLint _location, const glm::vec2& _v) const { glUniform2fv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::vec3& _v) const { glUniform3fv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::vec4& _v) const { glUniform4fv(_location, 1, glm::value_ptr(_v)); }
149

150 151
    // float DSA by location
    inline void setProgramUniform (GLint _location, GLfloat _v)          const { glProgramUniform1f (mObjectName, _location, _v); }
152 153 154
    inline void setProgramUniform (GLint _location, const glm::vec2& _v) const { glProgramUniform2fv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::vec3& _v) const { glProgramUniform3fv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::vec4& _v) const { glProgramUniform4fv(mObjectName, _location, 1, glm::value_ptr(_v)); }
155

156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
#if (ACGL_OPENGL_VERSION >= 40)
    // double by location
    inline void setUniform (GLint _location, GLdouble _v)          const { glUniform1d (_location, _v); }
    inline void setUniform (GLint _location, const glm::dvec2& _v) const { glUniform2dv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dvec3& _v) const { glUniform3dv(_location, 1, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dvec4& _v) const { glUniform4dv(_location, 1, glm::value_ptr(_v)); }

    // double DSA by location
    inline void setProgramUniform (GLint _location, GLdouble _v)          const { glProgramUniform1d (mObjectName, _location, _v); }
    inline void setProgramUniform (GLint _location, const glm::dvec2& _v) const { glProgramUniform2dv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dvec3& _v) const { glProgramUniform3dv(mObjectName, _location, 1, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dvec4& _v) const { glProgramUniform4dv(mObjectName, _location, 1, glm::value_ptr(_v)); }
#endif // OpenGL >= 4.0

    // float matrix by location
    inline void setUniform (GLint _location, const glm::mat2&   _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix2fv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat2x3& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix2x3fv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat2x4& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix2x4fv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat3x2& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix3x2fv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat3&   _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix3fv  (_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat3x4& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix3x4fv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat4x2& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix4x2fv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat4x3& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix4x3fv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::mat4&   _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix4fv  (_location, 1, _transpose, glm::value_ptr(_v)); }

    // float matrix DSA by location
    inline void setProgramUniform (GLint _location, const glm::mat2&   _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix2fv  (mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat2x3& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix2x3fv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat2x4& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix2x4fv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat3x2& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix3x2fv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat3&   _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix3fv  (mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat3x4& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix3x4fv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat4x2& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix4x2fv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat4x3& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix4x3fv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::mat4&   _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix4fv  (mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }

#if (ACGL_OPENGL_VERSION >= 40)
    // double matrix by location
    inline void setUniform (GLint _location, const glm::dmat2&   _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix2dv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat2x3& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix2x3dv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat2x4& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix2x4dv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat3x2& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix3x2dv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat3&   _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix3dv  (_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat3x4& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix3x4dv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat4x2& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix4x2dv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat4x3& _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix4x3dv(_location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setUniform (GLint _location, const glm::dmat4&   _v, GLboolean _transpose = GL_FALSE) const { glUniformMatrix4dv  (_location, 1, _transpose, glm::value_ptr(_v)); }

    // double matrix DSA by location
    inline void setProgramUniform (GLint _location, const glm::dmat2&   _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix2dv  (mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat2x3& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix2x3dv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat2x4& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix2x4dv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat3x2& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix3x2dv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat3&   _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix3dv  (mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat3x4& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix3x4dv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat4x2& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix4x2dv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat4x3& _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix4x3dv(mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
    inline void setProgramUniform (GLint _location, const glm::dmat4&   _v, GLboolean _transpose = GL_FALSE) const { glProgramUniformMatrix4dv  (mObjectName, _location, 1, _transpose, glm::value_ptr(_v)); }
#endif // OpenGL >= 4.0

    // texture
    inline void setTexture        (GLint _location,                  const ConstSharedTexture& _texture, GLenum _unit = 0) const { glUniform1i(_location, _unit);                                        _texture->bind(_unit); }
    inline void setProgramTexture (const std::string& _nameInShader, const ConstSharedTexture& _texture, GLenum _unit = 0) const { setProgramUniform( getUniformLocation(_nameInShader), (GLint) _unit); _texture->bind(_unit); }
219

220 221 222
    // ======================================================================================================= \/
    // ============================================================================================ HIGH LEVEL \/
    // ======================================================================================================= \/
223

224 225 226 227 228 229
    // normal:
    template <typename T>
    inline void setUniform (const std::string& _nameInShader, T _v) const
    {
        setUniform( getUniformLocation(_nameInShader), _v);
    }
230

231 232 233 234 235 236
    // DSA:
    template <typename T>
    inline void setProgramUniform (const std::string& _nameInShader, T _v) const
    {
        setProgramUniform( getUniformLocation(_nameInShader), _v);
    }
237

238 239 240 241 242 243
    // normal for matrices with additional transpose parameter
    template <typename T>
    inline void setUniform (const std::string& _nameInShader, T _v, GLboolean _transpose) const
    {
        setUniform( getUniformLocation(_nameInShader), _v, _transpose);
    }
244

245 246 247 248 249 250
    // DSA for matrices with additional transpose parameter
    template <typename T>
    inline void setProgramUniform (const std::string& _nameInShader, T _v, GLboolean _transpose) const
    {
        setProgramUniform( getUniformLocation(_nameInShader), _v, _transpose);
    }
Robert Menzel's avatar
Robert Menzel committed
251

252 253 254
    inline void setTexture        (const std::string& _nameInShader, const ConstSharedTexture& _texture, GLenum _unit = 0) const { setUniform( getUniformLocation(_nameInShader), (GLint) _unit);        _texture->bind(_unit); }
    inline void setProgramTexture (GLint _location,                  const ConstSharedTexture& _texture, GLenum _unit = 0) const { glProgramUniform1i(mObjectName, _location, _unit);                    _texture->bind(_unit); }
    
Robert Menzel's avatar
Robert Menzel committed
255 256 257 258 259

    // =================================================================================================== \/
    // ============================================================================================ FIELDS \/
    // =================================================================================================== \/
protected:
260
    GLuint               mObjectName;
261
    ConstSharedShaderVec mShaders;
Robert Menzel's avatar
Robert Menzel committed
262 263
};

264
ACGL_SHARED_TYPEDEF(ShaderProgram)
Robert Menzel's avatar
Robert Menzel committed
265 266

} // OpenGL
Robert Menzel's avatar
Robert Menzel committed
267 268
} // ACGL

269
#endif // ACGL_OPENGL_OBJECTS_SHADERPROGRAM_HH