Browse Source

Shaders: implement texture coordinate transformation for all shaders.

Except MeshVisualizer and VertexColor, which don't have any texturing,
so there it's not needed. In most cases the tests are reusing existing
ground truth files and only modifying transformations / flipping images.
pull/430/head
Vladimír Vondruš 6 years ago
parent
commit
9a06b3515b
  1. 5
      doc/changelog.dox
  2. 5
      src/Magnum/Shaders/AbstractVector.h
  3. 19
      src/Magnum/Shaders/AbstractVector2D.vert
  4. 19
      src/Magnum/Shaders/AbstractVector3D.vert
  5. 6
      src/Magnum/Shaders/CMakeLists.txt
  6. 40
      src/Magnum/Shaders/DistanceFieldVector.cpp
  7. 8
      src/Magnum/Shaders/DistanceFieldVector.frag
  8. 84
      src/Magnum/Shaders/DistanceFieldVector.h
  9. 16
      src/Magnum/Shaders/Flat.cpp
  10. 6
      src/Magnum/Shaders/Flat.frag
  11. 34
      src/Magnum/Shaders/Flat.h
  12. 19
      src/Magnum/Shaders/Flat2D.vert
  13. 19
      src/Magnum/Shaders/Flat3D.vert
  14. 17
      src/Magnum/Shaders/Phong.cpp
  15. 25
      src/Magnum/Shaders/Phong.h
  16. 19
      src/Magnum/Shaders/Phong.vert
  17. 127
      src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp
  18. 24
      src/Magnum/Shaders/Test/DistanceFieldVectorTest.cpp
  19. 113
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  20. 44
      src/Magnum/Shaders/Test/PhongGLTest.cpp
  21. BIN
      src/Magnum/Shaders/Test/PhongTestFiles/textured-diffuse-transformed.tga
  22. 148
      src/Magnum/Shaders/Test/VectorGLTest.cpp
  23. 24
      src/Magnum/Shaders/Test/VectorTest.cpp
  24. 40
      src/Magnum/Shaders/Vector.cpp
  25. 4
      src/Magnum/Shaders/Vector.frag
  26. 80
      src/Magnum/Shaders/Vector.h

5
doc/changelog.dox

@ -180,6 +180,11 @@ See also:
and @ref SceneGraph::AbstractBasicTranslationRotation3D::rotateLocal(const Math::Quaternion<T>&) "rotateLocal()"
overloads taking a @ref Math::Quaternion
@subsubsection changelog-latest-new-shaders Shaders library
- Texture coordinate transformation in @ref Shaders::DistanceFieldVector,
@ref Shaders::Flat, @ref Shaders::Phong and @ref Shaders::Vector
@subsubsection changelog-latest-new-trade Trade library
- A new, redesigned @ref Trade::MeshData class that allows much more flexible

5
src/Magnum/Shaders/AbstractVector.h

@ -83,6 +83,11 @@ template<UnsignedInt dimensions> class AbstractVector: public GL::AbstractShader
/**
* @brief Bind vector texture
* @return Reference to self (for method chaining)
*
* @see @ref DistanceFieldVector::Flag::TextureTransformation,
* @ref Vector::Flag::TextureTransformation,
* @ref DistanceFieldVector::setTextureMatrix(),
* @ref Vector::setTextureMatrix()
*/
AbstractVector<dimensions>& bindVectorTexture(GL::Texture2D& texture);

19
src/Magnum/Shaders/AbstractVector2D.vert

@ -37,6 +37,17 @@ uniform highp mat3 transformationProjectionMatrix
#endif
;
#ifdef TEXTURE_TRANSFORMATION
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
uniform mediump mat3 textureMatrix
#ifndef GL_ES
= mat3(1.0)
#endif
;
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = POSITION_ATTRIBUTE_LOCATION)
#endif
@ -51,5 +62,11 @@ out mediump vec2 interpolatedTextureCoordinates;
void main() {
gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0);
interpolatedTextureCoordinates = textureCoordinates;
interpolatedTextureCoordinates =
#ifdef TEXTURE_TRANSFORMATION
(textureMatrix*vec3(textureCoordinates, 1.0)).xy
#else
textureCoordinates
#endif
;
}

19
src/Magnum/Shaders/AbstractVector3D.vert

@ -37,6 +37,17 @@ uniform highp mat4 transformationProjectionMatrix
#endif
;
#ifdef TEXTURE_TRANSFORMATION
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
uniform mediump mat3 textureMatrix
#ifndef GL_ES
= mat3(1.0)
#endif
;
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = POSITION_ATTRIBUTE_LOCATION)
#endif
@ -51,5 +62,11 @@ out mediump vec2 interpolatedTextureCoordinates;
void main() {
gl_Position = transformationProjectionMatrix*position;
interpolatedTextureCoordinates = textureCoordinates;
interpolatedTextureCoordinates =
#ifdef TEXTURE_TRANSFORMATION
(textureMatrix*vec3(textureCoordinates, 1.0)).xy
#else
textureCoordinates
#endif
;
}

6
src/Magnum/Shaders/CMakeLists.txt

@ -32,16 +32,16 @@ set_target_properties(MagnumShaders_RCS-dependencies PROPERTIES FOLDER "Magnum/S
set(MagnumShaders_SRCS
AbstractVector.cpp
DistanceFieldVector.cpp
Vector.cpp
VertexColor.cpp
${MagnumShaders_RCS})
set(MagnumShaders_GracefulAssert_SRCS
DistanceFieldVector.cpp
Flat.cpp
MeshVisualizer.cpp
Phong.cpp)
Phong.cpp
Vector.cpp)
set(MagnumShaders_HEADERS
DistanceFieldVector.h

40
src/Magnum/Shaders/DistanceFieldVector.cpp

@ -25,6 +25,7 @@
#include "DistanceFieldVector.h"
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Reference.h>
#include <Corrade/Utility/Resource.h>
@ -45,7 +46,7 @@ namespace {
template<> constexpr const char* vertexShaderName<3>() { return "AbstractVector3D.vert"; }
}
template<UnsignedInt dimensions> DistanceFieldVector<dimensions>::DistanceFieldVector() {
template<UnsignedInt dimensions> DistanceFieldVector<dimensions>::DistanceFieldVector(const Flags flags): _flags{flags} {
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShaders"))
@ -62,7 +63,8 @@ template<UnsignedInt dimensions> DistanceFieldVector<dimensions>::DistanceFieldV
GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex);
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
vert.addSource(rs.get("generic.glsl"))
vert.addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "")
.addSource(rs.get("generic.glsl"))
.addSource(rs.get(vertexShaderName<dimensions>()));
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("DistanceFieldVector.frag"));
@ -89,6 +91,8 @@ template<UnsignedInt dimensions> DistanceFieldVector<dimensions>::DistanceFieldV
#endif
{
_transformationProjectionMatrixUniform = GL::AbstractShaderProgram::uniformLocation("transformationProjectionMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = GL::AbstractShaderProgram::uniformLocation("textureMatrix");
_colorUniform = GL::AbstractShaderProgram::uniformLocation("color");
_outlineColorUniform = GL::AbstractShaderProgram::uniformLocation("outlineColor");
_outlineRangeUniform = GL::AbstractShaderProgram::uniformLocation("outlineRange");
@ -106,6 +110,7 @@ template<UnsignedInt dimensions> DistanceFieldVector<dimensions>::DistanceFieldV
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix({});
if(flags & Flag::TextureTransformation) setTextureMatrix({});
setColor(Color4{1.0f}); /* Outline color is zero by default */
setOutlineRange(0.5f, 1.0f);
setSmoothness(0.04f);
@ -117,6 +122,13 @@ template<UnsignedInt dimensions> DistanceFieldVector<dimensions>& DistanceFieldV
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVector<dimensions>& DistanceFieldVector<dimensions>::setTextureMatrix(const Matrix3& matrix) {
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVector::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
GL::AbstractShaderProgram::setUniform(_textureMatrixUniform, matrix);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVector<dimensions>& DistanceFieldVector<dimensions>::setColor(const Color4& color) {
GL::AbstractShaderProgram::setUniform(_colorUniform, color);
return *this;
@ -140,4 +152,28 @@ template<UnsignedInt dimensions> DistanceFieldVector<dimensions>& DistanceFieldV
template class DistanceFieldVector<2>;
template class DistanceFieldVector<3>;
namespace Implementation {
Debug& operator<<(Debug& debug, const DistanceFieldVectorFlag value) {
debug << "Shaders::DistanceFieldVector::Flag" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case DistanceFieldVectorFlag::v: return debug << "::" #v;
_c(TextureTransformation)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const DistanceFieldVectorFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::DistanceFieldVector::Flags{}", {
DistanceFieldVectorFlag::TextureTransformation
});
}
}
}}

