diff --git a/doc/changelog.dox b/doc/changelog.dox index cafc2ff23..13ca18fdd 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -205,6 +205,8 @@ See also: updated with an introduction the new features. - @ref Shaders::FlatGL and @ref Shaders::PhongGL now support texture arrays, available also in multi-draw and instanced scenarios +- @ref Shaders::FlatGL now supports object ID textures in addition to uniform + and per-vertex object ID - Added @ref Shaders::PhongGL::setNormalTextureScale(), consuming the recently added @ref Trade::MaterialAttribute::NormalTextureScale material attribute diff --git a/src/Magnum/Shaders/Flat.frag b/src/Magnum/Shaders/Flat.frag index dff034e23..ccc125605 100644 --- a/src/Magnum/Shaders/Flat.frag +++ b/src/Magnum/Shaders/Flat.frag @@ -131,9 +131,22 @@ uniform lowp textureData; #endif +#ifdef OBJECT_ID_TEXTURE +#ifdef EXPLICIT_BINDING +layout(binding = 5) +#endif +uniform lowp + #ifndef TEXTURE_ARRAYS + usampler2D + #else + usampler2DArray + #endif + objectIdTextureData; +#endif + /* Inputs */ -#ifdef TEXTURED +#if defined(TEXTURED) || defined(OBJECT_ID_TEXTURE) in mediump #ifndef TEXTURE_ARRAYS vec2 @@ -208,6 +221,9 @@ void main() { #ifdef INSTANCED_OBJECT_ID interpolatedInstanceObjectId + #endif + #ifdef OBJECT_ID_TEXTURE + texture(objectIdTextureData, interpolatedTextureCoordinates).r + + #endif objectId; #endif } diff --git a/src/Magnum/Shaders/Flat.h b/src/Magnum/Shaders/Flat.h index 8e22d887d..686f43000 100644 --- a/src/Magnum/Shaders/Flat.h +++ b/src/Magnum/Shaders/Flat.h @@ -143,8 +143,10 @@ struct FlatDrawUniform { * uniform data. Default value is @cpp 0 @ce. * * Used only if @ref FlatGL::Flag::ObjectId is enabled, ignored otherwise. - * If @ref FlatGL::Flag::InstancedObjectId is enabled as well, this value - * is added to the ID coming from the @ref FlatGL::ObjectId attribute. + * If @ref FlatGL::Flag::InstancedObjectId and/or + * @ref FlatGL::Flag::ObjectIdTexture is enabled as well, this value is + * added to the ID coming from the @ref FlatGL::ObjectId attribute and/or + * the texture. * @see @ref FlatGL::setObjectId() */ UnsignedInt objectId; diff --git a/src/Magnum/Shaders/FlatGL.cpp b/src/Magnum/Shaders/FlatGL.cpp index cf281c50d..3a0a6aac3 100644 --- a/src/Magnum/Shaders/FlatGL.cpp +++ b/src/Magnum/Shaders/FlatGL.cpp @@ -49,7 +49,11 @@ namespace Magnum { namespace Shaders { namespace { - enum: Int { TextureUnit = 0 }; + enum: Int { + TextureUnit = 0, + /* 1/2/3 taken by Phong (D/S/N), 4 by MeshVisualizer colormap */ + ObjectIdTextureUnit = 5 + }; #ifndef MAGNUM_TARGET_GLES2 enum: Int { @@ -74,8 +78,17 @@ template FlatGL::FlatGL(const Flags flags , _materialCount{materialCount}, _drawCount{drawCount} #endif { - CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & Flag::Textured), - "Shaders::FlatGL: texture transformation enabled but the shader is not textured", ); + #ifndef CORRADE_NO_ASSERT + { + const bool textureTransformationNotEnabledOrTextured = !(flags & Flag::TextureTransformation) || flags & Flag::Textured + #ifndef MAGNUM_TARGET_GLES2 + || flags >= Flag::ObjectIdTexture + #endif + ; + CORRADE_ASSERT(textureTransformationNotEnabledOrTextured, + "Shaders::FlatGL: texture transformation enabled but the shader is not textured", ); + } + #endif #ifndef MAGNUM_TARGET_GLES2 CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, @@ -85,7 +98,7 @@ template FlatGL::FlatGL(const Flags flags #endif #ifndef MAGNUM_TARGET_GLES2 - CORRADE_ASSERT(!(flags & Flag::TextureArrays) || (flags & Flag::Textured), + CORRADE_ASSERT(!(flags & Flag::TextureArrays) || flags & Flag::Textured || flags >= Flag::ObjectIdTexture, "Shaders::FlatGL: texture arrays enabled but the shader is not textured", ); CORRADE_ASSERT(!(flags & Flag::UniformBuffers) || !(flags & Flag::TextureArrays) || flags >= (Flag::TextureArrays|Flag::TextureTransformation), "Shaders::FlatGL: texture arrays require texture transformation enabled as well if uniform buffers are used", ); @@ -129,7 +142,11 @@ template FlatGL::FlatGL(const Flags flags GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex); GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); - vert.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") + vert.addSource((flags & Flag::Textured + #ifndef MAGNUM_TARGET_GLES2 + || flags >= Flag::ObjectIdTexture + #endif + ) ? "#define TEXTURED\n" : "") .addSource(flags & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "") .addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "") #ifndef MAGNUM_TARGET_GLES2 @@ -161,6 +178,7 @@ template FlatGL::FlatGL(const Flags flags #ifndef MAGNUM_TARGET_GLES2 .addSource(flags & Flag::ObjectId ? "#define OBJECT_ID\n" : "") .addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") + .addSource(flags >= Flag::ObjectIdTexture ? "#define OBJECT_ID_TEXTURE\n" : "") #endif ; #ifndef MAGNUM_TARGET_GLES2 @@ -189,7 +207,11 @@ template FlatGL::FlatGL(const Flags flags #endif { bindAttributeLocation(Position::Location, "position"); - if(flags & Flag::Textured) + if(flags & Flag::Textured + #ifndef MAGNUM_TARGET_GLES2 + || flags >= Flag::ObjectIdTexture + #endif + ) bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); if(flags & Flag::VertexColor) bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ @@ -241,6 +263,7 @@ template FlatGL::FlatGL(const Flags flags { if(flags & Flag::Textured) setUniform(uniformLocation("textureData"), TextureUnit); #ifndef MAGNUM_TARGET_GLES2 + if(flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"), ObjectIdTextureUnit); if(flags >= Flag::UniformBuffers) { setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); @@ -429,12 +452,42 @@ template FlatGL& FlatGL::bindTex } #endif +#ifndef MAGNUM_TARGET_GLES2 +template FlatGL& FlatGL::bindObjectIdTexture(GL::Texture2D& texture) { + CORRADE_ASSERT(_flags >= Flag::ObjectIdTexture, + "Shaders::FlatGL::bindObjectIdTexture(): the shader was not created with object ID texture enabled", *this); + #ifndef MAGNUM_TARGET_GLES2 + CORRADE_ASSERT(!(_flags & Flag::TextureArrays), + "Shaders::FlatGL::bindObjectIdTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead", *this); + #endif + texture.bind(ObjectIdTextureUnit); + return *this; +} + +template FlatGL& FlatGL::bindObjectIdTexture(GL::Texture2DArray& texture) { + CORRADE_ASSERT(_flags >= Flag::ObjectIdTexture, + "Shaders::FlatGL::bindObjectIdTexture(): the shader was not created with object ID texture enabled", *this); + CORRADE_ASSERT(_flags & Flag::TextureArrays, + "Shaders::FlatGL::bindObjectIdTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead", *this); + texture.bind(ObjectIdTextureUnit); + return *this; +} +#endif + template class MAGNUM_SHADERS_EXPORT FlatGL<2>; template class MAGNUM_SHADERS_EXPORT FlatGL<3>; namespace Implementation { Debug& operator<<(Debug& debug, const FlatGLFlag value) { + #ifndef MAGNUM_TARGET_GLES2 + /* Special case coming from the FlatGLFlags printer. As both flags are a + superset of ObjectId, printing just one would result in + `Flag::InstancedObjectId|Flag(0x800)` in the output. */ + if(value == FlatGLFlag(UnsignedShort(FlatGLFlag::InstancedObjectId|FlatGLFlag::ObjectIdTexture))) + return debug << FlatGLFlag::InstancedObjectId << Debug::nospace << "|" << Debug::nospace << FlatGLFlag::ObjectIdTexture; + #endif + debug << "Shaders::FlatGL::Flag" << Debug::nospace; switch(value) { @@ -447,6 +500,7 @@ Debug& operator<<(Debug& debug, const FlatGLFlag value) { #ifndef MAGNUM_TARGET_GLES2 _c(ObjectId) _c(InstancedObjectId) + _c(ObjectIdTexture) #endif _c(InstancedTransformation) _c(InstancedTextureOffset) @@ -470,7 +524,12 @@ Debug& operator<<(Debug& debug, const FlatGLFlags value) { FlatGLFlag::InstancedTextureOffset, /* Superset of TextureTransformation */ FlatGLFlag::TextureTransformation, #ifndef MAGNUM_TARGET_GLES2 + /* Both are a superset of ObjectId, meaning printing just one would + result in `Flag::InstancedObjectId|Flag(0x800)` in the output. So we + pass both and let the FlatGLFlag printer deal with that. */ + FlatGLFlag(UnsignedShort(FlatGLFlag::InstancedObjectId|FlatGLFlag::ObjectIdTexture)), FlatGLFlag::InstancedObjectId, /* Superset of ObjectId */ + FlatGLFlag::ObjectIdTexture, /* Superset of ObjectId */ FlatGLFlag::ObjectId, #endif FlatGLFlag::InstancedTransformation, diff --git a/src/Magnum/Shaders/FlatGL.h b/src/Magnum/Shaders/FlatGL.h index dc9aa7a63..47bc2dbe7 100644 --- a/src/Magnum/Shaders/FlatGL.h +++ b/src/Magnum/Shaders/FlatGL.h @@ -46,6 +46,7 @@ namespace Implementation { #ifndef MAGNUM_TARGET_GLES2 ObjectId = 1 << 4, InstancedObjectId = (1 << 5)|ObjectId, + ObjectIdTexture = (1 << 11)|ObjectId, #endif InstancedTransformation = 1 << 6, InstancedTextureOffset = (1 << 7)|TextureTransformation, @@ -128,8 +129,10 @@ on framebuffers with integer attachments. If you have a batch of meshes with different object IDs, enable @ref Flag::InstancedObjectId and supply per-vertex IDs to the @ref ObjectId -attribute. The output will contain a sum of the per-vertex ID and ID coming -from @ref setObjectId(). +attribute. The object ID can be also supplied from an integer texture bound via +@ref bindObjectIdTexture() if @ref Flag::ObjectIdTexture is enabled. The output +will contain a sum of the per-vertex ID, texture ID and ID coming from +@ref setObjectId(). @requires_gl30 Extension @gl_extension{EXT,texture_integer} @requires_gles30 Object ID output requires integer support in shaders, which @@ -315,8 +318,9 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: * Object ID shader output. @ref shaders-generic "Generic output", * present only if @ref Flag::ObjectId is set. Expects a * single-component unsigned integral attachment. Writes the value - * set in @ref setObjectId() there, see - * @ref Shaders-FlatGL-object-id for more information. + * set in @ref setObjectId() and possibly also a per-vertex ID and + * an ID fetched from a texture, see @ref Shaders-FlatGL-object-id + * for more information. * @requires_gl30 Extension @gl_extension{EXT,texture_integer} * @requires_gles30 Object ID output requires integer support in * shaders, which is not available in OpenGL ES 2.0. @@ -397,6 +401,23 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: * @m_since{2020,06} */ InstancedObjectId = (1 << 5)|ObjectId, + + /** + * Object ID texture. Retrieves object IDs from a texture bound + * with @ref bindObjectIdTexture(), outputting a sum of the object + * ID texture, the ID coming from @ref setObjectId() or + * @ref FlatDrawUniform::objectId and possibly also the per-vertex + * ID, if @ref Flag::InstancedObjectId is enabled as well. + * Implicitly enables @ref Flag::ObjectId. See + * @ref Shaders-FlatGL-object-id for more information. + * @requires_gl30 Extension @gl_extension{EXT,gpu_shader4} + * @requires_gles30 Object ID output requires integer support in + * shaders, which is not available in OpenGL ES 2.0. + * @requires_webgl20 Object ID output requires integer support in + * shaders, which is not available in WebGL 1.0. + * @m_since_latest + */ + ObjectIdTexture = (1 << 11)|ObjectId, #endif /** @@ -728,8 +749,10 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: * Expects that the shader was created with @ref Flag::ObjectId * enabled. Value set here is written to the @ref ObjectIdOutput, see * @ref Shaders-FlatGL-object-id for more information. Default is - * @cpp 0 @ce. If @ref Flag::InstancedObjectId is enabled as well, this - * value is added to the ID coming from the @ref ObjectId attribute. + * @cpp 0 @ce. If @ref Flag::InstancedObjectId and/or + * @ref Flag::ObjectIdTexture is enabled as well, this value is added + * to the ID coming from the @ref ObjectId attribute and/or the + * texture. * * Expects that @ref Flag::UniformBuffers is not set, in that case fill * @ref FlatDrawUniform::objectId and call @ref bindDrawBuffer() @@ -903,6 +926,51 @@ template class MAGNUM_SHADERS_EXPORT FlatGL: public GL:: FlatGL& bindTexture(GL::Texture2DArray& texture); #endif + #ifndef MAGNUM_TARGET_GLES2 + /** + * @brief Bind an object ID texture + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Expects that the shader was created with @ref Flag::ObjectIdTexture + * enabled. If @ref Flag::TextureArrays is enabled as well, use + * @ref bindObjectIdTexture(GL::Texture2DArray&) instead. The texture + * needs to have an unsigned integer format. + * @see @ref setObjectId(), @ref Flag::TextureTransformation, + * @ref setTextureMatrix() + * @requires_gl30 Extension @gl_extension{EXT,gpu_shader4} + * @requires_gles30 Object ID output requires integer support in + * shaders, which is not available in OpenGL ES 2.0. + * @requires_webgl20 Object ID output requires integer support in + * shaders, which is not available in WebGL 1.0. + */ + FlatGL& bindObjectIdTexture(GL::Texture2D& texture); + + /** + * @brief Bind an object ID array texture + * @return Reference to self (for method chaining) + * @m_since_latest + * + * Expects that the shader was created with both + * @ref Flag::ObjectIdTexture and @ref Flag::TextureArrays enabled. If + * @ref Flag::UniformBuffers is not enabled, the layer is set via + * @ref setTextureLayer(); if @ref Flag::UniformBuffers is enabled, + * @ref Flag::TextureTransformation has to be enabled as well and the + * layer is set via @ref TextureTransformationUniform::layer. + * @see @ref setObjectId(), @ref Flag::TextureTransformation, + * @ref setTextureLayer() + * @requires_gl30 Extension @gl_extension{EXT,gpu_shader4} and + * @gl_extension{EXT,texture_array} + * @requires_gles30 Object ID output requires integer support in + * shaders, which is not available in OpenGL ES 2.0. Texture + * arrays are not available in OpenGL ES 2.0. + * @requires_webgl20 Object ID output requires integer support in + * shaders, which is not available in WebGL 1.0. Texture arrays + * are not available in WebGL 1.0. + */ + FlatGL& bindObjectIdTexture(GL::Texture2DArray& texture); + #endif + /** * @} */ diff --git a/src/Magnum/Shaders/Test/FlatGLTest.cpp b/src/Magnum/Shaders/Test/FlatGLTest.cpp index cbabf71ba..87c832e1c 100644 --- a/src/Magnum/Shaders/Test/FlatGLTest.cpp +++ b/src/Magnum/Shaders/Test/FlatGLTest.cpp @@ -94,9 +94,9 @@ struct FlatGLTest: GL::OpenGLTester { template void setUniformUniformBuffersEnabled(); template void bindBufferUniformBuffersNotEnabled(); #endif - template void bindTextureInvalid(); + template void bindTexturesInvalid(); #ifndef MAGNUM_TARGET_GLES2 - template void bindTextureArrayInvalid(); + template void bindTextureArraysInvalid(); #endif template void setAlphaMaskNotEnabled(); template void setTextureMatrixNotEnabled(); @@ -211,6 +211,9 @@ constexpr struct { {"object ID", FlatGL2D::Flag::ObjectId}, {"instanced object ID", FlatGL2D::Flag::InstancedObjectId}, {"object ID + alpha mask + textured", FlatGL2D::Flag::ObjectId|FlatGL2D::Flag::AlphaMask|FlatGL2D::Flag::Textured}, + {"object ID texture", FlatGL2D::Flag::ObjectIdTexture}, + {"instanced object ID texture array + texture transformation", FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::InstancedObjectId|FlatGL2D::Flag::TextureArrays|FlatGL2D::Flag::TextureTransformation}, + {"object ID texture + textured", FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::Textured}, #endif {"instanced transformation", FlatGL2D::Flag::InstancedTransformation}, {"instanced texture offset", FlatGL2D::Flag::Textured|FlatGL2D::Flag::InstancedTextureOffset}, @@ -235,6 +238,9 @@ constexpr struct { {"texture arrays + texture transformation", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureTransformation, 1, 1}, {"alpha mask", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask, 1, 1}, {"object ID", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::ObjectId, 1, 1}, + {"object ID texture", FlatGL2D::Flag::ObjectIdTexture, 1, 1}, + {"instanced object ID texture array + texture transformation", FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::InstancedObjectId|FlatGL2D::Flag::TextureArrays|FlatGL2D::Flag::TextureTransformation, 1, 1}, + {"object ID texture + textured", FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::Textured, 1, 1}, {"instanced texture array offset + layer", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureArrays|FlatGL2D::Flag::InstancedTextureOffset, 1, 1}, {"multidraw with all the things", FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureArrays|FlatGL2D::Flag::AlphaMask|FlatGL2D::Flag::ObjectId|FlatGL2D::Flag::InstancedTextureOffset|FlatGL2D::Flag::InstancedTransformation|FlatGL2D::Flag::InstancedObjectId, 8, 48} }; @@ -245,10 +251,20 @@ constexpr struct { FlatGL2D::Flags flags; const char* message; } ConstructInvalidData[]{ - {"texture transformation but not textured", FlatGL2D::Flag::TextureTransformation, + {"texture transformation but not textured", + /* ObjectId shares bits with ObjectIdTexture but should still trigger + the assert */ + FlatGL2D::Flag::TextureTransformation + #ifndef MAGNUM_TARGET_GLES2 + |FlatGL2D::Flag::ObjectId + #endif + , "texture transformation enabled but the shader is not textured"}, #ifndef MAGNUM_TARGET_GLES2 - {"texture arrays but not textured", FlatGL2D::Flag::TextureArrays, + {"texture arrays but not textured", + /* ObjectId shares bits with ObjectIdTexture but should still trigger + the assert */ + FlatGL2D::Flag::TextureArrays|FlatGL2D::Flag::ObjectId, "texture arrays enabled but the shader is not textured"} #endif }; @@ -273,12 +289,25 @@ constexpr struct { const char* name; FlatGL2D::Flags flags; const char* message; -} BindTextureInvalidData[]{ - {"not textured", {}, - "the shader was not created with texturing enabled"}, +} BindTexturesInvalidData[]{ + {"not textured", + FlatGL2D::Flags{} + #ifndef MAGNUM_TARGET_GLES2 + /* ObjectId shares bits with ObjectIdTexture but should still + trigger the assert */ + |FlatGL2D::Flag::ObjectId + #endif + , + "Shaders::FlatGL::bindTexture(): the shader was not created with texturing enabled\n" + #ifndef MAGNUM_TARGET_GLES2 + "Shaders::FlatGL::bindObjectIdTexture(): the shader was not created with object ID texture enabled\n" + #endif + }, #ifndef MAGNUM_TARGET_GLES2 - {"array", FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureArrays, - "the shader was created with texture arrays enabled, use a Texture2DArray instead"} + {"array", + FlatGL2D::Flag::Textured|FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureArrays, + "Shaders::FlatGL::bindTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead\n" + "Shaders::FlatGL::bindObjectIdTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead\n"} #endif }; @@ -287,11 +316,17 @@ constexpr struct { const char* name; FlatGL2D::Flags flags; const char* message; -} BindTextureArrayInvalidData[]{ - {"not textured", {}, - "the shader was not created with texturing enabled"}, - {"not array", FlatGL2D::Flag::Textured, - "the shader was not created with texture arrays enabled, use a Texture2D instead"} +} BindTextureArraysInvalidData[]{ + {"not textured", + /* ObjectId shares bits with ObjectIdTexture but should still trigger + the assert */ + FlatGL2D::Flag::ObjectId, + "Shaders::FlatGL::bindTexture(): the shader was not created with texturing enabled\n" + "Shaders::FlatGL::bindObjectIdTexture(): the shader was not created with object ID texture enabled\n"}, + {"not array", + FlatGL2D::Flag::Textured|FlatGL2D::Flag::ObjectIdTexture, + "Shaders::FlatGL::bindTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead\n" + "Shaders::FlatGL::bindObjectIdTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead\n"} }; #endif @@ -358,6 +393,39 @@ const struct { /* texture arrays are orthogonal to this, no need to be tested here */ }; +#ifndef MAGNUM_TARGET_GLES2 +const struct { + const char* name; + UnsignedInt expected[4]; + FlatGL2D::Flags flags; + Matrix3 textureTransformation; + Int layer; +} RenderObjectIdData[]{ + {"", + {40006, 40006, 40006, 40006}, + {}, {}, 0}, + {"textured", + {40106, 40206, 40306, 40406}, + FlatGL2D::Flag::ObjectIdTexture, {}, 0}, + {"textured, texture transformation", + {40406, 40306, 40206, 40106}, + FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureTransformation, + Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}), 0}, + {"texture array, first layer", + {40106, 40206, 40306, 40406}, + FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureArrays, + {}, 0}, + {"texture array, arbitrary layer", + {40106, 40206, 40306, 40406}, + FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureArrays, + {}, 6}, + {"texture array, texture transformation, arbitrary layer", + {40406, 40306, 40206, 40106}, + FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::TextureArrays, + Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}), 6}, +}; +#endif + constexpr struct { const char* name; const char* expected2D; @@ -382,6 +450,21 @@ constexpr struct { FlatGL2D::Flag::InstancedObjectId, /* Minor differences on SwiftShader */ 164.4f, 0.094f}, + {"colored + textured object ID", + "instanced2D.tga", "instanced3D.tga", {3000, 4000, 5000}, + FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::InstancedTextureOffset, + /* Minor differences on SwiftShader */ + 164.4f, 0.094f}, + {"colored + instanced textured object ID", + "instanced2D.tga", "instanced3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::InstancedObjectId|FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::InstancedTextureOffset, + /* Minor differences on SwiftShader */ + 164.4f, 0.094f}, + {"colored + instanced textured array object ID", + "instanced2D.tga", "instanced3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::InstancedObjectId|FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::InstancedTextureOffset|FlatGL2D::Flag::TextureArrays, + /* Minor differences on SwiftShader */ + 164.4f, 0.094f}, #endif {"textured", "instanced-textured2D.tga", "instanced-textured3D.tga", {}, @@ -417,6 +500,14 @@ constexpr struct { "multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363}, FlatGL2D::Flag::ObjectId, 1, 1, 16, 0.0f, 0.0f}, + {"bind with offset, colored + textured object ID", + "multidraw2D.tga", "multidraw3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::ObjectIdTexture, + 1, 1, 16, 0.0f, 0.0f}, + {"bind with offset, colored + textured array object ID", + "multidraw2D.tga", "multidraw3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureArrays, + 1, 1, 16, 0.0f, 0.0f}, {"bind with offset, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga", {}, FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured, @@ -438,6 +529,14 @@ constexpr struct { "multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363}, FlatGL2D::Flag::ObjectId, 2, 3, 1, 0.0f, 0.0f}, + {"draw offset, colored + textured object ID", + "multidraw2D.tga", "multidraw3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::ObjectIdTexture, + 2, 3, 1, 0.0f, 0.0f}, + {"draw offset, colored + textured array object ID", + "multidraw2D.tga", "multidraw3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureArrays, + 2, 3, 1, 0.0f, 0.0f}, {"draw offset, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga", {}, FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured, @@ -458,6 +557,14 @@ constexpr struct { "multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363}, FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::ObjectId, 2, 3, 1, 0.0f, 0.0f}, + {"multidraw, colored + textured object ID", + "multidraw2D.tga", "multidraw3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::ObjectIdTexture, + 2, 3, 1, 0.0f, 0.0f}, + {"multidraw, colored + textured array object ID", + "multidraw2D.tga", "multidraw3D.tga", {3211, 8627, 40363}, + FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::ObjectIdTexture|FlatGL2D::Flag::TextureArrays, + 2, 3, 1, 0.0f, 0.0f}, {"multidraw, textured", "multidraw-textured2D.tga", "multidraw-textured3D.tga", {}, FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured, @@ -519,15 +626,15 @@ FlatGLTest::FlatGLTest() { }); addInstancedTests({ - &FlatGLTest::bindTextureInvalid<2>, - &FlatGLTest::bindTextureInvalid<3>}, - Containers::arraySize(BindTextureInvalidData)); + &FlatGLTest::bindTexturesInvalid<2>, + &FlatGLTest::bindTexturesInvalid<3>}, + Containers::arraySize(BindTexturesInvalidData)); #ifndef MAGNUM_TARGET_GLES2 addInstancedTests({ - &FlatGLTest::bindTextureArrayInvalid<2>, - &FlatGLTest::bindTextureArrayInvalid<3>}, - Containers::arraySize(BindTextureArrayInvalidData)); + &FlatGLTest::bindTextureArraysInvalid<2>, + &FlatGLTest::bindTextureArraysInvalid<3>}, + Containers::arraySize(BindTextureArraysInvalidData)); #endif addTests({ @@ -644,11 +751,12 @@ FlatGLTest::FlatGLTest() { #ifndef MAGNUM_TARGET_GLES2 /* MSVC needs explicit type due to default template args */ - addTests({ + addInstancedTests({ &FlatGLTest::renderObjectId2D, &FlatGLTest::renderObjectId2D, &FlatGLTest::renderObjectId3D, &FlatGLTest::renderObjectId3D}, + Containers::arraySize(RenderObjectIdData), &FlatGLTest::renderObjectIdSetup, &FlatGLTest::renderObjectIdTeardown); #endif @@ -935,8 +1043,8 @@ template void FlatGLTest::bindBufferUniformBuffersNotEna } #endif -template void FlatGLTest::bindTextureInvalid() { - auto&& data = BindTextureInvalidData[testCaseInstanceId()]; +template void FlatGLTest::bindTexturesInvalid() { + auto&& data = BindTexturesInvalidData[testCaseInstanceId()]; setTestCaseTemplateName(std::to_string(dimensions)); setTestCaseDescription(data.name); @@ -955,13 +1063,15 @@ template void FlatGLTest::bindTextureInvalid() { FlatGL shader{data.flags}; GL::Texture2D texture; shader.bindTexture(texture); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Shaders::FlatGL::bindTexture(): {}\n", data.message)); + #ifndef MAGNUM_TARGET_GLES2 + shader.bindObjectIdTexture(texture); + #endif + CORRADE_COMPARE(out.str(), data.message); } #ifndef MAGNUM_TARGET_GLES2 -template void FlatGLTest::bindTextureArrayInvalid() { - auto&& data = BindTextureArrayInvalidData[testCaseInstanceId()]; +template void FlatGLTest::bindTextureArraysInvalid() { + auto&& data = BindTextureArraysInvalidData[testCaseInstanceId()]; setTestCaseTemplateName(std::to_string(dimensions)); setTestCaseDescription(data.name); @@ -980,8 +1090,8 @@ template void FlatGLTest::bindTextureArrayInvalid() { FlatGL shader{data.flags}; GL::Texture2DArray textureArray; shader.bindTexture(textureArray); - CORRADE_COMPARE(out.str(), Utility::formatString( - "Shaders::FlatGL::bindTexture(): {}\n", data.message)); + shader.bindObjectIdTexture(textureArray); + CORRADE_COMPARE(out.str(), data.message); } #endif @@ -2318,6 +2428,9 @@ void FlatGLTest::renderObjectIdTeardown() { } template void FlatGLTest::renderObjectId2D() { + auto&& data = RenderObjectIdData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + if(flag == FlatGL2D::Flag::UniformBuffers) { setTestCaseTemplateName("Flag::UniformBuffers"); @@ -2332,16 +2445,60 @@ template void FlatGLTest::renderObjectId2D() { CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); #endif + #ifndef MAGNUM_TARGET_GLES + if((data.flags & FlatGL2D::Flag::TextureArrays) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported."); + #endif + CORRADE_COMPARE(_framebuffer.checkStatus(GL::FramebufferTarget::Draw), GL::Framebuffer::Status::Complete); - GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32)); + Primitives::Circle2DFlags circleFlags; + if(data.flags & FlatGL2D::Flag::ObjectIdTexture) + circleFlags |= Primitives::Circle2DFlag::TextureCoordinates; + GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32, circleFlags)); - FlatGL2D shader{FlatGL2D::Flag::ObjectId|flag}; + FlatGL2D::Flags flags = data.flags|flag; + if(flag == FlatGL2D::Flag::UniformBuffers && (data.flags & FlatGL2D::Flag::TextureArrays) && !(data.flags & FlatGL2D::Flag::TextureTransformation)) { + CORRADE_INFO("Texture arrays currently require texture transformation if UBOs are used, enabling implicitly."); + flags |= FlatGL2D::Flag::TextureTransformation; + } + FlatGL2D shader{FlatGL2D::Flag::ObjectId|flags}; + + GL::Texture2D texture{NoCreate}; + GL::Texture2DArray textureArray{NoCreate}; + if(data.flags >= FlatGL2D::Flag::ObjectIdTexture) { + const UnsignedShort imageData[]{ + 100, 200, 300, 400 + }; + ImageView2D image{PixelFormat::R16UI, {2, 2}, imageData}; + + if(data.flags & FlatGL2D::Flag::TextureArrays) { + textureArray = GL::Texture2DArray{}; + textureArray.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, {image.size(), data.layer + 1}) + .setSubImage(0, {0, 0, data.layer}, image); + shader.bindObjectIdTexture(textureArray); + if(flag != FlatGL2D::Flag::UniformBuffers && data.layer != 0) + shader.setTextureLayer(data.layer); /* to verify the default */ + } else { + texture = GL::Texture2D{}; + texture.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(texture); + } + } if(flag == FlatGL2D::Flag{}) { + if(data.textureTransformation != Matrix3{}) + shader.setTextureMatrix(data.textureTransformation); shader.setColor(0x9999ff_rgbf) .setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f})) - .setObjectId(48526) + .setObjectId(40006) .draw(circle); } else if(flag == FlatGL2D::Flag::UniformBuffers) { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, { @@ -2350,12 +2507,21 @@ template void FlatGLTest::renderObjectId2D() { }}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { FlatDrawUniform{} - .setObjectId(48526) + .setObjectId(40006) + }}; + GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, { + TextureTransformationUniform{} + .setTextureMatrix(data.textureTransformation) + .setLayer(data.layer) }}; GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { FlatMaterialUniform{} .setColor(0x9999ff_rgbf) }}; + /* Also take into account the case when texture transform needs to be + enabled for texture arrays, so not data.flags but flags */ + if(flags & FlatGL2D::Flag::TextureTransformation) + shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) .bindMaterialBuffer(materialUniform) @@ -2387,10 +2553,16 @@ template void FlatGLTest::renderObjectId2D() { /* Outside of the object, cleared to 27 */ CORRADE_COMPARE(image.pixels()[10][10], 27); /* Inside of the object */ - CORRADE_COMPARE(image.pixels()[40][46], 48526); + CORRADE_COMPARE(image.pixels()[30][30], data.expected[0]); + CORRADE_COMPARE(image.pixels()[30][50], data.expected[1]); + CORRADE_COMPARE(image.pixels()[50][30], data.expected[2]); + CORRADE_COMPARE(image.pixels()[50][50], data.expected[3]); } template void FlatGLTest::renderObjectId3D() { + auto&& data = RenderObjectIdData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + if(flag == FlatGL3D::Flag::UniformBuffers) { setTestCaseTemplateName("Flag::UniformBuffers"); @@ -2405,20 +2577,64 @@ template void FlatGLTest::renderObjectId3D() { CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); #endif + #ifndef MAGNUM_TARGET_GLES + if((data.flags & FlatGL3D::Flag::TextureArrays) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported."); + #endif + CORRADE_COMPARE(_framebuffer.checkStatus(GL::FramebufferTarget::Draw), GL::Framebuffer::Status::Complete); - GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32)); + Primitives::UVSphereFlags sphereFlags; + if(data.flags & FlatGL3D::Flag::ObjectIdTexture) + sphereFlags |= Primitives::UVSphereFlag::TextureCoordinates; + GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32, sphereFlags)); - FlatGL3D shader{FlatGL3D::Flag::ObjectId|flag}; + FlatGL3D::Flags flags = data.flags|flag; + if(flag == FlatGL3D::Flag::UniformBuffers && (data.flags & FlatGL3D::Flag::TextureArrays) && !(data.flags & FlatGL3D::Flag::TextureTransformation)) { + CORRADE_INFO("Texture arrays currently require texture transformation if UBOs are used, enabling implicitly."); + flags |= FlatGL3D::Flag::TextureTransformation; + } + FlatGL3D shader{FlatGL3D::Flag::ObjectId|flags}; + + GL::Texture2D texture{NoCreate}; + GL::Texture2DArray textureArray{NoCreate}; + if(data.flags & FlatGL3D::Flag::ObjectIdTexture) { + const UnsignedShort imageData[]{ + 100, 200, 300, 400 + }; + ImageView2D image{PixelFormat::R16UI, {2, 2}, imageData}; + + if(data.flags & FlatGL2D::Flag::TextureArrays) { + textureArray = GL::Texture2DArray{}; + textureArray.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, {image.size(), data.layer + 1}) + .setSubImage(0, {0, 0, data.layer}, image); + shader.bindObjectIdTexture(textureArray); + if(flag != FlatGL2D::Flag::UniformBuffers && data.layer != 0) + shader.setTextureLayer(data.layer); /* to verify the default */ + } else { + texture = GL::Texture2D{}; + texture.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(texture); + } + } if(flag == FlatGL3D::Flag{}) { + if(data.textureTransformation != Matrix3{}) + shader.setTextureMatrix(data.textureTransformation); shader.setColor(0x9999ff_rgbf) .setTransformationProjectionMatrix( Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* Matrix4::translation(Vector3::zAxis(-2.15f))* Matrix4::rotationY(-15.0_degf)* Matrix4::rotationX(15.0_degf)) - .setObjectId(48526) + .setObjectId(40006) .draw(sphere); } else if(flag == FlatGL3D::Flag::UniformBuffers) { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, { @@ -2432,12 +2648,21 @@ template void FlatGLTest::renderObjectId3D() { }}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { FlatDrawUniform{} - .setObjectId(48526) + .setObjectId(40006) + }}; + GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, { + TextureTransformationUniform{} + .setTextureMatrix(data.textureTransformation) + .setLayer(data.layer) }}; GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { FlatMaterialUniform{} .setColor(0x9999ff_rgbf) }}; + /* Also take into account the case when texture transform needs to be + enabled for texture arrays, so not data.flags but flags */ + if(flags & FlatGL2D::Flag::TextureTransformation) + shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) .bindMaterialBuffer(materialUniform) @@ -2476,8 +2701,13 @@ template void FlatGLTest::renderObjectId3D() { MAGNUM_VERIFY_NO_GL_ERROR(); /* Outside of the object, cleared to 27 */ CORRADE_COMPARE(image.pixels()[10][10], 27); - /* Inside of the object */ - CORRADE_COMPARE(image.pixels()[40][46], 48526); + /* Inside of the object. It's a sphere and the seam is at the front, + rotated to bottom left, meaning left is actually the right part of the + texture and right is the left part of the texture. */ + CORRADE_COMPARE(image.pixels()[20][50], data.expected[0]); + CORRADE_COMPARE(image.pixels()[20][20], data.expected[1]); + CORRADE_COMPARE(image.pixels()[50][50], data.expected[2]); + CORRADE_COMPARE(image.pixels()[50][20], data.expected[3]); } #endif @@ -2629,6 +2859,52 @@ template void FlatGLTest::renderInstanced2D() { } } + #ifndef MAGNUM_TARGET_GLES2 + GL::Texture2D objectIdTexture{NoCreate}; + GL::Texture2DArray objectIdTextureArray{NoCreate}; + if(data.flags >= FlatGL2D::Flag::ObjectIdTexture) { + /* This should match transformation done for the diffuse/normal + texture */ + if(data.flags & FlatGL2D::Flag::TextureArrays) { + /* 2 extra slices as a base offset, each slice has half height, + second slice has the data in the right half */ + const UnsignedShort imageData[]{ + 0, 0, + 0, 0, + 2000, 0, + 0, 3000, + 4000, 0 + }; + ImageView3D image{PixelFormat::R16UI, {2, 1, 5}, imageData}; + + objectIdTextureArray = GL::Texture2DArray{}; + objectIdTextureArray.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTextureArray); + } else { + /* First is taken from bottom left, second from bottom right, third + from top center (there I just duplicate the pixel on both + sides) */ + const UnsignedShort imageData[]{ + 2000, 3000, + 4000, 4000 + }; + ImageView2D image{PixelFormat::R16UI, {2, 2}, imageData}; + + objectIdTexture = GL::Texture2D{}; + objectIdTexture.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTexture); + } + } + #endif + if(flag == FlatGL2D::Flag{}) { shader .setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) @@ -2896,6 +3172,52 @@ template void FlatGLTest::renderInstanced3D() { } } + #ifndef MAGNUM_TARGET_GLES2 + GL::Texture2D objectIdTexture{NoCreate}; + GL::Texture2DArray objectIdTextureArray{NoCreate}; + if(data.flags >= FlatGL3D::Flag::ObjectIdTexture) { + /* This should match transformation done for the diffuse/normal + texture */ + if(data.flags & FlatGL3D::Flag::TextureArrays) { + /* 2 extra slices as a base offset, each slice has half height, + second slice has the data in the right half */ + const UnsignedShort imageData[]{ + 0, 0, + 0, 0, + 2000, 0, + 0, 3000, + 4000, 0 + }; + ImageView3D image{PixelFormat::R16UI, {2, 1, 5}, imageData}; + + objectIdTextureArray = GL::Texture2DArray{}; + objectIdTextureArray.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTextureArray); + } else { + /* First is taken from bottom left, second from bottom right, third + from top center (there I just duplicate the pixel on both + sides) */ + const UnsignedShort imageData[]{ + 2000, 3000, + 4000, 4000 + }; + ImageView2D image{PixelFormat::R16UI, {2, 2}, imageData}; + + objectIdTexture = GL::Texture2D{}; + objectIdTexture.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTexture); + } + } + #endif + if(flag == FlatGL3D::Flag{}) { shader .setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) @@ -3106,6 +3428,48 @@ void FlatGLTest::renderMulti2D() { } } + GL::Texture2D objectIdTexture{NoCreate}; + GL::Texture2DArray objectIdTextureArray{NoCreate}; + if(data.flags >= FlatGL2D::Flag::ObjectIdTexture) { + /* This should match transformation done for the diffuse/normal + texture */ + if(data.flags & FlatGL2D::Flag::TextureArrays) { + /* Each slice has half height, second slice has the data in the + right half */ + const UnsignedShort imageData[]{ + 2000, 0, + 0, 3000, + 4000, 0 + }; + ImageView3D image{PixelFormat::R16UI, {2, 1, 3}, imageData}; + + objectIdTextureArray = GL::Texture2DArray{}; + objectIdTextureArray.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTextureArray); + } else { + /* First is taken from bottom left, second from bottom right, third + from top center (there I just duplicate the pixel on both + sides) */ + const UnsignedShort imageData[]{ + 2000, 3000, + 4000, 4000 + }; + ImageView2D image{PixelFormat::R16UI, {2, 2}, imageData}; + + objectIdTexture = GL::Texture2D{}; + objectIdTexture.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTexture); + } + } + /* Circle is a fan, plane is a strip, make it indexed first */ Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32, Primitives::Circle2DFlag::TextureCoordinates)); @@ -3400,6 +3764,48 @@ void FlatGLTest::renderMulti3D() { } } + GL::Texture2D objectIdTexture{NoCreate}; + GL::Texture2DArray objectIdTextureArray{NoCreate}; + if(data.flags >= FlatGL3D::Flag::ObjectIdTexture) { + /* This should match transformation done for the diffuse/normal + texture */ + if(data.flags & FlatGL3D::Flag::TextureArrays) { + /* Each slice has half height, second slice has the data in the + right half */ + const UnsignedShort imageData[]{ + 2000, 0, + 0, 3000, + 4000, 0 + }; + ImageView3D image{PixelFormat::R16UI, {2, 1, 3}, imageData}; + + objectIdTextureArray = GL::Texture2DArray{}; + objectIdTextureArray.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTextureArray); + } else { + /* First is taken from bottom left, second from bottom right, third + from top center (there I just duplicate the pixel on both + sides) */ + const UnsignedShort imageData[]{ + 2000, 3000, + 4000, 4000 + }; + ImageView2D image{PixelFormat::R16UI, {2, 2}, imageData}; + + objectIdTexture = GL::Texture2D{}; + objectIdTexture.setMinificationFilter(GL::SamplerFilter::Nearest) + .setMagnificationFilter(GL::SamplerFilter::Nearest) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, GL::TextureFormat::R16UI, image.size()) + .setSubImage(0, {}, image); + shader.bindObjectIdTexture(objectIdTexture); + } + } + Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32, Primitives::UVSphereFlag::TextureCoordinates); /* Plane is a strip, make it indexed first */ diff --git a/src/Magnum/Shaders/Test/FlatGL_Test.cpp b/src/Magnum/Shaders/Test/FlatGL_Test.cpp index f4e9c183c..0201b3ef9 100644 --- a/src/Magnum/Shaders/Test/FlatGL_Test.cpp +++ b/src/Magnum/Shaders/Test/FlatGL_Test.cpp @@ -91,12 +91,20 @@ void FlatGL_Test::debugFlags() { void FlatGL_Test::debugFlagsSupersets() { #ifndef MAGNUM_TARGET_GLES2 - /* InstancedObjectId is a superset of ObjectId so only one should be - printed */ + /* InstancedObjectId and ObjectIdTexture are a superset of ObjectId so only + one should be printed, but if there are both then both should be */ { std::ostringstream out; Debug{&out} << (FlatGL3D::Flag::ObjectId|FlatGL3D::Flag::InstancedObjectId); CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::InstancedObjectId\n"); + } { + std::ostringstream out; + Debug{&out} << (FlatGL3D::Flag::ObjectId|FlatGL3D::Flag::ObjectIdTexture); + CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::ObjectIdTexture\n"); + } { + std::ostringstream out; + Debug{&out} << (FlatGL3D::Flag::ObjectId|FlatGL3D::Flag::InstancedObjectId|FlatGL3D::Flag::ObjectIdTexture); + CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::InstancedObjectId|Shaders::FlatGL::Flag::ObjectIdTexture\n"); } #endif