Browse Source

Shaders: support object ID textures in the FlatGL shader.

pull/547/head
Vladimír Vondruš 4 years ago
parent
commit
b2a400f898
  1. 2
      doc/changelog.dox
  2. 18
      src/Magnum/Shaders/Flat.frag
  3. 6
      src/Magnum/Shaders/Flat.h
  4. 71
      src/Magnum/Shaders/FlatGL.cpp
  5. 80
      src/Magnum/Shaders/FlatGL.h
  6. 486
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  7. 12
      src/Magnum/Shaders/Test/FlatGL_Test.cpp

2
doc/changelog.dox

@ -205,6 +205,8 @@ See also:
updated with an introduction the new features. updated with an introduction the new features.
- @ref Shaders::FlatGL and @ref Shaders::PhongGL now support texture arrays, - @ref Shaders::FlatGL and @ref Shaders::PhongGL now support texture arrays,
available also in multi-draw and instanced scenarios 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 - Added @ref Shaders::PhongGL::setNormalTextureScale(), consuming the
recently added @ref Trade::MaterialAttribute::NormalTextureScale material recently added @ref Trade::MaterialAttribute::NormalTextureScale material
attribute attribute

18
src/Magnum/Shaders/Flat.frag

@ -131,9 +131,22 @@ uniform lowp
textureData; textureData;
#endif #endif
#ifdef OBJECT_ID_TEXTURE
#ifdef EXPLICIT_BINDING
layout(binding = 5)
#endif
uniform lowp
#ifndef TEXTURE_ARRAYS
usampler2D
#else
usampler2DArray
#endif
objectIdTextureData;
#endif
/* Inputs */ /* Inputs */
#ifdef TEXTURED #if defined(TEXTURED) || defined(OBJECT_ID_TEXTURE)
in mediump in mediump
#ifndef TEXTURE_ARRAYS #ifndef TEXTURE_ARRAYS
vec2 vec2
@ -208,6 +221,9 @@ void main() {
#ifdef INSTANCED_OBJECT_ID #ifdef INSTANCED_OBJECT_ID
interpolatedInstanceObjectId + interpolatedInstanceObjectId +
#endif #endif
#ifdef OBJECT_ID_TEXTURE
texture(objectIdTextureData, interpolatedTextureCoordinates).r +
#endif
objectId; objectId;
#endif #endif
} }

6
src/Magnum/Shaders/Flat.h