8
src/Magnum/Shaders/DistanceFieldVector.frag

@ -30,7 +30,7 @@
#endif
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
layout(location = 2)
#endif
uniform lowp vec4 color
#ifndef GL_ES
@ -39,12 +39,12 @@ uniform lowp vec4 color
;
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
layout(location = 3)
#endif
uniform lowp vec4 outlineColor; /* defaults to zero */
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 3)
layout(location = 4)
#endif
uniform lowp vec2 outlineRange
#ifndef GL_ES
@ -53,7 +53,7 @@ uniform lowp vec2 outlineRange
;
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 4)
layout(location = 5)
#endif
uniform lowp float smoothness
#ifndef GL_ES

84
src/Magnum/Shaders/DistanceFieldVector.h

@ -35,6 +35,13 @@
namespace Magnum { namespace Shaders {
namespace Implementation {
enum class DistanceFieldVectorFlag: UnsignedByte {
TextureTransformation = 1 << 0
};
typedef Containers::EnumSet<DistanceFieldVectorFlag> DistanceFieldVectorFlags;
}
/**
@brief Distance field vector shader
@ -67,7 +74,41 @@ Common rendering setup:
*/
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector: public AbstractVector<dimensions> {
public:
explicit DistanceFieldVector();
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Flag
* @m_since_latest
*
* @see @ref Flags, @ref flags()
*/
enum class Flag: UnsignedByte {
/**
* Enable texture coordinate transformation.
* @see @ref setTextureMatrix()
* @m_since_latest
*/
TextureTransformation = 1 << 0
};
/**
* @brief Flags
* @m_since_latest
*
* @see @ref flags()
*/
typedef Containers::EnumSet<Flag> Flags;
#else
/* Done this way to be prepared for possible future diversion of 2D
and 3D flags (e.g. introducing 3D-specific features) */
typedef Implementation::DistanceFieldVectorFlag Flag;
typedef Implementation::DistanceFieldVectorFlags Flags;
#endif
/**
* @brief Constructor
* @param flags Flags
*/
explicit DistanceFieldVector(Flags flags = {});
/**
* @brief Construct without creating the underlying OpenGL object
@ -100,6 +141,12 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
/** @brief Move assignment */
DistanceFieldVector<dimensions>& operator=(DistanceFieldVector<dimensions>&&) noexcept = default;
/**
* @brief Flags
* @m_since_latest
*/
Flags flags() const { return _flags; }
/**
* @brief Set transformation and projection matrix
* @return Reference to self (for method chaining)
@ -108,6 +155,17 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
*/
DistanceFieldVector<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix);
/**
* @brief Set texture coordinate transformation matrix
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with
* @ref Flag::TextureTransformation enabled. Initial value is an
* identity matrix.
*/
DistanceFieldVector<dimensions>& setTextureMatrix(const Matrix3& matrix);
/**
* @brief Set fill color
* @return Reference to self (for method chaining)
@ -170,11 +228,13 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
using GL::AbstractShaderProgram::dispatchCompute;
#endif
Flags _flags;
Int _transformationProjectionMatrixUniform{0},
_colorUniform{1},
_outlineColorUniform{2},
_outlineRangeUniform{3},
_smoothnessUniform{4};
_textureMatrixUniform{1},
_colorUniform{2},
_outlineColorUniform{3},
_outlineRangeUniform{4},
_smoothnessUniform{5};
};
/** @brief Two-dimensional distance field vector shader */
@ -183,6 +243,20 @@ typedef DistanceFieldVector<2> DistanceFieldVector2D;
/** @brief Three-dimensional distance field vector shader */
typedef DistanceFieldVector<3> DistanceFieldVector3D;
#ifdef DOXYGEN_GENERATING_OUTPUT
/** @debugoperatorclassenum{DistanceFieldVector,DistanceFieldVector::Flag} */
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, DistanceFieldVector<dimensions>::Flag value);
/** @debugoperatorclassenum{DistanceFieldVector,DistanceFieldVector::Flags} */
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, DistanceFieldVector<dimensions>::Flags value);
#else
namespace Implementation {
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, DistanceFieldVectorFlag value);
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, DistanceFieldVectorFlags value);
CORRADE_ENUMSET_OPERATORS(DistanceFieldVectorFlags)
}
#endif
}}
#endif

16
src/Magnum/Shaders/Flat.cpp

