#ifndef Magnum_AbstractShaderProgram_h #define Magnum_AbstractShaderProgram_h /* Copyright © 2010, 2011, 2012 Vladimír Vondruš This file is part of Magnum. Magnum is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3 only, as published by the Free Software Foundation. Magnum 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 version 3 for more details. */ /** @file * @brief Class Magnum::AbstractShaderProgram */ #include #include #include #include "Magnum.h" #include "TypeTraits.h" #include "magnumVisibility.h" namespace Magnum { namespace Math { template class RectangularMatrix; template class Matrix; template class Vector; } class Context; class Shader; #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Attribute; } #endif /** @brief Base for shader program implementations @section AbstractShaderProgram-subclassing Subclassing workflow This class is designed to be used via subclassing. Subclasses define these functions and properties: - %Attribute definitions with location and type for configuring meshes, for example: @code static const Attribute<0, Point3D> Position; static const Attribute<1, Vector3> Normal; static const Attribute<2, Vector2> TextureCoordinates; @endcode @todoc Output attribute location (for bindFragmentDataLocationIndexed(), referenced also from Framebuffer::mapDefaultForDraw() / Framebuffer::mapForDraw()) - **Layers for texture uniforms** to which the textures will be bound before rendering, for example: @code static const GLint DiffuseTextureLayer = 0; static const GLint SpecularTextureLayer = 1; @endcode - **Uniform locations** for setting uniform data (see below) (private constants), for example: @code static const GLint TransformationUniform = 0; static const GLint ProjectionUniform = 1; static const GLint DiffuseTextureUniform = 2; static const GLint SpecularTextureUniform = 3; @endcode - **Constructor**, which attaches particular shaders, links the program and gets uniform locations, for example: @code MyShader() { // Load shaders from file and attach them to the program attachShader(Shader::fromFile(Version::430, Shader::Type::Vertex, "PhongShader.vert")); attachShader(Shader::fromFile(Version::430, Shader::Type::Fragment, "PhongShader.frag")); // Link link(); } @endcode - **Uniform setting functions**, which will provide public interface for protected setUniform() functions. For usability purposes you can implement also method chaining. Example: @code MyShader* setTransformation(const Matrix4& matrix) { setUniform(TransformationUniform, matrix); return this; } MyShader* setProjection(const Matrix4& matrix) { setUniform(ProjectionUniform, matrix); return this; } @endcode @subsection AbstractShaderProgram-attribute-location Binding attribute location The preferred workflow is to specify attribute location for vertex shader input attributes and fragment shader output attributes explicitly in the shader code, e.g.: @code // GLSL 3.30, or #extension GL_ARB_explicit_attrib_location: enable layout(location = 0) in vec4 position; layout(location = 1) in vec3 normal; layout(location = 2) in vec2 textureCoordinates; @endcode Similarly for ouput attributes, you can also specify blend equation color index for them (see Framebuffer::BlendFunction for more information about using color input index): @code layout(location = 0, index = 0) out vec4 color; layout(location = 1, index = 1) out vec4 ambient; @endcode If you don't have the required extension, you can use functions bindAttributeLocation() and bindFragmentDataLocation() / bindFragmentDataLocationIndexed() between attaching the shaders and linking the program: @code // Shaders attached... bindAttributeLocation(Position.Location, "position"); bindAttributeLocation(Normal.Location, "normal"); bindAttributeLocation(TextureCoords.Location, "textureCoordinates"); bindFragmentDataLocationIndexed(0, 0, "color"); bindFragmentDataLocationIndexed(1, 1, "ambient"); // Link... @endcode @requires_gl30 %Extension @extension{EXT,gpu_shader4} for using bindFragmentDataLocation(). @requires_gl33 %Extension @extension{ARB,blend_func_extended} for using bindFragmentDataLocationIndexed(). @requires_gl33 %Extension @extension{ARB,explicit_attrib_location} for explicit attribute location instead of using bindAttributeLocation(), bindFragmentDataLocation() or bindFragmentDataLocationIndexed(). @requires_gles30 Explicit location specification of input attributes is not supported in OpenGL ES 2.0, use bindAttributeLocation() instead. @requires_gles30 Multiple fragment shader outputs are not available in OpenGL ES 2.0, similar functionality is available in extension @extension{NV,draw_buffers}. @subsection AbstractShaderProgram-uniform-location Uniform locations The preferred workflow is to specify uniform locations directly in the shader code, e.g.: @code // GLSL 4.30, or #extension GL_ARB_explicit_uniform_location: enable layout(location = 0) uniform mat4 transformation; layout(location = 1) uniform mat4 projection; @endcode If you don't have the required extension, you can get uniform location using uniformLocation() after linking stage: @code GLint transformationUniform = uniformLocation("transformation"); GLint projectionUniform = uniformLocation("projection"); @endcode @requires_gl43 Extension @extension{ARB,explicit_uniform_location} for explicit uniform location instead of using uniformLocation(). @requires_gl Explicit uniform location is not supported in OpenGL ES. Use uniformLocation() instead. @subsection AbstractShaderProgram-texture-layer Binding texture layer uniforms The preferred workflow is to specify texture layers directly in the shader code, e.g.: @code // GLSL 4.20, or #extension GL_ARB_shading_language_420pack: enable layout(binding = 0) uniform sampler2D diffuseTexture; layout(binding = 1) uniform sampler2D specularTexture; @endcode If you don't have the required extension (or if you want to change the layer later), you can set the texture layer uniform using setUniform(GLint, GLint): @code setUniform(DiffuseTextureUniform, DiffuseTextureLayer); setUniform(SpecularTextureUniform, SpecularTextureLayer); @endcode @requires_gl42 Extension @extension{ARB,shading_language_420pack} for explicit texture layer binding instead of using setUniform(GLint, GLint). @requires_gl Explicit texture layer binding is not supported in OpenGL ES. Use setUniform(GLint, GLint) instead. @section AbstractShaderProgram-rendering-workflow Rendering workflow Basic workflow with %AbstractShaderProgram subclasses is to instance the class and configuring attribute binding in meshes (see @ref Mesh-configuration "Mesh documentation" for more information) at the beginning, then in draw event setting uniforms and marking the shader for use, binding required textures to their respective layers using AbstractTexture::bind(GLint) and calling Mesh::draw(). Example: @code shader->setTransformation(transformation) ->setProjection(projection) ->use(); diffuseTexture->bind(MyShader::DiffuseTextureLayer); specularTexture->bind(MyShader::SpecularTextureLayer); mesh.draw(); @endcode @section AbstractShaderProgram-types Mapping between GLSL and Magnum types - `vec2`, `vec3` and `vec4` is @ref Math::Vector "Math::Vector<2, GLfloat>", @ref Math::Vector "Math::Vector<3, GLfloat>" and @ref Math::Vector "Math::Vector<4, GLfloat>". - `mat2`, `mat3` and `mat4` is @ref Math::Matrix "Math::Matrix<2, GLfloat>", @ref Math::Matrix "Math::Matrix<3, GLfloat>" and @ref Math::Matrix "Math::Matrix<4, GLfloat>". - `mat2x3`, `mat3x2`, `mat2x4`, `mat4x2`, `mat3x4`, `mat4x3` is @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 3, GLfloat>", @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 2, GLfloat>", @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 4, GLfloat>", @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 2, GLfloat>", @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 4, GLfloat>" and @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 3, GLfloat>". - `ivec2`, `ivec3` and `ivec4` is @ref Math::Vector "Math::Vector<2, GLint>", @ref Math::Vector "Math::Vector<3, GLint>" and @ref Math::Vector "Math::Vector<4, GLint>", `uvec2`, `uvec3` and `uvec4` is @ref Math::Vector "Math::Vector<2, GLuint>", @ref Math::Vector "Math::Vector<3, GLuint>" and @ref Math::Vector "Math::Vector<4, GLuint>". @requires_gl30 %Extension @extension{EXT,gpu_shader4} (for integer attributes and unsigned integer uniforms) @requires_gles30 Integer attributes and unsigned integer uniforms are not available in OpenGL ES 2.0. - `dvec2`, `dvec3` and `dvec4` is @ref Math::Vector "Math::Vector<2, GLdouble>", @ref Math::Vector "Math::Vector<3, GLdouble>" and @ref Math::Vector "Math::Vector<4, GLdouble>", `dmat2`, `dmat3` and `dmat4` is @ref Math::Matrix "Math::Matrix<2, GLdouble>", @ref Math::Matrix "Math::Matrix<3, GLdouble>" and @ref Math::Matrix "Math::Matrix<4, GLdouble>", `dmat2x3`, `dmat3x2`, `dmat2x4`, `dmat4x2`, `dmat3x4`, `dmat4x3` is @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 3, GLdouble>", @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 2, GLdouble>", @ref Math::RectangularMatrix "Math::RectangularMatrix<2, 4, GLdouble>", @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 2, GLdouble>", @ref Math::RectangularMatrix "Math::RectangularMatrix<3, 4, GLdouble>" and @ref Math::RectangularMatrix "Math::RectangularMatrix<4, 3, GLdouble>". @requires_gl41 %Extension @extension{ARB,vertex_attrib_64bit} (for double attributes) @requires_gl Double attributes are not available in OpenGL ES. Only types listed here (and their subclasses and specializations, such as @ref Matrix3 or Color4) can be used for setting uniforms and specifying vertex attributes. See also TypeTraits::AttributeType. @section AbstractShaderProgram-performance-optimization Performance optimizations The engine tracks currently used shader program to avoid unnecessary calls to @fn_gl{UseProgram}. If extension @extension{ARB,separate_shader_objects} or @extension{EXT,direct_state_access} is available, uniform setting functions use DSA functions to avoid unnecessary calls to @fn_gl{UseProgram}. See setUniform(GLint, GLfloat) documentation for more information. To achieve least state changes, set all uniforms in one run -- method chaining comes in handy. @todo Uniform arrays support */ class MAGNUM_EXPORT AbstractShaderProgram { friend class Context; AbstractShaderProgram(const AbstractShaderProgram& other) = delete; AbstractShaderProgram(AbstractShaderProgram&& other) = delete; AbstractShaderProgram& operator=(const AbstractShaderProgram& other) = delete; AbstractShaderProgram& operator=(AbstractShaderProgram&& other) = delete; public: /** * @brief Base struct for attribute location and type * * Template parameter @p T is the type which is used for shader * attribute, e.g. @ref Math::Vector4 "Vector4" for `ivec4`. * DataType is type of passed data when adding vertex buffers to mesh. * By default it is the same as type used in shader (e.g. * @ref DataType "DataType::Int" for @ref Math::Vector4 "Vector4"). * It's also possible to pass integer data to floating-point shader * inputs. In this case you may want to normalize the values (e.g. * color components from 0-255 to 0.0f-1.0f) - see * @ref DataOption "DataOption::Normalize". * * Only some types are allowed as attribute types, see * @ref AbstractShaderProgram-types or TypeTraits::AttributeType for * more information. * * See @ref AbstractShaderProgram-subclassing for example usage in * shaders and @ref Mesh-configuration for example usage when adding * vertex buffers to mesh. */ template class Attribute { public: /** @brief Location to which the attribute is bound */ static const GLuint Location = i; /** * @brief Type * * Type used in shader code. * @see DataType */ typedef typename TypeTraits::AttributeType Type; /** * @brief Data type * * Type of data passed to shader. * @see Type, DataOptions, Attribute() */ #ifdef DOXYGEN_GENERATING_OUTPUT enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, /**< Unsigned byte */ Byte = GL_BYTE, /**< Byte */ UnsignedShort = GL_UNSIGNED_SHORT, /**< Unsigned short */ Short = GL_SHORT, /**< Short */ UnsignedInt = GL_UNSIGNED_INT, /**< Unsigned int */ Int = GL_INT, /**< Int */ /** * Half float. Only for float attribute types. * @requires_gl30 %Extension @extension{NV,half_float} * @requires_gles30 %Extension @es_extension{OES,vertex_half_float} */ Half = GL_HALF_FLOAT, /** Float. Only for float attribute types. */ Float = GL_FLOAT, #ifndef MAGNUM_TARGET_GLES /** * Double. Only for float and double attribute types. * @requires_gl Only floats are available in OpenGL ES. */ Double = GL_DOUBLE, #endif /* GL_FIXED not supported */ /** * Unsigned 2.10.10.10 packed integer. Only for * four-component float vector attribute type. * @todo How about (incompatible) @es_extension{OES,vertex_type_10_10_10_2}? * @requires_gl33 %Extension @extension{ARB,vertex_type_2_10_10_10_rev} * @requires_gles30 (no extension providing this functionality) */ UnsignedInt2101010REV = GL_UNSIGNED_INT_2_10_10_10_REV, /** * Signed 2.10.10.10 packed integer. Only for * four-component float vector attribute type. * @requires_gl33 %Extension @extension{ARB,vertex_type_2_10_10_10_rev} * @requires_gles30 (no extension providing this functionality) */ Int2101010REV = GL_INT_2_10_10_10_REV }; #else typedef typename Implementation::Attribute::DataType DataType; #endif /** * @brief Data option * @see DataOptions, Attribute() */ #ifdef DOXYGEN_GENERATING_OUTPUT enum class DataOption: std::uint8_t { /** * Normalize integer components. Only for float attribute * types. Default is to not normalize. */ Normalize = 1 << 0, /** * BGRA component ordering. Default is RGBA. Only for * four-component float vector attribute type. * @requires_gl32 %Extension @extension{ARB,vertex_array_bgra} * @requires_gl Only RGBA component ordering is supported * in OpenGL ES. */ BGRA = 1 << 1 }; #else typedef typename Implementation::Attribute::DataOption DataOption; #endif /** * @brief Data options * @see Attribute() */ #ifdef DOXYGEN_GENERATING_OUTPUT typedef typename Corrade::Containers::EnumSet DataOptions; #else typedef typename Implementation::Attribute::DataOptions DataOptions; #endif /** * @brief Constructor * @param dataType Type of passed data. Default is the * same as type used in shader (e.g. DataType::Integer * for Vector4). * @param dataOptions Data options. Default is no options. */ inline constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _dataType(dataType), _dataOptions(dataOptions) {} /** @brief Type of passed data */ inline constexpr DataType dataType() const { return _dataType; } /** @brief Data options */ inline constexpr DataOptions dataOptions() const { return _dataOptions; } private: const DataType _dataType; const DataOptions _dataOptions; }; /** * @brief Constructor * * Creates one OpenGL shader program. * @see @fn_gl{CreateProgram} */ inline AbstractShaderProgram(): state(Initialized) { _id = glCreateProgram(); } /** * @brief Destructor * * Deletes associated OpenGL shader program. * @see @fn_gl{DeleteProgram} */ virtual ~AbstractShaderProgram() = 0; /** * @brief Use shader for rendering * @return False if the program wasn't successfully linked, true * otherwise. * * @see @fn_gl{UseProgram} */ bool use(); protected: /** * @brief Allow retrieving program binary * * Initially disabled. * @note This function should be called after attachShader() calls and * before link(). * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_BINARY_RETRIEVABLE_HINT} * @requires_gl41 Extension @extension{ARB,get_program_binary} * @requires_gles30 Always allowed in OpenGL ES 2.0. */ inline void setRetrievableBinary(bool enabled) { glProgramParameteri(_id, GL_PROGRAM_BINARY_RETRIEVABLE_HINT, enabled ? GL_TRUE : GL_FALSE); } /** * @brief Allow the program to be bound to individual pipeline stages * * Initially disabled. * @note This function should be called after attachShader() calls and * before link(). * @see @fn_gl{ProgramParameter} with @def_gl{PROGRAM_SEPARABLE} * @requires_gl41 Extension @extension{ARB,separate_shader_objects} * @requires_es_extension %Extension @es_extension{EXT,separate_shader_objects} */ inline void setSeparable(bool enabled) { /** @todo Remove when extension wrangler is available for ES */ #ifndef MAGNUM_TARGET_GLES glProgramParameteri(_id, GL_PROGRAM_SEPARABLE, enabled ? GL_TRUE : GL_FALSE); #else static_cast(enabled); #endif } /** * @brief Load shader * @return False if the shader wasn't successfully compiled, true * otherwise. * * Compiles the shader, if it is not already, and prepares it for * linking. * @see Shader::compile(), @fn_gl{AttachShader} */ bool attachShader(Shader& shader); /** @overload */ inline bool attachShader(Shader&& shader) { return attachShader(shader); } /** * @brief Bind attribute to given location * @param location Location * @param name Attribute name * * Binds attribute to location which is used later for binding vertex * buffers. * @note This function should be called after attachShader() calls and * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-attribute-location "class documentation" * for more information. * @see @fn_gl{BindAttribLocation} */ void bindAttributeLocation(GLuint location, const std::string& name); #ifndef MAGNUM_TARGET_GLES /** * @brief Bind fragment data to given location and color input index * @param location Location * @param name Fragment output variable name * @param index Blend equation color input index (`0` or `1`) * * Binds fragment data to location which is used later for framebuffer * operations. See also Framebuffer::BlendFunction for more * information about using color input index. * @note This function should be called after attachShader() calls and * before link(). * @deprecated Preferred usage is to specify attribute location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-attribute-location "class documentation" * for more information. * @see @fn_gl{BindFragDataLocationIndexed} * @requires_gl33 Extension @extension{ARB,blend_func_extended} * @requires_gl Multiple blend function inputs are not available in * OpenGL ES. */ void bindFragmentDataLocationIndexed(GLuint location, GLuint index, const std::string& name); /** * @brief Bind fragment data to given location and first color input index * @param location Location * @param name Fragment output variable name * * The same as bindFragmentDataLocationIndexed(), but with `index` set * to `0`. * @see @fn_gl{BindFragDataLocation} * @requires_gl30 Extension @extension{EXT,gpu_shader4} * @requires_gl Use explicit location specification in OpenGL ES 3.0 * instead. */ void bindFragmentDataLocation(GLuint location, const std::string& name); #endif /** * @brief Link the shader * * Binds previously specified attributes to given indexes and links the * shader program together. * @see @fn_gl{LinkProgram}, @fn_gl{GetProgram} with * @def_gl{LINK_STATUS}, @fn_gl{GetProgramInfoLog} */ void link(); /** * @brief Get uniform location * @param name Uniform name * * @note This function should be called after link(). * @deprecated Preferred usage is to specify uniform location * explicitly in the shader instead of using this function. See * @ref AbstractShaderProgram-uniform-location "class documentation" * for more information. * @see @fn_gl{GetUniformLocation} */ GLint uniformLocation(const std::string& name); /** * @brief Set uniform value * @param location Uniform location (see uniformLocation()) * @param value Value * * If neither @extension{ARB,separate_shader_objects} nor * @extension{EXT,direct_state_access} is available, the shader is * marked for use before the operation. * @see @fn_gl{UseProgram}, @fn_gl{Uniform} or `glProgramUniform()` * from @extension{ARB,separate_shader_objects}/@extension{EXT,direct_state_access}. */ inline void setUniform(GLint location, GLfloat value) { (this->*uniform1fImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Vector<2, GLfloat>& value) { (this->*uniform2fvImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Vector<3, GLfloat>& value) { (this->*uniform3fvImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Vector<4, GLfloat>& value) { (this->*uniform4fvImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, GLint value) { (this->*uniform1iImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Vector<2, GLint>& value) { (this->*uniform2ivImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Vector<3, GLint>& value) { (this->*uniform3ivImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Vector<4, GLint>& value) { (this->*uniform4ivImplementation)(location, value); } #ifndef MAGNUM_TARGET_GLES2 /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl30 Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, GLuint value) { (this->*uniform1uiImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl30 Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::Vector<2, GLuint>& value) { (this->*uniform2uivImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl30 Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::Vector<3, GLuint>& value) { (this->*uniform3uivImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl30 Extension @extension{EXT,gpu_shader4} * @requires_gles30 Only signed integers are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::Vector<4, GLuint>& value) { (this->*uniform4uivImplementation)(location, value); } #endif #ifndef MAGNUM_TARGET_GLES /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, GLdouble value) { (this->*uniform1dImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::Vector<2, GLdouble>& value) { (this->*uniform2dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::Vector<3, GLdouble>& value) { (this->*uniform3dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::Vector<4, GLdouble>& value) { (this->*uniform4dvImplementation)(location, value); } #endif /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Matrix<2, GLfloat>& value) { (this->*uniformMatrix2fvImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Matrix<3, GLfloat>& value) { (this->*uniformMatrix3fvImplementation)(location, value); } /** @copydoc setUniform(GLint, GLfloat) */ inline void setUniform(GLint location, const Math::Matrix<4, GLfloat>& value) { (this->*uniformMatrix4fvImplementation)(location, value); } #ifndef MAGNUM_TARGET_GLES2 /** * @copydoc setUniform(GLint, GLfloat) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::RectangularMatrix<2, 3, GLfloat>& value) { (this->*uniformMatrix2x3fvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::RectangularMatrix<3, 2, GLfloat>& value) { (this->*uniformMatrix3x2fvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::RectangularMatrix<2, 4, GLfloat>& value) { (this->*uniformMatrix2x4fvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::RectangularMatrix<4, 2, GLfloat>& value) { (this->*uniformMatrix4x2fvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::RectangularMatrix<3, 4, GLfloat>& value) { (this->*uniformMatrix3x4fvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gles30 Only square matrices are available in OpenGL ES 2.0. */ inline void setUniform(GLint location, const Math::RectangularMatrix<4, 3, GLfloat>& value) { (this->*uniformMatrix4x3fvImplementation)(location, value); } #endif #ifndef MAGNUM_TARGET_GLES /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::Matrix<2, GLdouble>& value) { (this->*uniformMatrix2dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::Matrix<3, GLdouble>& value) { (this->*uniformMatrix3dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::Matrix<4, GLdouble>& value) { (this->*uniformMatrix4dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::RectangularMatrix<2, 3, GLdouble>& value) { (this->*uniformMatrix2x3dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::RectangularMatrix<3, 2, GLdouble>& value) { (this->*uniformMatrix3x2dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::RectangularMatrix<2, 4, GLdouble>& value) { (this->*uniformMatrix2x4dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::RectangularMatrix<4, 2, GLdouble>& value) { (this->*uniformMatrix4x2dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::RectangularMatrix<3, 4, GLdouble>& value) { (this->*uniformMatrix3x4dvImplementation)(location, value); } /** * @copydoc setUniform(GLint, GLfloat) * @requires_gl40 Extension @extension{ARB,gpu_shader_fp64} * @requires_gl Only floats are available in OpenGL ES. */ inline void setUniform(GLint location, const Math::RectangularMatrix<4, 3, GLdouble>& value) { (this->*uniformMatrix4x3dvImplementation)(location, value); } #endif private: enum State { Initialized, Linked, Failed }; static void MAGNUM_LOCAL initializeContextBasedFunctionality(Context* context); typedef void(AbstractShaderProgram::*Uniform1fImplementation)(GLint, GLfloat); typedef void(AbstractShaderProgram::*Uniform2fvImplementation)(GLint, const Math::Vector<2, GLfloat>&); typedef void(AbstractShaderProgram::*Uniform3fvImplementation)(GLint, const Math::Vector<3, GLfloat>&); typedef void(AbstractShaderProgram::*Uniform4fvImplementation)(GLint, const Math::Vector<4, GLfloat>&); typedef void(AbstractShaderProgram::*Uniform1iImplementation)(GLint, GLint); typedef void(AbstractShaderProgram::*Uniform2ivImplementation)(GLint, const Math::Vector<2, GLint>&); typedef void(AbstractShaderProgram::*Uniform3ivImplementation)(GLint, const Math::Vector<3, GLint>&); typedef void(AbstractShaderProgram::*Uniform4ivImplementation)(GLint, const Math::Vector<4, GLint>&); #ifndef MAGNUM_TARGET_GLES2 typedef void(AbstractShaderProgram::*Uniform1uiImplementation)(GLint, GLuint); typedef void(AbstractShaderProgram::*Uniform2uivImplementation)(GLint, const Math::Vector<2, GLuint>&); typedef void(AbstractShaderProgram::*Uniform3uivImplementation)(GLint, const Math::Vector<3, GLuint>&); typedef void(AbstractShaderProgram::*Uniform4uivImplementation)(GLint, const Math::Vector<4, GLuint>&); #endif #ifndef MAGNUM_TARGET_GLES typedef void(AbstractShaderProgram::*Uniform1dImplementation)(GLint, GLdouble); typedef void(AbstractShaderProgram::*Uniform2dvImplementation)(GLint, const Math::Vector<2, GLdouble>&); typedef void(AbstractShaderProgram::*Uniform3dvImplementation)(GLint, const Math::Vector<3, GLdouble>&); typedef void(AbstractShaderProgram::*Uniform4dvImplementation)(GLint, const Math::Vector<4, GLdouble>&); #endif void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLfloat value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<3, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<4, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLint value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<2, GLint>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<3, GLint>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<4, GLint>& value); #ifndef MAGNUM_TARGET_GLES2 void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLuint value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<2, GLuint>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<3, GLuint>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<4, GLuint>& value); #endif #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL uniformImplementationDefault(GLint location, GLdouble value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<3, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Vector<4, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLfloat value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<3, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<4, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLint value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<2, GLint>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<3, GLint>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<4, GLint>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLuint value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<2, GLuint>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<3, GLuint>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<4, GLuint>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, GLdouble value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<3, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Vector<4, GLdouble>& value); #endif static Uniform1fImplementation uniform1fImplementation; static Uniform2fvImplementation uniform2fvImplementation; static Uniform3fvImplementation uniform3fvImplementation; static Uniform4fvImplementation uniform4fvImplementation; static Uniform1iImplementation uniform1iImplementation; static Uniform2ivImplementation uniform2ivImplementation; static Uniform3ivImplementation uniform3ivImplementation; static Uniform4ivImplementation uniform4ivImplementation; #ifndef MAGNUM_TARGET_GLES2 static Uniform1uiImplementation uniform1uiImplementation; static Uniform2uivImplementation uniform2uivImplementation; static Uniform3uivImplementation uniform3uivImplementation; static Uniform4uivImplementation uniform4uivImplementation; #endif #ifndef MAGNUM_TARGET_GLES static Uniform1dImplementation uniform1dImplementation; static Uniform2dvImplementation uniform2dvImplementation; static Uniform3dvImplementation uniform3dvImplementation; static Uniform4dvImplementation uniform4dvImplementation; #endif typedef void(AbstractShaderProgram::*UniformMatrix2fvImplementation)(GLint, const Math::Matrix<2, GLfloat>&); typedef void(AbstractShaderProgram::*UniformMatrix3fvImplementation)(GLint, const Math::Matrix<3, GLfloat>&); typedef void(AbstractShaderProgram::*UniformMatrix4fvImplementation)(GLint, const Math::Matrix<4, GLfloat>&); #ifndef MAGNUM_TARGET_GLES2 typedef void(AbstractShaderProgram::*UniformMatrix2x3fvImplementation)(GLint, const Math::RectangularMatrix<2, 3, GLfloat>&); typedef void(AbstractShaderProgram::*UniformMatrix3x2fvImplementation)(GLint, const Math::RectangularMatrix<3, 2, GLfloat>&); typedef void(AbstractShaderProgram::*UniformMatrix2x4fvImplementation)(GLint, const Math::RectangularMatrix<2, 4, GLfloat>&); typedef void(AbstractShaderProgram::*UniformMatrix4x2fvImplementation)(GLint, const Math::RectangularMatrix<4, 2, GLfloat>&); typedef void(AbstractShaderProgram::*UniformMatrix3x4fvImplementation)(GLint, const Math::RectangularMatrix<3, 4, GLfloat>&); typedef void(AbstractShaderProgram::*UniformMatrix4x3fvImplementation)(GLint, const Math::RectangularMatrix<4, 3, GLfloat>&); #endif #ifndef MAGNUM_TARGET_GLES typedef void(AbstractShaderProgram::*UniformMatrix2dvImplementation)(GLint, const Math::Matrix<2, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix3dvImplementation)(GLint, const Math::Matrix<3, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix4dvImplementation)(GLint, const Math::Matrix<4, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix2x3dvImplementation)(GLint, const Math::RectangularMatrix<2, 3, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix3x2dvImplementation)(GLint, const Math::RectangularMatrix<3, 2, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix2x4dvImplementation)(GLint, const Math::RectangularMatrix<2, 4, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix4x2dvImplementation)(GLint, const Math::RectangularMatrix<4, 2, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix3x4dvImplementation)(GLint, const Math::RectangularMatrix<3, 4, GLdouble>&); typedef void(AbstractShaderProgram::*UniformMatrix4x3dvImplementation)(GLint, const Math::RectangularMatrix<4, 3, GLdouble>&); #endif void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Matrix<2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Matrix<3, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Matrix<4, GLfloat>& value); #ifndef MAGNUM_TARGET_GLES2 void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 3, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 4, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 4, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 3, GLfloat>& value); #endif #ifndef MAGNUM_TARGET_GLES void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Matrix<2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Matrix<3, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::Matrix<4, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 3, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<2, 4, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<3, 4, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDefault(GLint location, const Math::RectangularMatrix<4, 3, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Matrix<2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Matrix<3, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Matrix<4, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 3, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 4, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 2, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 4, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 3, GLfloat>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Matrix<2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Matrix<3, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::Matrix<4, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 3, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<2, 4, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 2, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<3, 4, GLdouble>& value); void MAGNUM_LOCAL uniformImplementationDSA(GLint location, const Math::RectangularMatrix<4, 3, GLdouble>& value); #endif static UniformMatrix2fvImplementation uniformMatrix2fvImplementation; static UniformMatrix3fvImplementation uniformMatrix3fvImplementation; static UniformMatrix4fvImplementation uniformMatrix4fvImplementation; #ifndef MAGNUM_TARGET_GLES2 static UniformMatrix2x3fvImplementation uniformMatrix2x3fvImplementation; static UniformMatrix3x2fvImplementation uniformMatrix3x2fvImplementation; static UniformMatrix2x4fvImplementation uniformMatrix2x4fvImplementation; static UniformMatrix4x2fvImplementation uniformMatrix4x2fvImplementation; static UniformMatrix3x4fvImplementation uniformMatrix3x4fvImplementation; static UniformMatrix4x3fvImplementation uniformMatrix4x3fvImplementation; #endif #ifndef MAGNUM_TARGET_GLES static UniformMatrix2dvImplementation uniformMatrix2dvImplementation; static UniformMatrix3dvImplementation uniformMatrix3dvImplementation; static UniformMatrix4dvImplementation uniformMatrix4dvImplementation; static UniformMatrix2x3dvImplementation uniformMatrix2x3dvImplementation; static UniformMatrix3x2dvImplementation uniformMatrix3x2dvImplementation; static UniformMatrix2x4dvImplementation uniformMatrix2x4dvImplementation; static UniformMatrix4x2dvImplementation uniformMatrix4x2dvImplementation; static UniformMatrix3x4dvImplementation uniformMatrix3x4dvImplementation; static UniformMatrix4x3dvImplementation uniformMatrix4x3dvImplementation; #endif GLuint _id; State state; }; #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Attribute {}; template<> struct Attribute { enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, Byte = GL_BYTE, UnsignedShort = GL_UNSIGNED_SHORT, Short = GL_SHORT, UnsignedInt = GL_UNSIGNED_INT, Int = GL_INT, HalfFloat = GL_HALF_FLOAT, Float = GL_FLOAT #ifndef MAGNUM_TARGET_GLES , Double = GL_DOUBLE #endif }; enum class DataOption: std::uint8_t { Normalized = 1 << 0 }; typedef Corrade::Containers::EnumSet DataOptions; static const DataType DefaultDataType = DataType::Float; inline constexpr static GLint size(DataOptions) { return 1; } inline constexpr static std::size_t vectorCount() { return 1; } }; CORRADE_ENUMSET_OPERATORS(Attribute::DataOptions) template struct Attribute>: public Attribute { inline constexpr static GLint size(DataOptions) { return vectorSize; } inline constexpr static std::size_t vectorCount() { return 1; } }; template struct Attribute>: public Attribute { inline constexpr static GLint size(DataOptions) { return rows; } inline constexpr static std::size_t vectorCount() { return cols; } }; template struct Attribute>: public Attribute { inline constexpr static GLint size(DataOptions) { return matrixSize; } inline constexpr static std::size_t vectorCount() { return matrixSize; } }; template<> struct Attribute> { enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, Byte = GL_BYTE, UnsignedShort = GL_UNSIGNED_SHORT, Short = GL_SHORT, UnsignedInt = GL_UNSIGNED_INT, Int = GL_INT, Half = GL_HALF_FLOAT, Float = GL_FLOAT, #ifndef MAGNUM_TARGET_GLES Double = GL_DOUBLE, #endif UnsignedAlpha2RGB10 = GL_UNSIGNED_INT_2_10_10_10_REV, Alpha2RGB10 = GL_INT_2_10_10_10_REV }; enum class DataOption: std::uint8_t { Normalized = 1 << 0 #ifndef MAGNUM_TARGET_GLES , BGRA = 2 << 0 #endif }; typedef Corrade::Containers::EnumSet DataOptions; static const DataType DefaultDataType = DataType::Float; #ifndef MAGNUM_TARGET_GLES inline constexpr static GLint size(DataOptions options) { return options & DataOption::BGRA ? GL_BGRA : 4; } #else inline constexpr static GLint size(DataOptions) { return 4; } #endif inline constexpr static std::size_t vectorCount() { return 1; } }; typedef Math::Vector<4, GLfloat> _Vector4; CORRADE_ENUMSET_OPERATORS(Attribute<_Vector4>::DataOptions) template<> struct Attribute { enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, Byte = GL_BYTE, UnsignedShort = GL_UNSIGNED_SHORT, Short = GL_SHORT, UnsignedInt = GL_UNSIGNED_INT, Int = GL_INT }; enum class DataOption: std::uint8_t {}; typedef Corrade::Containers::EnumSet DataOptions; static const DataType DefaultDataType = DataType::Int; inline constexpr static GLint size() { return 1; } }; template<> struct Attribute { typedef Attribute::DataType DataType; typedef Attribute::DataOption DataOption; typedef Corrade::Containers::EnumSet DataOptions; static const DataType DefaultDataType = DataType::UnsignedInt; inline constexpr static GLint size() { return 1; } }; template struct Attribute>: public Attribute { inline constexpr static GLint size() { return size; } }; template struct Attribute>: public Attribute { inline constexpr static GLint size() { return size; } }; #ifndef MAGNUM_TARGET_GLES template<> struct Attribute { enum class DataType: GLenum { Double = GL_DOUBLE }; enum class DataOption: std::uint8_t {}; typedef Corrade::Containers::EnumSet DataOptions; static const DataType DefaultDataType = DataType::Double; inline constexpr static GLint size() { return 1; } inline constexpr static std::size_t vectorCount() { return 1; } }; template struct Attribute>: public Attribute { inline constexpr static GLint size() { return rows; } inline constexpr static std::size_t vectorCount() { return cols; } }; template struct Attribute>: public Attribute { inline constexpr static GLint size() { return size; } inline constexpr static std::size_t vectorCount() { return size; } }; template struct Attribute>: public Attribute { inline constexpr static GLint size() { return size; } inline constexpr static std::size_t vectorCount() { return size; } }; #endif template struct Attribute>: public Attribute> {}; template struct Attribute>: public Attribute> {}; template struct Attribute>: public Attribute> {}; template struct Attribute>: public Attribute> {}; template struct Attribute>: public Attribute> {}; template class Color3; template class Color4; template struct Attribute>: public Attribute> {}; template struct Attribute>: public Attribute> {}; template struct Attribute>: public Attribute> {}; template struct Attribute>: public Attribute> {}; } #endif } #endif