From 3379e6c7943fb4c812593aecbe4918550ec9df9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 21 Feb 2013 20:54:22 +0100 Subject: [PATCH] Ability to send less than all attribute components to the shader. Remaining unspecified components are set to 0, 0, 1, according to spec. Also cleaned up and simplified the internals, added debug output operators for attribute component count and types and tested the whole thing. --- src/AbstractShaderProgram.cpp | 179 ++++++++++- src/AbstractShaderProgram.h | 427 +++++++++++++++---------- src/Mesh.h | 41 ++- src/Test/AbstractShaderProgramTest.cpp | 219 +++++++++++++ src/Test/CMakeLists.txt | 1 + 5 files changed, 676 insertions(+), 191 deletions(-) create mode 100644 src/Test/AbstractShaderProgramTest.cpp 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)