@ -143,8 +143,10 @@ struct FlatDrawUniform {
* uniform data. Default value is @cpp 0 @ce. * uniform data. Default value is @cpp 0 @ce.
* *
* Used only if @ref FlatGL::Flag::ObjectId is enabled, ignored otherwise. * Used only if @ref FlatGL::Flag::ObjectId is enabled, ignored otherwise.
* If @ref FlatGL::Flag::InstancedObjectId is enabled as well, this value * If @ref FlatGL::Flag::InstancedObjectId and/or
* is added to the ID coming from the @ref FlatGL::ObjectId attribute. * @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() * @see @ref FlatGL::setObjectId()
*/ */
UnsignedInt objectId; UnsignedInt objectId;

71
src/Magnum/Shaders/FlatGL.cpp

@ -49,7 +49,11 @@
namespace Magnum { namespace Shaders { namespace Magnum { namespace Shaders {
namespace { 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 #ifndef MAGNUM_TARGET_GLES2
enum: Int { enum: Int {
@ -74,8 +78,17 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
, _materialCount{materialCount}, _drawCount{drawCount} , _materialCount{materialCount}, _drawCount{drawCount}
#endif #endif
{ {
CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & Flag::Textured), #ifndef CORRADE_NO_ASSERT
"Shaders::FlatGL: texture transformation enabled but the shader is not textured", ); {
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 #ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount, CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount,
@ -85,7 +98,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
#endif #endif
#ifndef MAGNUM_TARGET_GLES2 #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", ); "Shaders::FlatGL: texture arrays enabled but the shader is not textured", );
CORRADE_ASSERT(!(flags & Flag::UniformBuffers) || !(flags & Flag::TextureArrays) || flags >= (Flag::TextureArrays|Flag::TextureTransformation), 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", ); "Shaders::FlatGL: texture arrays require texture transformation enabled as well if uniform buffers are used", );
@ -129,7 +142,11 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex); GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex);
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment); 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::VertexColor ? "#define VERTEX_COLOR\n" : "")
.addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "") .addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "")
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
@ -161,6 +178,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
.addSource(flags & Flag::ObjectId ? "#define OBJECT_ID\n" : "") .addSource(flags & Flag::ObjectId ? "#define OBJECT_ID\n" : "")
.addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "") .addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
.addSource(flags >= Flag::ObjectIdTexture ? "#define OBJECT_ID_TEXTURE\n" : "")
#endif #endif
; ;
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
@ -189,7 +207,11 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
#endif #endif
{ {
bindAttributeLocation(Position::Location, "position"); bindAttributeLocation(Position::Location, "position");
if(flags & Flag::Textured) if(flags & Flag::Textured
#ifndef MAGNUM_TARGET_GLES2
|| flags >= Flag::ObjectIdTexture
#endif
)
bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates"); bindAttributeLocation(TextureCoordinates::Location, "textureCoordinates");
if(flags & Flag::VertexColor) if(flags & Flag::VertexColor)
bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */ bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */
@ -241,6 +263,7 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
{ {
if(flags & Flag::Textured) setUniform(uniformLocation("textureData"), TextureUnit); if(flags & Flag::Textured) setUniform(uniformLocation("textureData"), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::ObjectIdTexture) setUniform(uniformLocation("objectIdTextureData"), ObjectIdTextureUnit);
if(flags >= Flag::UniformBuffers) { if(flags >= Flag::UniformBuffers) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding); setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding); setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
@ -429,12 +452,42 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTex
} }
#endif #endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::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<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::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<2>;
template class MAGNUM_SHADERS_EXPORT FlatGL<3>; template class MAGNUM_SHADERS_EXPORT FlatGL<3>;
namespace Implementation { namespace Implementation {
Debug& operator<<(Debug& debug, const FlatGLFlag value) { 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; debug << "Shaders::FlatGL::Flag" << Debug::nospace;
switch(value) { switch(value) {
@ -447,6 +500,7 @@ Debug& operator<<(Debug& debug, const FlatGLFlag value) {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
_c(ObjectId) _c(ObjectId)
_c(InstancedObjectId) _c(InstancedObjectId)
_c(ObjectIdTexture)
#endif #endif
_c(InstancedTransformation) _c(InstancedTransformation)
_c(InstancedTextureOffset) _c(InstancedTextureOffset)
@ -470,7 +524,12 @@ Debug& operator<<(Debug& debug, const FlatGLFlags value) {
FlatGLFlag::InstancedTextureOffset, /* Superset of TextureTransformation */ FlatGLFlag::InstancedTextureOffset, /* Superset of TextureTransformation */
FlatGLFlag::TextureTransformation, FlatGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2 #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::InstancedObjectId, /* Superset of ObjectId */
FlatGLFlag::ObjectIdTexture, /* Superset of ObjectId */
FlatGLFlag::ObjectId, FlatGLFlag::ObjectId,
#endif #endif
FlatGLFlag::InstancedTransformation, FlatGLFlag::InstancedTransformation,

80
src/Magnum/Shaders/FlatGL.h

@ -46,6 +46,7 @@ namespace Implementation {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
ObjectId = 1 << 4, ObjectId = 1 << 4,
InstancedObjectId = (1 << 5)|ObjectId, InstancedObjectId = (1 << 5)|ObjectId,
ObjectIdTexture = (1 << 11)|ObjectId,
#endif #endif
InstancedTransformation = 1 << 6, InstancedTransformation = 1 << 6,
InstancedTextureOffset = (1 << 7)|TextureTransformation, 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 If you have a batch of meshes with different object IDs, enable
@ref Flag::InstancedObjectId and supply per-vertex IDs to the @ref ObjectId @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 attribute. The object ID can be also supplied from an integer texture bound via
from @ref setObjectId(). @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_gl30 Extension @gl_extension{EXT,texture_integer}
@requires_gles30 Object ID output requires integer support in shaders, which @requires_gles30 Object ID output requires integer support in shaders, which
@ -315,8 +318,9 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* Object ID shader output. @ref shaders-generic "Generic output", * Object ID shader output. @ref shaders-generic "Generic output",
* present only if @ref Flag::ObjectId is set. Expects a * present only if @ref Flag::ObjectId is set. Expects a
* single-component unsigned integral attachment. Writes the value * single-component unsigned integral attachment. Writes the value
* set in @ref setObjectId() there, see * set in @ref setObjectId() and possibly also a per-vertex ID and
* @ref Shaders-FlatGL-object-id for more information. * an ID fetched from a texture, see @ref Shaders-FlatGL-object-id
* for more information.
* @requires_gl30 Extension @gl_extension{EXT,texture_integer} * @requires_gl30 Extension @gl_extension{EXT,texture_integer}
* @requires_gles30 Object ID output requires integer support in * @requires_gles30 Object ID output requires integer support in
* shaders, which is not available in OpenGL ES 2.0. * shaders, which is not available in OpenGL ES 2.0.
@ -397,6 +401,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @m_since{2020,06} * @m_since{2020,06}
*/ */
InstancedObjectId = (1 << 5)|ObjectId, 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 #endif
/** /**
@ -728,8 +749,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* Expects that the shader was created with @ref Flag::ObjectId * Expects that the shader was created with @ref Flag::ObjectId
* enabled. Value set here is written to the @ref ObjectIdOutput, see * enabled. Value set here is written to the @ref ObjectIdOutput, see
* @ref Shaders-FlatGL-object-id for more information. Default is * @ref Shaders-FlatGL-object-id for more information. Default is
* @cpp 0 @ce. If @ref Flag::InstancedObjectId is enabled as well, this * @cpp 0 @ce. If @ref Flag::InstancedObjectId and/or
* value is added to the ID coming from the @ref ObjectId attribute. * @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 * Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref FlatDrawUniform::objectId and call @ref bindDrawBuffer() * @ref FlatDrawUniform::objectId and call @ref bindDrawBuffer()
@ -903,6 +926,51 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
FlatGL<dimensions>& bindTexture(GL::Texture2DArray& texture); FlatGL<dimensions>& bindTexture(GL::Texture2DArray& texture);
#endif #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<dimensions>& 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<dimensions>& bindObjectIdTexture(GL::Texture2DArray& texture);
#endif
/** /**
* @} * @}
*/ */

486
src/Magnum/Shaders/Test/FlatGLTest.cpp

@ -94,9 +94,9 @@ struct FlatGLTest: GL::OpenGLTester {
template<UnsignedInt dimensions> void setUniformUniformBuffersEnabled(); template<UnsignedInt dimensions> void setUniformUniformBuffersEnabled();
template<UnsignedInt dimensions> void bindBufferUniformBuffersNotEnabled(); template<UnsignedInt dimensions> void bindBufferUniformBuffersNotEnabled();
#endif #endif
template<UnsignedInt dimensions> void bindTextureInvalid(); template<UnsignedInt dimensions> void bindTexturesInvalid();
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void bindTextureArrayInvalid(); template<UnsignedInt dimensions> void bindTextureArraysInvalid();
#endif #endif
template<UnsignedInt dimensions> void setAlphaMaskNotEnabled(); template<UnsignedInt dimensions> void setAlphaMaskNotEnabled();
template<UnsignedInt dimensions> void setTextureMatrixNotEnabled(); template<UnsignedInt dimensions> void setTextureMatrixNotEnabled();
@ -211,6 +211,9 @@ constexpr struct {
{"object ID", FlatGL2D::Flag::ObjectId}, {"object ID", FlatGL2D::Flag::ObjectId},
{"instanced object ID", FlatGL2D::Flag::InstancedObjectId}, {"instanced object ID", FlatGL2D::Flag::InstancedObjectId},
{"object ID + alpha mask + textured", FlatGL2D::Flag::ObjectId|FlatGL2D::Flag::AlphaMask|FlatGL2D::Flag::Textured}, {"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 #endif
{"instanced transformation", FlatGL2D::Flag::InstancedTransformation}, {"instanced transformation", FlatGL2D::Flag::InstancedTransformation},
{"instanced texture offset", FlatGL2D::Flag::Textured|FlatGL2D::Flag::InstancedTextureOffset}, {"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}, {"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}, {"alpha mask", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::AlphaMask, 1, 1},
{"object ID", FlatGL2D::Flag::UniformBuffers|FlatGL2D::Flag::ObjectId, 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}, {"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} {"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; FlatGL2D::Flags flags;
const char* message; const char* message;
} ConstructInvalidData[]{ } 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"}, "texture transformation enabled but the shader is not textured"},
#ifndef MAGNUM_TARGET_GLES2 #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"} "texture arrays enabled but the shader is not textured"}
#endif #endif
}; };
@ -273,12 +289,25 @@ constexpr struct {
const char* name; const char* name;
FlatGL2D::Flags flags; FlatGL2D::Flags flags;
const char* message; const char* message;
} BindTextureInvalidData[]{ } BindTexturesInvalidData[]{
{"not textured", {}, {"not textured",
"the shader was not created with texturing enabled"}, 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 #ifndef MAGNUM_TARGET_GLES2
{"array", FlatGL2D::Flag::Textured|FlatGL2D::Flag::TextureArrays, {"array",
"the shader was created with texture arrays enabled, use a Texture2DArray instead"} 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 #endif
}; };
@ -287,11 +316,17 @@ constexpr struct {
const char* name; const char* name;
FlatGL2D::Flags flags; FlatGL2D::Flags flags;
const char* message; const char* message;
} BindTextureArrayInvalidData[]{ } BindTextureArraysInvalidData[]{
{"not textured", {}, {"not textured",
"the shader was not created with texturing enabled"}, /* ObjectId shares bits with ObjectIdTexture but should still trigger
{"not array", FlatGL2D::Flag::Textured, the assert */
"the shader was not created with texture arrays enabled, use a Texture2D instead"} 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 #endif
@ -358,6 +393,39 @@ const struct {
/* texture arrays are orthogonal to this, no need to be tested here */ /* 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 { constexpr struct {
const char* name; const char* name;
const char* expected2D; const char* expected2D;
@ -382,6 +450,21 @@ constexpr struct {
FlatGL2D::Flag::InstancedObjectId, FlatGL2D::Flag::InstancedObjectId,
/* Minor differences on SwiftShader */ /* Minor differences on SwiftShader */
164.4f, 0.094f}, 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 #endif
{"textured", {"textured",
"instanced-textured2D.tga", "instanced-textured3D.tga", {}, "instanced-textured2D.tga", "instanced-textured3D.tga", {},
@ -417,6 +500,14 @@ constexpr struct {
"multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363}, "multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363},
FlatGL2D::Flag::ObjectId, FlatGL2D::Flag::ObjectId,
1, 1, 16, 0.0f, 0.0f}, 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", {"bind with offset, textured",
"multidraw-textured2D.tga", "multidraw-textured3D.tga", {}, "multidraw-textured2D.tga", "multidraw-textured3D.tga", {},
FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured, FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
@ -438,6 +529,14 @@ constexpr struct {
"multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363}, "multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363},
FlatGL2D::Flag::ObjectId, FlatGL2D::Flag::ObjectId,
2, 3, 1, 0.0f, 0.0f}, 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", {"draw offset, textured",
"multidraw-textured2D.tga", "multidraw-textured3D.tga", {}, "multidraw-textured2D.tga", "multidraw-textured3D.tga", {},
FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured, FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
@ -458,6 +557,14 @@ constexpr struct {
"multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363}, "multidraw2D.tga", "multidraw3D.tga", {1211, 5627, 36363},
FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::ObjectId, FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::ObjectId,
2, 3, 1, 0.0f, 0.0f}, 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, textured",
"multidraw-textured2D.tga", "multidraw-textured3D.tga", {}, "multidraw-textured2D.tga", "multidraw-textured3D.tga", {},
FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured, FlatGL2D::Flag::MultiDraw|FlatGL2D::Flag::TextureTransformation|FlatGL2D::Flag::Textured,
@ -519,15 +626,15 @@ FlatGLTest::FlatGLTest() {
}); });
addInstancedTests<FlatGLTest>({ addInstancedTests<FlatGLTest>({
&FlatGLTest::bindTextureInvalid<2>, &FlatGLTest::bindTexturesInvalid<2>,
&FlatGLTest::bindTextureInvalid<3>}, &FlatGLTest::bindTexturesInvalid<3>},
Containers::arraySize(BindTextureInvalidData)); Containers::arraySize(BindTexturesInvalidData));
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
addInstancedTests<FlatGLTest>({ addInstancedTests<FlatGLTest>({
&FlatGLTest::bindTextureArrayInvalid<2>, &FlatGLTest::bindTextureArraysInvalid<2>,
&FlatGLTest::bindTextureArrayInvalid<3>}, &FlatGLTest::bindTextureArraysInvalid<3>},
Containers::arraySize(BindTextureArrayInvalidData)); Containers::arraySize(BindTextureArraysInvalidData));
#endif #endif
addTests<FlatGLTest>({ addTests<FlatGLTest>({
@ -644,11 +751,12 @@ FlatGLTest::FlatGLTest() {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
/* MSVC needs explicit type due to default template args */ /* MSVC needs explicit type due to default template args */
addTests<FlatGLTest>({ addInstancedTests<FlatGLTest>({
&FlatGLTest::renderObjectId2D, &FlatGLTest::renderObjectId2D,
&FlatGLTest::renderObjectId2D<FlatGL2D::Flag::UniformBuffers>, &FlatGLTest::renderObjectId2D<FlatGL2D::Flag::UniformBuffers>,
&FlatGLTest::renderObjectId3D, &FlatGLTest::renderObjectId3D,
&FlatGLTest::renderObjectId3D<FlatGL3D::Flag::UniformBuffers>}, &FlatGLTest::renderObjectId3D<FlatGL3D::Flag::UniformBuffers>},
Containers::arraySize(RenderObjectIdData),
&FlatGLTest::renderObjectIdSetup, &FlatGLTest::renderObjectIdSetup,
&FlatGLTest::renderObjectIdTeardown); &FlatGLTest::renderObjectIdTeardown);
#endif #endif
@ -935,8 +1043,8 @@ template<UnsignedInt dimensions> void FlatGLTest::bindBufferUniformBuffersNotEna
} }
#endif #endif
template<UnsignedInt dimensions> void FlatGLTest::bindTextureInvalid() { template<UnsignedInt dimensions> void FlatGLTest::bindTexturesInvalid() {
auto&& data = BindTextureInvalidData[testCaseInstanceId()]; auto&& data = BindTexturesInvalidData[testCaseInstanceId()];
setTestCaseTemplateName(std::to_string(dimensions)); setTestCaseTemplateName(std::to_string(dimensions));
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -955,13 +1063,15 @@ template<UnsignedInt dimensions> void FlatGLTest::bindTextureInvalid() {
FlatGL<dimensions> shader{data.flags}; FlatGL<dimensions> shader{data.flags};
GL::Texture2D texture; GL::Texture2D texture;
shader.bindTexture(texture); shader.bindTexture(texture);
CORRADE_COMPARE(out.str(), Utility::formatString( #ifndef MAGNUM_TARGET_GLES2
"Shaders::FlatGL::bindTexture(): {}\n", data.message)); shader.bindObjectIdTexture(texture);
#endif
CORRADE_COMPARE(out.str(), data.message);
} }
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void FlatGLTest::bindTextureArrayInvalid() { template<UnsignedInt dimensions> void FlatGLTest::bindTextureArraysInvalid() {
auto&& data = BindTextureArrayInvalidData[testCaseInstanceId()]; auto&& data = BindTextureArraysInvalidData[testCaseInstanceId()];
setTestCaseTemplateName(std::to_string(dimensions)); setTestCaseTemplateName(std::to_string(dimensions));
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -980,8 +1090,8 @@ template<UnsignedInt dimensions> void FlatGLTest::bindTextureArrayInvalid() {
FlatGL<dimensions> shader{data.flags}; FlatGL<dimensions> shader{data.flags};
GL::Texture2DArray textureArray; GL::Texture2DArray textureArray;
shader.bindTexture(textureArray); shader.bindTexture(textureArray);
CORRADE_COMPARE(out.str(), Utility::formatString( shader.bindObjectIdTexture(textureArray);
"Shaders::FlatGL::bindTexture(): {}\n", data.message)); CORRADE_COMPARE(out.str(), data.message);
} }
#endif #endif
@ -2318,6 +2428,9 @@ void FlatGLTest::renderObjectIdTeardown() {
} }
template<FlatGL2D::Flag flag> void FlatGLTest::renderObjectId2D() { template<FlatGL2D::Flag flag> void FlatGLTest::renderObjectId2D() {
auto&& data = RenderObjectIdData[testCaseInstanceId()];
setTestCaseDescription(data.name);
if(flag == FlatGL2D::Flag::UniformBuffers) { if(flag == FlatGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -2332,16 +2445,60 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderObjectId2D() {
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported.");
#endif #endif
#ifndef MAGNUM_TARGET_GLES
if((data.flags & FlatGL2D::Flag::TextureArrays) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
CORRADE_COMPARE(_framebuffer.checkStatus(GL::FramebufferTarget::Draw), GL::Framebuffer::Status::Complete); 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(flag == FlatGL2D::Flag{}) {
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
shader.setColor(0x9999ff_rgbf) shader.setColor(0x9999ff_rgbf)
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f})) .setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
.setObjectId(48526) .setObjectId(40006)
.draw(circle); .draw(circle);
} else if(flag == FlatGL2D::Flag::UniformBuffers) { } else if(flag == FlatGL2D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
@ -2350,12 +2507,21 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderObjectId2D() {
}}; }};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{} 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, { GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{} FlatMaterialUniform{}
.setColor(0x9999ff_rgbf) .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) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform) .bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform) .bindMaterialBuffer(materialUniform)
@ -2387,10 +2553,16 @@ template<FlatGL2D::Flag flag> void FlatGLTest::renderObjectId2D() {
/* Outside of the object, cleared to 27 */ /* Outside of the object, cleared to 27 */
CORRADE_COMPARE(image.pixels<UnsignedInt>()[10][10], 27); CORRADE_COMPARE(image.pixels<UnsignedInt>()[10][10], 27);
/* Inside of the object */ /* Inside of the object */
CORRADE_COMPARE(image.pixels<UnsignedInt>()[40][46], 48526); CORRADE_COMPARE(image.pixels<UnsignedInt>()[30][30], data.expected[0]);
CORRADE_COMPARE(image.pixels<UnsignedInt>()[30][50], data.expected[1]);
CORRADE_COMPARE(image.pixels<UnsignedInt>()[50][30], data.expected[2]);
CORRADE_COMPARE(image.pixels<UnsignedInt>()[50][50], data.expected[3]);
} }
template<FlatGL3D::Flag flag> void FlatGLTest::renderObjectId3D() { template<FlatGL3D::Flag flag> void FlatGLTest::renderObjectId3D() {
auto&& data = RenderObjectIdData[testCaseInstanceId()];
setTestCaseDescription(data.name);
if(flag == FlatGL3D::Flag::UniformBuffers) { if(flag == FlatGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers"); setTestCaseTemplateName("Flag::UniformBuffers");
@ -2405,20 +2577,64 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderObjectId3D() {
CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported."); CORRADE_SKIP(GL::Extensions::EXT::gpu_shader4::string() << "is not supported.");
#endif #endif
#ifndef MAGNUM_TARGET_GLES
if((data.flags & FlatGL3D::Flag::TextureArrays) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
CORRADE_COMPARE(_framebuffer.checkStatus(GL::FramebufferTarget::Draw), GL::Framebuffer::Status::Complete); 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(flag == FlatGL3D::Flag{}) {
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
shader.setColor(0x9999ff_rgbf) shader.setColor(0x9999ff_rgbf)
.setTransformationProjectionMatrix( .setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))* Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)* Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationX(15.0_degf)) Matrix4::rotationX(15.0_degf))
.setObjectId(48526) .setObjectId(40006)
.draw(sphere); .draw(sphere);
} else if(flag == FlatGL3D::Flag::UniformBuffers) { } else if(flag == FlatGL3D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, { GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
@ -2432,12 +2648,21 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderObjectId3D() {
}}; }};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
FlatDrawUniform{} 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, { GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
FlatMaterialUniform{} FlatMaterialUniform{}
.setColor(0x9999ff_rgbf) .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) shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform) .bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform) .bindMaterialBuffer(materialUniform)
@ -2476,8 +2701,13 @@ template<FlatGL3D::Flag flag> void FlatGLTest::renderObjectId3D() {
MAGNUM_VERIFY_NO_GL_ERROR(); MAGNUM_VERIFY_NO_GL_ERROR();
/* Outside of the object, cleared to 27 */ /* Outside of the object, cleared to 27 */
CORRADE_COMPARE(image.pixels<UnsignedInt>()[10][10], 27); CORRADE_COMPARE(image.pixels<UnsignedInt>()[10][10], 27);
/* Inside of the object */ /* Inside of the object. It's a sphere and the seam is at the front,
CORRADE_COMPARE(image.pixels<UnsignedInt>()[40][46], 48526); 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<UnsignedInt>()[20][50], data.expected[0]);
CORRADE_COMPARE(image.pixels<UnsignedInt>()[20][20], data.expected[1]);
CORRADE_COMPARE(image.pixels<UnsignedInt>()[50][50], data.expected[2]);
CORRADE_COMPARE(image.pixels<UnsignedInt>()[50][20], data.expected[3]);
} }
#endif #endif
@ -2629,6 +2859,52 @@ template<FlatGL2D::Flag flag> 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{}) { if(flag == FlatGL2D::Flag{}) {
shader shader
.setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) .setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf)
@ -2896,6 +3172,52 @@ template<FlatGL3D::Flag flag> 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{}) { if(flag == FlatGL3D::Flag{}) {
shader shader
.setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) .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 */ /* Circle is a fan, plane is a strip, make it indexed first */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32, Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32,
Primitives::Circle2DFlag::TextureCoordinates)); 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, Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereFlag::TextureCoordinates); Primitives::UVSphereFlag::TextureCoordinates);
/* Plane is a strip, make it indexed first */ /* Plane is a strip, make it indexed first */

12
src/Magnum/Shaders/Test/FlatGL_Test.cpp

@ -91,12 +91,20 @@ void FlatGL_Test::debugFlags() {
void FlatGL_Test::debugFlagsSupersets() { void FlatGL_Test::debugFlagsSupersets() {
#ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES2
/* InstancedObjectId is a superset of ObjectId so only one should be /* InstancedObjectId and ObjectIdTexture are a superset of ObjectId so only
printed */ one should be printed, but if there are both then both should be */
{ {
std::ostringstream out; std::ostringstream out;
Debug{&out} << (FlatGL3D::Flag::ObjectId|FlatGL3D::Flag::InstancedObjectId); Debug{&out} << (FlatGL3D::Flag::ObjectId|FlatGL3D::Flag::InstancedObjectId);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::InstancedObjectId\n"); 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 #endif

Loading…
Cancel
Save