diff --git a/src/AbstractShaderProgram.cpp b/src/AbstractShaderProgram.cpp index 664a6e800..b8a3c03f1 100644 --- a/src/AbstractShaderProgram.cpp +++ b/src/AbstractShaderProgram.cpp @@ -586,7 +586,7 @@ void AbstractShaderProgram::uniformImplementationDSA(GLint location, const Math: #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { -std::size_t Attribute::size(GLint components, DataType dataType) { +std::size_t FloatAttribute::size(GLint components, DataType dataType) { switch(dataType) { case DataType::UnsignedByte: case DataType::Byte: @@ -609,7 +609,8 @@ std::size_t Attribute::size(GLint components, DataType dataType) { return 0; } -std::size_t Attribute::size(GLint components, DataType dataType) { +#ifndef MAGNUM_TARGET_GLES2 +std::size_t IntAttribute::size(GLint components, DataType dataType) { switch(dataType) { case DataType::UnsignedByte: case DataType::Byte: @@ -625,9 +626,10 @@ std::size_t Attribute::size(GLint components, DataType dataType) { CORRADE_INTERNAL_ASSERT(false); return 0; } +#endif #ifndef MAGNUM_TARGET_GLES -std::size_t Attribute::size(GLint components, DataType dataType) { +std::size_t DoubleAttribute::size(GLint components, DataType dataType) { switch(dataType) { case DataType::Double: return 8*components; @@ -639,6 +641,10 @@ std::size_t Attribute::size(GLint components, DataType dataType) { #endif std::size_t Attribute>::size(GLint components, DataType dataType) { + #ifndef MAGNUM_TARGET_GLES + if(components == GL_BGRA) components = 4; + #endif + switch(dataType) { case DataType::UnsignedByte: case DataType::Byte: @@ -668,6 +674,173 @@ std::size_t Attribute>::size(GLint components, DataType return 0; } +Debug operator<<(Debug debug, SizedAttribute<1, 1>::Components value) { + switch(value) { + case SizedAttribute<1, 1>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedAttribute<1, 2>::Components value) { + switch(value) { + case SizedAttribute<1, 2>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case SizedAttribute<1, 2>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedAttribute<1, 3>::Components value) { + switch(value) { + case SizedAttribute<1, 3>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case SizedAttribute<1, 3>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + case SizedAttribute<1, 3>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedAttribute<1, 4>::Components value) { + switch(value) { + case SizedAttribute<1, 4>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case SizedAttribute<1, 4>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + case SizedAttribute<1, 4>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + case SizedAttribute<1, 4>::Components::Four: + return debug << "AbstractShaderProgram::Attribute::Components::Four"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedMatrixAttribute<2>::Components value) { + switch(value) { + case SizedMatrixAttribute<2>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedMatrixAttribute<3>::Components value) { + switch(value) { + case SizedMatrixAttribute<3>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, SizedMatrixAttribute<4>::Components value) { + switch(value) { + case SizedMatrixAttribute<4>::Components::Four: + return debug << "AbstractShaderProgram::Attribute::Components::Four"; + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, Attribute>::Components value) { + switch(value) { + case Attribute>::Components::One: + return debug << "AbstractShaderProgram::Attribute::Components::One"; + case Attribute>::Components::Two: + return debug << "AbstractShaderProgram::Attribute::Components::Two"; + case Attribute>::Components::Three: + return debug << "AbstractShaderProgram::Attribute::Components::Three"; + case Attribute>::Components::Four: + return debug << "AbstractShaderProgram::Attribute::Components::Four"; + #ifndef MAGNUM_TARGET_GLES + case Attribute>::Components::BGRA: + return debug << "AbstractShaderProgram::Attribute::Components::BGRA"; + #endif + } + + return debug << "AbstractShaderProgram::Attribute::Components::(invalid)"; +} + +Debug operator<<(Debug debug, FloatAttribute::DataType value) { + switch(value) { + #define _c(value) case FloatAttribute::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(UnsignedByte) + _c(Byte) + _c(UnsignedShort) + _c(Short) + _c(UnsignedInt) + _c(Int) + _c(HalfFloat) + _c(Float) + #ifndef MAGNUM_TARGET_GLES + _c(Double) + #endif + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} + +#ifndef MAGNUM_TARGET_GLES2 +Debug operator<<(Debug debug, IntAttribute::DataType value) { + switch(value) { + #define _c(value) case IntAttribute::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(UnsignedByte) + _c(Byte) + _c(UnsignedShort) + _c(Short) + _c(UnsignedInt) + _c(Int) + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} +#endif + +#ifndef MAGNUM_TARGET_GLES +Debug operator<<(Debug debug, DoubleAttribute::DataType value) { + switch(value) { + #define _c(value) case DoubleAttribute::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(Double) + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} +#endif + +Debug operator<<(Debug debug, Attribute>::DataType value) { + switch(value) { + #define _c(value) case Attribute>::DataType::value: return debug << "AbstractShaderProgram::Attribute::DataType::" #value; + _c(UnsignedByte) + _c(Byte) + _c(UnsignedShort) + _c(Short) + _c(UnsignedInt) + _c(Int) + _c(HalfFloat) + _c(Float) + #ifndef MAGNUM_TARGET_GLES + _c(Double) + #endif + #ifndef MAGNUM_TARGET_GLES2 + _c(UnsignedInt2101010Rev) + _c(Int2101010Rev) + #endif + #undef _c + } + + return debug << "AbstractShaderProgram::Attribute::DataType::(invalid)"; +} + } #endif diff --git a/src/AbstractShaderProgram.h b/src/AbstractShaderProgram.h index d69bf7fc9..9a28886a0 100644 --- a/src/AbstractShaderProgram.h +++ b/src/AbstractShaderProgram.h @@ -33,7 +33,6 @@ namespace Magnum { #ifndef DOXYGEN_GENERATING_OUTPUT namespace Implementation { template struct Attribute; - template struct AttributeTraits; } #endif @@ -330,7 +329,61 @@ class MAGNUM_EXPORT AbstractShaderProgram { * Type used in shader code. * @see DataType */ - typedef typename Implementation::AttributeTraits::AttributeType Type; + typedef typename Implementation::Attribute::Type Type; + + /** + * @brief Component count + * + * Count of components passed to the shader. If passing smaller + * count of components than corresponding type has, unspecified + * components are set to default values (second and third to `0`, + * fourth to `1`). + */ + #ifdef DOXYGEN_GENERATING_OUTPUT + enum class Components: GLint { + /** + * Only first component is specified. Second, third and + * fourth component are set to `0`, `0`, `1`, respectively. + * Only for scalar and vector types, not matrices. + */ + One = 1, + + /** + * First two components are specified. Third and fourth + * component are set to `0`, `1`, respectively. Only for + * two, three and four-component vector types and 2x2, 3x2 + * and 4x2 matrix types. + */ + Two = 2, + + /** + * First three components are specified. Fourth component is + * set to `1`. Only for three and four-component vector + * types, 2x3, 3x3 and 4x3 matrix types. + */ + Three = 3, + + /** + * All four components are specified. Only for four-component + * vector types and 2x4, 3x4 and 4x4 matrix types. + */ + Four = 4 + + #ifndef MAGNUM_TARGET_GLES + , + /** + * Four components with BGRA ordering. Only for four-component + * float vector type. + * @requires_gl32 %Extension @extension{ARB,vertex_array_bgra} + * @requires_gl Only RGBA component ordering is supported + * in OpenGL ES. + */ + BGRA = 1 << 1 + #endif + }; + #else + typedef typename Implementation::Attribute::Components Components; + #endif /** * @brief Data type @@ -400,16 +453,7 @@ class MAGNUM_EXPORT AbstractShaderProgram { * 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 + Normalize = 1 << 0 }; #else typedef typename Implementation::Attribute::DataOption DataOption; @@ -427,25 +471,42 @@ class MAGNUM_EXPORT AbstractShaderProgram { /** * @brief Constructor + * @param components Component count * @param dataType Type of passed data. Default is the * same as type used in shader (e.g. DataType::Integer * for Vector4i). * @param dataOptions Data options. Default is no options. */ - inline constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _dataType(dataType), _dataOptions(dataOptions) {} + inline constexpr Attribute(Components components, DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(components), _dataType(dataType), _dataOptions(dataOptions) {} + + /** + * @brief Constructor + * @param dataType Type of passed data. Default is the + * same as type used in shader (e.g. DataType::Integer + * for Vector4i). + * @param dataOptions Data options. Default is no options. + * + * Component count is set to the same value as in type used in + * shader (e.g. @ref Components "Components::Three" for Vector3). + */ + inline constexpr Attribute(DataType dataType = Implementation::Attribute::DefaultDataType, DataOptions dataOptions = DataOptions()): _components(Implementation::Attribute::DefaultComponents), _dataType(dataType), _dataOptions(dataOptions) {} + + /** @brief Component count of passed data */ + inline constexpr Components components() const { return _components; } /** @brief Type of passed data */ inline constexpr DataType dataType() const { return _dataType; } /** @brief Size of passed data */ inline std::size_t dataSize() const { - return Implementation::Attribute::size(Implementation::Attribute::components(), _dataType); + return Implementation::Attribute::size(GLint(_components)*Implementation::Attribute::vectorCount(), _dataType); } /** @brief Data options */ inline constexpr DataOptions dataOptions() const { return _dataOptions; } private: + const Components _components; const DataType _dataType; const DataOptions _dataOptions; }; @@ -1065,63 +1126,81 @@ class MAGNUM_EXPORT AbstractShaderProgram { 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, - #ifndef MAGNUM_TARGET_GLES2 - HalfFloat = GL_HALF_FLOAT, - #else - HalfFloat = GL_HALF_FLOAT_OES, - #endif - Float = GL_FLOAT - - #ifndef MAGNUM_TARGET_GLES - , - Double = GL_DOUBLE - #endif - }; +#ifdef DOXYGEN_GENERATING_OUTPUT +/** @debugoperator{Magnum::AbstractShaderProgram::Attribute} */ +template Debug operator<<(Debug debug, AbstractShaderProgram::Attribute::Components); - enum class DataOption: std::uint8_t { - Normalized = 1 << 0 - }; +/** @debugoperator{Magnum::AbstractShaderProgram::Attribute} */ +template Debug operator<<(Debug debug, AbstractShaderProgram::Attribute::DataType); +#endif - typedef Corrade::Containers::EnumSet DataOptions; +#ifndef DOXYGEN_GENERATING_OUTPUT +namespace Implementation { - static const DataType DefaultDataType = DataType::Float; +/* Base for sized attributes */ +template struct SizedAttribute; - inline constexpr static GLint components(DataOptions = {}) { return 1; } - static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); - inline constexpr static std::size_t vectorCount() { return 1; } +/* Vector attribute sizes */ +template struct SizedVectorAttribute { + inline constexpr static std::size_t vectorCount() { return cols; } }; - -CORRADE_ENUMSET_OPERATORS(Attribute::DataOptions) - -template struct Attribute>: public Attribute { - inline constexpr static GLint components(DataOptions = {}) { return vectorSize; } - inline constexpr static std::size_t vectorCount() { return 1; } +template<> struct SizedAttribute<1, 1>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1 }; + constexpr static Components DefaultComponents = Components::One; }; - -template struct Attribute>: public Attribute { - inline constexpr static GLint components(DataOptions = {}) { return rows; } - inline constexpr static std::size_t vectorCount() { return cols; } +template<> struct SizedAttribute<1, 2>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1, Two = 2 }; + constexpr static Components DefaultComponents = Components::Two; }; - -template struct Attribute>: public Attribute { - inline constexpr static GLint components(DataOptions = {}) { return matrixSize; } - inline constexpr static std::size_t vectorCount() { return matrixSize; } +template<> struct SizedAttribute<1, 3>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1, Two = 2, Three = 3 }; + constexpr static Components DefaultComponents = Components::Three; +}; +template<> struct SizedAttribute<1, 4>: SizedVectorAttribute<1> { + enum class Components: GLint { One = 1, Two = 2, Three = 3, Four = 4 }; + constexpr static Components DefaultComponents = Components::Four; +}; +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 1>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 2>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 3>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedAttribute<1, 4>::Components value); + +/* Matrix attribute sizes */ +template struct SizedMatrixAttribute; +template<> struct SizedMatrixAttribute<2> { + enum class Components: GLint { Two = 2 }; + constexpr static Components DefaultComponents = Components::Two; +}; +template<> struct SizedMatrixAttribute<3> { + enum class Components: GLint { Three = 3 }; + constexpr static Components DefaultComponents = Components::Three; +}; +template<> struct SizedMatrixAttribute<4> { + enum class Components: GLint { Four = 4 }; + constexpr static Components DefaultComponents = Components::Four; }; +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedMatrixAttribute<2>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedMatrixAttribute<3>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, SizedMatrixAttribute<4>::Components value); +template<> struct SizedAttribute<2, 2>: SizedVectorAttribute<2>, SizedMatrixAttribute<2> {}; +template<> struct SizedAttribute<3, 3>: SizedVectorAttribute<3>, SizedMatrixAttribute<3> {}; +template<> struct SizedAttribute<4, 4>: SizedVectorAttribute<4>, SizedMatrixAttribute<4> {}; +#ifndef MAGNUM_TARGET_GLES2 +template<> struct SizedAttribute<2, 3>: SizedVectorAttribute<2>, SizedMatrixAttribute<3> {}; +template<> struct SizedAttribute<3, 2>: SizedVectorAttribute<3>, SizedMatrixAttribute<2> {}; +template<> struct SizedAttribute<2, 4>: SizedVectorAttribute<2>, SizedMatrixAttribute<4> {}; +template<> struct SizedAttribute<4, 2>: SizedVectorAttribute<4>, SizedMatrixAttribute<2> {}; +template<> struct SizedAttribute<3, 4>: SizedVectorAttribute<3>, SizedMatrixAttribute<4> {}; +template<> struct SizedAttribute<4, 3>: SizedVectorAttribute<4>, SizedMatrixAttribute<3> {}; +#endif + +/* Base for attributes */ +template struct Attribute; + +/* Base for float attributes */ +struct FloatAttribute { + typedef GLfloat Type; -template<> struct Attribute> { enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, Byte = GL_BYTE, @@ -1135,46 +1214,31 @@ template<> struct Attribute> { HalfFloat = GL_HALF_FLOAT_OES, #endif Float = GL_FLOAT + #ifndef MAGNUM_TARGET_GLES , Double = GL_DOUBLE #endif - #ifndef MAGNUM_TARGET_GLES2 - , - UnsignedInt2101010REV = GL_UNSIGNED_INT_2_10_10_10_REV, - Int2101010REV = GL_INT_2_10_10_10_REV - #endif }; + constexpr static DataType DefaultDataType = DataType::Float; 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 components(DataOptions options = {}) { - return options & DataOption::BGRA ? GL_BGRA : 4; - } - #else - inline constexpr static GLint components(DataOptions = {}) { return 4; } - #endif - static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); - inline constexpr static std::size_t vectorCount() { return 1; } }; -typedef Math::Vector<4, GLfloat> _Vector4; -CORRADE_ENUMSET_OPERATORS(Attribute<_Vector4>::DataOptions) +CORRADE_ENUMSET_OPERATORS(FloatAttribute::DataOptions) + +Debug MAGNUM_EXPORT operator<<(Debug debug, FloatAttribute::DataType value); + +#ifndef MAGNUM_TARGET_GLES2 +/* Base for int attributes */ +struct IntAttribute { + typedef GLint Type; -template<> struct Attribute { enum class DataType: GLenum { UnsignedByte = GL_UNSIGNED_BYTE, Byte = GL_BYTE, @@ -1183,135 +1247,148 @@ template<> struct Attribute { UnsignedInt = GL_UNSIGNED_INT, Int = GL_INT }; + constexpr static DataType DefaultDataType = DataType::Int; enum class DataOption: std::uint8_t {}; - typedef Corrade::Containers::EnumSet DataOptions; - static const DataType DefaultDataType = DataType::Int; - - inline constexpr static GLint components() { return 1; } static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; -template<> struct Attribute { - typedef Attribute::DataType DataType; - typedef Attribute::DataOption DataOption; +Debug MAGNUM_EXPORT operator<<(Debug debug, IntAttribute::DataType value); - typedef Corrade::Containers::EnumSet DataOptions; +/* Base for unsigned int attributes */ +struct UnsignedIntAttribute { + typedef GLuint Type; + + typedef IntAttribute::DataType DataType; + constexpr static DataType DefaultDataType = DataType::UnsignedInt; - static const DataType DefaultDataType = DataType::UnsignedInt; + typedef IntAttribute::DataOption DataOption; + typedef Corrade::Containers::EnumSet DataOptions; - inline constexpr static GLint components() { return 1; } inline static std::size_t size(GLint components, DataType dataType) { - return Attribute::size(components, dataType); + return IntAttribute::size(components, dataType); } }; - -template struct Attribute>: public Attribute { - inline constexpr static GLint components() { return size_; } -}; - -template struct Attribute>: public Attribute { - inline constexpr static GLint components() { return size_; } -}; +#endif #ifndef MAGNUM_TARGET_GLES -template<> struct Attribute { +/* Base for double attributes */ +struct DoubleAttribute { + typedef GLdouble Type; + enum class DataType: GLenum { Double = GL_DOUBLE }; + constexpr static DataType DefaultDataType = DataType::Double; enum class DataOption: std::uint8_t {}; - typedef Corrade::Containers::EnumSet DataOptions; - static const DataType DefaultDataType = DataType::Double; - - inline constexpr static GLint components() { return 1; } - inline constexpr static std::size_t vectorCount() { return 1; } static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); }; -template struct Attribute>: public Attribute { - inline constexpr static GLint components() { return rows; } - inline constexpr static std::size_t vectorCount() { return cols; } -}; +Debug MAGNUM_EXPORT operator<<(Debug debug, DoubleAttribute::DataType value); +#endif -template struct Attribute>: public Attribute { - inline constexpr static GLint components() { return size_; } - inline constexpr static std::size_t vectorCount() { return size_; } -}; +/* Floating-point four-component vector is absolutely special case */ +template<> struct Attribute> { + typedef GLfloat Type; -template struct Attribute>: public Attribute { - inline constexpr static GLint components() { return size_; } - inline constexpr static std::size_t vectorCount() { return size_; } -}; -#endif + enum class Components: GLint { + One = 1, + Two = 2, + Three = 3, + Four = 4 + #ifndef MAGNUM_TARGET_GLES + , + BGRA = GL_BGRA + #endif + }; + constexpr static Components DefaultComponents = Components::Four; + + 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, + #ifndef MAGNUM_TARGET_GLES2 + HalfFloat = GL_HALF_FLOAT, + #else + HalfFloat = GL_HALF_FLOAT_OES, + #endif + Float = GL_FLOAT + #ifndef MAGNUM_TARGET_GLES + , + Double = GL_DOUBLE + #endif + #ifndef MAGNUM_TARGET_GLES2 + , + UnsignedInt2101010Rev = GL_UNSIGNED_INT_2_10_10_10_REV, + Int2101010Rev = GL_INT_2_10_10_10_REV + #endif + }; + constexpr static DataType DefaultDataType = DataType::Float; -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; + enum class DataOption: std::uint8_t { + Normalized = 1 << 0 + }; + typedef Corrade::Containers::EnumSet DataOptions; -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; + inline constexpr static std::size_t vectorCount() { return 1; } + + static std::size_t MAGNUM_EXPORT size(GLint components, DataType dataType); +}; -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; +typedef Math::Vector<4, GLfloat> _Vector4; +CORRADE_ENUMSET_OPERATORS(Attribute<_Vector4>::DataOptions) -template struct Attribute>: public Attribute> {}; -template struct Attribute>: public Attribute> {}; +Debug MAGNUM_EXPORT operator<<(Debug debug, Attribute>::Components value); +Debug MAGNUM_EXPORT operator<<(Debug debug, Attribute>::DataType value); -/* Types allowed as GLSL attributes */ -template<> struct AttributeTraits { typedef GLuint AttributeType; }; -template<> struct AttributeTraits { typedef GLint AttributeType; }; -template<> struct AttributeTraits { typedef GLfloat AttributeType; }; +/* Common float, int, unsigned int and double scalar attributes */ +template<> struct Attribute: FloatAttribute, SizedAttribute<1, 1> {}; +#ifndef MAGNUM_TARGET_GLES2 +template<> struct Attribute: IntAttribute, SizedAttribute<1, 1> {}; +template<> struct Attribute: UnsignedIntAttribute, SizedAttribute<1, 1> {}; #ifndef MAGNUM_TARGET_GLES -template<> struct AttributeTraits { typedef GLdouble AttributeType; }; +template<> struct Attribute: DoubleAttribute, SizedAttribute<1, 1> {}; +#endif #endif -/* Only some vectors can be used as attributes */ -template struct VectorAttributeTraits {}; -template<> struct VectorAttributeTraits { typedef GLuint AttributeType; }; -template<> struct VectorAttributeTraits { typedef GLint AttributeType; }; -template<> struct VectorAttributeTraits { typedef GLfloat AttributeType; }; +/* Common float, int, unsigned int and double vector attributes */ +template struct Attribute>: FloatAttribute, SizedAttribute<1, size_> {}; +#ifndef MAGNUM_TARGET_GLES2 +template struct Attribute>: IntAttribute, SizedAttribute<1, size_> {}; +template struct Attribute>: UnsignedIntAttribute, SizedAttribute<1, size_> {}; #ifndef MAGNUM_TARGET_GLES -template<> struct VectorAttributeTraits { typedef GLdouble AttributeType; }; +template struct Attribute>: DoubleAttribute, SizedAttribute<1, size_> {}; #endif - -template struct AttributeTraits>: VectorAttributeTraits {}; -template struct AttributeTraits>: VectorAttributeTraits {}; -template struct AttributeTraits>: VectorAttributeTraits {}; - -template struct AttributeTraits>: AttributeTraits> {}; -template struct AttributeTraits>: AttributeTraits> {}; -template struct AttributeTraits>: AttributeTraits> {}; -template struct AttributeTraits>: AttributeTraits> {}; -template struct AttributeTraits>: AttributeTraits> {}; -template struct AttributeTraits>: AttributeTraits> {}; -template struct AttributeTraits>: AttributeTraits> {}; - -/* Only some floating-point matrices can be used as attributes */ -template struct MatrixAttributeTraits {}; -template<> struct MatrixAttributeTraits { typedef GLfloat AttributeType; }; +#endif +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; + +/* Common float and double rectangular matrix attributes */ +template struct Attribute>: FloatAttribute, SizedAttribute {}; #ifndef MAGNUM_TARGET_GLES -template<> struct MatrixAttributeTraits { typedef GLdouble AttributeType; }; +template struct Attribute>: DoubleAttribute, SizedAttribute {}; #endif -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; -#ifndef MAGNUM_TARGET_GLES2 -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; +/* Common float and double square matrix attributes */ +template struct Attribute>: Attribute> {}; +#ifndef MAGNUM_TARGET_GLES +template struct Attribute>: Attribute> {}; #endif - -template struct AttributeTraits>: MatrixAttributeTraits {}; -template struct AttributeTraits>: MatrixAttributeTraits {}; +template struct Attribute>: Attribute> {}; +template struct Attribute>: Attribute> {}; } #endif diff --git a/src/Mesh.h b/src/Mesh.h index 959a0f334..60edb1c8b 100644 --- a/src/Mesh.h +++ b/src/Mesh.h @@ -163,24 +163,39 @@ mesh->setPrimitive(plane.primitive()) // Custom shader with colors specified as four floating-point values class MyShader: public AbstractShaderProgram { public: + typedef Attribute<0, Vector3> Position; typedef Attribute<1, Color4<>> Color; // ... }; Mesh* mesh; -Buffer* colorBuffer; -// Fill vertex buffer with colors specified as four-byte BGRA (e.g. directly +// Fill position buffer with positions specified as two-component XY (i.e., +// no Z component, which is meant to be always 0) +Buffer* positionBuffer; +Vector2 positions[30] = { + // ... +}; + +// Specify layout of positions buffer -- only two components, unspecified Z +// component will be automatically set to 0 +mesh->addVertexBuffer(positionBuffer, 0, + MyShader::Position(MyShader::Position::Components::Two)); + +// Fill color buffer with colors specified as four-byte BGRA (e.g. directly // from TGA file) +Buffer* colorBuffer; GLubyte colors[4*30] = { // ... }; colorBuffer.setData(colors, Buffer::Usage::StaticDraw); -// Specify layout of color buffer -- each component is unsigned byte, we want -// to normalize them from [0, 255] to [0.0f, 1.0f] and reorder from BGRA -mesh->addVertexBuffer(colorBuffer, 0, - MyShader::Color(MyShader::Color::DataType::UsignedByte, MyShader::Color::DataOption::Normalized|MyShader::Color::DataOption::BGRA)); +// Specify layout of color buffer -- BGRA, each component unsigned byte and we +// want to normalize them from [0, 255] to [0.0f, 1.0f] +mesh->addVertexBuffer(colorBuffer, 0, MyShader::Color( + MyShader::Color::Components::BGRA, + MyShader::Color::DataType::UnsignedByte, + MyShader::Color::DataOption::Normalized)); @endcode @section Mesh-drawing Rendering meshes @@ -797,25 +812,25 @@ class MAGNUM_EXPORT Mesh { } inline void addInterleavedVertexBufferInternal(Buffer*, GLsizei, GLintptr) {} - template inline void addVertexAttribute(typename std::enable_if::AttributeType, GLfloat>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template inline void addVertexAttribute(typename std::enable_if::Type, GLfloat>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { for(GLuint i = 0; i != Implementation::Attribute::vectorCount(); ++i) (this->*attributePointerImplementation)(Attribute{ buffer, location+i, - Implementation::Attribute::components(attribute.dataOptions()), + static_cast(attribute.components()), static_cast(attribute.dataType()), - !!(attribute.dataOptions() & AbstractShaderProgram::Attribute::DataOption::Normalized), + bool(attribute.dataOptions() & AbstractShaderProgram::Attribute::DataOption::Normalized), offset, stride }); } #ifndef MAGNUM_TARGET_GLES2 - template inline void addVertexAttribute(typename std::enable_if::AttributeType>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template inline void addVertexAttribute(typename std::enable_if::Type>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { (this->*attributeIPointerImplementation)(IntegerAttribute{ buffer, location, - Implementation::Attribute::components(), + static_cast(attribute.components()), static_cast(attribute.dataType()), offset, stride @@ -823,12 +838,12 @@ class MAGNUM_EXPORT Mesh { } #ifndef MAGNUM_TARGET_GLES - template inline void addVertexAttribute(typename std::enable_if::AttributeType, GLdouble>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { + template inline void addVertexAttribute(typename std::enable_if::Type, GLdouble>::value, Buffer*>::type buffer, const AbstractShaderProgram::Attribute& attribute, GLintptr offset, GLsizei stride) { for(GLuint i = 0; i != Implementation::Attribute::vectorCount(); ++i) (this->*attributeLPointerImplementation)(LongAttribute{ buffer, location+i, - Implementation::Attribute::components(), + static_cast(attribute.components()), static_cast(attribute.dataType()), offset, stride diff --git a/src/Test/AbstractShaderProgramTest.cpp b/src/Test/AbstractShaderProgramTest.cpp new file mode 100644 index 000000000..7a3de5032 --- /dev/null +++ b/src/Test/AbstractShaderProgramTest.cpp @@ -0,0 +1,219 @@ +/* + 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. +*/ + +#include + +#include "AbstractShaderProgram.h" + +namespace Magnum { namespace Test { + +class AbstractShaderProgramTest: public Corrade::TestSuite::Tester { + public: + explicit AbstractShaderProgramTest(); + + void attributeScalar(); + void attributeScalarInt(); + void attributeScalarUnsignedInt(); + void attributeScalarDouble(); + + void attributeVector(); + void attributeVectorInt(); + void attributeVectorUnsignedInt(); + void attributeVectorDouble(); + void attributeVector4(); + void attributeVectorBGRA(); + + void attributeMatrix(); + void attributeMatrixDouble(); +}; + +AbstractShaderProgramTest::AbstractShaderProgramTest() { + addTests(&AbstractShaderProgramTest::attributeScalar, + &AbstractShaderProgramTest::attributeScalarInt, + &AbstractShaderProgramTest::attributeScalarUnsignedInt, + &AbstractShaderProgramTest::attributeScalarDouble, + + &AbstractShaderProgramTest::attributeVector, + &AbstractShaderProgramTest::attributeVectorInt, + &AbstractShaderProgramTest::attributeVectorUnsignedInt, + &AbstractShaderProgramTest::attributeVectorDouble, + &AbstractShaderProgramTest::attributeVector4, + &AbstractShaderProgramTest::attributeVectorBGRA, + + &AbstractShaderProgramTest::attributeMatrix, + &AbstractShaderProgramTest::attributeMatrixDouble); +} + +void AbstractShaderProgramTest::attributeScalar() { + typedef AbstractShaderProgram::Attribute<3, GLfloat> Attribute; + CORRADE_COMPARE(Attribute::Location, 3); + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::One); + CORRADE_VERIFY(!a.dataOptions()); + CORRADE_COMPARE(a.dataSize(), 4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); + + /* Options */ + Attribute b(Attribute::DataType::UnsignedShort, Attribute::DataOption::Normalized); + CORRADE_COMPARE(b.dataSize(), 2); + CORRADE_VERIFY(b.dataOptions() <= Attribute::DataOption::Normalized); +} + +void AbstractShaderProgramTest::attributeScalarInt() { + typedef AbstractShaderProgram::Attribute<3, GLint> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.dataSize(), 4); + + /* Options */ + Attribute b(Attribute::DataType::Short); + CORRADE_COMPARE(b.dataSize(), 2); +} + +void AbstractShaderProgramTest::attributeScalarUnsignedInt() { + typedef AbstractShaderProgram::Attribute<3, GLuint> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.dataSize(), 4); + + /* Options */ + Attribute b(Attribute::DataType::UnsignedByte); + CORRADE_COMPARE(b.dataSize(), 1); +} + +void AbstractShaderProgramTest::attributeScalarDouble() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, GLdouble> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.dataSize(), 8); + #else + CORRADE_SKIP("Double attributes are not available in OpenGL ES."); + #endif +} + +void AbstractShaderProgramTest::attributeVector() { + typedef AbstractShaderProgram::Attribute<3, Vector3> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Three); + CORRADE_COMPARE(a.dataSize(), 3*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); + + /* Options */ + Attribute b(Attribute::Components::Two, Attribute::DataType::Double); + CORRADE_COMPARE(b.components(), Attribute::Components::Two); + CORRADE_COMPARE(b.dataSize(), 2*8); +} + +void AbstractShaderProgramTest::attributeVectorInt() { + typedef AbstractShaderProgram::Attribute<3, Vector2i> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Two); + CORRADE_COMPARE(a.dataSize(), 2*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Int); + + /* Options */ + Attribute b(Attribute::Components::One, Attribute::DataType::Int); + CORRADE_COMPARE(b.dataSize(), 4); +} + +void AbstractShaderProgramTest::attributeVectorUnsignedInt() { + typedef AbstractShaderProgram::Attribute<3, Vector4ui> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Four); + CORRADE_COMPARE(a.dataSize(), 4*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::UnsignedInt); + + /* Options */ + Attribute b(Attribute::Components::Three, Attribute::DataType::UnsignedShort); + CORRADE_COMPARE(b.dataSize(), 3*2); +} + +void AbstractShaderProgramTest::attributeVectorDouble() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, Vector2d> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Two); + CORRADE_COMPARE(a.dataSize(), 2*8); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Double); + + /* Options */ + Attribute b(Attribute::Components::One); + CORRADE_COMPARE(b.dataSize(), 8); + #else + CORRADE_SKIP("Double attributes are not available in OpenGL ES."); + #endif +} + +void AbstractShaderProgramTest::attributeVector4() { + typedef AbstractShaderProgram::Attribute<3, Vector4> Attribute; + + /* Custom type */ + Attribute a(Attribute::DataType::UnsignedInt2101010Rev); + CORRADE_COMPARE(a.dataSize(), 4); +} + +void AbstractShaderProgramTest::attributeVectorBGRA() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, Vector4> Attribute; + + /* BGRA */ + Attribute a(Attribute::Components::BGRA); + CORRADE_COMPARE(a.dataSize(), 4*4); + #else + CORRADE_SKIP("BGRA attribute component ordering is not available in OpenGL ES."); + #endif +} + +void AbstractShaderProgramTest::attributeMatrix() { + typedef AbstractShaderProgram::Attribute<3, Matrix3> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Three); + CORRADE_COMPARE(a.dataSize(), 3*3*4); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Float); +} + +void AbstractShaderProgramTest::attributeMatrixDouble() { + #ifndef MAGNUM_TARGET_GLES + typedef AbstractShaderProgram::Attribute<3, Matrix4d> Attribute; + + /* Default constructor */ + Attribute a; + CORRADE_COMPARE(a.components(), Attribute::Components::Four); + CORRADE_COMPARE(a.dataSize(), 4*4*8); + CORRADE_COMPARE(a.dataType(), Attribute::DataType::Double); + #else + CORRADE_SKIP("Double attributes are not available in OpenGL ES."); + #endif +} + +}} + +CORRADE_TEST_MAIN(Magnum::Test::AbstractShaderProgramTest) diff --git a/src/Test/CMakeLists.txt b/src/Test/CMakeLists.txt index 44d840117..5b4b97791 100644 --- a/src/Test/CMakeLists.txt +++ b/src/Test/CMakeLists.txt @@ -1,4 +1,5 @@ corrade_add_test(AbstractImageTest AbstractImageTest.cpp LIBRARIES Magnum) +corrade_add_test(AbstractShaderProgramTest AbstractShaderProgramTest.cpp LIBRARIES Magnum) corrade_add_test(ArrayTest ArrayTest.cpp) corrade_add_test(ColorTest ColorTest.cpp LIBRARIES MagnumMathTestLib) corrade_add_test(MeshTest MeshTest.cpp LIBRARIES Magnum)