@ -50,6 +50,9 @@ namespace {
}
template<UnsignedInt dimensions> Flat<dimensions>::Flat(const Flags flags): _flags(flags) {
CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & Flag::Textured),
"Shaders::Flat: texture transformation enabled but the shader is not textured", );
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShaders"))
@ -68,6 +71,7 @@ template<UnsignedInt dimensions> Flat<dimensions>::Flat(const Flags flags): _fla
vert.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "")
.addSource(flags & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "")
.addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "")
.addSource(rs.get("generic.glsl"))
.addSource(rs.get(vertexShaderName<dimensions>()));
frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "")
@ -111,6 +115,8 @@ template<UnsignedInt dimensions> Flat<dimensions>::Flat(const Flags flags): _fla
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_colorUniform = uniformLocation("color");
if(flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask");
#ifndef MAGNUM_TARGET_GLES2
@ -128,6 +134,7 @@ template<UnsignedInt dimensions> Flat<dimensions>::Flat(const Flags flags): _fla
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix({});
if(flags & Flag::TextureTransformation) setTextureMatrix({});
setColor(Magnum::Color4{1.0f});
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
@ -139,6 +146,13 @@ template<UnsignedInt dimensions> Flat<dimensions>& Flat<dimensions>::setTransfor
return *this;
}
template<UnsignedInt dimensions> Flat<dimensions>& Flat<dimensions>::setTextureMatrix(const Matrix3& matrix) {
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::Flat::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
setUniform(_textureMatrixUniform, matrix);
return *this;
}
template<UnsignedInt dimensions> Flat<dimensions>& Flat<dimensions>::setColor(const Magnum::Color4& color) {
setUniform(_colorUniform, color);
return *this;
@ -181,6 +195,7 @@ Debug& operator<<(Debug& debug, const FlatFlag value) {
_c(Textured)
_c(AlphaMask)
_c(VertexColor)
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(ObjectId)
#endif
@ -196,6 +211,7 @@ Debug& operator<<(Debug& debug, const FlatFlags value) {
FlatFlag::Textured,
FlatFlag::AlphaMask,
FlatFlag::VertexColor,
FlatFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
FlatFlag::ObjectId
#endif

6
src/Magnum/Shaders/Flat.frag

@ -37,7 +37,7 @@ uniform lowp sampler2D textureData;
#endif
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
layout(location = 2)
#endif
uniform lowp vec4 color
#ifndef GL_ES
@ -47,7 +47,7 @@ uniform lowp vec4 color
#ifdef ALPHA_MASK
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
layout(location = 3)
#endif
uniform lowp float alphaMask
#ifndef GL_ES
@ -58,7 +58,7 @@ uniform lowp float alphaMask
#ifdef OBJECT_ID
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 3)
layout(location = 4)
#endif
/* mediump is just 2^10, which might not be enough, this is 2^16 */
uniform highp uint objectId; /* defaults to zero */

34
src/Magnum/Shaders/Flat.h

@ -41,8 +41,9 @@ namespace Implementation {
Textured = 1 << 0,
AlphaMask = 1 << 1,
VertexColor = 1 << 2,
TextureTransformation = 1 << 3,
#ifndef MAGNUM_TARGET_GLES2
ObjectId = 1 << 3
ObjectId = 1 << 4
#endif
};
typedef Containers::EnumSet<FlatFlag> FlatFlags;
@ -216,6 +217,14 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab
*/
VertexColor = 1 << 2,
/**
* Enable texture coordinate transformation. If this flag is set,
* the shader expects that @ref Flag::Textured is enabled as well.
* @see @ref setTextureMatrix()
* @m_since_latest
*/
TextureTransformation = 1 << 3,
#ifndef MAGNUM_TARGET_GLES2
/**
* Enable object ID output. See @ref Shaders-Flat-usage-object-id
@ -225,7 +234,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab
* WebGL 1.0.
* @m_since{2019,10}
*/
ObjectId = 1 << 3
ObjectId = 1 << 4
#endif
};
@ -285,6 +294,17 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab
*/
Flat<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix);
/**
* @brief Set texture coordinate transformation matrix
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with
* @ref Flag::TextureTransformation enabled. Initial value is an
* identity matrix.
*/
Flat<dimensions>& setTextureMatrix(const Matrix3& matrix);
/**
* @brief Set color
* @return Reference to self (for method chaining)
@ -302,7 +322,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab
*
* Expects that the shader was created with @ref Flag::Textured
* enabled.
* @see @ref setColor()
* @see @ref setColor(), @ref Flag::TextureTransformation,
* @ref setTextureMatrix()
*/
Flat<dimensions>& bindTexture(GL::Texture2D& texture);
@ -344,10 +365,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Flat: public GL::Ab
Flags _flags;
Int _transformationProjectionMatrixUniform{0},
_colorUniform{1},
_alphaMaskUniform{2};
_textureMatrixUniform{1},
_colorUniform{2},
_alphaMaskUniform{3};
#ifndef MAGNUM_TARGET_GLES2
Int _objectIdUniform{3};
Int _objectIdUniform{4};
#endif
};

19
src/Magnum/Shaders/Flat2D.vert

