diff --git a/src/Shaders/Flat.cpp b/src/Shaders/Flat.cpp index e554ce9ed..864890981 100644 --- a/src/Shaders/Flat.cpp +++ b/src/Shaders/Flat.cpp @@ -37,7 +37,7 @@ namespace { template<> constexpr const char* vertexShaderName<3>() { return "Flat3D.vert"; } } -template Flat::Flat(): transformationProjectionMatrixUniform(0), colorUniform(1) { +template Flat::Flat(const Flags flags): transformationProjectionMatrixUniform(0), colorUniform(1), _flags(flags) { Utility::Resource rs("MagnumShaders"); #ifndef MAGNUM_TARGET_GLES @@ -46,18 +46,20 @@ template Flat::Flat(): transformationProject const Version version = Context::current()->supportedVersion({Version::GLES300, Version::GLES200}); #endif - Shader frag(version, Shader::Type::Vertex); - frag.addSource(rs.get("compatibility.glsl")) - .addSource(rs.get(vertexShaderName())); - CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); - attachShader(frag); - Shader vert(version, Shader::Type::Fragment); - vert.addSource(rs.get("compatibility.glsl")) + vert.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") + .addSource(rs.get("compatibility.glsl")) .addSource(rs.get("Flat.frag")); CORRADE_INTERNAL_ASSERT_OUTPUT(vert.compile()); attachShader(vert); + Shader frag(version, Shader::Type::Vertex); + frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") + .addSource(rs.get("compatibility.glsl")) + .addSource(rs.get(vertexShaderName())); + CORRADE_INTERNAL_ASSERT_OUTPUT(frag.compile()); + attachShader(frag); + #ifndef MAGNUM_TARGET_GLES if(!Context::current()->isExtensionSupported(version)) #else @@ -65,6 +67,7 @@ template Flat::Flat(): transformationProject #endif { bindAttributeLocation(Position::Location, "position"); + if(flags & Flag::Textured) bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); } CORRADE_INTERNAL_ASSERT_OUTPUT(link()); @@ -74,7 +77,14 @@ template Flat::Flat(): transformationProject #endif { transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"); - colorUniform = uniformLocation("color"); + if(!(flags & Flag::Textured)) colorUniform = uniformLocation("color"); + } + + #ifndef MAGNUM_TARGET_GLES + if(flags && !Context::current()->isExtensionSupported(version)) + #endif + { + if(flags & Flag::Textured) setUniform(uniformLocation("textureData"), TextureLayer); } } diff --git a/src/Shaders/Flat.frag b/src/Shaders/Flat.frag index 8f3066029..665ed51d6 100644 --- a/src/Shaders/Flat.frag +++ b/src/Shaders/Flat.frag @@ -24,18 +24,35 @@ #ifndef NEW_GLSL #define fragmentColor gl_FragColor +#define texture texture2D #endif +#ifdef TEXTURED +#ifdef EXPLICIT_TEXTURE_LAYER +layout(binding = 0) uniform sampler2D textureData; +#else +uniform sampler2D textureData; +#endif +#else #ifdef EXPLICIT_UNIFORM_LOCATION layout(location = 1) uniform vec4 color; #else uniform lowp vec4 color; #endif +#endif + +#ifdef TEXTURED +in mediump vec2 interpolatedTextureCoords; +#endif #ifdef NEW_GLSL out lowp vec4 fragmentColor; #endif void main() { + #ifdef TEXTURED + fragmentColor = texture(textureData, interpolatedTextureCoords); + #else fragmentColor = color; + #endif } diff --git a/src/Shaders/Flat.h b/src/Shaders/Flat.h index d8efe6abe..f36f106f8 100644 --- a/src/Shaders/Flat.h +++ b/src/Shaders/Flat.h @@ -38,18 +38,78 @@ namespace Magnum { namespace Shaders { +namespace Implementation { + enum class FlatFlag: UnsignedByte { Textured = 1 << 0 }; + typedef Containers::EnumSet FlatFlags; +} + /** @brief Flat shader -Draws whole mesh with one color. -@see Flat2D, Flat3D +Draws whole mesh with given unshaded color or texture. For colored mesh you +need to provide @ref Position attribute in your triangle mesh and call at least +@ref setTransformationProjectionMatrix() and @ref setColor(). + +If you want to use texture instead of color, you need to provide also +@ref TextureCoordinates attribute. Pass @ref Flag::Textured to constructor and +then at render time bind the texture to its respective layer instead of calling +@ref setColor(). Example: +@code +Shaders::Flat2D shader(Shaders::Flat2D::Flag::Textured); + +// ... + +myTexture.bind(Shaders::Flat2D::TextureLayer); +@endcode + +@see @ref Flat2D, @ref Flat3D */ template class MAGNUM_SHADERS_EXPORT Flat: public AbstractShaderProgram { public: /** @brief Vertex position */ typedef Attribute<0, typename DimensionTraits::VectorType> Position; - explicit Flat(); + /** + * @brief Texture coordinates + * + * Used only if @ref Flag::Textured is set. + */ + typedef Attribute<2, Vector2> TextureCoordinates; + + enum: Int { + /** Layer for color texture. Used only if @ref Flag::Textured is set. */ + TextureLayer = 0 + }; + + #ifdef DOXYGEN_GENERATING_OUTPUT + /** + * @brief Shader flag + * + * @see @ref Flags, @ref flags() + */ + enum class Flag: UnsignedByte { + Textured = 1 << 0 /**< The shader uses texture instead of color */ + }; + + /** + * @brief Shader flags + * + * @see @ref flags() + */ + typedef Containers::EnumSet Flags; + #else + typedef Implementation::FlatFlag Flag; + typedef Implementation::FlatFlags Flags; + #endif + + /** + * @brief Constructor + * @param flags Shader flags + */ + explicit Flat(Flags flags = Flags()); + + /** @brief Shader flags */ + Flags flags() const { return _flags; } /** * @brief Set transformation and projection matrix @@ -63,15 +123,16 @@ template class MAGNUM_SHADERS_EXPORT Flat: public Abstra /** * @brief Set color * @return Reference to self (for method chaining) + * + * Has no effect if @ref Flag::Textured is set. */ - Flat& setColor(const Color4& color) { - setUniform(colorUniform, color); - return *this; - } + Flat& setColor(const Color4& color); private: Int transformationProjectionMatrixUniform, colorUniform; + + Flags _flags; }; /** @brief 2D flat shader */ @@ -80,6 +141,13 @@ typedef Flat<2> Flat2D; /** @brief 3D flat shader */ typedef Flat<3> Flat3D; +CORRADE_ENUMSET_OPERATORS(Implementation::FlatFlags) + +template inline Flat& Flat::setColor(const Color4& color) { + if(!(_flags & Flag::Textured)) setUniform(colorUniform, color); + return *this; +} + }} #endif diff --git a/src/Shaders/Flat2D.vert b/src/Shaders/Flat2D.vert index 9e983a978..aa0577bc7 100644 --- a/src/Shaders/Flat2D.vert +++ b/src/Shaders/Flat2D.vert @@ -24,6 +24,7 @@ #ifndef NEW_GLSL #define in attribute +#define out varying #endif #ifdef EXPLICIT_UNIFORM_LOCATION @@ -38,6 +39,20 @@ layout(location = 0) in highp vec2 position; in highp vec2 position; #endif +#ifdef TEXTURED +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 1) in mediump vec2 textureCoords; +#else +in mediump vec2 textureCoords; +#endif +out mediump vec2 interpolatedTextureCoords; +#endif + void main() { gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0); + + #ifdef TEXTURED + /* Texture coordinates, if needed */ + interpolatedTextureCoords = textureCoords; + #endif } diff --git a/src/Shaders/Flat3D.vert b/src/Shaders/Flat3D.vert index 2f4b875c5..5ddc90060 100644 --- a/src/Shaders/Flat3D.vert +++ b/src/Shaders/Flat3D.vert @@ -24,6 +24,7 @@ #ifndef NEW_GLSL #define in attribute +#define out varying #endif #ifdef EXPLICIT_UNIFORM_LOCATION @@ -38,6 +39,20 @@ layout(location = 0) in highp vec4 position; in highp vec4 position; #endif +#ifdef TEXTURED +#ifdef EXPLICIT_ATTRIB_LOCATION +layout(location = 1) in mediump vec2 textureCoords; +#else +in mediump vec2 textureCoords; +#endif +out mediump vec2 interpolatedTextureCoords; +#endif + void main() { gl_Position = transformationProjectionMatrix*position; + + #ifdef TEXTURED + /* Texture coordinates, if needed */ + interpolatedTextureCoords = textureCoords; + #endif } diff --git a/src/Shaders/Test/FlatTest.cpp b/src/Shaders/Test/FlatTest.cpp index 3576beefb..fd376a76c 100644 --- a/src/Shaders/Test/FlatTest.cpp +++ b/src/Shaders/Test/FlatTest.cpp @@ -33,11 +33,15 @@ class FlatTest: public Magnum::Test::AbstractOpenGLTester { void compile2D(); void compile3D(); + void compile2DTextured(); + void compile3DTextured(); }; FlatTest::FlatTest() { addTests({&FlatTest::compile2D, - &FlatTest::compile3D}); + &FlatTest::compile3D, + &FlatTest::compile2DTextured, + &FlatTest::compile3DTextured}); } void FlatTest::compile2D() { @@ -50,6 +54,16 @@ void FlatTest::compile3D() { CORRADE_VERIFY(shader.validate().first); } +void FlatTest::compile2DTextured() { + Shaders::Flat2D shader(Shaders::Flat2D::Flag::Textured); + CORRADE_VERIFY(shader.validate().first); +} + +void FlatTest::compile3DTextured() { + Shaders::Flat3D shader(Shaders::Flat3D::Flag::Textured); + CORRADE_VERIFY(shader.validate().first); +} + }}} CORRADE_TEST_MAIN(Magnum::Shaders::Test::FlatTest)