Browse Source

Shaders: add {DistanceField}VectorGL::Flag::TextureArrays.

Apart from instancing, which isn't done yet, this achieves feature
parity with the Phong and Flat shaders. Compared to those, the texture
layer can be supplied also from the attribute, which is what the Text
library needs. (And lack of texture array use in the text library
was until now a reason why those two shaders didn't have texture array
support so far.)
pull/674/head
Vladimír Vondruš 1 year ago
parent
commit
c331591c87
  1. 24
      src/Magnum/Shaders/DistanceFieldVector.frag
  2. 49
      src/Magnum/Shaders/DistanceFieldVectorGL.cpp
  3. 104
      src/Magnum/Shaders/DistanceFieldVectorGL.h
  4. 577
      src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp
  5. 4
      src/Magnum/Shaders/Test/DistanceFieldVectorGL_Test.cpp
  6. 573
      src/Magnum/Shaders/Test/VectorGLTest.cpp
  7. 4
      src/Magnum/Shaders/Test/VectorGL_Test.cpp
  8. 20
      src/Magnum/Shaders/Vector.frag
  9. 49
      src/Magnum/Shaders/Vector.vert
  10. 49
      src/Magnum/Shaders/VectorGL.cpp
  11. 100
      src/Magnum/Shaders/VectorGL.h

24
src/Magnum/Shaders/DistanceFieldVector.frag

@ -42,7 +42,7 @@
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
layout(location = 3)
#endif
uniform lowp vec4 color
#ifndef GL_ES
@ -51,12 +51,12 @@ uniform lowp vec4 color
;
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 3)
layout(location = 4)
#endif
uniform lowp vec4 outlineColor; /* defaults to zero */
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 4)
layout(location = 5)
#endif
uniform lowp vec2 outlineRange
#ifndef GL_ES
@ -65,7 +65,7 @@ uniform lowp vec2 outlineRange
;
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 5)
layout(location = 6)
#endif
uniform lowp float smoothness
#ifndef GL_ES
@ -141,11 +141,23 @@ layout(std140
#ifdef EXPLICIT_BINDING
layout(binding = 6)
#endif
uniform lowp sampler2D vectorTexture;
uniform lowp
#ifndef TEXTURE_ARRAYS
sampler2D
#else
sampler2DArray
#endif
vectorTexture;
/* Inputs */
in mediump vec2 interpolatedTextureCoordinates;
in mediump
#ifndef TEXTURE_ARRAYS
vec2
#else
vec3
#endif
interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat in highp uint drawId;

49
src/Magnum/Shaders/DistanceFieldVectorGL.cpp

@ -45,6 +45,7 @@
#include <Corrade/Utility/Format.h>
#include "Magnum/GL/Buffer.h"
#include "Magnum/GL/TextureArray.h"
#endif
#ifdef MAGNUM_BUILD_STATIC
@ -110,6 +111,10 @@ template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::Com
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::TextureArrays)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::EXT::texture_array);
#endif
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
@ -133,6 +138,9 @@ template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::Com
GL::Shader vert{version, GL::Shader::Type::Vertex};
vert.addSource(rs.getString("compatibility.glsl"_s))
.addSource(configuration.flags() & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n"_s : ""_s)
#ifndef MAGNUM_TARGET_GLES2
.addSource(configuration.flags() & Flag::TextureArrays ? "#define TEXTURE_ARRAYS\n"_s : ""_s)
#endif
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
@ -159,7 +167,11 @@ template<UnsignedInt dimensions> typename DistanceFieldVectorGL<dimensions>::Com
.submitCompile();
GL::Shader frag{version, GL::Shader::Type::Fragment};
frag.addSource(rs.getString("compatibility.glsl"_s));
frag.addSource(rs.getString("compatibility.glsl"_s))
#ifndef MAGNUM_TARGET_GLES2
.addSource(configuration.flags() & Flag::TextureArrays ? "#define TEXTURE_ARRAYS\n"_s : ""_s)
#endif
;
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
#ifndef MAGNUM_TARGET_WEBGL
@ -259,6 +271,10 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"_s);
if(_flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix"_s);
#ifndef MAGNUM_TARGET_GLES2
if(_flags & Flag::TextureArrays)
_textureLayerUniform = uniformLocation("textureLayer"_s);
#endif
_colorUniform = uniformLocation("color"_s);
_outlineColorUniform = uniformLocation("outlineColor"_s);
_outlineRangeUniform = uniformLocation("outlineRange"_s);
@ -300,6 +316,7 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(_flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
/* Texture layer is zero by default */
setColor(Color4{1.0f});
/* Outline color is zero by default */
setOutlineRange(0.5f, 1.0f);
@ -344,6 +361,17 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFiel
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setTextureLayer(UnsignedInt id) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::DistanceFieldVectorGL::setTextureLayer(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureArrays,
"Shaders::DistanceFieldVectorGL::setTextureLayer(): the shader was not created with texture arrays enabled", *this);
setUniform(_textureLayerUniform, id);
return *this;
}
#endif
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
@ -493,10 +521,25 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFiel
#endif
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindVectorTexture(GL::Texture2D& texture) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags & Flag::TextureArrays),
"Shaders::DistanceFieldVectorGL::bindVectorTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead", *this);
#endif
texture.bind(TextureUnit);
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindVectorTexture(GL::Texture2DArray& texture) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(_flags & Flag::TextureArrays,
"Shaders::DistanceFieldVectorGL::bindVectorTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead", *this);
#endif
texture.bind(TextureUnit);
return *this;
}
#endif
template class MAGNUM_SHADERS_EXPORT DistanceFieldVectorGL<2>;
template class MAGNUM_SHADERS_EXPORT DistanceFieldVectorGL<3>;
@ -523,6 +566,7 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
_c(TextureArrays)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -545,7 +589,8 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlags value) {
#ifndef MAGNUM_TARGET_WEBGL
DistanceFieldVectorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
DistanceFieldVectorGLFlag::UniformBuffers
DistanceFieldVectorGLFlag::UniformBuffers,
DistanceFieldVectorGLFlag::TextureArrays
#endif
});
}

104
src/Magnum/Shaders/DistanceFieldVectorGL.h

@ -50,7 +50,8 @@ namespace Implementation {
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
MultiDraw = UniformBuffers|(1 << 2)
MultiDraw = UniformBuffers|(1 << 2),
TextureArrays = 1 << 4
#endif
};
typedef Containers::EnumSet<DistanceFieldVectorGLFlag> DistanceFieldVectorGLFlags;
@ -89,6 +90,12 @@ Common rendering setup:
@snippet Shaders-gl.cpp DistanceFieldVectorGL-usage2
If @ref Flag::TextureArrays is enabled, pass a @ref GL::Texture2DArray instance
instead of @ref GL::Texture2D. The layer is taken from the third coordinate of
@ref TextureArrayCoordinates, if used instead of @ref TextureCoordinates,
otherwise layer @cpp 0 @ce is picked. Additionally, the value of
@ref setTextureLayer(), which is @cpp 0 @ce by default, is added to the layer.
@section Shaders-DistanceFieldVectorGL-ubo Uniform buffers
See @ref shaders-usage-ubo for a high-level overview that applies to all
@ -148,10 +155,26 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @brief 2D texture coordinates
*
* @ref shaders-generic "Generic attribute",
* @relativeref{Magnum,Vector2}.
* @relativeref{Magnum,Vector2}. Use either this or the
* @ref TextureArrayCoordinates attribute.
*/
typedef typename GenericGL<dimensions>::TextureCoordinates TextureCoordinates;
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief 2D array texture coordinates
*
* @ref shaders-generic "Generic attribute",
* @relativeref{Magnum,Vector3}. Use either this or the
* @ref TextureCoordinates attribute. The third component is used only
* if @ref Flag::TextureArrays is set.
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES 2.0.
* @requires_webgl20 Texture arrays are not available in WebGL 1.0.
*/
typedef typename GenericGL<dimensions>::TextureArrayCoordinates TextureArrayCoordinates;
#endif
enum: UnsignedInt {
/**
* Color shader output. @ref shaders-generic "Generic output",
@ -233,7 +256,27 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* relies on uniform buffers, which require WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 2)
MultiDraw = UniformBuffers|(1 << 2),
/**
* Use 2D texture arrays. Expects that the texture is supplied via
* @ref bindVectorTexture(GL::Texture2DArray&) instead of
* @ref bindVectorTexture(GL::Texture2D&). The layer is taken from
* the third coordinate of @ref TextureArrayCoordinates, if used
* instead of @ref TextureCoordinates, otherwise layer @cpp 0 @ce
* is picked. Additionally, if @ref Flag::UniformBuffers is not
* enabled, the value of @ref setTextureLayer() is added to the
* layer; if @ref Flag::UniformBuffers is enabled and
* @ref Flag::TextureTransformation is enabled as well, the value
* of @ref TextureTransformationUniform::layer is added to the
* layer.
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Texture arrays are not available in WebGL 1.0.
* @m_since_latest
*/
TextureArrays = 1 << 4,
#endif
};
@ -428,6 +471,28 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
*/
DistanceFieldVectorGL<dimensions>& setTextureMatrix(const Matrix3& matrix);
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Set texture array layer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with @ref Flag::TextureArrays
* enabled. Initial value is @cpp 0 @ce. If a three-component
* @ref TextureArrayCoordinates attribute is used instead of
* @ref TextureCoordinates, this value is added to the layer coming
* from the third component.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TextureTransformationUniform::layer and call
* @ref bindTextureTransformationBuffer() instead.
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES 2.0.
* @requires_webgl20 Texture arrays are not available in WebGL 1.0.
*/
DistanceFieldVectorGL<dimensions>& setTextureLayer(UnsignedInt layer);
#endif
/**
* @brief Set fill color
* @return Reference to self (for method chaining)
@ -622,10 +687,32 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @brief Bind a vector texture
* @return Reference to self (for method chaining)
*
* If @ref Flag::TextureArrays is enabled, use
* @ref bindVectorTexture(GL::Texture2DArray&) instead.
* @see @ref Flag::TextureTransformation, @ref setTextureMatrix()
*/
DistanceFieldVectorGL<dimensions>& bindVectorTexture(GL::Texture2D& texture);
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Bind a vector array texture
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with @ref Flag::TextureArrays
* enabled. The layer is taken from the third coordinate of
* @ref TextureArrayCoordinates, if used instead of
* @ref TextureCoordinates, otherwise layer @cpp 0 @ce is picked.
* Additionally, if @ref Flag::UniformBuffers is not enabled, the layer
* index is offset with the value set in @ref setTextureLayer(); if
* @ref Flag::UniformBuffers is enabled and
* @ref Flag::TextureTransformation is enabled as well, the layer index
* is offset with @ref TextureTransformationUniform::layer.
* @see @ref Flag::TextureTransformation, @ref setTextureMatrix()
*/
DistanceFieldVectorGL<dimensions>& bindVectorTexture(GL::Texture2DArray& texture);
#endif
/**
* @}
*/
@ -643,10 +730,13 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
#endif
Int _transformationProjectionMatrixUniform{0},
_textureMatrixUniform{1},
_colorUniform{2},
_outlineColorUniform{3},
_outlineRangeUniform{4},
_smoothnessUniform{5};
#ifndef MAGNUM_TARGET_GLES2
_textureLayerUniform{2},
#endif
_colorUniform{3},
_outlineColorUniform{4},
_outlineRangeUniform{5},
_smoothnessUniform{6};
#ifndef MAGNUM_TARGET_GLES2
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */

577
src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp

@ -63,6 +63,7 @@
#include "Magnum/GL/Extensions.h"
#include "Magnum/GL/MeshView.h"
#include "Magnum/GL/TextureArray.h"
#include "Magnum/MeshTools/Concatenate.h"
#include "Magnum/MeshTools/GenerateIndices.h"
#include "Magnum/Primitives/Circle.h"
@ -100,9 +101,12 @@ struct DistanceFieldVectorGLTest: GL::OpenGLTester {
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setUniformUniformBuffersEnabled();
template<UnsignedInt dimensions> void bindBufferUniformBuffersNotEnabled();
template<UnsignedInt dimensions> void bindTextureInvalid();
template<UnsignedInt dimensions> void bindTextureArrayInvalid();
#endif
template<UnsignedInt dimensions> void setTextureMatrixNotEnabled();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setTextureLayerNotArray();
template<UnsignedInt dimensions> void bindTextureTransformBufferNotEnabled();
#endif
#ifndef MAGNUM_TARGET_GLES2
@ -167,7 +171,11 @@ constexpr struct {
DistanceFieldVectorGL2D::Flags flags;
} ConstructData[]{
{"", {}},
{"texture transformation", DistanceFieldVectorGL2D::Flag::TextureTransformation}
{"texture transformation", DistanceFieldVectorGL2D::Flag::TextureTransformation},
#ifndef MAGNUM_TARGET_GLES2
{"texture arrays", DistanceFieldVectorGL2D::Flag::TextureArrays},
{"texture transformation + texture arrays", DistanceFieldVectorGL2D::Flag::TextureTransformation|DistanceFieldVectorGL2D::Flag::TextureArrays},
#endif
};
#ifndef MAGNUM_TARGET_GLES2
@ -179,12 +187,14 @@ constexpr struct {
{"classic fallback", {}, 1, 1},
{"", DistanceFieldVectorGL2D::Flag::UniformBuffers, 1, 1},
{"texture transformation", DistanceFieldVectorGL2D::Flag::UniformBuffers|DistanceFieldVectorGL2D::Flag::TextureTransformation, 1, 1},
{"texture arrays", DistanceFieldVectorGL2D::Flag::TextureArrays, 1, 1},
{"texture transformation + texture arrays", DistanceFieldVectorGL2D::Flag::TextureTransformation|DistanceFieldVectorGL2D::Flag::TextureArrays, 1, 1},
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
and 3+1 in 2D, per-material 4 */
{"multiple materials, draws", DistanceFieldVectorGL2D::Flag::UniformBuffers, 16, 48},
{"multidraw with all the things", DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation, 16, 48},
{"multidraw with all the things", DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation|DistanceFieldVectorGL2D::Flag::TextureArrays, 16, 48},
#ifndef MAGNUM_TARGET_WEBGL
{"shader storage + multidraw with all the things", DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation, 0, 0}
{"shader storage + multidraw with all the things", DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL2D::Flag::MultiDraw|DistanceFieldVectorGL2D::Flag::TextureTransformation|DistanceFieldVectorGL2D::Flag::TextureArrays, 0, 0}
#endif
};
@ -206,22 +216,77 @@ const struct {
const char* name;
DistanceFieldVectorGL2D::Flags flags;
Matrix3 textureTransformation;
bool arrayTextureCoordinates;
Int layerAttribute, layerUniform;
Color4 color, outlineColor;
Float outlineRangeStart, outlineRangeEnd, smoothness;
const char* file2D;
const char* file3D;
bool flip;
} RenderData[] {
{"texture transformation", DistanceFieldVectorGL2D::Flag::TextureTransformation,
{"texture transformation",
DistanceFieldVectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
0xffffff_rgbf, 0x00000000_rgbaf, 0.5f, 1.0f, 0.04f,
false, 0, 0, 0xffffff_rgbf, 0x00000000_rgbaf, 0.5f, 1.0f, 0.04f,
"defaults-distancefield.tga", "defaults-distancefield.tga", true},
{"smooth0.1", {}, {}, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
{"smooth0.1",
{}, {},
false, 0, 0, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
"smooth0.1-2D.tga", "smooth0.1-3D.tga", false},
{"smooth0.2", {}, {}, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.2f,
{"smooth0.2",
{}, {},
false, 0, 0, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.2f,
"smooth0.2-2D.tga", "smooth0.2-3D.tga", false},
{"outline", {}, {}, 0xffff99_rgbf, 0x9999ff_rgbf, 0.6f, 0.45f, 0.05f,
"outline2D.tga", "outline3D.tga", false}
{"outline",
{}, {},
false, 0, 0, 0xffff99_rgbf, 0x9999ff_rgbf, 0.6f, 0.45f, 0.05f,
"outline2D.tga", "outline3D.tga", false},
#ifndef MAGNUM_TARGET_GLES2
{"array texture, 2D coordinates, first layer",
DistanceFieldVectorGL2D::Flag::TextureArrays, {},
false, 0, 0, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
"smooth0.1-2D.tga", "smooth0.1-3D.tga", false},
{"array texture, 2D coordinates, arbitrary layer from uniform",
DistanceFieldVectorGL2D::Flag::TextureArrays, {},
false, 0, 6, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
"smooth0.1-2D.tga", "smooth0.1-3D.tga", false},
{"array texture, 2D coordinates, texture transformation, arbitrary layer from uniform",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
false, 0, 6, 0xffffff_rgbf, 0x00000000_rgbaf, 0.5f, 1.0f, 0.04f,
"defaults-distancefield.tga", "defaults-distancefield.tga", true},
{"array texture, array coordinates, first layer",
DistanceFieldVectorGL2D::Flag::TextureArrays, {},
true, 0, 0, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
"smooth0.1-2D.tga", "smooth0.1-3D.tga", false},
{"array texture, array coordinates, arbitrary layer from attribute",
DistanceFieldVectorGL2D::Flag::TextureArrays, {},
true, 6, 0, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
"smooth0.1-2D.tga", "smooth0.1-3D.tga", false},
{"array texture, array coordinates, arbitrary layer from uniform",
DistanceFieldVectorGL2D::Flag::TextureArrays, {},
true, 0, 6, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
"smooth0.1-2D.tga", "smooth0.1-3D.tga", false},
{"array texture, array coordinates, arbitrary layer from both",
DistanceFieldVectorGL2D::Flag::TextureArrays, {},
true, 2, 4, 0xffff99_rgbf, 0x9999ff_rgbf, 0.5f, 1.0f, 0.1f,
"smooth0.1-2D.tga", "smooth0.1-3D.tga", false},
{"array texture, array coordinates, texture transformation, arbitrary layer from attribute",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
true, 6, 0, 0xffffff_rgbf, 0x00000000_rgbaf, 0.5f, 1.0f, 0.04f,
"defaults-distancefield.tga", "defaults-distancefield.tga", true},
{"array texture, array coordinates, texture transformation, arbitrary layer from uniform",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
true, 0, 6, 0xffffff_rgbf, 0x00000000_rgbaf, 0.5f, 1.0f, 0.04f,
"defaults-distancefield.tga", "defaults-distancefield.tga", true},
{"array texture, array coordinates, texture transformation, arbitrary layer from both",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
true, 2, 4, 0xffffff_rgbf, 0x00000000_rgbaf, 0.5f, 1.0f, 0.04f,
"defaults-distancefield.tga", "defaults-distancefield.tga", true},
#endif
};
#ifndef MAGNUM_TARGET_GLES2
@ -239,31 +304,55 @@ constexpr struct {
{}, 1, 1, true, 16,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"bind with offset, texture array", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::TextureArrays, 1, 1, true, 16,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#ifndef MAGNUM_TARGET_WEBGL
{"bind with offset, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers, 0, 0, true, 16,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"bind with offset, texture array, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers, 0, 0, true, 16,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#endif
{"draw offset", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
{}, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"draw offset, texture array", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::TextureArrays, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#ifndef MAGNUM_TARGET_WEBGL
{"draw offset, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"draw offset, texture array, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#endif
{"multidraw", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::MultiDraw, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"multidraw, texture array", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::MultiDraw, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL2D::Flag::MultiDraw, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
{"multidraw, texture array, shader storage", "multidraw2D-distancefield.tga", "multidraw3D-distancefield.tga",
DistanceFieldVectorGL2D::Flag::TextureArrays|DistanceFieldVectorGL2D::Flag::ShaderStorageBuffers|DistanceFieldVectorGL2D::Flag::MultiDraw, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.67f, 0.012f},
#endif
};
#endif
@ -312,10 +401,16 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() {
&DistanceFieldVectorGLTest::setUniformUniformBuffersEnabled<3>,
&DistanceFieldVectorGLTest::bindBufferUniformBuffersNotEnabled<2>,
&DistanceFieldVectorGLTest::bindBufferUniformBuffersNotEnabled<3>,
&DistanceFieldVectorGLTest::bindTextureInvalid<2>,
&DistanceFieldVectorGLTest::bindTextureInvalid<3>,
&DistanceFieldVectorGLTest::bindTextureArrayInvalid<2>,
&DistanceFieldVectorGLTest::bindTextureArrayInvalid<3>,
#endif
&DistanceFieldVectorGLTest::setTextureMatrixNotEnabled<2>,
&DistanceFieldVectorGLTest::setTextureMatrixNotEnabled<3>,
#ifndef MAGNUM_TARGET_GLES2
&DistanceFieldVectorGLTest::setTextureLayerNotArray<2>,
&DistanceFieldVectorGLTest::setTextureLayerNotArray<3>,
&DistanceFieldVectorGLTest::bindTextureTransformBufferNotEnabled<2>,
&DistanceFieldVectorGLTest::bindTextureTransformBufferNotEnabled<3>,
#endif
@ -633,6 +728,7 @@ template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::setUniformUnifo
Error redirectError{&out};
shader.setTransformationProjectionMatrix({})
.setTextureMatrix({})
.setTextureLayer({})
.setColor({})
.setOutlineColor({})
.setOutlineRange({}, {})
@ -640,6 +736,7 @@ template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::setUniformUnifo
CORRADE_COMPARE(out,
"Shaders::DistanceFieldVectorGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled\n"
"Shaders::DistanceFieldVectorGL::setTextureMatrix(): the shader was created with uniform buffers enabled\n"
"Shaders::DistanceFieldVectorGL::setTextureLayer(): the shader was created with uniform buffers enabled\n"
"Shaders::DistanceFieldVectorGL::setColor(): the shader was created with uniform buffers enabled\n"
"Shaders::DistanceFieldVectorGL::setOutlineColor(): the shader was created with uniform buffers enabled\n"
"Shaders::DistanceFieldVectorGL::setOutlineRange(): the shader was created with uniform buffers enabled\n"
@ -676,6 +773,45 @@ template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::bindBufferUnifo
"Shaders::DistanceFieldVectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::DistanceFieldVectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled\n");
}
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::bindTextureInvalid() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
CORRADE_SKIP_IF_NO_ASSERT();
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
GL::Texture2D texture;
DistanceFieldVectorGL<dimensions> shader{typename DistanceFieldVectorGL<dimensions>::Configuration{}
.setFlags(DistanceFieldVectorGL<dimensions>::Flag::TextureArrays)};
Containers::String out;
Error redirectError{&out};
shader.bindVectorTexture(texture);
CORRADE_COMPARE(out, "Shaders::DistanceFieldVectorGL::bindVectorTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead\n");
}
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::bindTextureArrayInvalid() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
CORRADE_SKIP_IF_NO_ASSERT();
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
GL::Texture2DArray texture;
DistanceFieldVectorGL<dimensions> shader;
Containers::String out;
Error redirectError{&out};
shader.bindVectorTexture(texture);
CORRADE_COMPARE(out, "Shaders::DistanceFieldVectorGL::bindVectorTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead\n");
}
#endif
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::setTextureMatrixNotEnabled() {
@ -693,6 +829,25 @@ template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::setTextureMatri
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::setTextureLayerNotArray() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
CORRADE_SKIP_IF_NO_ASSERT();
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
GL::Texture2D texture;
DistanceFieldVectorGL<dimensions> shader;
Containers::String out;
Error redirectError{&out};
shader.setTextureLayer(37);
CORRADE_COMPARE(out, "Shaders::DistanceFieldVectorGL::setTextureLayer(): the shader was not created with texture arrays enabled\n");
}
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::bindTextureTransformBufferNotEnabled() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
@ -1032,36 +1187,89 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates));
struct Vertex {
Vector2 position;
Vector3 textureCoords;
} squareData[] {
{{ 1.0f, -1.0f}, {1.0f, 0.0f, Float(data.layerAttribute)}},
{{ 1.0f, 1.0f}, {1.0f, 1.0f, Float(data.layerAttribute)}},
{{-1.0f, -1.0f}, {0.0f, 0.0f, Float(data.layerAttribute)}},
{{-1.0f, 1.0f}, {0.0f, 1.0f, Float(data.layerAttribute)}}
};
GL::Mesh square{GL::MeshPrimitive::TriangleStrip};
#ifndef MAGNUM_TARGET_GLES2
if(data.arrayTextureCoordinates) {
square.addVertexBuffer(GL::Buffer{squareData}, 0,
GenericGL2D::Position{},
GenericGL2D::TextureArrayCoordinates{});
} else
#endif
{
square.addVertexBuffer(GL::Buffer{squareData}, 0,
GenericGL2D::Position{},
GenericGL2D::TextureCoordinates{},
sizeof(Float));
}
square.setCount(4);
DistanceFieldVectorGL2D::Flags flags = data.flags|flag;
#ifndef MAGNUM_TARGET_GLES2
if(flag & DistanceFieldVectorGL2D::Flag::UniformBuffers && (data.flags & DistanceFieldVectorGL2D::Flag::TextureArrays) && !(data.flags & DistanceFieldVectorGL2D::Flag::TextureTransformation) && data.layerUniform) {
CORRADE_INFO("Texture arrays with layer passed from a uniform currently require texture transformation if UBOs are used, enabling implicitly.");
flags |= DistanceFieldVectorGL2D::Flag::TextureTransformation;
}
#endif
DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Configuration{}
.setFlags(flags)};
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
GL::Texture2D texture;
GL::Texture2D texture{NoCreate};
#ifndef MAGNUM_TARGET_GLES2
GL::Texture2DArray textureArray{NoCreate};
#endif
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0)));
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#ifndef MAGNUM_TARGET_GLES2
if(data.flags & DistanceFieldVectorGL2D::Flag::TextureArrays) {
textureArray = GL::Texture2DArray{};
textureArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, {image->size(), data.layerUniform + data.layerAttribute + 1})
.setSubImage(0, {0, 0, data.layerUniform + data.layerAttribute}, ImageView2D{*image});
shader.bindVectorTexture(textureArray);
} else
#endif
{
texture = GL::Texture2D{};
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#endif
DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Configuration{}
.setFlags(data.flags|flag)};
shader.bindVectorTexture(texture);
shader.bindVectorTexture(texture);
}
if(flag == DistanceFieldVectorGL2D::Flag{}) {
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
else shader.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f}));
#ifndef MAGNUM_TARGET_GLES2
if(data.layerUniform != 0) /* to verify the default */
shader.setTextureLayer(data.layerUniform);
#endif
shader.setColor(data.color)
.setOutlineColor(data.outlineColor)
.setOutlineRange(data.outlineRangeStart, data.outlineRangeEnd)
@ -1095,8 +1303,9 @@ template<DistanceFieldVectorGL2D::Flag flag> void DistanceFieldVectorGLTest::ren
GL::Buffer textureTransformationlUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
.setLayer(data.layerUniform)
}};
if(data.flags & DistanceFieldVectorGL2D::Flag::TextureTransformation)
if(flags & DistanceFieldVectorGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationlUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
@ -1163,30 +1372,79 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates));
struct Vertex {
Vector3 position;
Vector3 textureCoords;
} planeData[] {
{{ 1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, Float(data.layerAttribute)}},
{{ 1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, Float(data.layerAttribute)}},
{{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, Float(data.layerAttribute)}},
{{-1.0f, 1.0f, 0.0f}, {0.0f, 1.0f, Float(data.layerAttribute)}}
};
GL::Mesh plane{GL::MeshPrimitive::TriangleStrip};
#ifndef MAGNUM_TARGET_GLES2
if(data.arrayTextureCoordinates) {
plane.addVertexBuffer(GL::Buffer{planeData}, 0,
GenericGL3D::Position{},
GenericGL3D::TextureArrayCoordinates{});
} else
#endif
{
plane.addVertexBuffer(GL::Buffer{planeData}, 0,
GenericGL3D::Position{},
GenericGL3D::TextureCoordinates{},
sizeof(Float));
}
plane.setCount(4);
DistanceFieldVectorGL3D::Flags flags = data.flags|flag;
#ifndef MAGNUM_TARGET_GLES2
if(flag & DistanceFieldVectorGL3D::Flag::UniformBuffers && (data.flags & DistanceFieldVectorGL3D::Flag::TextureArrays) && !(data.flags & DistanceFieldVectorGL3D::Flag::TextureTransformation) && data.layerUniform) {
CORRADE_INFO("Texture arrays with layer passed from a uniform currently require texture transformation if UBOs are used, enabling implicitly.");
flags |= DistanceFieldVectorGL3D::Flag::TextureTransformation;
}
#endif
DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Configuration{}
.setFlags(flags)};
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
GL::Texture2D texture;
GL::Texture2D texture{NoCreate};
#ifndef MAGNUM_TARGET_GLES2
GL::Texture2DArray textureArray{NoCreate};
#endif
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0)));
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#ifndef MAGNUM_TARGET_GLES2
if(data.flags & DistanceFieldVectorGL3D::Flag::TextureArrays) {
textureArray = GL::Texture2DArray{};
textureArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, {image->size(), data.layerUniform + data.layerAttribute + 1})
.setSubImage(0, {0, 0, data.layerUniform + data.layerAttribute}, ImageView2D{*image});
shader.bindVectorTexture(textureArray);
} else
#endif
{
texture = GL::Texture2D{};
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#endif
DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Configuration{}
.setFlags(data.flags|flag)};
shader.bindVectorTexture(texture);
shader.bindVectorTexture(texture);
}
if(flag == DistanceFieldVectorGL3D::Flag{}) {
if(data.textureTransformation != Matrix3{})
@ -1196,6 +1454,10 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationZ(15.0_degf));
#ifndef MAGNUM_TARGET_GLES2
if(data.layerUniform != 0) /* to verify the default */
shader.setTextureLayer(data.layerUniform);
#endif
shader.setColor(data.color)
.setOutlineColor(data.outlineColor)
.setOutlineRange(data.outlineRangeStart, data.outlineRangeEnd)
@ -1232,8 +1494,9 @@ template<DistanceFieldVectorGL3D::Flag flag> void DistanceFieldVectorGLTest::ren
GL::Buffer textureTransformationlUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
.setLayer(data.layerUniform)
}};
if(data.flags & DistanceFieldVectorGL2D::Flag::TextureTransformation)
if(flags & DistanceFieldVectorGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationlUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
@ -1308,6 +1571,11 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
CORRADE_SKIP("UBOs with dynamically indexed arrays are a crashy dumpster fire on SwiftShader, can't test.");
#endif
DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Configuration{}
.setFlags(DistanceFieldVectorGL2D::Flag::UniformBuffers|DistanceFieldVectorGL2D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1317,12 +1585,36 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0)));
GL::Texture2D vector;
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
/* For arrays we the original image three times to different offsets in
three different slices */
GL::Texture2D vector{NoCreate};
GL::Texture2DArray vectorArray{NoCreate};
if(data.flags & DistanceFieldVectorGL2D::Flag::TextureArrays) {
Vector3i size{image->size().x(), image->size().y()*2, 6};
vectorArray = GL::Texture2DArray{};
vectorArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, size)
/* Clear to all zeros for reproducible output */
.setSubImage(0, {}, Image3D{PixelFormat::R8Unorm, size, Containers::Array<char>{ValueInit, std::size_t(size.product())}})
.setSubImage(0, {0, size.y()/4, 1}, ImageView2D{*image})
.setSubImage(0, {0, size.y()/2, 3}, ImageView2D{*image})
.setSubImage(0, {0, 0, 5}, ImageView2D{*image});
shader.bindVectorTexture(vectorArray);
} else {
vector = GL::Texture2D{};
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
shader.bindVectorTexture(vector);
}
/* Circle is a fan, plane is a strip, make it indexed first */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32,
@ -1331,7 +1623,47 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
Primitives::SquareFlag::TextureCoordinates));
Trade::MeshData triangleData = MeshTools::generateIndices(Primitives::circle2DSolid(3,
Primitives::Circle2DFlag::TextureCoordinates));
GL::Mesh mesh = MeshTools::compile(MeshTools::concatenate({circleData, squareData, triangleData}));
/* Assuming the texture coordinates are the last attribute, add a four-byte
padding after, which we subsequently abuse as the layer index */
/** @todo clean this up once MeshData (and primitives?) support array
coordinates directly */
Trade::MeshData meshData = MeshTools::interleave(
MeshTools::concatenate({circleData, squareData, triangleData}),
{Trade::MeshAttributeData{4}});
CORRADE_COMPARE(meshData.attributeCount(), 2);
CORRADE_COMPARE(meshData.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(meshData.attributeName(1), Trade::MeshAttribute::TextureCoordinates);
/* Manual cast because the real attribute type is Vector2 */
const Containers::StridedArrayView1D<Vector3> textureCoordinates = Containers::arrayCast<Vector3>(meshData.mutableAttribute<Vector2>(Trade::MeshAttribute::TextureCoordinates));
/* The circle will use the last slice, coming from just the attribute
alone */
for(UnsignedInt i = 0; i != circleData.vertexCount(); ++i)
textureCoordinates[i].z() = 5;
/* The square will use the third slice, coming from both the attribute and
the uniform */
for(UnsignedInt i = 0; i != squareData.vertexCount(); ++i)
textureCoordinates[circleData.vertexCount() + i].z() = 1;
/* The triangle will use the second slice, coming from just the uniform.
The memory isn't initialized by default however, so set the attribute to
0. */
for(UnsignedInt i = 0; i != triangleData.vertexCount(); ++i)
textureCoordinates[circleData.vertexCount() + squareData.vertexCount() + i].z() = 0;
/* Making some assumptions about the layout for simplicity */
CORRADE_COMPARE(meshData.attributeStride(0), sizeof(Vector2) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeStride(1), sizeof(Vector2) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeOffset(0), 0);
CORRADE_COMPARE(meshData.attributeOffset(1), sizeof(Vector2));
GL::Mesh mesh;
mesh.addVertexBuffer(GL::Buffer{meshData.vertexData()}, 0,
GenericGL2D::Position{},
GenericGL2D::TextureArrayCoordinates{})
.setIndexBuffer(GL::Buffer{GL::Buffer::TargetHint::ElementArray, meshData.indexData()}, 0,
meshData.indexType())
.setCount(meshData.indexCount());
GL::MeshView circle{mesh};
circle.setCount(circleData.indexCount());
GL::MeshView square{mesh};
@ -1379,17 +1711,30 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
Containers::Array<TextureTransformationUniform> textureTransformationData{2*data.uniformIncrement + 1};
textureTransformationData[0*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & DistanceFieldVectorGL2D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.0f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation({0.5f, 0.5f})*
Matrix3::rotation(180.0_degf)*
Matrix3::translation({-0.5f, -0.5f})
);
Matrix3::translation({-0.5f, -0.5f}))
.setLayer(0); /* ignored if not array */
textureTransformationData[1*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & DistanceFieldVectorGL2D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.5f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation(Vector2::xAxis(1.0f))*
Matrix3::scaling(Vector2::xScale(-1.0f))
);
Matrix3::scaling(Vector2::xScale(-1.0f)))
.setLayer(2); /* ignored if not array */
textureTransformationData[2*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(Matrix3{});
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & DistanceFieldVectorGL2D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.25f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{}))
.setLayer(1); /* ignored if not array */
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<DistanceFieldVectorDrawUniform> drawData{2*data.uniformIncrement + 1};
@ -1403,12 +1748,6 @@ void DistanceFieldVectorGLTest::renderMulti2D() {
.setMaterialId(data.bindWithOffset ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL2D shader{DistanceFieldVectorGL2D::Configuration{}
.setFlags(DistanceFieldVectorGL2D::Flag::UniformBuffers|DistanceFieldVectorGL2D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
@ -1528,6 +1867,11 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
CORRADE_SKIP("UBOs with dynamically indexed arrays are a crashy dumpster fire on SwiftShader, can't test.");
#endif
DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Configuration{}
.setFlags(DistanceFieldVectorGL3D::Flag::UniformBuffers|DistanceFieldVectorGL3D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1537,12 +1881,36 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0)));
GL::Texture2D vector;
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
/* For arrays we the original image three times to different offsets in
three different slices */
GL::Texture2D vector{NoCreate};
GL::Texture2DArray vectorArray{NoCreate};
if(data.flags & DistanceFieldVectorGL3D::Flag::TextureArrays) {
Vector3i size{image->size().x(), image->size().y()*2, 6};
vectorArray = GL::Texture2DArray{};
vectorArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, size)
/* Clear to all zeros for reproducible output */
.setSubImage(0, {}, Image3D{PixelFormat::R8Unorm, size, Containers::Array<char>{ValueInit, std::size_t(size.product())}})
.setSubImage(0, {0, size.y()/4, 1}, ImageView2D{*image})
.setSubImage(0, {0, size.y()/2, 3}, ImageView2D{*image})
.setSubImage(0, {0, 0, 5}, ImageView2D{*image});
shader.bindVectorTexture(vectorArray);
} else {
vector = GL::Texture2D{};
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
shader.bindVectorTexture(vector);
}
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereFlag::TextureCoordinates);
@ -1551,7 +1919,51 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
Primitives::PlaneFlag::TextureCoordinates));
Trade::MeshData coneData = Primitives::coneSolid(1, 32, 1.0f,
Primitives::ConeFlag::TextureCoordinates);
GL::Mesh mesh = MeshTools::compile(MeshTools::concatenate({sphereData, planeData, coneData}));
/* Assuming the texture coordinates are the last attribute, add a four-byte
padding after, which we subsequently abuse as the layer index */
/** @todo clean this up once MeshData (and primitives?) support array
coordinates directly */
Trade::MeshData meshData = MeshTools::interleave(
MeshTools::concatenate({sphereData, planeData, coneData}),
{Trade::MeshAttributeData{4}});
CORRADE_COMPARE(meshData.attributeCount(), 3);
CORRADE_COMPARE(meshData.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(meshData.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(meshData.attributeName(2), Trade::MeshAttribute::TextureCoordinates);
/* Manual cast because the real attribute type is Vector2 */
const Containers::StridedArrayView1D<Vector3> textureCoordinates = Containers::arrayCast<Vector3>(meshData.mutableAttribute<Vector2>(Trade::MeshAttribute::TextureCoordinates));
/* The sphere will use the last slice, coming from just the attribute
alone */
for(UnsignedInt i = 0; i != sphereData.vertexCount(); ++i)
textureCoordinates[i].z() = 5;
/* The plane will use the third slice, coming from both the attribute and
the uniform */
for(UnsignedInt i = 0; i != planeData.vertexCount(); ++i)
textureCoordinates[sphereData.vertexCount() + i].z() = 1;
/* The cone will use the first slice, coming from just the uniform. The
memory isn't initialized by default however, so set the attribute to
0. */
for(UnsignedInt i = 0; i != coneData.vertexCount(); ++i)
textureCoordinates[sphereData.vertexCount() + planeData.vertexCount() + i].z() = 0;
/* Making some assumptions about the layout for simplicity */
CORRADE_COMPARE(meshData.attributeStride(0), sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeStride(1), sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeStride(2), sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeOffset(0), 0);
CORRADE_COMPARE(meshData.attributeOffset(1), sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeOffset(2), sizeof(Vector3) + sizeof(Vector3));
GL::Mesh mesh;
mesh.addVertexBuffer(GL::Buffer{meshData.vertexData()}, 0,
GenericGL3D::Position{},
GenericGL3D::Normal{},
GenericGL3D::TextureArrayCoordinates{})
.setIndexBuffer(GL::Buffer{GL::Buffer::TargetHint::ElementArray, meshData.indexData()}, 0,
meshData.indexType())
.setCount(meshData.indexCount());
GL::MeshView sphere{mesh};
sphere.setCount(sphereData.indexCount());
GL::MeshView plane{mesh};
@ -1604,17 +2016,30 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
Containers::Array<TextureTransformationUniform> textureTransformationData{2*data.uniformIncrement + 1};
textureTransformationData[0*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & DistanceFieldVectorGL3D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.0f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation({0.5f, 0.5f})*
Matrix3::rotation(180.0_degf)*
Matrix3::translation({-0.5f, -0.5f})
);
Matrix3::translation({-0.5f, -0.5f}))
.setLayer(0); /* ignored if not array */
textureTransformationData[1*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & DistanceFieldVectorGL3D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.5f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation(Vector2::xAxis(1.0f))*
Matrix3::scaling(Vector2::xScale(-1.0f))
);
Matrix3::scaling(Vector2::xScale(-1.0f)))
.setLayer(2); /* ignored if not array */
textureTransformationData[2*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(Matrix3{});
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & DistanceFieldVectorGL3D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.25f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{}))
.setLayer(1); /* ignored if not array */
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<DistanceFieldVectorDrawUniform> drawData{2*data.uniformIncrement + 1};
@ -1628,12 +2053,6 @@ void DistanceFieldVectorGLTest::renderMulti3D() {
.setMaterialId(data.bindWithOffset ? 0 : 0);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
DistanceFieldVectorGL3D shader{DistanceFieldVectorGL3D::Configuration{}
.setFlags(DistanceFieldVectorGL3D::Flag::UniformBuffers|DistanceFieldVectorGL3D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,

4
src/Magnum/Shaders/Test/DistanceFieldVectorGL_Test.cpp

@ -92,8 +92,8 @@ void DistanceFieldVectorGL_Test::debugFlag() {
void DistanceFieldVectorGL_Test::debugFlags() {
Containers::String out;
Debug{&out} << DistanceFieldVectorGL3D::Flags{DistanceFieldVectorGL3D::Flag::TextureTransformation|DistanceFieldVectorGL3D::Flag(0xf0)} << DistanceFieldVectorGL3D::Flags{};
CORRADE_COMPARE(out, "Shaders::DistanceFieldVectorGL::Flag::TextureTransformation|Shaders::DistanceFieldVectorGL::Flag(0xf0) Shaders::DistanceFieldVectorGL::Flags{}\n");
Debug{&out} << DistanceFieldVectorGL3D::Flags{DistanceFieldVectorGL3D::Flag::TextureTransformation|DistanceFieldVectorGL3D::Flag(0x80)} << DistanceFieldVectorGL3D::Flags{};
CORRADE_COMPARE(out, "Shaders::DistanceFieldVectorGL::Flag::TextureTransformation|Shaders::DistanceFieldVectorGL::Flag(0x80) Shaders::DistanceFieldVectorGL::Flags{}\n");
}
#ifndef MAGNUM_TARGET_GLES2

573
src/Magnum/Shaders/Test/VectorGLTest.cpp

@ -61,6 +61,7 @@
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/Extensions.h"
#include "Magnum/GL/MeshView.h"
#include "Magnum/GL/TextureArray.h"
#include "Magnum/MeshTools/Concatenate.h"
#include "Magnum/MeshTools/GenerateIndices.h"
#include "Magnum/Primitives/Circle.h"
@ -99,9 +100,12 @@ struct VectorGLTest: GL::OpenGLTester {
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setUniformUniformBuffersEnabled();
template<UnsignedInt dimensions> void bindBufferUniformBuffersNotEnabled();
template<UnsignedInt dimensions> void bindTextureInvalid();
template<UnsignedInt dimensions> void bindTextureArrayInvalid();
#endif
template<UnsignedInt dimensions> void setTextureMatrixNotEnabled();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setTextureLayerNotArray();
template<UnsignedInt dimensions> void bindTextureTransformBufferNotEnabled();
#endif
#ifndef MAGNUM_TARGET_GLES2
@ -166,7 +170,11 @@ constexpr struct {
VectorGL2D::Flags flags;
} ConstructData[]{
{"", {}},
{"texture transformation", VectorGL2D::Flag::TextureTransformation}
{"texture transformation", VectorGL2D::Flag::TextureTransformation},
#ifndef MAGNUM_TARGET_GLES2
{"texture arrays", VectorGL2D::Flag::TextureArrays},
{"texture transformation + texture arrays", VectorGL2D::Flag::TextureTransformation|VectorGL2D::Flag::TextureArrays},
#endif
};
#ifndef MAGNUM_TARGET_GLES2
@ -178,12 +186,14 @@ constexpr struct {
{"classic fallback", {}, 1, 1},
{"", VectorGL2D::Flag::UniformBuffers, 1, 1},
{"texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 1, 1},
{"texture arrays", VectorGL2D::Flag::TextureArrays, 1, 1},
{"texture transformation + texture arrays", VectorGL2D::Flag::TextureTransformation|VectorGL2D::Flag::TextureArrays, 1, 1},
/* SwiftShader has 256 uniform vectors at most, per-draw is 4+1 in 3D case
and 3+1 in 2D, per-material 3 */
{"multiple materials, draws", VectorGL2D::Flag::UniformBuffers, 15, 42},
{"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 15, 42},
{"multidraw with all the things", VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation|VectorGL2D::Flag::TextureArrays, 15, 42},
#ifndef MAGNUM_TARGET_WEBGL
{"shader storage + multidraw with all the things", VectorGL2D::Flag::ShaderStorageBuffers|VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation, 0, 0}
{"shader storage + multidraw with all the things", VectorGL2D::Flag::ShaderStorageBuffers|VectorGL2D::Flag::MultiDraw|VectorGL2D::Flag::TextureTransformation|VectorGL2D::Flag::TextureArrays, 0, 0}
#endif
};
#endif
@ -207,17 +217,68 @@ const struct {
const char* name;
VectorGL2D::Flags flags;
Matrix3 textureTransformation;
bool arrayTextureCoordinates;
Int layerAttribute, layerUniform;
Color4 backgroundColor, color;
const char* file2D;
const char* file3D;
bool flip;
} RenderData[] {
{"texture transformation", VectorGL2D::Flag::TextureTransformation,
{"texture transformation",
VectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
false, 0, 0, 0x00000000_rgbaf, 0xffffff_rgbf,
"defaults.tga", "defaults.tga", true},
{"",
{}, {},
false, 0, 0, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false},
#ifndef MAGNUM_TARGET_GLES2
{"array texture, 2D coordinates, first layer",
VectorGL2D::Flag::TextureArrays, {},
false, 0, 0, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false},
{"array texture, 2D coordinates, arbitrary layer from uniform",
VectorGL2D::Flag::TextureArrays, {},
false, 0, 6, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false},
{"array texture, 2D coordinates, texture transformation, arbitrary layer from uniform",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
false, 0, 6, 0x00000000_rgbaf, 0xffffff_rgbf,
"defaults.tga", "defaults.tga", true},
{"array texture, array coordinates, first layer",
VectorGL2D::Flag::TextureArrays, {},
true, 0, 0, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false},
{"array texture, array coordinates, arbitrary layer from attribute",
VectorGL2D::Flag::TextureArrays, {},
true, 6, 0, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false},
{"array texture, array coordinates, arbitrary layer from uniform",
VectorGL2D::Flag::TextureArrays, {},
true, 0, 6, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false},
{"array texture, array coordinates, arbitrary layer from both",
VectorGL2D::Flag::TextureArrays, {},
true, 2, 4, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false},
{"array texture, array coordinates, texture transformation, arbitrary layer from attribute",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
true, 6, 0, 0x00000000_rgbaf, 0xffffff_rgbf,
"defaults.tga", "defaults.tga", true},
{"array texture, array coordinates, texture transformation, arbitrary layer from uniform",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
0x00000000_rgbaf, 0xffffff_rgbf,
true, 0, 6, 0x00000000_rgbaf, 0xffffff_rgbf,
"defaults.tga", "defaults.tga", true},
{"", {}, {}, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false}
{"array texture, array coordinates, texture transformation, arbitrary layer from both",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
true, 2, 4, 0x00000000_rgbaf, 0xffffff_rgbf,
"defaults.tga", "defaults.tga", true},
#endif
};
#ifndef MAGNUM_TARGET_GLES2
@ -235,31 +296,55 @@ constexpr struct {
{}, 1, 1, true, 16,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"bind with offset, texture array", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::TextureArrays, 1, 1, true, 16,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#ifndef MAGNUM_TARGET_WEBGL
{"bind with offset, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::ShaderStorageBuffers, 0, 0, true, 16,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"bind with offset, texture array, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::ShaderStorageBuffers, 0, 0, true, 16,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#endif
{"draw offset", "multidraw2D.tga", "multidraw3D.tga",
{}, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"draw offset, texture array", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::TextureArrays, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#ifndef MAGNUM_TARGET_WEBGL
{"draw offset, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::ShaderStorageBuffers, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"draw offset, texture array, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::ShaderStorageBuffers, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#endif
{"multidraw", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::MultiDraw, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"multidraw, texture array", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::MultiDraw, 2, 3, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#ifndef MAGNUM_TARGET_WEBGL
{"multidraw, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::ShaderStorageBuffers|VectorGL2D::Flag::MultiDraw, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
{"multidraw, texture array, shader storage", "multidraw2D.tga", "multidraw3D.tga",
VectorGL2D::Flag::TextureArrays|VectorGL2D::Flag::ShaderStorageBuffers|VectorGL2D::Flag::MultiDraw, 0, 0, false, 1,
/* Minor differences on ARM Mali */
1.34f, 0.02f},
#endif
};
#endif
@ -308,10 +393,16 @@ VectorGLTest::VectorGLTest() {
&VectorGLTest::setUniformUniformBuffersEnabled<3>,
&VectorGLTest::bindBufferUniformBuffersNotEnabled<2>,
&VectorGLTest::bindBufferUniformBuffersNotEnabled<3>,
&VectorGLTest::bindTextureInvalid<2>,
&VectorGLTest::bindTextureInvalid<3>,
&VectorGLTest::bindTextureArrayInvalid<2>,
&VectorGLTest::bindTextureArrayInvalid<3>,
#endif
&VectorGLTest::setTextureMatrixNotEnabled<2>,
&VectorGLTest::setTextureMatrixNotEnabled<3>,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::setTextureLayerNotArray<2>,
&VectorGLTest::setTextureLayerNotArray<3>,
&VectorGLTest::bindTextureTransformBufferNotEnabled<2>,
&VectorGLTest::bindTextureTransformBufferNotEnabled<3>,
#endif
@ -628,11 +719,13 @@ template<UnsignedInt dimensions> void VectorGLTest::setUniformUniformBuffersEnab
Error redirectError{&out};
shader.setTransformationProjectionMatrix({})
.setTextureMatrix({})
.setTextureLayer({})
.setBackgroundColor({})
.setColor({});
CORRADE_COMPARE(out,
"Shaders::VectorGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled\n"
"Shaders::VectorGL::setTextureMatrix(): the shader was created with uniform buffers enabled\n"
"Shaders::VectorGL::setTextureLayer(): the shader was created with uniform buffers enabled\n"
"Shaders::VectorGL::setBackgroundColor(): the shader was created with uniform buffers enabled\n"
"Shaders::VectorGL::setColor(): the shader was created with uniform buffers enabled\n");
}
@ -667,6 +760,45 @@ template<UnsignedInt dimensions> void VectorGLTest::bindBufferUniformBuffersNotE
"Shaders::VectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled\n");
}
template<UnsignedInt dimensions> void VectorGLTest::bindTextureInvalid() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
CORRADE_SKIP_IF_NO_ASSERT();
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
GL::Texture2D texture;
VectorGL<dimensions> shader{typename VectorGL<dimensions>::Configuration{}
.setFlags(VectorGL<dimensions>::Flag::TextureArrays)};
Containers::String out;
Error redirectError{&out};
shader.bindVectorTexture(texture);
CORRADE_COMPARE(out, "Shaders::VectorGL::bindVectorTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead\n");
}
template<UnsignedInt dimensions> void VectorGLTest::bindTextureArrayInvalid() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
CORRADE_SKIP_IF_NO_ASSERT();
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
GL::Texture2DArray texture;
VectorGL<dimensions> shader;
Containers::String out;
Error redirectError{&out};
shader.bindVectorTexture(texture);
CORRADE_COMPARE(out, "Shaders::VectorGL::bindVectorTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead\n");
}
#endif
template<UnsignedInt dimensions> void VectorGLTest::setTextureMatrixNotEnabled() {
@ -684,6 +816,25 @@ template<UnsignedInt dimensions> void VectorGLTest::setTextureMatrixNotEnabled()
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VectorGLTest::setTextureLayerNotArray() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
CORRADE_SKIP_IF_NO_ASSERT();
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::texture_array>())
CORRADE_SKIP(GL::Extensions::EXT::texture_array::string() << "is not supported.");
#endif
GL::Texture2D texture;
VectorGL<dimensions> shader;
Containers::String out;
Error redirectError{&out};
shader.setTextureLayer(37);
CORRADE_COMPARE(out, "Shaders::VectorGL::setTextureLayer(): the shader was not created with texture arrays enabled\n");
}
template<UnsignedInt dimensions> void VectorGLTest::bindTextureTransformBufferNotEnabled() {
setTestCaseTemplateName(Utility::format("{}", dimensions));
@ -1007,30 +1158,81 @@ template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareFlag::TextureCoordinates));
/** @todo clean this up once MeshData (and primitives?) support array
coordinates directly */
struct Vertex {
Vector2 position;
Vector3 textureCoords;
} squareData[] {
{{ 1.0f, -1.0f}, {1.0f, 0.0f, Float(data.layerAttribute)}},
{{ 1.0f, 1.0f}, {1.0f, 1.0f, Float(data.layerAttribute)}},
{{-1.0f, -1.0f}, {0.0f, 0.0f, Float(data.layerAttribute)}},
{{-1.0f, 1.0f}, {0.0f, 1.0f, Float(data.layerAttribute)}}
};
GL::Mesh square{GL::MeshPrimitive::TriangleStrip};
#ifndef MAGNUM_TARGET_GLES2
if(data.arrayTextureCoordinates) {
square.addVertexBuffer(GL::Buffer{squareData}, 0,
GenericGL2D::Position{},
GenericGL2D::TextureArrayCoordinates{});
} else
#endif
{
square.addVertexBuffer(GL::Buffer{squareData}, 0,
GenericGL2D::Position{},
GenericGL2D::TextureCoordinates{},
sizeof(Float));
}
square.setCount(4);
VectorGL2D::Flags flags = data.flags|flag;
#ifndef MAGNUM_TARGET_GLES2
if(flag & VectorGL2D::Flag::UniformBuffers && (data.flags & VectorGL2D::Flag::TextureArrays) && !(data.flags & VectorGL2D::Flag::TextureTransformation) && data.layerUniform) {
CORRADE_INFO("Texture arrays with layer passed from a uniform currently require texture transformation if UBOs are used, enabling implicitly.");
flags |= VectorGL2D::Flag::TextureTransformation;
}
#endif
VectorGL2D shader{VectorGL2D::Configuration{}
.setFlags(flags)};
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
GL::Texture2D texture;
GL::Texture2D texture{NoCreate};
#ifndef MAGNUM_TARGET_GLES2
GL::Texture2DArray textureArray{NoCreate};
#endif
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector.tga")) && (image = importer->image2D(0)));
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#ifndef MAGNUM_TARGET_GLES2
if(data.flags & VectorGL2D::Flag::TextureArrays) {
textureArray = GL::Texture2DArray{};
textureArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, TextureFormatR, {image->size(), data.layerUniform + data.layerAttribute + 1})
.setSubImage(0, {0, 0, data.layerUniform + data.layerAttribute}, ImageView2D{*image});
shader.bindVectorTexture(textureArray);
} else
#endif
{
texture = GL::Texture2D{};
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#endif
VectorGL2D shader{VectorGL2D::Configuration{}
.setFlags(data.flags|flag)};
shader.bindVectorTexture(texture);
shader.bindVectorTexture(texture);
}
if(flag == VectorGL2D::Flag{}) {
shader.setBackgroundColor(data.backgroundColor)
@ -1040,6 +1242,10 @@ template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
else shader.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::rotation(5.0_degf));
#ifndef MAGNUM_TARGET_GLES2
if(data.layerUniform != 0) /* to verify the default */
shader.setTextureLayer(data.layerUniform);
#endif
shader.draw(square);
}
#ifndef MAGNUM_TARGET_GLES2
@ -1063,13 +1269,14 @@ template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
.setLayer(data.layerUniform)
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
VectorMaterialUniform{}
.setBackgroundColor(data.backgroundColor)
.setColor(data.color)
}};
if(data.flags & VectorGL2D::Flag::TextureTransformation)
if(flags & VectorGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
@ -1135,30 +1342,79 @@ template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneFlag::TextureCoordinates));
struct Vertex {
Vector3 position;
Vector3 textureCoords;
} planeData[] {
{{ 1.0f, -1.0f, 0.0f}, {1.0f, 0.0f, Float(data.layerAttribute)}},
{{ 1.0f, 1.0f, 0.0f}, {1.0f, 1.0f, Float(data.layerAttribute)}},
{{-1.0f, -1.0f, 0.0f}, {0.0f, 0.0f, Float(data.layerAttribute)}},
{{-1.0f, 1.0f, 0.0f}, {0.0f, 1.0f, Float(data.layerAttribute)}}
};
GL::Mesh plane{GL::MeshPrimitive::TriangleStrip};
#ifndef MAGNUM_TARGET_GLES2
if(data.arrayTextureCoordinates) {
plane.addVertexBuffer(GL::Buffer{planeData}, 0,
GenericGL3D::Position{},
GenericGL3D::TextureArrayCoordinates{});
} else
#endif
{
plane.addVertexBuffer(GL::Buffer{planeData}, 0,
GenericGL3D::Position{},
GenericGL3D::TextureCoordinates{},
sizeof(Float));
}
plane.setCount(4);
VectorGL3D::Flags flags = data.flags|flag;
#ifndef MAGNUM_TARGET_GLES2
if(flag & VectorGL3D::Flag::UniformBuffers && (data.flags & VectorGL3D::Flag::TextureArrays) && !(data.flags & VectorGL3D::Flag::TextureTransformation) && data.layerUniform) {
CORRADE_INFO("Texture arrays with layer passed from a uniform currently require texture transformation if UBOs are used, enabling implicitly.");
flags |= VectorGL3D::Flag::TextureTransformation;
}
#endif
VectorGL3D shader{VectorGL3D::Configuration{}
.setFlags(flags)};
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
GL::Texture2D texture;
GL::Texture2D texture{NoCreate};
#ifndef MAGNUM_TARGET_GLES2
GL::Texture2DArray textureArray{NoCreate};
#endif
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector.tga")) && (image = importer->image2D(0)));
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#ifndef MAGNUM_TARGET_GLES2
if(data.flags & VectorGL3D::Flag::TextureArrays) {
textureArray = GL::Texture2DArray{};
textureArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, TextureFormatR, {image->size(), data.layerUniform + data.layerAttribute + 1})
.setSubImage(0, {0, 0, data.layerUniform + data.layerAttribute}, ImageView2D{*image});
shader.bindVectorTexture(textureArray);
} else
#endif
{
texture = GL::Texture2D{};
texture.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge);
#ifdef MAGNUM_TARGET_GLES2
/* Don't want to bother with the fiasco of single-channel formats and
texture storage extensions on ES2 */
texture.setImage(0, TextureFormatR, *image);
#else
texture.setStorage(1, TextureFormatR, image->size())
.setSubImage(0, {}, *image);
#endif
VectorGL3D shader{VectorGL3D::Configuration{}
.setFlags(data.flags|flag)};
shader.bindVectorTexture(texture);
shader.bindVectorTexture(texture);
}
if(flag == VectorGL3D::Flag{}) {
shader.setBackgroundColor(data.backgroundColor)
@ -1170,6 +1426,10 @@ template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationZ(15.0_degf));
#ifndef MAGNUM_TARGET_GLES2
if(data.layerUniform != 0) /* to verify the default */
shader.setTextureLayer(data.layerUniform);
#endif
shader.draw(plane);
}
#ifndef MAGNUM_TARGET_GLES2
@ -1195,13 +1455,14 @@ template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
.setLayer(data.layerUniform)
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
VectorMaterialUniform{}
.setBackgroundColor(data.backgroundColor)
.setColor(data.color)
}};
if(data.flags & VectorGL3D::Flag::TextureTransformation)
if(flags & VectorGL3D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
@ -1275,6 +1536,11 @@ void VectorGLTest::renderMulti2D() {
CORRADE_SKIP("UBOs with dynamically indexed arrays are a crashy dumpster fire on SwiftShader, can't test.");
#endif
VectorGL2D shader{VectorGL2D::Configuration{}
.setFlags(VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1284,21 +1550,85 @@ void VectorGLTest::renderMulti2D() {
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector.tga")) && (image = importer->image2D(0)));
GL::Texture2D vector;
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
/* Circle is a fan, plane is a strip, make it indexed first */
/* For arrays we the original image three times to different offsets in
three different slices */
GL::Texture2D vector{NoCreate};
GL::Texture2DArray vectorArray{NoCreate};
if(data.flags & VectorGL2D::Flag::TextureArrays) {
Vector3i size{image->size().x(), image->size().y()*2, 6};
vectorArray = GL::Texture2DArray{};
vectorArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, size)
/* Clear to all zeros for reproducible output */
.setSubImage(0, {}, Image3D{PixelFormat::R8Unorm, size, Containers::Array<char>{ValueInit, std::size_t(size.product())}})
.setSubImage(0, {0, size.y()/4, 1}, ImageView2D{*image})
.setSubImage(0, {0, size.y()/2, 3}, ImageView2D{*image})
.setSubImage(0, {0, 0, 5}, ImageView2D{*image});
shader.bindVectorTexture(vectorArray);
} else {
vector = GL::Texture2D{};
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
shader.bindVectorTexture(vector);
}
/* Circle is a fan, square is a strip, make it indexed first */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32,
Primitives::Circle2DFlag::TextureCoordinates));
Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid(
Primitives::SquareFlag::TextureCoordinates));
Trade::MeshData triangleData = MeshTools::generateIndices(Primitives::circle2DSolid(3,
Primitives::Circle2DFlag::TextureCoordinates));
GL::Mesh mesh = MeshTools::compile(MeshTools::concatenate({circleData, squareData, triangleData}));
/* Assuming the texture coordinates are the last attribute, add a four-byte
padding after, which we subsequently abuse as the layer index */
/** @todo clean this up once MeshData (and primitives?) support array
coordinates directly */
Trade::MeshData meshData = MeshTools::interleave(
MeshTools::concatenate({circleData, squareData, triangleData}),
{Trade::MeshAttributeData{4}});
CORRADE_COMPARE(meshData.attributeCount(), 2);
CORRADE_COMPARE(meshData.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(meshData.attributeName(1), Trade::MeshAttribute::TextureCoordinates);
/* Manual cast because the real attribute type is Vector2 */
const Containers::StridedArrayView1D<Vector3> textureCoordinates = Containers::arrayCast<Vector3>(meshData.mutableAttribute<Vector2>(Trade::MeshAttribute::TextureCoordinates));
/* The circle will use the last slice, coming from just the attribute
alone */
for(UnsignedInt i = 0; i != circleData.vertexCount(); ++i)
textureCoordinates[i].z() = 5;
/* The square will use the third slice, coming from both the attribute and
the uniform */
for(UnsignedInt i = 0; i != squareData.vertexCount(); ++i)
textureCoordinates[circleData.vertexCount() + i].z() = 1;
/* The triangle will use the second slice, coming from just the uniform.
The memory isn't initialized by default however, so set the attribute to
0. */
for(UnsignedInt i = 0; i != triangleData.vertexCount(); ++i)
textureCoordinates[circleData.vertexCount() + squareData.vertexCount() + i].z() = 0;
/* Making some assumptions about the layout for simplicity */
CORRADE_COMPARE(meshData.attributeStride(0), sizeof(Vector2) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeStride(1), sizeof(Vector2) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeOffset(0), 0);
CORRADE_COMPARE(meshData.attributeOffset(1), sizeof(Vector2));
GL::Mesh mesh;
mesh.addVertexBuffer(GL::Buffer{meshData.vertexData()}, 0,
GenericGL2D::Position{},
GenericGL2D::TextureArrayCoordinates{})
.setIndexBuffer(GL::Buffer{GL::Buffer::TargetHint::ElementArray, meshData.indexData()}, 0,
meshData.indexType())
.setCount(meshData.indexCount());
GL::MeshView circle{mesh};
circle.setCount(circleData.indexCount());
GL::MeshView square{mesh};
@ -1346,17 +1676,30 @@ void VectorGLTest::renderMulti2D() {
Containers::Array<TextureTransformationUniform> textureTransformationData{2*data.uniformIncrement + 1};
textureTransformationData[0*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & VectorGL2D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.0f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation({0.5f, 0.5f})*
Matrix3::rotation(180.0_degf)*
Matrix3::translation({-0.5f, -0.5f})
);
Matrix3::translation({-0.5f, -0.5f}))
.setLayer(0); /* ignored if not array */
textureTransformationData[1*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & VectorGL2D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.5f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation(Vector2::xAxis(1.0f))*
Matrix3::scaling(Vector2::xScale(-1.0f))
);
Matrix3::scaling(Vector2::xScale(-1.0f)))
.setLayer(2); /* ignored if not array */
textureTransformationData[2*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(Matrix3{});
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & VectorGL2D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.25f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{}))
.setLayer(1); /* ignored if not array */
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<VectorDrawUniform> drawData{2*data.uniformIncrement + 1};
@ -1370,12 +1713,6 @@ void VectorGLTest::renderMulti2D() {
.setMaterialId(data.bindWithOffset ? 0 : 1);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL2D shader{VectorGL2D::Configuration{}
.setFlags(VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,
@ -1495,6 +1832,11 @@ void VectorGLTest::renderMulti3D() {
CORRADE_SKIP("UBOs with dynamically indexed arrays are a crashy dumpster fire on SwiftShader, can't test.");
#endif
VectorGL3D shader{VectorGL3D::Configuration{}
.setFlags(VectorGL3D::Flag::UniformBuffers|VectorGL3D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -1504,12 +1846,36 @@ void VectorGLTest::renderMulti3D() {
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Path::join(_testDir, "TestFiles/vector.tga")) && (image = importer->image2D(0)));
GL::Texture2D vector;
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
/* For arrays we the original image three times to different offsets in
three different slices */
GL::Texture2D vector{NoCreate};
GL::Texture2DArray vectorArray{NoCreate};
if(data.flags & VectorGL2D::Flag::TextureArrays) {
Vector3i size{image->size().x(), image->size().y()*2, 6};
vectorArray = GL::Texture2DArray{};
vectorArray.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, size)
/* Clear to all zeros for reproducible output */
.setSubImage(0, {}, Image3D{PixelFormat::R8Unorm, size, Containers::Array<char>{ValueInit, std::size_t(size.product())}})
.setSubImage(0, {0, size.y()/4, 1}, ImageView2D{*image})
.setSubImage(0, {0, size.y()/2, 3}, ImageView2D{*image})
.setSubImage(0, {0, 0, 5}, ImageView2D{*image});
shader.bindVectorTexture(vectorArray);
} else {
vector = GL::Texture2D{};
vector.setMinificationFilter(GL::SamplerFilter::Linear)
.setMagnificationFilter(GL::SamplerFilter::Linear)
.setWrapping(GL::SamplerWrapping::ClampToEdge)
.setStorage(1, GL::TextureFormat::R8, image->size())
.setSubImage(0, {}, *image);
shader.bindVectorTexture(vector);
}
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereFlag::TextureCoordinates);
@ -1518,7 +1884,51 @@ void VectorGLTest::renderMulti3D() {
Primitives::PlaneFlag::TextureCoordinates));
Trade::MeshData coneData = Primitives::coneSolid(1, 32, 1.0f,
Primitives::ConeFlag::TextureCoordinates);
GL::Mesh mesh = MeshTools::compile(MeshTools::concatenate({sphereData, planeData, coneData}));
/* Assuming the texture coordinates are the last attribute, add a four-byte
padding after, which we subsequently abuse as the layer index */
/** @todo clean this up once MeshData (and primitives?) support array
coordinates directly */
Trade::MeshData meshData = MeshTools::interleave(
MeshTools::concatenate({sphereData, planeData, coneData}),
{Trade::MeshAttributeData{4}});
CORRADE_COMPARE(meshData.attributeCount(), 3);
CORRADE_COMPARE(meshData.attributeName(0), Trade::MeshAttribute::Position);
CORRADE_COMPARE(meshData.attributeName(1), Trade::MeshAttribute::Normal);
CORRADE_COMPARE(meshData.attributeName(2), Trade::MeshAttribute::TextureCoordinates);
/* Manual cast because the real attribute type is Vector2 */
const Containers::StridedArrayView1D<Vector3> textureCoordinates = Containers::arrayCast<Vector3>(meshData.mutableAttribute<Vector2>(Trade::MeshAttribute::TextureCoordinates));
/* The sphere will use the last slice, coming from just the attribute
alone */
for(UnsignedInt i = 0; i != sphereData.vertexCount(); ++i)
textureCoordinates[i].z() = 5;
/* The plane will use the third slice, coming from both the attribute and
the uniform */
for(UnsignedInt i = 0; i != planeData.vertexCount(); ++i)
textureCoordinates[sphereData.vertexCount() + i].z() = 1;
/* The cone will use the first slice, coming from just the uniform. The
memory isn't initialized by default however, so set the attribute to
0. */
for(UnsignedInt i = 0; i != coneData.vertexCount(); ++i)
textureCoordinates[sphereData.vertexCount() + planeData.vertexCount() + i].z() = 0;
/* Making some assumptions about the layout for simplicity */
CORRADE_COMPARE(meshData.attributeStride(0), sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeStride(1), sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeStride(2), sizeof(Vector3) + sizeof(Vector3) + sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeOffset(0), 0);
CORRADE_COMPARE(meshData.attributeOffset(1), sizeof(Vector3));
CORRADE_COMPARE(meshData.attributeOffset(2), sizeof(Vector3) + sizeof(Vector3));
GL::Mesh mesh;
mesh.addVertexBuffer(GL::Buffer{meshData.vertexData()}, 0,
GenericGL3D::Position{},
GenericGL3D::Normal{},
GenericGL3D::TextureArrayCoordinates{})
.setIndexBuffer(GL::Buffer{GL::Buffer::TargetHint::ElementArray, meshData.indexData()}, 0,
meshData.indexType())
.setCount(meshData.indexCount());
GL::MeshView sphere{mesh};
sphere.setCount(sphereData.indexCount());
GL::MeshView plane{mesh};
@ -1571,17 +1981,30 @@ void VectorGLTest::renderMulti3D() {
Containers::Array<TextureTransformationUniform> textureTransformationData{2*data.uniformIncrement + 1};
textureTransformationData[0*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & VectorGL3D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.0f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation({0.5f, 0.5f})*
Matrix3::rotation(180.0_degf)*
Matrix3::translation({-0.5f, -0.5f})
);
Matrix3::translation({-0.5f, -0.5f}))
.setLayer(0); /* ignored if not array */
textureTransformationData[1*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & VectorGL3D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.5f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{})*
Matrix3::translation(Vector2::xAxis(1.0f))*
Matrix3::scaling(Vector2::xScale(-1.0f))
);
Matrix3::scaling(Vector2::xScale(-1.0f)))
.setLayer(2); /* ignored if not array */
textureTransformationData[2*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(Matrix3{});
.setTextureMatrix(
/* Additional Y shift + scale in the array slice */
(data.flags & VectorGL3D::Flag::TextureArrays ?
Matrix3::translation(Vector2::yAxis(0.25f))*
Matrix3::scaling(Vector2::yScale(0.5f)) : Matrix3{}))
.setLayer(1); /* ignored if not array */
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<VectorDrawUniform> drawData{2*data.uniformIncrement + 1};
@ -1595,12 +2018,6 @@ void VectorGLTest::renderMulti3D() {
.setMaterialId(data.bindWithOffset ? 0 : 1);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL3D shader{VectorGL3D::Configuration{}
.setFlags(VectorGL3D::Flag::UniformBuffers|VectorGL3D::Flag::TextureTransformation|data.flags)
.setMaterialCount(data.materialCount)
.setDrawCount(data.drawCount)};
shader.bindVectorTexture(vector);
/* Rebinding UBOs / SSBOs each time */
if(data.bindWithOffset) {
shader.bindMaterialBuffer(materialUniform,

4
src/Magnum/Shaders/Test/VectorGL_Test.cpp

@ -92,8 +92,8 @@ void VectorGL_Test::debugFlag() {
void VectorGL_Test::debugFlags() {
Containers::String out;
Debug{&out} << VectorGL3D::Flags{VectorGL3D::Flag::TextureTransformation|VectorGL3D::Flag(0xf0)} << VectorGL3D::Flags{};
CORRADE_COMPARE(out, "Shaders::VectorGL::Flag::TextureTransformation|Shaders::VectorGL::Flag(0xf0) Shaders::VectorGL::Flags{}\n");
Debug{&out} << VectorGL3D::Flags{VectorGL3D::Flag::TextureTransformation|VectorGL3D::Flag(0x80)} << VectorGL3D::Flags{};
CORRADE_COMPARE(out, "Shaders::VectorGL::Flag::TextureTransformation|Shaders::VectorGL::Flag(0x80) Shaders::VectorGL::Flags{}\n");
}
#ifndef MAGNUM_TARGET_GLES2

20
src/Magnum/Shaders/Vector.frag

@ -42,12 +42,12 @@
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
layout(location = 3)
#endif
uniform lowp vec4 backgroundColor; /* defaults to zero */
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 3)
layout(location = 4)
#endif
uniform lowp vec4 color
#ifndef GL_ES
@ -120,11 +120,23 @@ layout(std140
#ifdef EXPLICIT_BINDING
layout(binding = 6)
#endif
uniform lowp sampler2D vectorTexture;
uniform lowp
#ifndef TEXTURE_ARRAYS
sampler2D
#else
sampler2DArray
#endif
vectorTexture;
/* Inputs */
in mediump vec2 interpolatedTextureCoordinates;
in mediump
#ifndef TEXTURE_ARRAYS
vec2
#else
vec3
#endif
interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat in highp uint drawId;

49
src/Magnum/Shaders/Vector.vert

@ -24,6 +24,10 @@
DEALINGS IN THE SOFTWARE.
*/
#if defined(UNIFORM_BUFFERS) && defined(TEXTURE_ARRAYS) && !defined(GL_ES)
#extension GL_ARB_shader_bit_encoding: require
#endif
#if defined(SHADER_STORAGE_BUFFERS) && !defined(GL_ES)
#extension GL_ARB_shader_storage_buffer_object: require
#endif
@ -78,6 +82,14 @@ uniform mediump mat3 textureMatrix
;
#endif
#ifdef TEXTURE_ARRAYS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
#endif
/* mediump is just 2^10, which might not be enough, this is 2^16 */
uniform highp uint textureLayer; /* defaults to zero */
#endif
/* Uniform / shader storage buffers */
#else
@ -127,8 +139,9 @@ layout(std140
#ifdef TEXTURE_TRANSFORMATION
struct TextureTransformationUniform {
highp vec4 rotationScaling;
highp vec4 offsetReservedReserved;
#define textureTransformation_offset offsetReservedReserved.xy
highp vec4 offsetLayerReserved;
#define textureTransformation_offset offsetLayerReserved.xy
#define textureTransformation_layer offsetLayerReserved.z
};
layout(std140
@ -157,11 +170,23 @@ in highp vec4 position;
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = TEXTURECOORDINATES_ATTRIBUTE_LOCATION)
#endif
in mediump vec2 textureCoordinates;
in mediump
#ifndef TEXTURE_ARRAYS
vec2
#else
vec3
#endif
textureCoordinates;
/* Outputs */
out mediump vec2 interpolatedTextureCoordinates;
out mediump
#ifndef TEXTURE_ARRAYS
vec2
#else
vec3
#endif
interpolatedTextureCoordinates;
#ifdef MULTI_DRAW
flat out highp uint drawId;
@ -190,6 +215,9 @@ void main() {
#endif
#ifdef TEXTURE_TRANSFORMATION
mediump const mat3 textureMatrix = mat3(textureTransformations[drawId].rotationScaling.xy, 0.0, textureTransformations[drawId].rotationScaling.zw, 0.0, textureTransformations[drawId].textureTransformation_offset, 1.0);
#ifdef TEXTURE_ARRAYS
highp const uint textureLayer = floatBitsToUint(textureTransformations[drawId].textureTransformation_layer);
#endif
#endif
#endif
@ -201,11 +229,18 @@ void main() {
#error
#endif
interpolatedTextureCoordinates =
interpolatedTextureCoordinates.xy =
#ifdef TEXTURE_TRANSFORMATION
(textureMatrix*vec3(textureCoordinates, 1.0)).xy
(textureMatrix*vec3(textureCoordinates.xy, 1.0)).xy
#else
textureCoordinates
textureCoordinates.xy
#endif
;
#ifdef TEXTURE_ARRAYS
interpolatedTextureCoordinates.z = textureCoordinates.z
#if !defined(UNIFORM_BUFFERS) || defined(TEXTURE_TRANSFORMATION)
+ float(textureLayer)
#endif
;
#endif
}

49
src/Magnum/Shaders/VectorGL.cpp

@ -45,6 +45,7 @@
#include <Corrade/Utility/Format.h>
#include "Magnum/GL/Buffer.h"
#include "Magnum/GL/TextureArray.h"
#endif
#ifdef MAGNUM_BUILD_STATIC
@ -110,6 +111,10 @@ template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState Vec
#endif
}
#endif
#ifndef MAGNUM_TARGET_GLES
if(configuration.flags() >= Flag::TextureArrays)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::EXT::texture_array);
#endif
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
@ -133,6 +138,9 @@ template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState Vec
GL::Shader vert{version, GL::Shader::Type::Vertex};
vert.addSource(rs.getString("compatibility.glsl"_s))
.addSource(configuration.flags() & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n"_s : ""_s)
#ifndef MAGNUM_TARGET_GLES2
.addSource(configuration.flags() & Flag::TextureArrays ? "#define TEXTURE_ARRAYS\n"_s : ""_s)
#endif
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n"_s : "#define THREE_DIMENSIONS\n"_s);
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
@ -159,7 +167,11 @@ template<UnsignedInt dimensions> typename VectorGL<dimensions>::CompileState Vec
.submitCompile();
GL::Shader frag{version, GL::Shader::Type::Fragment};
frag.addSource(rs.getString("compatibility.glsl"_s));
frag.addSource(rs.getString("compatibility.glsl"_s))
#ifndef MAGNUM_TARGET_GLES2
.addSource(configuration.flags() & Flag::TextureArrays ? "#define TEXTURE_ARRAYS\n"_s : ""_s)
#endif
;
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
#ifndef MAGNUM_TARGET_WEBGL
@ -260,6 +272,10 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(CompileState&& s
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix"_s);
if(_flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix"_s);
#ifndef MAGNUM_TARGET_GLES2
if(_flags & Flag::TextureArrays)
_textureLayerUniform = uniformLocation("textureLayer"_s);
#endif
_backgroundColorUniform = uniformLocation("backgroundColor"_s);
_colorUniform = uniformLocation("color"_s);
}
@ -299,6 +315,7 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(CompileState&& s
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(_flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
/* Texture layer is zero by default */
/* Background color is zero by default */
setColor(Color4{1.0f});
}
@ -341,6 +358,17 @@ template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::set
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setTextureLayer(UnsignedInt id) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::VectorGL::setTextureLayer(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureArrays,
"Shaders::VectorGL::setTextureLayer(): the shader was not created with texture arrays enabled", *this);
setUniform(_textureLayerUniform, id);
return *this;
}
#endif
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setBackgroundColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
@ -472,10 +500,25 @@ template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bin
#endif
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindVectorTexture(GL::Texture2D& texture) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags & Flag::TextureArrays),
"Shaders::VectorGL::bindVectorTexture(): the shader was created with texture arrays enabled, use a Texture2DArray instead", *this);
#endif
texture.bind(TextureUnit);
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindVectorTexture(GL::Texture2DArray& texture) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(_flags & Flag::TextureArrays,
"Shaders::VectorGL::bindVectorTexture(): the shader was not created with texture arrays enabled, use a Texture2D instead", *this);
#endif
texture.bind(TextureUnit);
return *this;
}
#endif
template class MAGNUM_SHADERS_EXPORT VectorGL<2>;
template class MAGNUM_SHADERS_EXPORT VectorGL<3>;
@ -502,6 +545,7 @@ Debug& operator<<(Debug& debug, const VectorGLFlag value) {
_c(ShaderStorageBuffers)
#endif
_c(MultiDraw)
_c(TextureArrays)
#endif
#undef _c
/* LCOV_EXCL_STOP */
@ -524,7 +568,8 @@ Debug& operator<<(Debug& debug, const VectorGLFlags value) {
#ifndef MAGNUM_TARGET_WEBGL
VectorGLFlag::ShaderStorageBuffers, /* Superset of UniformBuffers */
#endif
VectorGLFlag::UniformBuffers
VectorGLFlag::UniformBuffers,
VectorGLFlag::TextureArrays
#endif
});
}

100
src/Magnum/Shaders/VectorGL.h

@ -50,7 +50,8 @@ namespace Implementation {
#ifndef MAGNUM_TARGET_WEBGL
ShaderStorageBuffers = UniformBuffers|(1 << 3),
#endif
MultiDraw = UniformBuffers|(1 << 2)
MultiDraw = UniformBuffers|(1 << 2),
TextureArrays = 1 << 4
#endif
};
typedef Containers::EnumSet<VectorGLFlag> VectorGLFlags;
@ -87,6 +88,12 @@ Common rendering setup:
@snippet Shaders-gl.cpp VectorGL-usage2
If @ref Flag::TextureArrays is enabled, pass a @ref GL::Texture2DArray instance
instead of @ref GL::Texture2D. The layer is taken from the third coordinate of
@ref TextureArrayCoordinates, if used instead of @ref TextureCoordinates,
otherwise layer @cpp 0 @ce is picked. Additionally, the value of
@ref setTextureLayer(), which is @cpp 0 @ce by default, is added to the layer.
@section Shaders-VectorGL-ubo Uniform buffers
See @ref shaders-usage-ubo for a high-level overview that applies to all
@ -142,10 +149,26 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @brief 2D texture coordinates
*
* @ref shaders-generic "Generic attribute",
* @relativeref{Magnum,Vector2}.
* @relativeref{Magnum,Vector2}. Use either this or the
* @ref TextureArrayCoordinates attribute.
*/
typedef typename GenericGL<dimensions>::TextureCoordinates TextureCoordinates;
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief 2D array texture coordinates
*
* @ref shaders-generic "Generic attribute",
* @relativeref{Magnum,Vector3}. Use either this or the
* @ref TextureCoordinates attribute. The third component is used only
* if @ref Flag::TextureArrays is set.
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES 2.0.
* @requires_webgl20 Texture arrays are not available in WebGL 1.0.
*/
typedef typename GenericGL<dimensions>::TextureArrayCoordinates TextureArrayCoordinates;
#endif
enum: UnsignedInt {
/**
* Color shader output. @ref shaders-generic "Generic output",
@ -227,7 +250,27 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* relies on uniform buffers, which require WebGL 2.0.
* @m_since_latest
*/
MultiDraw = UniformBuffers|(1 << 2)
MultiDraw = UniformBuffers|(1 << 2),
/**
* Use 2D texture arrays. Expects that the texture is supplied via
* @ref bindVectorTexture(GL::Texture2DArray&) instead of
* @ref bindVectorTexture(GL::Texture2D&). The layer is taken from
* the third coordinate of @ref TextureArrayCoordinates, if used
* instead of @ref TextureCoordinates, otherwise layer @cpp 0 @ce
* is picked. Additionally, if @ref Flag::UniformBuffers is not
* enabled, the value of @ref setTextureLayer() is added to the
* layer; if @ref Flag::UniformBuffers is enabled and
* @ref Flag::TextureTransformation is enabled as well, the value
* of @ref TextureTransformationUniform::layer is added to the
* layer.
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Texture arrays are not available in WebGL 1.0.
* @m_since_latest
*/
TextureArrays = 1 << 4,
#endif
};
@ -421,6 +464,28 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
*/
VectorGL<dimensions>& setTextureMatrix(const Matrix3& matrix);
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Set texture array layer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with @ref Flag::TextureArrays
* enabled. Initial value is @cpp 0 @ce. If a three-component
* @ref TextureArrayCoordinates attribute is used instead of
* @ref TextureCoordinates, this value is added to the layer coming
* from the third component.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TextureTransformationUniform::layer and call
* @ref bindTextureTransformationBuffer() instead.
* @requires_gl30 Extension @gl_extension{EXT,texture_array}
* @requires_gles30 Texture arrays are not available in OpenGL ES 2.0.
* @requires_webgl20 Texture arrays are not available in WebGL 1.0.
*/
VectorGL<dimensions>& setTextureLayer(UnsignedInt layer);
#endif
/**
* @brief Set background color
* @return Reference to self (for method chaining)
@ -579,10 +644,32 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @brief Bind a vector texture
* @return Reference to self (for method chaining)
*
* If @ref Flag::TextureArrays is enabled, use
* @ref bindVectorTexture(GL::Texture2DArray&) instead.
* @see @ref Flag::TextureTransformation, @ref setTextureMatrix()
*/
VectorGL<dimensions>& bindVectorTexture(GL::Texture2D& texture);
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Bind a vector array texture
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with @ref Flag::TextureArrays
* enabled. The layer is taken from the third coordinate of
* @ref TextureArrayCoordinates, if used instead of
* @ref TextureCoordinates, otherwise layer @cpp 0 @ce is picked.
* Additionally, if @ref Flag::UniformBuffers is not enabled, the layer
* index is offset with the value set in @ref setTextureLayer(); if
* @ref Flag::UniformBuffers is enabled and
* @ref Flag::TextureTransformation is enabled as well, the layer index
* is offset with @ref TextureTransformationUniform::layer.
* @see @ref Flag::TextureTransformation, @ref setTextureMatrix()
*/
VectorGL<dimensions>& bindVectorTexture(GL::Texture2DArray& texture);
#endif
/**
* @}
*/
@ -600,8 +687,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
#endif
Int _transformationProjectionMatrixUniform{0},
_textureMatrixUniform{1},
_backgroundColorUniform{2},
_colorUniform{3};
#ifndef MAGNUM_TARGET_GLES2
_textureLayerUniform{2},
#endif
_backgroundColorUniform{3},
_colorUniform{4};
#ifndef MAGNUM_TARGET_GLES2
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */

Loading…
Cancel
Save