@ -37,6 +37,17 @@ uniform highp mat3 transformationProjectionMatrix
#endif
;
#ifdef TEXTURE_TRANSFORMATION
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
uniform mediump mat3 textureMatrix
#ifndef GL_ES
= mat3(1.0)
#endif
;
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = POSITION_ATTRIBUTE_LOCATION)
#endif
@ -65,7 +76,13 @@ void main() {
#ifdef TEXTURED
/* Texture coordinates, if needed */
interpolatedTextureCoordinates = textureCoordinates;
interpolatedTextureCoordinates =
#ifdef TEXTURE_TRANSFORMATION
(textureMatrix*vec3(textureCoordinates, 1.0)).xy
#else
textureCoordinates
#endif
;
#endif
#ifdef VERTEX_COLOR

19
src/Magnum/Shaders/Flat3D.vert

@ -37,6 +37,17 @@ uniform highp mat4 transformationProjectionMatrix
#endif
;
#ifdef TEXTURE_TRANSFORMATION
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
#endif
uniform mediump mat3 textureMatrix
#ifndef GL_ES
= mat3(1.0)
#endif
;
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = POSITION_ATTRIBUTE_LOCATION)
#endif
@ -65,7 +76,13 @@ void main() {
#ifdef TEXTURED
/* Texture coordinates, if needed */
interpolatedTextureCoordinates = textureCoordinates;
interpolatedTextureCoordinates =
#ifdef TEXTURE_TRANSFORMATION
(textureMatrix*vec3(textureCoordinates, 1.0)).xy
#else
textureCoordinates
#endif
;
#endif
#ifdef VERTEX_COLOR

17
src/Magnum/Shaders/Phong.cpp

@ -38,6 +38,7 @@
#include "Magnum/GL/Shader.h"
#include "Magnum/GL/Texture.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
@ -54,6 +55,9 @@ namespace {
}
Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _lightCount{lightCount}, _lightColorsUniform{_lightPositionsUniform + Int(lightCount)} {
CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture)),
"Shaders::Phong: texture transformation enabled but the shader is not textured", );
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShaders"))
@ -95,6 +99,7 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
vert.addSource(flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture) ? "#define TEXTURED\n" : "")
.addSource(flags & Flag::NormalTexture ? "#define NORMAL_TEXTURE\n" : "")
.addSource(flags & Flag::VertexColor ? "#define VERTEX_COLOR\n" : "")
.addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "")
.addSource(Utility::formatString("#define LIGHT_COUNT {}\n", lightCount))
.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Phong.vert"));
@ -152,6 +157,8 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
#endif
{
_transformationMatrixUniform = uniformLocation("transformationMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_projectionMatrixUniform = uniformLocation("projectionMatrix");
_ambientColorUniform = uniformLocation("ambientColor");
if(lightCount) {
@ -195,6 +202,7 @@ Phong::Phong(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _l
/* Light position is zero by default */
setNormalMatrix({});
}
if(flags & Flag::TextureTransformation) setTextureMatrix({});
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
#endif
@ -286,6 +294,13 @@ Phong& Phong::setProjectionMatrix(const Matrix4& matrix) {
return *this;
}
Phong& Phong::setTextureMatrix(const Matrix3& matrix) {
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::Phong::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
setUniform(_textureMatrixUniform, matrix);
return *this;
}
Phong& Phong::setLightPositions(const Containers::ArrayView<const Vector3> positions) {
CORRADE_ASSERT(_lightCount == positions.size(),
"Shaders::Phong::setLightPositions(): expected" << _lightCount << "items but got" << positions.size(), *this);
@ -338,6 +353,7 @@ Debug& operator<<(Debug& debug, const Phong::Flag value) {
_c(NormalTexture)
_c(AlphaMask)
_c(VertexColor)
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(ObjectId)
#endif
@ -356,6 +372,7 @@ Debug& operator<<(Debug& debug, const Phong::Flags value) {
Phong::Flag::NormalTexture,
Phong::Flag::AlphaMask,
Phong::Flag::VertexColor,
Phong::Flag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
Phong::Flag::ObjectId
#endif

25
src/Magnum/Shaders/Phong.h

@ -251,6 +251,17 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
*/
VertexColor = 1 << 5,
/**
* Enable texture coordinate transformation. If this flag is set,
* the shader expects that at least one of
* @ref Flag::AmbientTexture, @ref Flag::DiffuseTexture,
* @ref Flag::SpecularTexture or @ref Flag::NormalTexture is
* enabled as well.
* @see @ref setTextureMatrix()
* @m_since_latest
*/
TextureTransformation = 1 << 6,
#ifndef MAGNUM_TARGET_GLES2
/**
* Enable object ID output. See @ref Shaders-Phong-usage-object-id
@ -260,7 +271,7 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
* WebGL 1.0.
* @m_since{2019,10}
*/
ObjectId = 1 << 6
ObjectId = 1 << 7
#endif
};
@ -481,6 +492,17 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
*/
Phong& setProjectionMatrix(const Matrix4& matrix);
/**
* @brief Set texture coordinate transformation matrix
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with
* @ref Flag::TextureTransformation enabled. Initial value is an
* identity matrix.
*/
Phong& setTextureMatrix(const Matrix3& matrix);
/**
* @brief Set light positions
* @return Reference to self (for method chaining)
@ -567,6 +589,7 @@ class MAGNUM_SHADERS_EXPORT Phong: public GL::AbstractShaderProgram {
Int _transformationMatrixUniform{0},
_projectionMatrixUniform{1},
_normalMatrixUniform{2},
_textureMatrixUniform{3},
_ambientColorUniform{4},
_diffuseColorUniform{5},
_specularColorUniform{6},

19
src/Magnum/Shaders/Phong.vert

@ -57,6 +57,17 @@ uniform mediump mat3 normalMatrix
;
#endif
#ifdef TEXTURE_TRANSFORMATION
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 3)
#endif
uniform mediump mat3 textureMatrix
#ifndef GL_ES
= mat3(1.0)
#endif
;
#endif
#if LIGHT_COUNT
/* Needs to be last because it uses locations 10 to 10 + LIGHT_COUNT - 1 */
#ifdef EXPLICIT_UNIFORM_LOCATION
@ -136,7 +147,13 @@ void main() {
#ifdef TEXTURED
/* Texture coordinates, if needed */
interpolatedTextureCoordinates = textureCoordinates;
interpolatedTextureCoordinates =
#ifdef TEXTURE_TRANSFORMATION
(textureMatrix*vec3(textureCoordinates, 1.0)).xy
#else
textureCoordinates
#endif
;
#endif
#ifdef VERTEX_COLOR

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

@ -23,10 +23,12 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Image.h"
#include "Magnum/ImageView.h"
@ -60,6 +62,8 @@ struct DistanceFieldVectorGLTest: GL::OpenGLTester {
template<UnsignedInt dimensions> void construct();
template<UnsignedInt dimensions> void constructMove();
template<UnsignedInt dimensions> void setTextureMatrixNotEnabled();
void renderSetup();
void renderTeardown();
@ -94,21 +98,46 @@ using namespace Math::Literals;
constexpr struct {
const char* name;
DistanceFieldVector2D::Flags flags;
} ConstructData[]{
{"", {}},
{"texture transformation", DistanceFieldVector2D::Flag::TextureTransformation}
};
const struct {
const char* name;
DistanceFieldVector2D::Flags flags;
Matrix3 textureTransformation;
Color4 color, outlineColor;
Float outlineRangeStart, outlineRangeEnd, smoothness;
const char* file2D;
const char* file3D;
bool flip;
} RenderData[] {
{"smooth0.1", 0.5f, 1.0f, 0.1f, "smooth0.1-2D.tga", "smooth0.1-3D.tga"},
{"smooth0.2", 0.5f, 1.0f, 0.2f, "smooth0.2-2D.tga", "smooth0.2-3D.tga"},
{"outline", 0.6f, 0.45f, 0.05f, "outline2D.tga", "outline3D.tga"}
{"texture transformation", DistanceFieldVector2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
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-2D.tga", "smooth0.1-3D.tga", false},
{"smooth0.2", {}, {}, 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}
};
DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() {
addTests<DistanceFieldVectorGLTest>({
addInstancedTests<DistanceFieldVectorGLTest>({
&DistanceFieldVectorGLTest::construct<2>,
&DistanceFieldVectorGLTest::construct<3>,
&DistanceFieldVectorGLTest::construct<3>},
Containers::arraySize(ConstructData));
addTests<DistanceFieldVectorGLTest>({
&DistanceFieldVectorGLTest::constructMove<2>,
&DistanceFieldVectorGLTest::constructMove<3>});
&DistanceFieldVectorGLTest::constructMove<3>,
&DistanceFieldVectorGLTest::setTextureMatrixNotEnabled<2>,
&DistanceFieldVectorGLTest::setTextureMatrixNotEnabled<3>});
addTests({&DistanceFieldVectorGLTest::renderDefaults2D,
&DistanceFieldVectorGLTest::renderDefaults3D},
@ -148,7 +177,11 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() {
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::construct() {
setTestCaseTemplateName(std::to_string(dimensions));
DistanceFieldVector<dimensions> shader;
auto&& data = ConstructData[testCaseInstanceId()];
setTestCaseDescription(data.name);
DistanceFieldVector<dimensions> shader{data.flags};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_VERIFY(shader.id());
{
#ifdef CORRADE_TARGET_APPLE
@ -163,7 +196,7 @@ template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::construct() {
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::constructMove() {
setTestCaseTemplateName(std::to_string(dimensions));
DistanceFieldVector<dimensions> a;
DistanceFieldVector<dimensions> a{DistanceFieldVector<dimensions>::Flag::TextureTransformation};
const GLuint id = a.id();
CORRADE_VERIFY(id);
@ -171,14 +204,29 @@ template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::constructMove()
DistanceFieldVector<dimensions> b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), DistanceFieldVector<dimensions>::Flag::TextureTransformation);
CORRADE_VERIFY(!a.id());
DistanceFieldVector<dimensions> c{NoCreate};
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), DistanceFieldVector<dimensions>::Flag::TextureTransformation);
CORRADE_VERIFY(!b.id());
}
template<UnsignedInt dimensions> void DistanceFieldVectorGLTest::setTextureMatrixNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
std::ostringstream out;
Error redirectError{&out};
DistanceFieldVector<dimensions> shader;
shader.setTextureMatrix({});
CORRADE_COMPARE(out.str(),
"Shaders::DistanceFieldVector::setTextureMatrix(): the shader was not created with texture transformation enabled\n");
}
constexpr Vector2i RenderSize{80, 80};
void DistanceFieldVectorGLTest::renderSetup() {
@ -355,18 +403,30 @@ void DistanceFieldVectorGLTest::render2D() {
.setSubImage(0, {}, *image);
#endif
DistanceFieldVector2D{}
DistanceFieldVector2D shader{data.flags};
shader
/** @todo implement background color */
.setColor(0xffff99_rgbf)
.setOutlineColor(0x9999ff_rgbf)
.setColor(data.color)
.setOutlineColor(data.outlineColor)
.setOutlineRange(data.outlineRangeStart, data.outlineRangeEnd)
.setSmoothness(data.smoothness)
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
.bindVectorTexture(texture)
.draw(square);
.bindVectorTexture(texture);
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
else shader.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f}));
shader.draw(square);
MAGNUM_VERIFY_NO_GL_ERROR();
Image2D rendered = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
/* Dropping the alpha channel, as it's always 1.0 */
Containers::StridedArrayView2D<Color3ub> pixels =
Containers::arrayCast<Color3ub>(rendered.pixels<Color4ub>());
if(data.flip) pixels = pixels.flipped<0>().flipped<1>();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has off-by-one differences when smoothing, Apple A8 a bit
more. */
@ -375,9 +435,7 @@ void DistanceFieldVectorGLTest::render2D() {
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 17.0f, meanThreshold = 2.386f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
CORRADE_COMPARE_WITH(pixels,
Utility::Directory::join({_testDir, "VectorTestFiles", data.file2D}),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
@ -411,22 +469,33 @@ void DistanceFieldVectorGLTest::render3D() {
.setSubImage(0, {}, *image);
#endif
DistanceFieldVector3D{}
DistanceFieldVector3D shader{data.flags};
shader
/** @todo implement background color */
.setColor(0xffff99_rgbf)
.setOutlineColor(0x9999ff_rgbf)
.setColor(data.color)
.setOutlineColor(data.outlineColor)
.setOutlineRange(data.outlineRangeStart, data.outlineRangeEnd)
.setSmoothness(data.smoothness)
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationZ(15.0_degf))
.bindVectorTexture(texture)
.draw(plane);
.bindVectorTexture(texture);
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
else shader.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationZ(15.0_degf));
shader.draw(plane);
MAGNUM_VERIFY_NO_GL_ERROR();
Image2D rendered = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
/* Dropping the alpha channel, as it's always 1.0 */
Containers::StridedArrayView2D<Color3ub> pixels =
Containers::arrayCast<Color3ub>(rendered.pixels<Color4ub>());
if(data.flip) pixels = pixels.flipped<0>().flipped<1>();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has off-by-one differences when smoothing plus a bunch of
different pixels on primitive edges, Apple A8 a bit more. */
@ -435,9 +504,7 @@ void DistanceFieldVectorGLTest::render3D() {
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 17.0f, meanThreshold = 1.613f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
CORRADE_COMPARE_WITH(pixels,
Utility::Directory::join({_testDir, "VectorTestFiles", data.file3D}),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}

24
src/Magnum/Shaders/Test/DistanceFieldVectorTest.cpp

@ -23,7 +23,9 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Shaders/DistanceFieldVector.h"
@ -37,6 +39,9 @@ struct DistanceFieldVectorTest: TestSuite::Tester {
void constructCopy2D();
void constructCopy3D();
void debugFlag();
void debugFlags();
};
DistanceFieldVectorTest::DistanceFieldVectorTest() {
@ -44,7 +49,10 @@ DistanceFieldVectorTest::DistanceFieldVectorTest() {
&DistanceFieldVectorTest::constructNoCreate3D,
&DistanceFieldVectorTest::constructCopy2D,
&DistanceFieldVectorTest::constructCopy3D});
&DistanceFieldVectorTest::constructCopy3D,
&DistanceFieldVectorTest::debugFlag,
&DistanceFieldVectorTest::debugFlags});
}
void DistanceFieldVectorTest::constructNoCreate2D() {
@ -75,6 +83,20 @@ void DistanceFieldVectorTest::constructCopy3D() {
CORRADE_VERIFY(!(std::is_assignable<DistanceFieldVector3D, const DistanceFieldVector3D&>{}));
}
void DistanceFieldVectorTest::debugFlag() {
std::ostringstream out;
Debug{&out} << DistanceFieldVector2D::Flag::TextureTransformation << DistanceFieldVector2D::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVector::Flag::TextureTransformation Shaders::DistanceFieldVector::Flag(0xf0)\n");
}
void DistanceFieldVectorTest::debugFlags() {
std::ostringstream out;
Debug{&out} << DistanceFieldVector3D::Flags{DistanceFieldVector3D::Flag::TextureTransformation|DistanceFieldVector3D::Flag(0xf0)} << DistanceFieldVector3D::Flags{};
CORRADE_COMPARE(out.str(), "Shaders::DistanceFieldVector::Flag::TextureTransformation|Shaders::DistanceFieldVector::Flag(0xf0) Shaders::DistanceFieldVector::Flags{}\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::DistanceFieldVectorTest)

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

@ -62,10 +62,14 @@ struct FlatGLTest: GL::OpenGLTester {
explicit FlatGLTest();
template<UnsignedInt dimensions> void construct();
template<UnsignedInt dimensions> void constructMove();
template<UnsignedInt dimensions> void constructTextureTransformationNotTextured();
template<UnsignedInt dimensions> void bindTextureNotEnabled();
template<UnsignedInt dimensions> void setAlphaMaskNotEnabled();
template<UnsignedInt dimensions> void setTextureMatrixNotEnabled();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setObjectIdNotEnabled();
#endif
@ -132,6 +136,7 @@ constexpr struct {
} ConstructData[]{
{"", {}},
{"textured", Flat2D::Flag::Textured},
{"textured + texture transformation", Flat2D::Flag::Textured|Flat2D::Flag::TextureTransformation},
{"alpha mask", Flat2D::Flag::AlphaMask},
{"alpha mask + textured", Flat2D::Flag::AlphaMask|Flat2D::Flag::Textured},
{"vertex colors", Flat2D::Flag::VertexColor},
@ -142,6 +147,19 @@ constexpr struct {
#endif
};
const struct {
const char* name;
Flat2D::Flags flags;
Matrix3 textureTransformation;
bool flip;
} RenderTexturedData[]{
{"", Flat2D::Flag::Textured, {}, false},
{"texture transformeation",
Flat2D::Flag::Textured|Flat2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
true},
};
const struct {
const char* name;
const char* expected2D;
@ -174,10 +192,15 @@ FlatGLTest::FlatGLTest() {
&FlatGLTest::constructMove<2>,
&FlatGLTest::constructMove<3>,
&FlatGLTest::constructTextureTransformationNotTextured<2>,
&FlatGLTest::constructTextureTransformationNotTextured<3>,
&FlatGLTest::bindTextureNotEnabled<2>,
&FlatGLTest::bindTextureNotEnabled<3>,
&FlatGLTest::setAlphaMaskNotEnabled<2>,
&FlatGLTest::setAlphaMaskNotEnabled<3>,
&FlatGLTest::setTextureMatrixNotEnabled<2>,
&FlatGLTest::setTextureMatrixNotEnabled<3>,
#ifndef MAGNUM_TARGET_GLES2
&FlatGLTest::setObjectIdNotEnabled<2>,
&FlatGLTest::setObjectIdNotEnabled<3>
@ -189,10 +212,17 @@ FlatGLTest::FlatGLTest() {
&FlatGLTest::renderColored2D,
&FlatGLTest::renderColored3D,
&FlatGLTest::renderSinglePixelTextured2D,
&FlatGLTest::renderSinglePixelTextured3D,
&FlatGLTest::renderTextured2D,
&FlatGLTest::renderTextured3D,
&FlatGLTest::renderVertexColor2D<Color3>,
&FlatGLTest::renderSinglePixelTextured3D},
&FlatGLTest::renderSetup,
&FlatGLTest::renderTeardown);
addInstancedTests({&FlatGLTest::renderTextured2D,
&FlatGLTest::renderTextured3D},
Containers::arraySize(RenderTexturedData),
&FlatGLTest::renderSetup,
&FlatGLTest::renderTeardown);
addTests({&FlatGLTest::renderVertexColor2D<Color3>,
&FlatGLTest::renderVertexColor2D<Color4>,
&FlatGLTest::renderVertexColor3D<Color3>,
&FlatGLTest::renderVertexColor3D<Color4>},
@ -276,6 +306,16 @@ template<UnsignedInt dimensions> void FlatGLTest::constructMove() {
CORRADE_VERIFY(!b.id());
}
template<UnsignedInt dimensions> void FlatGLTest::constructTextureTransformationNotTextured() {
setTestCaseTemplateName(std::to_string(dimensions));
std::ostringstream out;
Error redirectError{&out};
Flat<dimensions>{Flat<dimensions>::Flag::TextureTransformation};
CORRADE_COMPARE(out.str(),
"Shaders::Flat: texture transformation enabled but the shader is not textured\n");
}
template<UnsignedInt dimensions> void FlatGLTest::bindTextureNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
@ -302,6 +342,19 @@ template<UnsignedInt dimensions> void FlatGLTest::setAlphaMaskNotEnabled() {
"Shaders::Flat::setAlphaMask(): the shader was not created with alpha mask enabled\n");
}
template<UnsignedInt dimensions> void FlatGLTest::setTextureMatrixNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
std::ostringstream out;
Error redirectError{&out};
Flat<dimensions> shader;
shader.setTextureMatrix({});
CORRADE_COMPARE(out.str(),
"Shaders::Flat::setTextureMatrix(): the shader was not created with texture transformation enabled\n");
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void FlatGLTest::setObjectIdNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
@ -539,6 +592,9 @@ void FlatGLTest::renderSinglePixelTextured3D() {
}
void FlatGLTest::renderTextured2D() {
auto&& data = RenderTexturedData[testCaseInstanceId()];
setTestCaseDescription(data.name);
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
@ -558,16 +614,27 @@ void FlatGLTest::renderTextured2D() {
.setStorage(1, TextureFormatRGB, image->size())
.setSubImage(0, {}, *image);
Flat2D{Flat2D::Flag::Textured}
Flat2D shader{data.flags};
shader
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
/* Colorized. Case without a color (where it should be white) is tested
in renderSinglePixelTextured() */
.setColor(0x9999ff_rgbf)
.bindTexture(texture)
.draw(circle);
.bindTexture(texture);
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
shader.draw(circle);
MAGNUM_VERIFY_NO_GL_ERROR();
Image2D rendered = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
/* Dropping the alpha channel, as it's always 1.0 */
Containers::StridedArrayView2D<Color3ub> pixels =
Containers::arrayCast<Color3ub>(rendered.pixels<Color4ub>());
if(data.flip) pixels = pixels.flipped<0>().flipped<1>();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has minor rounding errors, Apple A8 slightly more */
const Float maxThreshold = 2.334f, meanThreshold = 0.023f;
@ -575,14 +642,15 @@ void FlatGLTest::renderTextured2D() {
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 15.667f, meanThreshold = 3.254f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
CORRADE_COMPARE_WITH(pixels,
Utility::Directory::join(_testDir, "FlatTestFiles/textured2D.tga"),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void FlatGLTest::renderTextured3D() {
auto&& data = RenderTexturedData[testCaseInstanceId()];
setTestCaseDescription(data.name);
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
@ -602,20 +670,31 @@ void FlatGLTest::renderTextured3D() {
.setStorage(1, TextureFormatRGB, image->size())
.setSubImage(0, {}, *image);
Flat3D{Flat3D::Flag::Textured}
Flat3D shader{data.flags};
shader
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationX(15.0_degf))
Matrix4::rotationY(data.flip ? 15.0_degf : -15.0_degf)*
Matrix4::rotationX(data.flip ? -15.0_degf : 15.0_degf))
/* Colorized. Case without a color (where it should be white) is tested
in renderSinglePixelTextured() */
.setColor(0x9999ff_rgbf)
.bindTexture(texture)
.draw(sphere);
.bindTexture(texture);
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
shader.draw(sphere);
MAGNUM_VERIFY_NO_GL_ERROR();
Image2D rendered = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
/* Dropping the alpha channel, as it's always 1.0 */
Containers::StridedArrayView2D<Color3ub> pixels =
Containers::arrayCast<Color3ub>(rendered.pixels<Color4ub>());
if(data.flip) pixels = pixels.flipped<0>().flipped<1>();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has 5 different pixels on the edges */
const Float maxThreshold = 139.0f, meanThreshold = 0.087f;
@ -623,9 +702,7 @@ void FlatGLTest::renderTextured3D() {
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 139.0f, meanThreshold = 2.896f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
CORRADE_COMPARE_WITH(pixels,
Utility::Directory::join(_testDir, "FlatTestFiles/textured3D.tga"),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}

44
src/Magnum/Shaders/Test/PhongGLTest.cpp

@ -65,8 +65,11 @@ struct PhongGLTest: GL::OpenGLTester {
void constructMove();
void constructTextureTransformationNotTextured();
void bindTexturesNotEnabled();
void setAlphaMaskNotEnabled();
void setTextureMatrixNotEnabled();
#ifndef MAGNUM_TARGET_GLES2
void setObjectIdNotEnabled();
#endif
@ -134,6 +137,7 @@ constexpr struct {
{"", {}, 1},
{"ambient texture", Phong::Flag::AmbientTexture, 1},
{"diffuse texture", Phong::Flag::DiffuseTexture, 1},
{"diffuse texture + texture transform", Phong::Flag::DiffuseTexture|Phong::Flag::TextureTransformation, 1},
{"specular texture", Phong::Flag::SpecularTexture, 1},
{"normal texture", Phong::Flag::NormalTexture, 1},
{"ambient + diffuse texture", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture, 1},
@ -174,15 +178,20 @@ constexpr struct {
{"multi bind", true}
};
constexpr struct {
const struct {
const char* name;
const char* expected;
Phong::Flags flags;
Matrix3 textureTransformation;
} RenderTexturedData[]{
{"all", "textured.tga", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture},
{"ambient", "textured-ambient.tga", Phong::Flag::AmbientTexture},
{"diffuse", "textured-diffuse.tga", Phong::Flag::DiffuseTexture},
{"specular", "textured-specular.tga", Phong::Flag::SpecularTexture}
{"all", "textured.tga", Phong::Flag::AmbientTexture|Phong::Flag::DiffuseTexture|Phong::Flag::SpecularTexture, {}},
{"ambient", "textured-ambient.tga", Phong::Flag::AmbientTexture, {}},
{"diffuse", "textured-diffuse.tga", Phong::Flag::DiffuseTexture, {}},
{"diffuse transformed", "textured-diffuse-transformed.tga",
Phong::Flag::DiffuseTexture|Phong::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f})
},
{"specular", "textured-specular.tga", Phong::Flag::SpecularTexture, {}}
};
/* MSVC 2015 doesn't like constexpr here due to the angles */
@ -262,8 +271,11 @@ PhongGLTest::PhongGLTest() {
addTests({&PhongGLTest::constructMove,
&PhongGLTest::constructTextureTransformationNotTextured,
&PhongGLTest::bindTexturesNotEnabled,
&PhongGLTest::setAlphaMaskNotEnabled,
&PhongGLTest::setTextureMatrixNotEnabled,
#ifndef MAGNUM_TARGET_GLES2
&PhongGLTest::setObjectIdNotEnabled,
#endif
@ -388,6 +400,14 @@ void PhongGLTest::constructMove() {
CORRADE_VERIFY(!b.id());
}
void PhongGLTest::constructTextureTransformationNotTextured() {
std::ostringstream out;
Error redirectError{&out};
Phong{Phong::Flag::TextureTransformation};
CORRADE_COMPARE(out.str(),
"Shaders::Phong: texture transformation enabled but the shader is not textured\n");
}
void PhongGLTest::bindTexturesNotEnabled() {
std::ostringstream out;
Error redirectError{&out};
@ -419,6 +439,17 @@ void PhongGLTest::setAlphaMaskNotEnabled() {
"Shaders::Phong::setAlphaMask(): the shader was not created with alpha mask enabled\n");
}
void PhongGLTest::setTextureMatrixNotEnabled() {
std::ostringstream out;
Error redirectError{&out};
Phong shader;
shader.setTextureMatrix({});
CORRADE_COMPARE(out.str(),
"Shaders::Phong::setTextureMatrix(): the shader was not created with texture transformation enabled\n");
}
#ifndef MAGNUM_TARGET_GLES2
void PhongGLTest::setObjectIdNotEnabled() {
std::ostringstream out;
@ -677,6 +708,9 @@ void PhongGLTest::renderTextured() {
Phong shader{data.flags, 2};
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);

BIN
src/Magnum/Shaders/Test/PhongTestFiles/textured-diffuse-transformed.tga

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

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

@ -23,10 +23,12 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Image.h"
#include "Magnum/ImageView.h"
@ -60,6 +62,8 @@ struct VectorGLTest: GL::OpenGLTester {
template<UnsignedInt dimensions> void construct();
template<UnsignedInt dimensions> void constructMove();
template<UnsignedInt dimensions> void setTextureMatrixNotEnabled();
void renderSetup();
void renderTeardown();
@ -92,17 +96,52 @@ struct VectorGLTest: GL::OpenGLTester {
using namespace Math::Literals;
constexpr struct {
const char* name;
Vector2D::Flags flags;
} ConstructData[]{
{"", {}},
{"texture transformation", Vector2D::Flag::TextureTransformation}
};
const struct {
const char* name;
Vector2D::Flags flags;
Matrix3 textureTransformation;
Color4 backgroundColor, color;
const char* file2D;
const char* file3D;
bool flip;
} RenderData[] {
{"texture transformation", Vector2D::Flag::TextureTransformation,
Matrix3::translation(Vector2{1.0f})*Matrix3::scaling(Vector2{-1.0f}),
0x00000000_rgbaf, 0xffffff_rgbf,
"defaults.tga", "defaults.tga", true},
{"", {}, {}, 0x9999ff_rgbf, 0xffff99_rgbf,
"vector2D.tga", "vector3D.tga", false}
};
VectorGLTest::VectorGLTest() {
addTests<VectorGLTest>({
addInstancedTests<VectorGLTest>({
&VectorGLTest::construct<2>,
&VectorGLTest::construct<3>,
&VectorGLTest::construct<3>},
Containers::arraySize(ConstructData));
addTests<VectorGLTest>({
&VectorGLTest::constructMove<2>,
&VectorGLTest::constructMove<3>});
&VectorGLTest::constructMove<3>,
&VectorGLTest::setTextureMatrixNotEnabled<2>,
&VectorGLTest::setTextureMatrixNotEnabled<3>});
addTests({&VectorGLTest::renderDefaults2D,
&VectorGLTest::renderDefaults3D,
&VectorGLTest::render2D,
&VectorGLTest::render3D},
&VectorGLTest::renderDefaults3D},
&VectorGLTest::renderSetup,
&VectorGLTest::renderTeardown);
addInstancedTests({&VectorGLTest::render2D,
&VectorGLTest::render3D},
Containers::arraySize(RenderData),
&VectorGLTest::renderSetup,
&VectorGLTest::renderTeardown);
@ -133,7 +172,11 @@ VectorGLTest::VectorGLTest() {
template<UnsignedInt dimensions> void VectorGLTest::construct() {
setTestCaseTemplateName(std::to_string(dimensions));
Vector<dimensions> shader;
auto&& data = ConstructData[testCaseInstanceId()];
setTestCaseDescription(data.name);
Vector<dimensions> shader{data.flags};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_VERIFY(shader.id());
{
#ifdef CORRADE_TARGET_APPLE
@ -148,7 +191,7 @@ template<UnsignedInt dimensions> void VectorGLTest::construct() {
template<UnsignedInt dimensions> void VectorGLTest::constructMove() {
setTestCaseTemplateName(std::to_string(dimensions));
Vector<dimensions> a;
Vector<dimensions> a{Vector<dimensions>::Flag::TextureTransformation};
const GLuint id = a.id();
CORRADE_VERIFY(id);
@ -156,14 +199,29 @@ template<UnsignedInt dimensions> void VectorGLTest::constructMove() {
Vector<dimensions> b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), Vector<dimensions>::Flag::TextureTransformation);
CORRADE_VERIFY(!a.id());
Vector<dimensions> c{NoCreate};
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), Vector<dimensions>::Flag::TextureTransformation);
CORRADE_VERIFY(!b.id());
}
template<UnsignedInt dimensions> void VectorGLTest::setTextureMatrixNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
std::ostringstream out;
Error redirectError{&out};
Vector<dimensions> shader;
shader.setTextureMatrix({});
CORRADE_COMPARE(out.str(),
"Shaders::Vector::setTextureMatrix(): the shader was not created with texture transformation enabled\n");
}
constexpr Vector2i RenderSize{80, 80};
void VectorGLTest::renderSetup() {
@ -294,6 +352,9 @@ void VectorGLTest::renderDefaults3D() {
}
void VectorGLTest::render2D() {
auto&& data = RenderData[testCaseInstanceId()];
setTestCaseDescription(data.name);
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
@ -319,17 +380,27 @@ void VectorGLTest::render2D() {
.setSubImage(0, {}, *image);
#endif
Vector2D{}
.setBackgroundColor(0x9999ff_rgbf)
.setColor(0xffff99_rgbf)
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::rotation(5.0_degf))
.bindVectorTexture(texture)
.draw(square);
Vector2D shader{data.flags};
shader.setBackgroundColor(data.backgroundColor)
.setColor(data.color)
.bindVectorTexture(texture);
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
else shader.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::rotation(5.0_degf));
shader.draw(square);
MAGNUM_VERIFY_NO_GL_ERROR();
Image2D rendered = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
/* Dropping the alpha channel, as it's always 1.0 */
Containers::StridedArrayView2D<Color3ub> pixels =
Containers::arrayCast<Color3ub>(rendered.pixels<Color4ub>());
if(data.flip) pixels = pixels.flipped<0>().flipped<1>();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels */
const Float maxThreshold = 170.0f, meanThreshold = 0.146f;
@ -337,14 +408,15 @@ void VectorGLTest::render2D() {
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 170.0f, meanThreshold = 0.962f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Directory::join(_testDir, "VectorTestFiles/vector2D.tga"),
CORRADE_COMPARE_WITH(pixels,
Utility::Directory::join({_testDir, "VectorTestFiles", data.file2D}),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void VectorGLTest::render3D() {
auto&& data = RenderData[testCaseInstanceId()];
setTestCaseDescription(data.name);
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
@ -370,19 +442,29 @@ void VectorGLTest::render3D() {
.setSubImage(0, {}, *image);
#endif
Vector3D{}
.setBackgroundColor(0x9999ff_rgbf)
.setColor(0xffff99_rgbf)
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationZ(15.0_degf))
.bindVectorTexture(texture)
.draw(plane);
Vector3D shader{data.flags};
shader.setBackgroundColor(data.backgroundColor)
.setColor(data.color)
.bindVectorTexture(texture);
if(data.textureTransformation != Matrix3{})
shader.setTextureMatrix(data.textureTransformation);
else shader.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::rotationY(-15.0_degf)*
Matrix4::rotationZ(15.0_degf));
shader.draw(plane);
MAGNUM_VERIFY_NO_GL_ERROR();
Image2D rendered = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm});
/* Dropping the alpha channel, as it's always 1.0 */
Containers::StridedArrayView2D<Color3ub> pixels =
Containers::arrayCast<Color3ub>(rendered.pixels<Color4ub>());
if(data.flip) pixels = pixels.flipped<0>().flipped<1>();
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels */
const Float maxThreshold = 170.0f, meanThreshold = 0.171f;
@ -390,10 +472,8 @@ void VectorGLTest::render3D() {
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 170.0f, meanThreshold = 0.660f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Directory::join(_testDir, "VectorTestFiles/vector3D.tga"),
CORRADE_COMPARE_WITH(pixels,
Utility::Directory::join({_testDir, "VectorTestFiles", data.file3D}),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}

24
src/Magnum/Shaders/Test/VectorTest.cpp

@ -23,7 +23,9 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Shaders/Vector.h"
@ -37,6 +39,9 @@ struct VectorTest: TestSuite::Tester {
void constructCopy2D();
void constructCopy3D();
void debugFlag();
void debugFlags();
};
VectorTest::VectorTest() {
@ -44,7 +49,10 @@ VectorTest::VectorTest() {
&VectorTest::constructNoCreate3D,
&VectorTest::constructCopy2D,
&VectorTest::constructCopy3D});
&VectorTest::constructCopy3D,
&VectorTest::debugFlag,
&VectorTest::debugFlags});
}
void VectorTest::constructNoCreate2D() {
@ -75,6 +83,20 @@ void VectorTest::constructCopy3D() {
CORRADE_VERIFY(!(std::is_assignable<Vector3D, const Vector3D&>{}));
}
void VectorTest::debugFlag() {
std::ostringstream out;
Debug{&out} << Vector2D::Flag::TextureTransformation << Vector2D::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::Vector::Flag::TextureTransformation Shaders::Vector::Flag(0xf0)\n");
}
void VectorTest::debugFlags() {
std::ostringstream out;
Debug{&out} << Vector3D::Flags{Vector3D::Flag::TextureTransformation|Vector3D::Flag(0xf0)} << Vector3D::Flags{};
CORRADE_COMPARE(out.str(), "Shaders::Vector::Flag::TextureTransformation|Shaders::Vector::Flag(0xf0) Shaders::Vector::Flags{}\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::VectorTest)

40
src/Magnum/Shaders/Vector.cpp

@ -25,6 +25,7 @@
#include "Vector.h"
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Reference.h>
#include <Corrade/Utility/Resource.h>
@ -45,7 +46,7 @@ namespace {
template<> constexpr const char* vertexShaderName<3>() { return "AbstractVector3D.vert"; }
}
template<UnsignedInt dimensions> Vector<dimensions>::Vector() {
template<UnsignedInt dimensions> Vector<dimensions>::Vector(const Flags flags): _flags{flags} {
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShaders"))
@ -62,7 +63,8 @@ template<UnsignedInt dimensions> Vector<dimensions>::Vector() {
GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex);
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
vert.addSource(rs.get("generic.glsl"))
vert.addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "")
.addSource(rs.get("generic.glsl"))
.addSource(rs.get(vertexShaderName<dimensions>()));
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Vector.frag"));
@ -89,6 +91,8 @@ template<UnsignedInt dimensions> Vector<dimensions>::Vector() {
#endif
{
_transformationProjectionMatrixUniform = GL::AbstractShaderProgram::uniformLocation("transformationProjectionMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = GL::AbstractShaderProgram::uniformLocation("textureMatrix");
_backgroundColorUniform = GL::AbstractShaderProgram::uniformLocation("backgroundColor");
_colorUniform = GL::AbstractShaderProgram::uniformLocation("color");
}
@ -103,6 +107,7 @@ template<UnsignedInt dimensions> Vector<dimensions>::Vector() {
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix({});
if(flags & Flag::TextureTransformation) setTextureMatrix({});
setColor(Color4{1.0f}); /* Background color is zero by default */
#endif
}
@ -112,6 +117,13 @@ template<UnsignedInt dimensions> Vector<dimensions>& Vector<dimensions>::setTran
return *this;
}
template<UnsignedInt dimensions> Vector<dimensions>& Vector<dimensions>::setTextureMatrix(const Matrix3& matrix) {
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::Vector::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
GL::AbstractShaderProgram::setUniform(_textureMatrixUniform, matrix);
return *this;
}
template<UnsignedInt dimensions> Vector<dimensions>& Vector<dimensions>::setBackgroundColor(const Color4& color) {
GL::AbstractShaderProgram::setUniform(_backgroundColorUniform, color);
return *this;
@ -125,4 +137,28 @@ template<UnsignedInt dimensions> Vector<dimensions>& Vector<dimensions>::setColo
template class Vector<2>;
template class Vector<3>;
namespace Implementation {
Debug& operator<<(Debug& debug, const VectorFlag value) {
debug << "Shaders::Vector::Flag" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case VectorFlag::v: return debug << "::" #v;
_c(TextureTransformation)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const VectorFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::Vector::Flags{}", {
VectorFlag::TextureTransformation
});
}
}
}}

4
src/Magnum/Shaders/Vector.frag

@ -30,12 +30,12 @@
#endif
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
layout(location = 2)
#endif
uniform lowp vec4 backgroundColor; /* defaults to zero */
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
layout(location = 3)
#endif
uniform lowp vec4 color
#ifndef GL_ES

80
src/Magnum/Shaders/Vector.h

@ -35,6 +35,13 @@
namespace Magnum { namespace Shaders {
namespace Implementation {
enum class VectorFlag: UnsignedByte {
TextureTransformation = 1 << 0
};
typedef Containers::EnumSet<VectorFlag> VectorFlags;
}
/**
@brief Vector shader
@ -63,7 +70,41 @@ Common rendering setup:
*/
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Vector: public AbstractVector<dimensions> {
public:
explicit Vector();
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Flag
* @m_since_latest
*
* @see @ref Flags, @ref flags()
*/
enum class Flag: UnsignedByte {
/**
* Enable texture coordinate transformation.
* @see @ref setTextureMatrix()
* @m_since_latest
*/
TextureTransformation = 1 << 0
};
/**
* @brief Flags
* @m_since_latest
*
* @see @ref flags()
*/
typedef Containers::EnumSet<Flag> Flags;
#else
/* Done this way to be prepared for possible future diversion of 2D
and 3D flags (e.g. introducing 3D-specific features) */
typedef Implementation::VectorFlag Flag;
typedef Implementation::VectorFlags Flags;
#endif
/**
* @brief Constructor
* @param flags Flags
*/
explicit Vector(Flags flags = {});
/**
* @brief Construct without creating the underlying OpenGL object
@ -96,6 +137,12 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Vector: public Abst
/** @brief Move assignment */
Vector<dimensions>& operator=(Vector<dimensions>&&) noexcept = default;
/**
* @brief Flags
* @m_since_latest
*/
Flags flags() const { return _flags; }
/**
* @brief Set transformation and projection matrix
* @return Reference to self (for method chaining)
@ -104,6 +151,17 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Vector: public Abst
*/
Vector<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix);
/**
* @brief Set texture coordinate transformation matrix
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that the shader was created with
* @ref Flag::TextureTransformation enabled. Initial value is an
* identity matrix.
*/
Vector<dimensions>& setTextureMatrix(const Matrix3& matrix);
/**
* @brief Set background color
* @return Reference to self (for method chaining)
@ -139,9 +197,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT Vector: public Abst
using GL::AbstractShaderProgram::dispatchCompute;
#endif
Flags _flags;
Int _transformationProjectionMatrixUniform{0},
_backgroundColorUniform{1},
_colorUniform{2};
_textureMatrixUniform{1},
_backgroundColorUniform{2},
_colorUniform{3};
};
/** @brief Two-dimensional vector shader */
@ -150,6 +210,20 @@ typedef Vector<2> Vector2D;
/** @brief Three-dimensional vector shader */
typedef Vector<3> Vector3D;
#ifdef DOXYGEN_GENERATING_OUTPUT
/** @debugoperatorclassenum{Vector,Vector::Flag} */
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, Vector<dimensions>::Flag value);
/** @debugoperatorclassenum{Vector,Vector::Flags} */
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, Vector<dimensions>::Flags value);
#else
namespace Implementation {
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, VectorFlag value);
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, VectorFlags value);
CORRADE_ENUMSET_OPERATORS(VectorFlags)
}
#endif
}}
#endif

Loading…
Cancel
Save