Browse Source

Shaders: add UBO support to all shaders.

pull/518/head
Vladimír Vondruš 5 years ago
parent
commit
ef9da0ec96
  1. 2
      doc/changelog.dox
  2. 1
      package/archlinux/PKGBUILD
  3. 1
      package/archlinux/PKGBUILD-coverage
  4. 1
      package/archlinux/PKGBUILD-release
  5. 17
      src/Magnum/Shaders/CMakeLists.txt
  6. 56
      src/Magnum/Shaders/DistanceFieldVector.frag
  7. 223
      src/Magnum/Shaders/DistanceFieldVector.h
  8. 223
      src/Magnum/Shaders/DistanceFieldVectorGL.cpp
  9. 244
      src/Magnum/Shaders/DistanceFieldVectorGL.h
  10. 47
      src/Magnum/Shaders/Flat.frag
  11. 132
      src/Magnum/Shaders/Flat.h
  12. 65
      src/Magnum/Shaders/Flat.vert
  13. 197
      src/Magnum/Shaders/FlatGL.cpp
  14. 208
      src/Magnum/Shaders/FlatGL.h
  15. 430
      src/Magnum/Shaders/Generic.h
  16. 79
      src/Magnum/Shaders/MeshVisualizer.frag
  17. 107
      src/Magnum/Shaders/MeshVisualizer.geom
  18. 416
      src/Magnum/Shaders/MeshVisualizer.h
  19. 108
      src/Magnum/Shaders/MeshVisualizer.vert
  20. 532
      src/Magnum/Shaders/MeshVisualizerGL.cpp
  21. 479
      src/Magnum/Shaders/MeshVisualizerGL.h
  22. 137
      src/Magnum/Shaders/Phong.frag
  23. 449
      src/Magnum/Shaders/Phong.h
  24. 119
      src/Magnum/Shaders/Phong.vert
  25. 377
      src/Magnum/Shaders/PhongGL.cpp
  26. 357
      src/Magnum/Shaders/PhongGL.h
  27. 45
      src/Magnum/Shaders/Test/CMakeLists.txt
  28. 959
      src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp
  29. 195
      src/Magnum/Shaders/Test/DistanceFieldVectorTest.cpp
  30. 1675
      src/Magnum/Shaders/Test/FlatGLTest.cpp
  31. 4
      src/Magnum/Shaders/Test/FlatGL_Test.cpp
  32. 124
      src/Magnum/Shaders/Test/FlatTest.cpp
  33. BIN
      src/Magnum/Shaders/Test/FlatTestFiles/multidraw-textured2D.tga
  34. BIN
      src/Magnum/Shaders/Test/FlatTestFiles/multidraw-textured3D.tga
  35. BIN
      src/Magnum/Shaders/Test/FlatTestFiles/multidraw2D.tga
  36. BIN
      src/Magnum/Shaders/Test/FlatTestFiles/multidraw3D.tga
  37. 408
      src/Magnum/Shaders/Test/GenericTest.cpp
  38. 1959
      src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp
  39. 302
      src/Magnum/Shaders/Test/MeshVisualizerTest.cpp
  40. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-vertexid2D.tga
  41. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-vertexid3D.tga
  42. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe-nogeo2D.tga
  43. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe-nogeo3D.tga
  44. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe-tbn3D.tga
  45. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe2D.tga
  46. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe3D.tga
  47. 1807
      src/Magnum/Shaders/Test/PhongGLTest.cpp
  48. 322
      src/Magnum/Shaders/Test/PhongTest.cpp
  49. BIN
      src/Magnum/Shaders/Test/PhongTestFiles/multidraw-textured.tga
  50. BIN
      src/Magnum/Shaders/Test/PhongTestFiles/multidraw.tga
  51. 863
      src/Magnum/Shaders/Test/VectorGLTest.cpp
  52. 118
      src/Magnum/Shaders/Test/VectorTest.cpp
  53. BIN
      src/Magnum/Shaders/Test/VectorTestFiles/multidraw2D-distancefield.tga
  54. BIN
      src/Magnum/Shaders/Test/VectorTestFiles/multidraw2D.tga
  55. BIN
      src/Magnum/Shaders/Test/VectorTestFiles/multidraw3D-distancefield.tga
  56. BIN
      src/Magnum/Shaders/Test/VectorTestFiles/multidraw3D.tga
  57. 650
      src/Magnum/Shaders/Test/VertexColorGLTest.cpp
  58. 34
      src/Magnum/Shaders/Test/VertexColorGL_Test.cpp
  59. BIN
      src/Magnum/Shaders/Test/VertexColorTestFiles/multidraw2D.tga
  60. BIN
      src/Magnum/Shaders/Test/VertexColorTestFiles/multidraw3D.tga
  61. 37
      src/Magnum/Shaders/Vector.frag
  62. 100
      src/Magnum/Shaders/Vector.h
  63. 65
      src/Magnum/Shaders/Vector.vert
  64. 186
      src/Magnum/Shaders/VectorGL.cpp
  65. 194
      src/Magnum/Shaders/VectorGL.h
  66. 46
      src/Magnum/Shaders/VertexColor.vert
  67. 140
      src/Magnum/Shaders/VertexColorGL.cpp
  68. 184
      src/Magnum/Shaders/VertexColorGL.h

2
doc/changelog.dox

@ -147,6 +147,8 @@ See also:
@subsubsection changelog-latest-new-shaders Shaders library
- All builtin shaders now have opt-in support for uniform buffers on desktop,
OpenGL ES 3.0+ and WebGL 2.0
- Added @ref Shaders::PhongGL::setNormalTextureScale(), consuming the
recently added @ref Trade::MaterialAttribute::NormalTextureScale material
attribute

1
package/archlinux/PKGBUILD

@ -72,6 +72,7 @@ check() {
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_direct_state_access" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_get_texture_sub_image" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_vertex_array_object" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_uniform_buffer_object" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_KHR_debug" ctest --output-on-failure -j5 -R GLTest
# Run all Vulkan tests with SwiftShader as well

1
package/archlinux/PKGBUILD-coverage

@ -73,6 +73,7 @@ check() {
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_direct_state_access GL_ARB_robustness GL_ARB_multi_bind" ctest --output-on-failure -j5 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_get_texture_sub_image" ctest --output-on-failure -j5 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_vertex_array_object" ctest --output-on-failure -j5 -R GLTest || true
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_uniform_buffer_object" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_KHR_debug" ctest --output-on-failure -j5 -R GLTest || true
# Run all Vulkan tests with SwiftShader as well

1
package/archlinux/PKGBUILD-release

@ -110,6 +110,7 @@ check() {
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_direct_state_access" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_get_texture_sub_image" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_vertex_array_object" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_ARB_uniform_buffer_object" ctest --output-on-failure -j5 -R GLTest
MAGNUM_DISABLE_EXTENSIONS="GL_KHR_debug" ctest --output-on-failure -j5 -R GLTest
# Run all Vulkan tests with SwiftShader as well

17
src/Magnum/Shaders/CMakeLists.txt

@ -31,8 +31,6 @@ corrade_add_resource(MagnumShaders_RESOURCES_GL resources-gl.conf)
set_target_properties(MagnumShaders_RESOURCES_GL-dependencies PROPERTIES FOLDER "Magnum/Shaders")
set(MagnumShaders_SRCS
VertexColorGL.cpp
${MagnumShaders_RESOURCES_GL})
set(MagnumShaders_GracefulAssert_SRCS
@ -40,15 +38,22 @@ set(MagnumShaders_GracefulAssert_SRCS
FlatGL.cpp
MeshVisualizerGL.cpp
PhongGL.cpp
VectorGL.cpp)
VectorGL.cpp
VertexColorGL.cpp)
set(MagnumShaders_HEADERS
DistanceFieldVector.h
DistanceFieldVectorGL.h
Flat.h
FlatGL.h
Generic.h
GenericGL.h
MeshVisualizer.h
MeshVisualizerGL.h
Phong.h
PhongGL.h
Shaders.h
Vector.h
VectorGL.h
VertexColorGL.h
@ -56,12 +61,6 @@ set(MagnumShaders_HEADERS
if(MAGNUM_BUILD_DEPRECATED)
list(APPEND MagnumShaders_HEADERS
DistanceFieldVector.h
Flat.h
Generic.h
MeshVisualizer.h
Phong.h
Vector.h
VertexColor.h)
endif()

56
src/Magnum/Shaders/DistanceFieldVector.frag

@ -29,8 +29,13 @@
#define texture texture2D
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
#endif
@ -63,6 +68,49 @@ uniform lowp float smoothness
#endif
;
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
struct DrawUniform {
highp uvec4 materialIdReservedReservedReservedReserved;
#define draw_materialIdReserved materialIdReservedReservedReservedReserved.x
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
lowp vec4 color;
lowp vec4 reserved;
lowp vec4 outlineColor;
lowp vec4 outlineRangeSmoothnessReserved;
#define material_outlineRange outlineRangeSmoothnessReserved.xy
#define material_smoothness outlineRangeSmoothnessReserved.z
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
};
#endif
/* Textures */
#ifdef EXPLICIT_BINDING
@ -84,6 +132,14 @@ out lowp vec4 fragmentColor;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu;
lowp const float smoothness = materials[materialId].material_smoothness;
lowp const vec4 color = materials[materialId].color;
lowp const vec4 outlineColor = materials[materialId].outlineColor;
lowp const vec2 outlineRange = materials[materialId].material_outlineRange;
#endif
lowp float intensity = texture(vectorTexture, interpolatedTextureCoordinates).r;
/* Fill color */

223
src/Magnum/Shaders/DistanceFieldVector.h

@ -25,26 +25,227 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file
* @brief Typedef @ref Magnum::Shaders::DistanceFieldVector, alias @ref Magnum::Shaders::DistanceFieldVector2D, @ref Magnum::Shaders::DistanceFieldVector3D
* @m_deprecated_since_latest Use @ref Magnum/Shaders/DistanceFieldVectorGL.h,
* the @ref Magnum::Shaders::DistanceFieldVectorGL "DistanceFieldVectorGL"
* class and related typedefs instead.
* @brief Struct @ref Magnum::Shaders::DistanceFieldVectorDrawUniform, @ref Magnum::Shaders::DistanceFieldVectorMaterialUniform
*/
#endif
#include "Magnum/configure.h"
#include "Magnum/Magnum.h"
#include "Magnum/Math/Color.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#include "Magnum/Shaders/DistanceFieldVectorGL.h"
CORRADE_DEPRECATED_FILE("use Magnum/Shaders/DistanceFieldVectorGL.h, the DistanceFieldVectorGL class and related typedefs instead")
#endif
namespace Magnum { namespace Shaders {
/**
@brief Per-draw uniform for distance field vector shaders
@m_since_latest
Together with the generic @ref TransformationProjectionUniform2D /
@ref TransformationProjectionUniform3D contains parameters that are specific to
each draw call. Texture transformation, if needed, is supplied separately in a
@ref TextureTransformationUniform; material-related properties are expected to
be shared among multiple draw calls and thus are provided in a separate
@ref DistanceFieldVectorMaterialUniform structure, referenced by
@ref materialId.
@see @ref DistanceFieldVectorGL::bindDrawBuffer()
*/
struct DistanceFieldVectorDrawUniform {
/** @brief Construct with default parameters */
constexpr explicit DistanceFieldVectorDrawUniform(DefaultInitT = DefaultInit) noexcept: materialId{0} {}
/** @brief Construct without initializing the contents */
explicit DistanceFieldVectorDrawUniform(NoInitT) noexcept {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref materialId field
* @return Reference to self (for method chaining)
*/
DistanceFieldVectorDrawUniform& setMaterialId(UnsignedInt id) {
materialId = id;
return *this;
}
/**
* @}
*/
/** @var materialId
* @brief Material ID
*
* References a particular material from a
* @ref DistanceFieldVectorMaterialUniform array. Useful when an UBO with
* more than one material is supplied or in a multi-draw scenario. Should
* be less than the material count passed to the
* @ref DistanceFieldVectorGL::DistanceFieldVectorGL(Flags, UnsignedInt, UnsignedInt)
* constructor. Default value is @cpp 0 @ce, meaning the first material
* gets used.
*/
/* This field is an UnsignedInt in the shader and materialId is extracted
as (value & 0xffff), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort materialId;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
UnsignedShort:16; /* reserved for skinOffset */
#endif
#else
UnsignedShort:16; /* reserved for skinOffset */
UnsignedShort materialId;
#endif
/* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32; /* reserved for objectId */
Int:32;
Int:32;
#endif
};
/**
@brief Material uniform for distance field vector shaders
@m_since_latest
Describes material properties referenced from
@ref DistanceFieldVectorDrawUniform::materialId.
@see @ref DistanceFieldVectorGL::bindMaterialBuffer()
*/
struct DistanceFieldVectorMaterialUniform {
/** @brief Construct with default parameters */
constexpr explicit DistanceFieldVectorMaterialUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, outlineColor{0.0f, 0.0f, 0.0f, 0.0f}, outlineStart{0.5f}, outlineEnd{1.0f}, smoothness{0.04f} {}
/** @brief Construct without initializing the contents */
explicit DistanceFieldVectorMaterialUniform(NoInitT) noexcept: color{NoInit}, outlineColor{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref color field
* @return Reference to self (for method chaining)
*/
DistanceFieldVectorMaterialUniform& setColor(const Color4& color) {
this->color = color;
return *this;
}
/**
* @brief Set the @ref outlineColor field
* @return Reference to self (for method chaining)
*/
DistanceFieldVectorMaterialUniform& setOutlineColor(const Color4& color) {
outlineColor = color;
return *this;
}
/**
* @brief Set the @ref outlineStart and @ref outlineEnd fields
* @return Reference to self (for method chaining)
*/
DistanceFieldVectorMaterialUniform& setOutlineRange(Float start, Float end) {
outlineStart = start;
outlineEnd = end;
return *this;
}
/**
* @brief Set the @ref smoothness field
* @return Reference to self (for method chaining)
*/
DistanceFieldVectorMaterialUniform& setSmoothness(Float smoothness) {
this->smoothness = smoothness;
return *this;
}
/**
* @}
*/
/**
* @brief Fill color
*
* Default value is @cpp 0xffffffff_rgbaf @ce.
* @see @ref DistanceFieldVectorGL::setColor()
*/
Color4 color;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32; /* reserved for backgroundColor */
Int:32;
Int:32;
Int:32;
#endif
/**
* @brief Outline color
*
* Default value is @cpp 0x00000000_rgbaf @ce and the outline is not drawn
* --- see @ref outlineStart and @ref outlineEnd for more information.
* @see @ref DistanceFieldVectorGL::setColor()
*/
Color4 outlineColor;
/**
* @brief Outline start
*
* Describe where fill ends and possible outline starts. Default value is
* @cpp 0.5f @ce, larger values will make the vector art look thinner,
* smaller will make it look thicker.
* @see @ref DistanceFieldVectorGL::setOutlineRange()
*/
Float outlineStart;
/**
* @brief Outline end
*
* Describe where outline ends. If set to a value larger than
* @ref outlineStart, the outline is not drawn. Initial value is
* @cpp 1.0f @ce.
* @see @ref DistanceFieldVectorGL::setOutlineRange()
*/
Float outlineEnd;
/**
* @brief Smoothness radius
*
* Larger values will make edges look less aliased (but blurry), smaller
* values will make them look more crisp (but possibly aliased). Initial
* value is @cpp 0.04f @ce.
* @see @ref DistanceFieldVectorGL::setSmoothness()
*/
Float smoothness;
/* warning: Member __pad4__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32;
#endif
};
#ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief DistanceFieldVectorGL
* @m_deprecated_since_latest Use @ref DistanceFieldVectorGL instead.
*/
@ -61,10 +262,8 @@ typedef CORRADE_DEPRECATED("use DistanceFieldVectorGL2D instead") DistanceFieldV
* @m_deprecated_since_latest Use @ref DistanceFieldVectorGL3D instead.
*/
typedef CORRADE_DEPRECATED("use DistanceFieldVectorGL3D instead") DistanceFieldVectorGL3D DistanceFieldVector3D;
#endif
}}
#else
#error use Magnum/Shaders/DistanceFieldVectorGL.h, the DistanceFieldVectorGL class and related typedefs instead
#endif
#endif

223
src/Magnum/Shaders/DistanceFieldVectorGL.cpp

@ -37,15 +37,55 @@
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include "Magnum/GL/Buffer.h"
#endif
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
namespace Magnum { namespace Shaders {
namespace {
enum: Int { TextureUnit = 6 };
#ifndef MAGNUM_TARGET_GLES2
enum: Int {
/* Not using the zero binding to avoid conflicts with
ProjectionBufferBinding from other shaders which can likely stay
bound to the same buffer for the whole time */
TransformationProjectionBufferBinding = 1,
DrawBufferBinding = 2,
TextureTransformationBufferBinding = 3,
MaterialBufferBinding = 4
};
#endif
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFieldVectorGL(const Flags flags): _flags{flags} {
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFieldVectorGL(const Flags flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt materialCount, const UnsignedInt drawCount
#endif
):
_flags{flags}
#ifndef MAGNUM_TARGET_GLES2
, _materialCount{materialCount},
_drawCount{drawCount}
#endif
{
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount,
"Shaders::DistanceFieldVectorGL: material count can't be zero", );
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::DistanceFieldVectorGL: draw count can't be zero", );
#endif
#ifndef MAGNUM_TARGET_GLES
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShadersGL"))
@ -65,9 +105,27 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
vert.addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "")
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n")
.addSource(rs.get("generic.glsl"))
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
vert.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
}
#endif
vert.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Vector.vert"));
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
frag.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define MATERIAL_COUNT {}\n"
"#define DRAW_COUNT {}\n",
materialCount,
drawCount));
}
#endif
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("DistanceFieldVector.frag"));
@ -92,13 +150,20 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_colorUniform = uniformLocation("color");
_outlineColorUniform = uniformLocation("outlineColor");
_outlineRangeUniform = uniformLocation("outlineRange");
_smoothnessUniform = uniformLocation("smoothness");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
_drawOffsetUniform = uniformLocation("drawOffset");
} else
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_colorUniform = uniformLocation("color");
_outlineColorUniform = uniformLocation("outlineColor");
_outlineRangeUniform = uniformLocation("outlineRange");
_smoothnessUniform = uniformLocation("smoothness");
}
}
#ifndef MAGNUM_TARGET_GLES
@ -106,25 +171,54 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFiel
#endif
{
setUniform(uniformLocation("vectorTexture"), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding);
if(flags & Flag::TextureTransformation)
setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding);
}
#endif
}
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
setColor(Color4{1.0f}); /* Outline color is zero by default */
setOutlineRange(0.5f, 1.0f);
setSmoothness(0.04f);
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
/* Draw offset is zero by default */
} else
#endif
{
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
setColor(Color4{1.0f});
/* Outline color is zero by default */
setOutlineRange(0.5f, 1.0f);
setSmoothness(0.04f);
}
#endif
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>::DistanceFieldVectorGL(const Flags flags): DistanceFieldVectorGL{flags, 1, 1} {}
#endif
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::DistanceFieldVectorGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_transformationProjectionMatrixUniform, matrix);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setTextureMatrix(const Matrix3& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::DistanceFieldVectorGL::setTextureMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVectorGL::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
setUniform(_textureMatrixUniform, matrix);
@ -132,25 +226,112 @@ template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFiel
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::DistanceFieldVectorGL::setColor(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_colorUniform, color);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setOutlineColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::DistanceFieldVectorGL::setOutlineColor(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_outlineColorUniform, color);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setOutlineRange(Float start, Float end) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::DistanceFieldVectorGL::setOutlineRange(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_outlineRangeUniform, Vector2(start, end));
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setSmoothness(Float value) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::DistanceFieldVectorGL::setSmoothness(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_smoothnessUniform, value);
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(offset < _drawCount,
"Shaders::DistanceFieldVectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTextureTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindTextureTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::DistanceFieldVectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::DistanceFieldVectorGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
#endif
template<UnsignedInt dimensions> DistanceFieldVectorGL<dimensions>& DistanceFieldVectorGL<dimensions>::bindVectorTexture(GL::Texture2D& texture) {
texture.bind(TextureUnit);
return *this;
@ -168,6 +349,9 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
/* LCOV_EXCL_START */
#define _c(v) case DistanceFieldVectorGLFlag::v: return debug << "::" #v;
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#endif
#undef _c
/* LCOV_EXCL_STOP */
}
@ -177,8 +361,11 @@ Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlag value) {
Debug& operator<<(Debug& debug, const DistanceFieldVectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::DistanceFieldVectorGL::Flags{}", {
DistanceFieldVectorGLFlag::TextureTransformation
});
DistanceFieldVectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
DistanceFieldVectorGLFlag::UniformBuffers
#endif
});
}
}

244
src/Magnum/Shaders/DistanceFieldVectorGL.h

@ -39,7 +39,10 @@ namespace Magnum { namespace Shaders {
namespace Implementation {
enum class DistanceFieldVectorGLFlag: UnsignedByte {
TextureTransformation = 1 << 0
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1
#endif
};
typedef Containers::EnumSet<DistanceFieldVectorGLFlag> DistanceFieldVectorGLFlags;
}
@ -122,7 +125,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @see @ref setTextureMatrix()
* @m_since{2020,06}
*/
TextureTransformation = 1 << 0
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer(),
* and @ref bindMaterialBuffer() instead of direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL
* 1.0.
* @m_since_latest
*/
UniformBuffers = 1 << 1
#endif
};
/**
@ -142,9 +161,50 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
/**
* @brief Constructor
* @param flags Flags
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref DistanceFieldVectorGL(Flags, UnsignedInt, UnsignedInt) with
* @p materialCount and @p drawCount set to @cpp 1 @ce.
*/
explicit DistanceFieldVectorGL(Flags flags = {});
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param materialCount Size of a @ref DistanceFieldVectorMaterialUniform
* buffer bound with @ref bindMaterialBuffer()
* @param drawCount Size of a @ref TransformationProjectionUniform2D
* / @ref TransformationProjectionUniform3D /
* @ref DistanceFieldVectorDrawUniform /
* @ref TextureTransformationUniform buffer bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer()
* and @ref bindTextureTransformationBuffer()
*
* If @p flags contains @ref Flag::UniformBuffers, @p materialCount and
* @p drawCount describe the uniform buffer sizes as these are required
* to have a statically defined size. The draw offset is then set via
* @ref setDrawOffset() and the per-draw materials are specified via
* @ref DistanceFieldVectorDrawUniform::materialId.
*
* If @p flags don't contain @ref Flag::UniformBuffers,
* @p materialCount and @p drawCount is ignored and the constructor
* behaves the same as @ref DistanceFieldVectorGL(Flags).
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
/** @todo this constructor will eventually need to have also joint
count, per-vertex weight count, view count for multiview and clip
plane count ... and putting them in arbitrary order next to each
other is too error-prone, so it needs some other solution
(accepting pairs of parameter type and value like in GL context
creation, e.g., which will probably need a new enum as reusing Flag
for this might be too confusing) */
explicit DistanceFieldVectorGL(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount);
#endif
/**
* @brief Construct without creating the underlying OpenGL object
*
@ -177,8 +237,40 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
*/
Flags flags() const { return _flags; }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Material count
* @m_since_latest
*
* Statically defined size of the
* @ref DistanceFieldVectorMaterialUniform uniform buffer. Has use only
* if @ref Flag::UniformBuffers is set.
* @see @ref bindMaterialBuffer()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt materialCount() const { return _materialCount; }
/**
* @brief Draw count
* @m_since_latest
*
* Statically defined size of each of the
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D,
* @ref DistanceFieldVectorDrawUniform and
* @ref TextureTransformationUniform uniform buffers. Has use only if
* @ref Flag::UniformBuffers is set.
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt drawCount() const { return _drawCount; }
#endif
/** @{
* @name Uniform setters
*
* Used only if @ref Flag::UniformBuffers is not set.
*/
/**
@ -186,6 +278,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @return Reference to self (for method chaining)
*
* Initial value is an identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix /
* @ref TransformationProjectionUniform3D::transformationProjectionMatrix
* and call @ref bindTransformationProjectionBuffer() instead.
*/
DistanceFieldVectorGL<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix);
@ -197,6 +294,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* Expects that the shader was created with
* @ref Flag::TextureTransformation enabled. Initial value is an
* identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TextureTransformationUniform::rotationScaling and
* @ref TextureTransformationUniform::offset and call
* @ref bindTextureTransformationBuffer() instead.
*/
DistanceFieldVectorGL<dimensions>& setTextureMatrix(const Matrix3& matrix);
@ -205,6 +307,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 0xffffffff_rgbaf @ce.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref DistanceFieldVectorMaterialUniform::color and call
* @ref bindMaterialBuffer() instead.
* @see @ref setOutlineColor()
*/
DistanceFieldVectorGL<dimensions>& setColor(const Color4& color);
@ -215,6 +321,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
*
* Initial value is @cpp 0x00000000_rgbaf @ce and the outline is not
* drawn --- see @ref setOutlineRange() for more information.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref DistanceFieldVectorMaterialUniform::outlineColor and call
* @ref bindMaterialBuffer() instead.
* @see @ref setOutlineRange(), @ref setColor()
*/
DistanceFieldVectorGL<dimensions>& setOutlineColor(const Color4& color);
@ -231,6 +341,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* larger than @p start, the outline is not drawn. Initial value is
* @cpp 1.0f @ce.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref DistanceFieldVectorMaterialUniform::outlineStart and
* @ref DistanceFieldVectorMaterialUniform::outlineEnd and call
* @ref bindMaterialBuffer() instead.
* @see @ref setOutlineColor()
*/
DistanceFieldVectorGL<dimensions>& setOutlineRange(Float start, Float end);
@ -242,6 +356,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* Larger values will make edges look less aliased (but blurry),
* smaller values will make them look more crisp (but possibly
* aliased). Initial value is @cpp 0.04f @ce.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref DistanceFieldVectorMaterialUniform::smoothness and call
* @ref bindMaterialBuffer() instead.
*/
DistanceFieldVectorGL<dimensions>& setSmoothness(Float value);
@ -249,6 +367,120 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
* @}
*/
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
/**
* @brief Set a draw offset
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Specifies which item in the @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D,
* @ref DistanceFieldVectorDrawUniform and
* @ref TextureTransformationUniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @p offset is
* less than @ref drawCount(). Initial value is @cpp 0 @ce.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
DistanceFieldVectorGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Set a transformation and projection uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D. At the very least you need
* to call also @ref bindDrawBuffer() and @ref bindMaterialBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
DistanceFieldVectorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
DistanceFieldVectorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a draw uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref DistanceFieldVectorDrawUniform. At the very least you need to
* call also @ref bindTransformationProjectionBuffer() and
* @ref bindMaterialBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
DistanceFieldVectorGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
DistanceFieldVectorGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a texture transformation uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that both @ref Flag::UniformBuffers and
* @ref Flag::TextureTransformation is set. The buffer is expected to
* contain @ref drawCount() instances of
* @ref TextureTransformationUniform.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
DistanceFieldVectorGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
DistanceFieldVectorGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a material uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref materialCount() instances of
* @ref DistanceFieldVectorMaterialUniform. At the very least you need
* to call also @ref bindTransformationProjectionBuffer() and
* @ref bindDrawBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
DistanceFieldVectorGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
DistanceFieldVectorGL<dimensions>& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @}
*/
#endif
/** @{
* @name Texture binding
*/
@ -278,12 +510,20 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT DistanceFieldVector
#endif
Flags _flags;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _materialCount{}, _drawCount{};
#endif
Int _transformationProjectionMatrixUniform{0},
_textureMatrixUniform{1},
_colorUniform{2},
_outlineColorUniform{3},
_outlineRangeUniform{4},
_smoothnessUniform{5};
#ifndef MAGNUM_TARGET_GLES2
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */
Int _drawOffsetUniform{0};
#endif
};
/**

47
src/Magnum/Shaders/Flat.frag

@ -27,14 +27,23 @@
#extension GL_EXT_gpu_shader4: require
#endif
#if defined(UNIFORM_BUFFERS) && defined(ALPHA_MASK) && !defined(GL_ES)
#extension GL_ARB_shader_bit_encoding: require
#endif
#ifndef NEW_GLSL
#define fragmentColor gl_FragColor
#define texture texture2D
#define in varying
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
#endif
@ -63,6 +72,34 @@ layout(location = 4)
uniform highp uint objectId; /* defaults to zero */
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
struct DrawUniform {
lowp vec4 color;
highp uvec4 objectIdReservedAlphaMaskReserved;
#define draw_objectId objectIdReservedAlphaMaskReserved.x
#define draw_alphaMask objectIdReservedAlphaMaskReserved.z
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
#endif
/* Textures */
#ifdef TEXTURED
@ -103,6 +140,16 @@ out highp uint fragmentObjectId;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
lowp const vec4 color = draws[drawOffset].color;
#ifdef OBJECT_ID
highp const uint objectId = draws[drawOffset].draw_objectId;
#endif
#ifdef ALPHA_MASK
lowp const float alphaMask = uintBitsToFloat(draws[drawOffset].draw_alphaMask);
#endif
#endif
fragmentColor =
#ifdef TEXTURED
texture(textureData, interpolatedTextureCoordinates)*

132
src/Magnum/Shaders/Flat.h

@ -25,26 +25,136 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file
* @brief Typedef @ref Magnum::Shaders::Flat, alias @ref Magnum::Shaders::Flat2D, @ref Magnum::Shaders::Flat3D
* @m_deprecated_since_latest Use @ref Magnum/Shaders/FlatGL.h, the
* @ref Magnum::Shaders::FlatGL "FlatGL" class and
* related typedefs instead.
* @brief Struct @ref Magnum::Shaders::FlatDrawUniform
*/
#endif
#include "Magnum/configure.h"
#include "Magnum/Magnum.h"
#include "Magnum/Math/Color.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#include "Magnum/Shaders/FlatGL.h"
CORRADE_DEPRECATED_FILE("use Magnum/Shaders/FlatGL.h, the FlatGL class and related typedefs instead")
#endif
namespace Magnum { namespace Shaders {
/**
@brief Per-draw uniform for flat shaders
@m_since_latest
Together with the generic @ref TransformationProjectionUniform2D /
@ref TransformationProjectionUniform3D contains parameters that are specific to
each draw call. Texture transformation, if needed, is supplied separately in a
@ref TextureTransformationUniform.
@see @ref FlatGL::bindDrawBuffer()
*/
struct FlatDrawUniform {
/** @brief Construct with default parameters */
constexpr explicit FlatDrawUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, objectId{0}, alphaMask{0.5f} {}
/** @brief Construct without initializing the contents */
explicit FlatDrawUniform(NoInitT) noexcept: color{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref objectId field
* @return Reference to self (for method chaining)
*/
FlatDrawUniform& setObjectId(UnsignedInt id) {
objectId = id;
return *this;
}
/**
* @brief Set the @ref alphaMask field
* @return Reference to self (for method chaining)
*/
FlatDrawUniform& setAlphaMask(Float alphaMask) {
this->alphaMask = alphaMask;
return *this;
}
/**
* @brief Set the @ref color field
* @return Reference to self (for method chaining)
*/
FlatDrawUniform& setColor(const Color4& color) {
this->color = color;
return *this;
}
/**
* @}
*/
/**
* @brief Color
*
* Default value is @cpp 0xffffffff_rgbaf @ce.
*
* If @ref FlatGL::Flag::VertexColor is enabled, the color is multiplied
* with a color coming from the @ref FlatGL::Color3 / @ref FlatGL::Color4
* attribute.
* @see @ref FlatGL::setColor()
*/
Color4 color;
/**
* @brief Object ID
*
* Used only for the object ID framebuffer output, not to access any other
* uniform data. Default value is @cpp 0 @ce.
*
* Used only if @ref FlatGL::Flag::ObjectId is enabled, ignored otherwise.
* If @ref FlatGL::Flag::InstancedObjectId is enabled as well, this value
* is added to the ID coming from the @ref FlatGL::ObjectId attribute.
* @see @ref FlatGL::setObjectId()
*/
UnsignedInt objectId;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
/* This field is an UnsignedInt in the shader and skinOffset is extracted
as (value >> 16), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort:16;
UnsignedShort:16; /* reserved for skinOffset */
#else
UnsignedShort:16; /* reserved for skinOffset */
UnsignedShort:16;
#endif
#endif
/**
* @brief Alpha mask value
*
* Fragments with alpha values smaller than the mask value will be
* discarded. Default value is @cpp 0.5f @ce.
*
* Used only if @ref FlatGL::Flag::AlphaMask is enabled, ignored otherwise.
* @see @ref FlatGL::setAlphaMask()
*/
Float alphaMask;
/* warning: Member __pad2__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32;
#endif
};
#ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief FlatGL
* @m_deprecated_since_latest Use @ref FlatGL instead.
*/
@ -61,10 +171,8 @@ typedef CORRADE_DEPRECATED("use FlatGL2D instead") FlatGL2D Flat2D;
* @m_deprecated_since_latest Use @ref FlatGL3D instead.
*/
typedef CORRADE_DEPRECATED("use FlatGL3D instead") FlatGL3D Flat3D;
#endif
}}
#else
#error use Magnum/Shaders/FlatGL.h, the FlatGL class and related typedefs instead
#endif
#endif

65
src/Magnum/Shaders/Flat.vert

@ -32,8 +32,13 @@
#define out varying
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -64,6 +69,51 @@ uniform mediump mat3 textureMatrix
;
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 1
#endif
) uniform TransformationProjection {
highp
#ifdef TWO_DIMENSIONS
mat3
#elif defined(THREE_DIMENSIONS)
mat4
#else
#error
#endif
transformationProjectionMatrices[DRAW_COUNT];
};
#ifdef TEXTURE_TRANSFORMATION
struct TextureTransformationUniform {
highp vec4 rotationScaling;
highp vec4 offsetReservedReserved;
#define textureTransformation_offset offsetReservedReserved.xy
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 3
#endif
) uniform TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT];
};
#endif
#endif
/* Inputs */
#ifdef EXPLICIT_ATTRIB_LOCATION
@ -133,6 +183,21 @@ flat out highp uint interpolatedInstanceObjectId;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
highp const
#ifdef TWO_DIMENSIONS
mat3
#elif defined(THREE_DIMENSIONS)
mat4
#else
#error
#endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
#ifdef TEXTURE_TRANSFORMATION
mediump const mat3 textureMatrix = mat3(textureTransformations[drawOffset].rotationScaling.xy, 0.0, textureTransformations[drawOffset].rotationScaling.zw, 0.0, textureTransformations[drawOffset].textureTransformation_offset, 1.0);
#endif
#endif
#ifdef TWO_DIMENSIONS
gl_Position.xywz = vec4(transformationProjectionMatrix*
#ifdef INSTANCED_TRANSFORMATION

197
src/Magnum/Shaders/FlatGL.cpp

@ -39,16 +39,52 @@
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include "Magnum/GL/Buffer.h"
#endif
namespace Magnum { namespace Shaders {
namespace {
enum: Int { TextureUnit = 0 };
#ifndef MAGNUM_TARGET_GLES2
enum: Int {
/* Not using the zero binding to avoid conflicts with
ProjectionBufferBinding from other shaders which can likely stay
bound to the same buffer for the whole time */
TransformationProjectionBufferBinding = 1,
DrawBufferBinding = 2,
TextureTransformationBufferBinding = 3
};
#endif
}
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags): _flags(flags) {
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt drawCount
#endif
):
_flags{flags}
#ifndef MAGNUM_TARGET_GLES2
, _drawCount{drawCount}
#endif
{
CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & Flag::Textured),
"Shaders::FlatGL: texture transformation enabled but the shader is not textured", );
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::FlatGL: draw count can't be zero", );
#endif
#ifndef MAGNUM_TARGET_GLES
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShadersGL"))
@ -75,8 +111,16 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags):
.addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
#endif
.addSource(flags & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n" : "")
.addSource(flags >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : "")
.addSource(rs.get("generic.glsl"))
.addSource(flags >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : "");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
vert.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
}
#endif
vert.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Flat.vert"));
frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "")
.addSource(flags & Flag::AlphaMask ? "#define ALPHA_MASK\n" : "")
@ -85,7 +129,16 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags):
.addSource(flags & Flag::ObjectId ? "#define OBJECT_ID\n" : "")
.addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
#endif
.addSource(rs.get("generic.glsl"))
;
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
frag.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
}
#endif
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Flat.frag"));
CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag}));
@ -125,14 +178,21 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags):
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#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
if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId");
if(flags >= Flag::UniformBuffers) {
_drawOffsetUniform = uniformLocation("drawOffset");
} else
#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
if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId");
#endif
}
}
#ifndef MAGNUM_TARGET_GLES
@ -140,25 +200,52 @@ template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags):
#endif
{
if(flags & Flag::Textured) setUniform(uniformLocation("textureData"), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
if(flags & Flag::TextureTransformation)
setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding);
}
#endif
}
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
setColor(Magnum::Color4{1.0f});
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
/* Draw offset is zero by default */
} else
#endif
{
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
setColor(Magnum::Color4{1.0f});
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
}
#endif
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> FlatGL<dimensions>::FlatGL(const Flags flags): FlatGL{flags, 1} {}
#endif
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::FlatGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_transformationProjectionMatrixUniform, matrix);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setTextureMatrix(const Matrix3& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::FlatGL::setTextureMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::FlatGL::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
setUniform(_textureMatrixUniform, matrix);
@ -166,11 +253,19 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setText
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setColor(const Magnum::Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::FlatGL::setColor(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_colorUniform, color);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setAlphaMask(Float mask) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::FlatGL::setAlphaMask(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & Flag::AlphaMask,
"Shaders::FlatGL::setAlphaMask(): the shader was not created with alpha mask enabled", *this);
setUniform(_alphaMaskUniform, mask);
@ -179,6 +274,8 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setAlph
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setObjectId(UnsignedInt id) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::FlatGL::setObjectId(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::ObjectId,
"Shaders::FlatGL::setObjectId(): the shader was not created with object ID enabled", *this);
setUniform(_objectIdUniform, id);
@ -186,6 +283,63 @@ template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setObje
}
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(offset < _drawCount,
"Shaders::FlatGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTextureTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTextureTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::FlatGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
#endif
template<UnsignedInt dimensions> FlatGL<dimensions>& FlatGL<dimensions>::bindTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(_flags & Flag::Textured,
"Shaders::FlatGL::bindTexture(): the shader was not created with texturing enabled", *this);
@ -214,11 +368,14 @@ Debug& operator<<(Debug& debug, const FlatGLFlag value) {
#endif
_c(InstancedTransformation)
_c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#endif
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedShort(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const FlatGLFlags value) {
@ -232,7 +389,11 @@ Debug& operator<<(Debug& debug, const FlatGLFlags value) {
FlatGLFlag::InstancedObjectId, /* Superset of ObjectId */
FlatGLFlag::ObjectId,
#endif
FlatGLFlag::InstancedTransformation});
FlatGLFlag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2
FlatGLFlag::UniformBuffers
#endif
});
}
}

208
src/Magnum/Shaders/FlatGL.h

@ -38,7 +38,7 @@
namespace Magnum { namespace Shaders {
namespace Implementation {
enum class FlatGLFlag: UnsignedByte {
enum class FlatGLFlag: UnsignedShort {
Textured = 1 << 0,
AlphaMask = 1 << 1,
VertexColor = 1 << 2,
@ -48,7 +48,10 @@ namespace Implementation {
InstancedObjectId = (1 << 5)|ObjectId,
#endif
InstancedTransformation = 1 << 6,
InstancedTextureOffset = (1 << 7)|TextureTransformation
InstancedTextureOffset = (1 << 7)|TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 8
#endif
};
typedef Containers::EnumSet<FlatGLFlag> FlatGLFlags;
}
@ -269,7 +272,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*
* @see @ref Flags, @ref flags()
*/
enum class Flag: UnsignedByte {
enum class Flag: UnsignedShort {
/**
* Multiply color with a texture.
* @see @ref setColor(), @ref bindTexture()
@ -319,9 +322,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
/**
* Instanced object ID. Retrieves a per-instance / per-vertex
* object ID from the @ref ObjectId attribute, outputting a sum of
* the per-vertex ID and ID coming from @ref setObjectId().
* Implicitly enables @ref Flag::ObjectId. See
* @ref Shaders-FlatGL-object-id for more information.
* the per-vertex ID and ID coming from @ref setObjectId() or
* @ref FlatDrawUniform::objectId. Implicitly enables
* @ref Flag::ObjectId. See @ref Shaders-FlatGL-object-id for more
* information.
* @requires_gl30 Extension @gl_extension{EXT,gpu_shader4}
* @requires_gles30 Object ID output requires integer support in
* shaders, which is not available in OpenGL ES 2.0 or WebGL
@ -335,8 +339,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* Instanced transformation. Retrieves a per-instance
* transformation matrix from the @ref TransformationMatrix
* attribute and uses it together with the matrix coming from
* @ref setTransformationProjectionMatrix() (first the
* per-instance, then the uniform matrix). See
* @ref setTransformationProjectionMatrix() or
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix
* / @ref TransformationProjectionUniform3D::transformationProjectionMatrix
* (first the per-instance, then the uniform matrix). See
* @ref Shaders-FlatGL-instancing for more information.
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays}
* @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays},
@ -351,7 +357,9 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
/**
* Instanced texture offset. Retrieves a per-instance offset vector
* from the @ref TextureOffset attribute and uses it together with
* the matrix coming from @ref setTextureMatrix() (first the
* the matrix coming from @ref setTextureMatrix() or
* @ref TextureTransformationUniform::rotationScaling and
* @ref TextureTransformationUniform::offset (first the
* per-instance vector, then the uniform matrix). Instanced texture
* scaling and rotation is not supported at the moment, you can
* specify that only via the uniform @ref setTextureMatrix().
@ -365,7 +373,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* in WebGL 1.0.
* @m_since{2020,06}
*/
InstancedTextureOffset = (1 << 7)|TextureTransformation
InstancedTextureOffset = (1 << 7)|TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer()
* instead of direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL
* 1.0.
* @m_since_latest
*/
UniformBuffers = 1 << 8
#endif
};
/**
@ -384,9 +408,37 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
/**
* @brief Constructor
* @param flags Flags
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref FlatGL(Flags, UnsignedInt) with @p drawCount set to @cpp 1 @ce.
*/
explicit FlatGL(Flags flags = {});
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param drawCount Size of a @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D / @ref FlatDrawUniform /
* @ref TextureTransformationUniform buffer bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer()
* and @ref bindTextureTransformationBuffer()
*
* If @p flags contains @ref Flag::UniformBuffers, @p drawCount
* describes the uniform buffer sizes as these are required to have a
* statically defined size. The draw offset is then set via
* @ref setDrawOffset().
*
* If @p flags don't contain @ref Flag::UniformBuffers, @p drawCount is
* ignored and the constructor behaves the same as @ref FlatGL(Flags).
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
explicit FlatGL(Flags flags, UnsignedInt drawCount);
#endif
/**
* @brief Construct without creating the underlying OpenGL object
*
@ -416,8 +468,26 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
/** @brief Flags */
Flags flags() const { return _flags; }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Draw count
* @m_since_latest
*
* Statically defined size of each of the
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D, @ref FlatDrawUniform and
* @ref TextureTransformationUniform uniform buffers. Has use only if
* @ref Flag::UniformBuffers is set.
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt drawCount() const { return _drawCount; }
#endif
/** @{
* @name Uniform setters
*
* Used only if @ref Flag::UniformBuffers is not set.
*/
/**
@ -428,6 +498,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @ref Flag::InstancedTransformation is set, the per-instance
* transformation matrix coming from the @ref TransformationMatrix
* attribute is applied first, before this one.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix /
* @ref TransformationProjectionUniform3D::transformationProjectionMatrix
* and call @ref bindTransformationProjectionBuffer() instead.
*/
FlatGL<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix);
@ -441,6 +516,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* identity matrix. If @ref Flag::InstancedTextureOffset is set, the
* per-instance offset coming from the @ref TextureOffset attribute is
* applied first, before this matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TextureTransformationUniform::rotationScaling and
* @ref TextureTransformationUniform::offset and call
* @ref bindTextureTransformationBuffer() instead.
*/
FlatGL<dimensions>& setTextureMatrix(const Matrix3& matrix);
@ -452,6 +532,9 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* is set, the color is multiplied with the texture. If
* @ref Flag::VertexColor is set, the color is multiplied with a color
* coming from the @ref Color3 / @ref Color4 attribute.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref FlatDrawUniform::color and call @ref bindDrawBuffer() instead.
* @see @ref bindTexture()
*/
FlatGL<dimensions>& setColor(const Magnum::Color4& color);
@ -467,6 +550,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
*
* This corresponds to @m_class{m-doc-external} [glAlphaFunc()](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glAlphaFunc.xml)
* in classic OpenGL.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref FlatDrawUniform::alphaMask and call @ref bindDrawBuffer()
* instead.
* @m_keywords{glAlphaFunc()}
*/
FlatGL<dimensions>& setAlphaMask(Float mask);
@ -481,6 +568,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @ref Shaders-FlatGL-object-id for more information. Default is
* @cpp 0 @ce. If @ref Flag::InstancedObjectId is enabled as well, this
* value is added to the ID coming from the @ref ObjectId attribute.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref FlatDrawUniform::objectId and call @ref bindDrawBuffer()
* instead.
* @requires_gl30 Extension @gl_extension{EXT,gpu_shader4}
* @requires_gles30 Object ID output requires integer support in
* shaders, which is not available in OpenGL ES 2.0 or WebGL 1.0.
@ -492,6 +583,97 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
* @}
*/
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
/**
* @brief Set a draw offset
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Specifies which item in the @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D, @ref FlatDrawUniform and
* @ref TextureTransformationUniform buffers bound with
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindTextureTransformationBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @p offset is
* less than @ref drawCount(). Initial value is @cpp 0 @ce.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
FlatGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Set a transformation and projection uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D. At the very least you need
* to call also @ref bindDrawBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
FlatGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
FlatGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a draw uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref FlatDrawUniform. At the very least you need to call also
* @ref bindTransformationProjectionBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
FlatGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
FlatGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a texture transformation uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that both @ref Flag::UniformBuffers and
* @ref Flag::TextureTransformation is set. The buffer is expected to
* contain @ref drawCount() instances of
* @ref TextureTransformationUniform.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
FlatGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
FlatGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @}
*/
#endif
/** @{
* @name Texture binding
*/
@ -521,12 +703,18 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT FlatGL: public GL::
#endif
Flags _flags;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _drawCount{};
#endif
Int _transformationProjectionMatrixUniform{0},
_textureMatrixUniform{1},
_colorUniform{2},
_alphaMaskUniform{3};
#ifndef MAGNUM_TARGET_GLES2
Int _objectIdUniform{4};
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */
Int _drawOffsetUniform{0};
#endif
};

430
src/Magnum/Shaders/Generic.h

@ -25,32 +25,442 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file
* @brief Typedef @ref Magnum::Shaders::Generic, alias @ref Magnum::Shaders::Generic2D, @ref Magnum::Shaders::Generic3D
* @m_deprecated_since_latest Use @ref Magnum/Shaders/GenericGL.h, the
* @ref Magnum::Shaders::GenericGL "GenericGL" class and
* related typedefs instead.
* @brief Struct @ref Magnum::Shaders::ProjectionUniform2D, @ref Magnum::Shaders::ProjectionUniform3D, @ref Magnum::Shaders::TransformationUniform2D, @ref Magnum::Shaders::TransformationUniform3D, @ref Magnum::Shaders::TextureTransformationUniform
*/
#endif
#include "Magnum/configure.h"
#include "Magnum/Magnum.h"
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#include "Magnum/Shaders/GenericGL.h"
#endif
namespace Magnum { namespace Shaders {
/**
@brief 2D projection uniform common for all shaders
@m_since_latest
Contains the per-view projection matrix.
*/
struct ProjectionUniform2D {
/** @brief Construct with default parameters */
constexpr explicit ProjectionUniform2D(DefaultInitT = DefaultInit) noexcept: projectionMatrix{Math::IdentityInit} {}
/** @brief Construct without initializing the contents */
explicit ProjectionUniform2D(NoInitT) noexcept: projectionMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref projectionMatrix field
* @return Reference to self (for method chaining)
*
* The matrix is expanded to @relativeref{Magnum,Matrix3x4}, with the
* bottom row being zeros.
*/
ProjectionUniform2D& setProjectionMatrix(const Matrix3& matrix) {
projectionMatrix = Matrix3x4{matrix};
return *this;
}
/**
* @}
*/
/**
* @brief Projection matrix
*
* Default value is an identity matrix (i.e., an orthographic projection of
* the default @f$ [ -\boldsymbol{1} ; \boldsymbol{1} ] @f$ cube). The
* bottom row is unused and acts only as a padding to match uniform buffer
* packing rules.
*/
Matrix3x4 projectionMatrix;
};
/**
@brief 3D projection uniform common for all shaders
@m_since_latest
Contains the per-view projection matrix used by the @ref MeshVisualizerGL3D
and @ref PhongGL shaders that need a separate projection and transformation
matrix.
@see @ref MeshVisualizerGL3D::bindProjectionBuffer(),
@ref PhongGL::bindProjectionBuffer()
*/
struct ProjectionUniform3D {
/** @brief Construct with default parameters */
constexpr explicit ProjectionUniform3D(DefaultInitT = DefaultInit) noexcept: projectionMatrix{Math::IdentityInit} {}
/** @brief Construct without initializing the contents */
explicit ProjectionUniform3D(NoInitT) noexcept: projectionMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref projectionMatrix field
* @return Reference to self (for method chaining)
*/
ProjectionUniform3D& setProjectionMatrix(const Matrix4& matrix) {
projectionMatrix = matrix;
return *this;
}
/**
* @}
*/
/**
* @brief Projection matrix
*
* Default value is an identity matrix (i.e., an orthographic projection of
* the default @f$ [ -\boldsymbol{1} ; \boldsymbol{1} ] @f$ cube).
* @see @ref PhongGL::setProjectionMatrix()
*/
Matrix4 projectionMatrix;
};
/**
@brief 2D transformation uniform common for all shaders
@m_since_latest
Contains the per-draw transformation matrix.
*/
struct TransformationUniform2D {
/** @brief Construct with default parameters */
constexpr explicit TransformationUniform2D(DefaultInitT = DefaultInit) noexcept: transformationMatrix{Math::IdentityInit} {}
/** @brief Construct without initializing the contents */
explicit TransformationUniform2D(NoInitT) noexcept: transformationMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref transformationMatrix field
* @return Reference to self (for method chaining)
*
* The matrix is expanded to @relativeref{Magnum,Matrix3x4}, with the
* bottom row being zeros.
*/
TransformationUniform2D& setTransformationMatrix(const Matrix3& matrix) {
transformationMatrix = Matrix3x4{matrix};
return *this;
}
/**
* @}
*/
/**
* @brief Transformation matrix
*
* Default value is an identity matrix. The bottom row is unused and acts
* only as a padding to match uniform buffer packing rules.
*/
Matrix3x4 transformationMatrix;
};
/**
@brief 3D transformation uniform common for all shaders
@m_since_latest
Contains the per-draw transformation matrix used by the @ref MeshVisualizerGL3D
and @ref PhongGL shaders that need a separate projection and transformation
matrix.
@see @ref MeshVisualizerGL3D::bindTransformationBuffer(),
@ref PhongGL::bindTransformationBuffer()
*/
struct TransformationUniform3D {
/** @brief Construct with default parameters */
constexpr explicit TransformationUniform3D(DefaultInitT = DefaultInit) noexcept: transformationMatrix{Math::IdentityInit} {}
/** @brief Construct without initializing the contents */
explicit TransformationUniform3D(NoInitT) noexcept: transformationMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
CORRADE_DEPRECATED_FILE("use Magnum/Shaders/GenericGL.h, the GenericGL class and related typedefs instead")
/**
* @brief Set the @ref transformationMatrix field
* @return Reference to self (for method chaining)
*/
TransformationUniform3D& setTransformationMatrix(const Matrix4& matrix) {
transformationMatrix = matrix;
return *this;
}
/**
* @}
*/
/**
* @brief Transformation matrix
*
* Default value is an identity matrix.
*
* If @ref PhongGL::Flag::InstancedTransformation is enabled, the
* per-instance transformation coming from the
* @ref PhongGL::TransformationMatrix attribute is applied first, before
* this one.
* @see @ref PhongGL::setTransformationMatrix(),
* @ref MeshVisualizerGL3D::setTransformationMatrix()
*/
Matrix4 transformationMatrix;
};
/**
@brief Combined 2D projection and transformation uniform common for all shaders
@m_since_latest
Used by @ref FlatGL, @ref MeshVisualizerGL2D, @ref DistanceFieldVectorGL,
@ref VectorGL and @ref VertexColorGL that don't need to have a separate
projection matrix supplied.
@see @ref DistanceFieldVectorGL2D::bindTransformationProjectionBuffer(),
@ref FlatGL2D::bindTransformationProjectionBuffer(),
@ref MeshVisualizerGL2D::bindTransformationProjectionBuffer(),
@ref VectorGL2D::bindTransformationProjectionBuffer(),
@ref VertexColorGL2D::bindTransformationProjectionBuffer()
*/
struct TransformationProjectionUniform2D {
/** @brief Construct with default parameters */
constexpr explicit TransformationProjectionUniform2D(DefaultInitT = DefaultInit) noexcept: transformationProjectionMatrix{Math::IdentityInit} {}
/** @brief Construct without initializing the contents */
explicit TransformationProjectionUniform2D(NoInitT) noexcept: transformationProjectionMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref transformationProjectionMatrix field
* @return Reference to self (for method chaining)
*
* The matrix is expanded to @relativeref{Magnum,Matrix3x4}, with the
* bottom row being zeros.
*/
TransformationProjectionUniform2D& setTransformationProjectionMatrix(const Matrix3& matrix) {
transformationProjectionMatrix = Matrix3x4{matrix};
return *this;
}
/**
* @}
*/
/**
* @brief Transformation and projection matrix
*
* Default value is an identity matrix. The bottom row is unused and acts
* only as a padding to match uniform buffer packing rules.
*
* If @ref FlatGL::Flag::InstancedTransformation is enabled, the
* per-instance transformation coming from the
* @ref FlatGL::TransformationMatrix attribute is applied first, before
* this one.
* @see @ref DistanceFieldVectorGL2D::setTransformationProjectionMatrix(),
* @ref FlatGL2D::setTransformationProjectionMatrix(),
* @ref MeshVisualizerGL2D::setTransformationProjectionMatrix(),
* @ref VectorGL2D::setTransformationProjectionMatrix(),
* @ref VertexColorGL2D::setTransformationProjectionMatrix()
*/
Matrix3x4 transformationProjectionMatrix;
};
/**
@brief Combined 3D projection and transformation uniform common for all shaders
@m_since_latest
Used by @ref FlatGL, @ref DistanceFieldVectorGL, @ref VectorGL and
@ref VertexColorGL that don't need to have a separate projection matrix
supplied.
@see @ref DistanceFieldVectorGL3D::bindTransformationProjectionBuffer(),
@ref FlatGL3D::bindTransformationProjectionBuffer(),
@ref VectorGL3D::bindTransformationProjectionBuffer(),
@ref VertexColorGL3D::bindTransformationProjectionBuffer()
*/
struct TransformationProjectionUniform3D {
/** @brief Construct with default parameters */
constexpr explicit TransformationProjectionUniform3D(DefaultInitT = DefaultInit) noexcept: transformationProjectionMatrix{Math::IdentityInit} {}
/** @brief Construct without initializing the contents */
explicit TransformationProjectionUniform3D(NoInitT) noexcept: transformationProjectionMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref transformationProjectionMatrix field
* @return Reference to self (for method chaining)
*/
TransformationProjectionUniform3D& setTransformationProjectionMatrix(const Matrix4& matrix) {
transformationProjectionMatrix = matrix;
return *this;
}
/**
* @}
*/
/**
* @brief Transformation and projection matrix
*
* Default value is an identity matrix.
*
* If @ref FlatGL::Flag::InstancedTransformation is enabled, the
* per-instance transformation coming from the
* @ref FlatGL::TransformationMatrix attribute is applied first, before
* this one.
* @see @ref DistanceFieldVectorGL3D::setTransformationProjectionMatrix(),
* @ref FlatGL3D::setTransformationProjectionMatrix(),
* @ref VectorGL3D::setTransformationProjectionMatrix(),
* @ref VertexColorGL3D::setTransformationProjectionMatrix()
*/
Matrix4 transformationProjectionMatrix;
};
/**
@brief Texture transformation uniform common for all shaders
@m_since_latest
Expands upon @ref TransformationUniform2D / @ref TransformationUniform3D with
texture-related parameters.
Used only if @ref DistanceFieldVectorGL::Flag::TextureTransformation,
@ref FlatGL::Flag::TextureTransformation,
@ref PhongGL::Flag::TextureTransformation or
@ref VectorGL::Flag::TextureTransformation is enabled.
@see @ref DistanceFieldVectorGL::bindTextureTransformationBuffer(),
@ref FlatGL::bindTextureTransformationBuffer(),
@ref PhongGL::bindTextureTransformationBuffer(),
@ref VectorGL::bindTextureTransformationBuffer()
*/
struct TextureTransformationUniform {
/** @brief Construct with default parameters */
constexpr explicit TextureTransformationUniform(DefaultInitT = DefaultInit) noexcept: rotationScaling{Math::IdentityInit} {}
/** @brief Construct without initializing the contents */
explicit TextureTransformationUniform(NoInitT) noexcept: rotationScaling{NoInit}, offset{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref rotationScaling and @ref offset fields
* @return Reference to self (for method chaining)
*
* The @ref rotationScaling field is set to the upper left 2x2 corner of
* @p transformation, @ref offset to the two upper elements of the
* rightmost column of @p transformation. Bottom row is ignored, as it's
* expected to be always @cpp {0.0f, 0.0f, 1.0f} @ce.
*/
TextureTransformationUniform& setTextureMatrix(const Matrix3& transformation) {
rotationScaling = transformation.rotationScaling();
offset = transformation.translation();
return *this;
}
/**
* @}
*/
/**
* @brief Texture rotation and scaling
*
* The top left part of a 3x3 texture transformation matrix. The
* transformation is split between @ref rotationScaling and @ref offset to
* make it occupy just two @cb{.glsl} vec4 @ce slots in the uniform buffer
* instead of three. Default value is an identity matrix.
*
* If @ref FlatGL::Flag::InstancedTextureOffset /
* @ref PhongGL::Flag::InstancedTextureOffset is enabled, the
* per-instance offset coming from the @ref FlatGL::TextureOffset /
* @ref PhongGL::TextureOffset attribute is applied first, before
* this transformation.
* @see @ref DistanceFieldVectorGL::setTextureMatrix(),
* @ref FlatGL::setTextureMatrix(), @ref PhongGL::setTextureMatrix(),
* @ref VectorGL::setTextureMatrix()
*/
Matrix2x2 rotationScaling;
/**
* @brief Texture offset
*
* Top two elements of the rightmost column of a 3x3 texture transformation
* matrix. The transformation is split between @ref rotationScaling and
* @ref offset to make it occupy just two @cb{.glsl} vec4 @ce slots in the
* uniform buffer instead of three. Default value is a zero vector.
*
* If @ref FlatGL::Flag::InstancedTextureOffset /
* @ref PhongGL::Flag::InstancedTextureOffset is enabled, the
* per-instance offset coming from the @ref FlatGL::TextureOffset /
* @ref PhongGL::TextureOffset attribute is applied first, before
* this transformation.
* @see @ref DistanceFieldVectorGL::setTextureMatrix(),
* @ref FlatGL::setTextureMatrix(), @ref PhongGL::setTextureMatrix(),
* @ref VectorGL::setTextureMatrix()
*/
Vector2 offset;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32; /* reserved for layer */
Int:32; /* reserved for coordinateSet */
#endif
};
#ifdef MAGNUM_BUILD_DEPRECATED
/* Deprecated aliases not present here but in GenericGL.h instead, as a lot of
existing code relies on these being transitively included from Phong.h etc.,
and there are no forward declarations in Shaders.h as the type is never used
like that. While we *could* include Generic.h from Phong.h, we'd have to
also temporarily disable the CORRADE_DEPRECATED_FILE() macro there and it's
more pain than it's worth. */
#else
#error use Magnum/Shaders/GenericGL.h, the GenericGL class and related typedefs instead
#endif
}}
#endif

79
src/Magnum/Shaders/MeshVisualizer.frag

@ -46,6 +46,7 @@
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#if (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(VERTEX_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID)) && !defined(TBN_DIRECTION)
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
@ -110,6 +111,64 @@ uniform lowp vec2 colorMapOffsetScale
#define colorMapScale colorMapOffsetScale.y
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't
"outsource" to a common file because the extension directives need to be
always before any code. */
struct DrawUniform {
#ifdef THREE_DIMENSIONS
highp mat3 normalMatrix; /* actually mat3x4 */
#elif !defined(TWO_DIMENSIONS)
#error
#endif
highp uvec4 materialIdReservedReservedReservedReserved;
#define draw_materialIdReserved materialIdReservedReservedReservedReserved.x
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.geom. Can't
"outsource" to a common file because the extension directives need to be
always before any code. */
struct MaterialUniform {
lowp vec4 color;
lowp vec4 wireframeColor;
lowp vec4 wireframeWidthColorMapOffsetColorMapScaleLineWidth;
#define material_wireframeWidth wireframeWidthColorMapOffsetColorMapScaleLineWidth.x
#define material_colorMapOffset wireframeWidthColorMapOffsetColorMapScaleLineWidth.y
#define material_colorMapScale wireframeWidthColorMapOffsetColorMapScaleLineWidth.z
#define material_lineWidth wireframeWidthColorMapOffsetColorMapScaleLineWidth.w
lowp vec4 lineLengthSmoothnessReservedReserved;
#define material_lineLength lineLengthSmoothnessReservedReserved.x
#define material_smoothness lineLengthSmoothnessReservedReserved.y
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
};
#endif
/* Textures */
#if defined(INSTANCED_OBJECT_ID) || defined(VERTEX_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID)
@ -157,6 +216,26 @@ out lowp vec4 fragmentColor;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu;
#if (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(VERTEX_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID)) && !defined(TBN_DIRECTION)
lowp const vec4 color = materials[materialId].color;
lowp const vec4 wireframeColor = materials[materialId].wireframeColor;
#endif
#ifdef WIREFRAME_RENDERING
lowp const float wireframeWidth = materials[materialId].material_wireframeWidth;
#elif defined(TBN_DIRECTION)
lowp const float lineWidth = materials[materialId].material_lineWidth;
#endif
#if defined(WIREFRAME_RENDERING) || defined(TBN_DIRECTION)
lowp const float smoothness = materials[materialId].material_smoothness;
#endif
#if defined(INSTANCED_OBJECT_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID)
lowp const float colorMapOffset = materials[materialId].material_colorMapOffset;
lowp const float colorMapScale = materials[materialId].material_colorMapScale;
#endif
#endif
/* Map object/vertex/primitive ID to a color. Will be either combined with
the wireframe background color (if wireframe is enabled), ignored (if
rendering TBN direction) or used as-is if nothing else is enabled */

107
src/Magnum/Shaders/MeshVisualizer.geom

@ -36,12 +36,14 @@
/* Uniforms */
/* This one is for both classic and UBOs, as it's usually set globally instead
of changing per-draw */
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 5)
#endif
uniform lowp vec2 viewportSize; /* defaults to zero */
#ifndef UNIFORM_BUFFERS
#if (defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION)) && (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID))
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 1)
@ -82,6 +84,64 @@ uniform lowp float smoothness
;
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't
"outsource" to a common file because the #extension directives need to be
always before any code. */
struct DrawUniform {
#ifdef THREE_DIMENSIONS
highp mat3 normalMatrix; /* actually mat3x4 */
#elif !defined(TWO_DIMENSIONS)
#error
#endif
highp uvec4 materialIdReservedReservedReservedReserved;
#define draw_materialIdReserved materialIdReservedReservedReservedReserved.x
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
/* Keep in sync with MeshVisualizer.vert and MeshVisualizer.frag. Can't
"outsource" to a common file because the #extension directives need to be
always before any code. */
struct MaterialUniform {
lowp vec4 color;
lowp vec4 wireframeColor;
lowp vec4 wireframeWidthColorMapOffsetColorMapScaleLineWidth;
#define material_wireframeWidth wireframeWidthColorMapOffsetColorMapScaleLineWidth.x
#define material_colorMapOffset wireframeWidthColorMapOffsetColorMapScaleLineWidth.y
#define material_colorMapScale wireframeWidthColorMapOffsetColorMapScaleLineWidth.z
#define material_lineWidth wireframeWidthColorMapOffsetColorMapScaleLineWidth.w
lowp vec4 lineLengthSmoothnessReservedReserved;
#define material_lineLength lineLengthSmoothnessReservedReserved.x
#define material_smoothness lineLengthSmoothnessReservedReserved.y
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
};
#endif
/* Inputs */
layout(triangles) in;
@ -130,7 +190,17 @@ flat out highp uint interpolatedPrimitiveId;
out lowp vec4 backgroundColor;
out lowp vec4 lineColor;
void emitQuad(vec4 position, vec2 positionScreen, vec4 endpoint, vec2 endpointScreen) {
void emitQuad(
#ifdef UNIFORM_BUFFERS
uint materialId,
#endif
vec4 position, vec2 positionScreen, vec4 endpoint, vec2 endpointScreen
) {
#if defined(UNIFORM_BUFFERS) && (defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION))
lowp const float lineWidth = materials[materialId].material_lineWidth;
lowp const float smoothness = materials[materialId].material_smoothness;
#endif
/* Calculate screen-space locations for the bar vertices and form two
triangles out of them. In case TBN is rendered alone, half bar width is
lineWidth + smoothness to allow for antialiasing, in case it's rendered
@ -184,6 +254,18 @@ void emitQuad(vec4 position, vec2 positionScreen, vec4 endpoint, vec2 endpointSc
#endif
void main() {
#ifdef UNIFORM_BUFFERS
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu;
#if (defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION)) && (defined(WIREFRAME_RENDERING) || defined(INSTANCED_OBJECT_ID) || defined(PRIMITIVE_ID) || defined(PRIMITIVE_ID_FROM_VERTEX_ID))
lowp const vec4 color = materials[materialId].color;
lowp const vec4 wireframeColor = materials[materialId].wireframeColor;
#endif
#if defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(NORMAL_DIRECTION)
lowp const float lineWidth = materials[materialId].material_lineWidth;
lowp const float smoothness = materials[materialId].material_smoothness;
#endif
#endif
/* Passthrough for unchanged variables */
#ifdef INSTANCED_OBJECT_ID
interpolatedInstanceObjectId = interpolatedVsInstanceObjectId[0];
@ -262,17 +344,32 @@ void main() {
for(int i = 0; i != 3; ++i) {
#ifdef TANGENT_DIRECTION
lineColor = vec4(1.0, 0.0, 0.0, 1.0);
emitQuad(gl_in[i].gl_Position, p[i], tangentEndpoint[i], t[i]);
emitQuad(
#ifdef UNIFORM_BUFFERS
materialId,
#endif
gl_in[i].gl_Position, p[i], tangentEndpoint[i], t[i]
);
#endif
#ifdef BITANGENT_DIRECTION
lineColor = vec4(0.0, 1.0, 0.0, 1.0);
emitQuad(gl_in[i].gl_Position, p[i], bitangentEndpoint[i], b[i]);
emitQuad(
#ifdef UNIFORM_BUFFERS
materialId,
#endif
gl_in[i].gl_Position, p[i], bitangentEndpoint[i], b[i]
);
#endif
#ifdef NORMAL_DIRECTION
lineColor = vec4(0.0, 0.0, 1.0, 1.0);
emitQuad(gl_in[i].gl_Position, p[i], normalEndpoint[i], n[i]);
emitQuad(
#ifdef UNIFORM_BUFFERS
materialId,
#endif
gl_in[i].gl_Position, p[i], normalEndpoint[i], n[i]
);
#endif
}
#endif

416
src/Magnum/Shaders/MeshVisualizer.h

@ -25,27 +25,419 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file
* @brief Typedef @ref Magnum::Shaders::MeshVisualizer2D, @ref Magnum::Shaders::MeshVisualizer3D
* @m_deprecated_since_latest Use @ref Magnum/Shaders/MeshVisualizerGL.h and
* the @ref Magnum::Shaders::MeshVisualizerGL2D "MeshVisualizerGL2D" /
* @ref Magnum::Shaders::MeshVisualizerGL3D "MeshVisualizerGL3D" class
* instead
* @brief Struct @ref Magnum::Shaders::MeshVisualizerDrawUniform2D, @ref Magnum::Shaders::MeshVisualizerDrawUniform3D, @ref Magnum::Shaders::MeshVisualizerMaterialUniform
*/
#endif
#include "Magnum/configure.h"
#include "Magnum/Magnum.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Matrix.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#include "Magnum/Shaders/MeshVisualizerGL.h"
CORRADE_DEPRECATED_FILE("use Magnum/Shaders/MeshVisualizerGL.h and the MeshVisualizerGL2D / MeshVisualizer3D class instead")
#endif
namespace Magnum { namespace Shaders {
/**
@brief Per-draw uniform for 2D mesh visualizer shaders
@m_since_latest
Together with the generic @ref TransformationProjectionUniform2D contains
parameters that are specific to each draw call. Material-related properties are
expected to be shared among multiple draw calls and thus are provided in a
separate @ref MeshVisualizerMaterialUniform structure, referenced by
@ref materialId.
@see @ref MeshVisualizerGL2D::bindDrawBuffer()
*/
struct MeshVisualizerDrawUniform2D {
/** @brief Construct with default parameters */
constexpr explicit MeshVisualizerDrawUniform2D(DefaultInitT = DefaultInit) noexcept: materialId{0} {}
/** @brief Construct without initializing the contents */
explicit MeshVisualizerDrawUniform2D(NoInitT) noexcept {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref materialId field
* @return Reference to self (for method chaining)
*/
MeshVisualizerDrawUniform2D& setMaterialId(UnsignedInt id) {
materialId = id;
return *this;
}
/**
* @}
*/
/** @var materialId
* @brief Material ID
*
* References a particular material from a
* @ref MeshVisualizerMaterialUniform array. Useful when an UBO with
* more than one material is supplied or in a multi-draw scenario. Should
* be less than the material count passed to the @ref MeshVisualizerGL2D::MeshVisualizerGL2D(Flags, UnsignedInt, UnsignedInt)
* / @ref MeshVisualizerGL3D::MeshVisualizerGL3D(Flags, UnsignedInt, UnsignedInt)
* constructor. Default value is @cpp 0 @ce, meaning the first material
* gets used.
*/
/* This field is an UnsignedInt in the shader and materialId is extracted
as (value & 0xffff), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort materialId;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
UnsignedShort:16; /* reserved for skinOffset */
#endif
#else
UnsignedShort:16; /* reserved for skinOffset */
UnsignedShort materialId;
#endif
/* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32;
Int:32;
Int:32;
#endif
};
/**
@brief Per-draw uniform for 3D mesh visualizer shaders
@m_since_latest
Together with the generic @ref TransformationUniform3D contains parameters that
are specific to each draw call. Material-related properties are expected to be
shared among multiple draw calls and thus are provided in a separate
@ref MeshVisualizerMaterialUniform structure, referenced by @ref materialId.
@see @ref MeshVisualizerGL3D::bindDrawBuffer()
*/
struct MeshVisualizerDrawUniform3D {
/** @brief Construct with default parameters */
constexpr explicit MeshVisualizerDrawUniform3D(DefaultInitT = DefaultInit) noexcept: normalMatrix{Math::IdentityInit}, materialId{0} {}
/** @brief Construct without initializing the contents */
explicit MeshVisualizerDrawUniform3D(NoInitT) noexcept: normalMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref normalMatrix field
* @return Reference to self (for method chaining)
*
* The matrix is expanded to @relativeref{Magnum,Matrix3x4}, with the
* bottom row being zeros.
*/
MeshVisualizerDrawUniform3D& setNormalMatrix(const Matrix3x3& matrix) {
normalMatrix = Matrix3x4{matrix};
return *this;
}
/**
* @brief Set the @ref materialId field
* @return Reference to self (for method chaining)
*/
MeshVisualizerDrawUniform3D& setMaterialId(UnsignedInt id) {
materialId = id;
return *this;
}
/**
* @}
*/
/**
* @brief Normal matrix
*
* Default value is an identity matrix. The bottom row is unused and acts
* only as a padding to match uniform buffer packing rules.
* @see @ref MeshVisualizerGL3D::setNormalMatrix()
*/
Matrix3x4 normalMatrix;
/** @var materialId
* @brief Material ID
*
* References a particular material from a
* @ref MeshVisualizerMaterialUniform array. Useful when an UBO with
* more than one material is supplied or in a multi-draw scenario. Should
* be less than the material count passed to @ref MeshVisualizerGL2D /
* @ref MeshVisualizerGL3D constructor. Default value is @cpp 0 @ce,
* meaning the first material gets used.
*/
/* This field is an UnsignedInt in the shader and materialId is extracted
as (value & 0xffff), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort materialId;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
UnsignedShort:16; /* reserved for skinOffset */
#endif
#else
UnsignedShort:16; /* reserved for skinOffset */
UnsignedShort materialId;
#endif
/* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32;
Int:32;
Int:32;
#endif
};
/**
@brief Material uniform for mesh visualizer shaders
@m_since_latest
Describes material properties referenced from
@ref MeshVisualizerDrawUniform2D::materialId and
@ref MeshVisualizerDrawUniform3D::materialId.
*/
struct MeshVisualizerMaterialUniform {
/** @brief Construct with default parameters */
constexpr explicit MeshVisualizerMaterialUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, wireframeColor{0.0f, 0.0f, 0.0f, 1.0f}, wireframeWidth{1.0f}, colorMapOffset{1.0f/512.0f}, colorMapScale{1.0f/256.0f}, lineWidth{1.0f}, lineLength{1.0f}, smoothness{2.0f} {}
/** @brief Construct without initializing the contents */
explicit MeshVisualizerMaterialUniform(NoInitT) noexcept: color{NoInit}, wireframeColor{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref color field
* @return Reference to self (for method chaining)
*/
MeshVisualizerMaterialUniform& setColor(const Color4& color) {
this->color = color;
return *this;
}
/**
* @brief Set the @ref wireframeColor field
* @return Reference to self (for method chaining)
*/
MeshVisualizerMaterialUniform& setWireframeColor(const Color4& color) {
wireframeColor = color;
return *this;
}
/**
* @brief Set the @ref wireframeWidth field
* @return Reference to self (for method chaining)
*/
MeshVisualizerMaterialUniform& setWireframeWidth(Float width) {
wireframeWidth = width;
return *this;
}
/**
* @brief Set the @ref colorMapOffset and @ref colorMapScale fields
* @return Reference to self (for method chaining)
*/
MeshVisualizerMaterialUniform& setColorMapTransformation(Float offset, Float scale) {
colorMapOffset = offset;
colorMapScale = scale;
return *this;
}
/**
* @brief Set the @ref lineWidth field
* @return Reference to self (for method chaining)
*/
MeshVisualizerMaterialUniform& setLineWidth(Float width) {
lineWidth = width;
return *this;
}
/**
* @brief Set the @ref lineLength field
* @return Reference to self (for method chaining)
*/
MeshVisualizerMaterialUniform& setLineLength(Float length) {
lineLength = length;
return *this;
}
/**
* @brief Set the @ref smoothness field
* @return Reference to self (for method chaining)
*/
MeshVisualizerMaterialUniform& setSmoothness(Float smoothness) {
this->smoothness = smoothness;
return *this;
}
/**
* @}
*/
/**
* @brief Base object color
*
* Default value is @cpp 0xffffffff_rgbaf @ce.
*
* Used only if @ref MeshVisualizerGL3D::Flag::Wireframe "MeshVisualizerGL*D::Flag::Wireframe"
* or @relativeref{MeshVisualizerGL3D,Flag::InstancedObjectId} /
* @relativeref{MeshVisualizerGL3D,Flag::PrimitiveId} /
* @relativeref{MeshVisualizerGL3D,Flag::PrimitiveIdFromVertexId} is
* enabled. In case of the latter, the color is multiplied with the color
* map coming from @ref MeshVisualizerGL3D::bindColorMapTexture() "MeshVisualizerGL*D::bindColorMapTexture()".
* @see @ref MeshVisualizerGL2D::setColor(),
* @ref MeshVisualizerGL3D::setColor()
*/
Color4 color;
/**
* @brief Wireframe color
*
* Default value is @cpp 0x000000ff_rgbaf @ce.
*
* Used only if @ref MeshVisualizerGL3D::Flag::Wireframe "MeshVisualizerGL*D::Flag::Wireframe"
* is enabled.
* @see @ref MeshVisualizerGL2D::setWireframeColor(),
* @ref MeshVisualizerGL3D::setWireframeColor()
*/
Color4 wireframeColor;
/**
* @brief Wireframe width
*
* The value is in screen space (depending on
* @ref MeshVisualizerGL3D::setViewportSize() "MeshVisualizerGL*D::setViewportSize()"),
* default value is @cpp 1.0f @ce.
*
* Used only if @ref MeshVisualizerGL3D::Flag::Wireframe "MeshVisualizerGL*D::Flag::Wireframe"
* is enabled.
* @see @ref MeshVisualizerGL2D::setWireframeWidth(),
* @ref MeshVisualizerGL3D::setWireframeWidth()
*/
Float wireframeWidth;
/**
* @brief Color map offset
*
* Together with @ref colorMapScale forms an offset and scale applied to
* the input value coming either from the
* @ref MeshVisualizerGL3D::ObjectId "MeshVisualizerGL*D::ObjectId"
* attribute or @glsl gl_PrimitiveID @ce, resulting value is then used to
* fetch a color from a color map bound with @ref MeshVisualizerGL3D::bindColorMapTexture() "MeshVisualizerGL*D::bindColorMapTexture()".
* Default offset and scale values are @cpp 1.0f/512.0f @ce and
* @cpp 1.0/256.0f @ce, meaning that for a 256-entry colormap the first 256
* values get an exact color from it and the next values will be either
* clamped to last color or repeated depending on the color map texture
* wrapping mode.
*
* Used only if @ref MeshVisualizerGL3D::Flag::InstancedObjectId "MeshVisualizerGL*D::Flag::InstancedObjectId" or
* @relativeref{MeshVisualizerGL3D,Flag::PrimitiveId} /
* @relativeref{MeshVisualizerGL3D,Flag::PrimitiveIdFromVertexId} is
* enabled.
* @see @ref MeshVisualizerGL2D::setColorMapTransformation(),
* @ref MeshVisualizerGL3D::setColorMapTransformation()
*/
Float colorMapOffset;
/**
* @brief Color map offset
*
* See @ref colorMapOffset for more information.
*
* Used only by @ref MeshVisualizerGL3D and only if
* @ref MeshVisualizerGL3D::Flag::InstancedObjectId "MeshVisualizerGL*D::Flag::InstancedObjectId" or
* @relativeref{MeshVisualizerGL3D,Flag::PrimitiveId} /
* @relativeref{MeshVisualizerGL3D,Flag::PrimitiveIdFromVertexId} is
* enabled.
* @see @ref MeshVisualizerGL2D::setColorMapTransformation(),
* @ref MeshVisualizerGL3D::setColorMapTransformation()
*/
Float colorMapScale;
/**
* @brief Line width
*
* The value is in screen space (depending on
* @ref MeshVisualizerGL3D::setViewportSize() "MeshVisualizerGL*D::setViewportSize()"),
* default value is @cpp 1.0f @ce.
*
* Used only by @ref MeshVisualizerGL3D and only if
* @ref MeshVisualizerGL3D::Flag::TangentDirection,
* @relativeref{MeshVisualizerGL3D,Flag::BitangentFromTangentDirection},
* @relativeref{MeshVisualizerGL3D,Flag::BitangentDirection} or
* @relativeref{MeshVisualizerGL3D,Flag::NormalDirection} is enabled.
* @see @ref MeshVisualizerGL3D::setLineWidth()
*/
Float lineWidth;
/**
* @brief Line length
*
* The value is in object space, default value is @cpp 1.0f @ce.
*
* Used only by @ref MeshVisualizerGL3D and only if
* @ref MeshVisualizerGL3D::Flag::TangentDirection,
* @relativeref{MeshVisualizerGL3D,Flag::BitangentFromTangentDirection},
* @relativeref{MeshVisualizerGL3D,Flag::BitangentDirection} or
* @relativeref{MeshVisualizerGL3D,Flag::NormalDirection} is enabled.
* @see @ref MeshVisualizerGL3D::setLineLength()
*/
Float lineLength;
/**
* @brief Line smoothness
*
* The value is in screen space (depending on
* @ref MeshVisualizerGL3D::setViewportSize() "MeshVisualizerGL*D::setViewportSize()"),
* initial value is @cpp 2.0f @ce.
*
* Used only if @ref MeshVisualizerGL3D::Flag::Wireframe "MeshVisualizerGL*D::Flag::Wireframe",
* @ref MeshVisualizerGL3D::Flag::TangentDirection,
* @relativeref{MeshVisualizerGL3D,Flag::BitangentFromTangentDirection},
* @relativeref{MeshVisualizerGL3D,Flag::BitangentDirection} or
* @relativeref{MeshVisualizerGL3D,Flag::NormalDirection} is enabled.
* @see @ref MeshVisualizerGL2D::setSmoothness(),
* @ref MeshVisualizerGL3D::setSmoothness()
*/
Float smoothness;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32;
Int:32;
#endif
};
#ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief MeshVisualizerGL2D
* @m_deprecated_since_latest Use @ref MeshVisualizerGL2D instead.
*/
@ -60,10 +452,8 @@ typedef CORRADE_DEPRECATED("use MeshVisualizerGL3D instead") MeshVisualizerGL3D
* @m_deprecated_since{2020,06} Use @ref MeshVisualizerGL3D instead.
*/
typedef CORRADE_DEPRECATED("use MeshVisualizerGL3D instead") MeshVisualizerGL3D MeshVisualizer;
#endif
}}
#else
#error use Magnum/Shaders/MeshVisualizerGL.h and the MeshVisualizerGL2D / MeshVisualizer3D class instead
#endif
#endif

108
src/Magnum/Shaders/MeshVisualizer.vert

@ -32,8 +32,13 @@
#define out varying
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef TWO_DIMENSIONS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
@ -97,6 +102,92 @@ uniform highp float lineLength
;
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
#ifdef TWO_DIMENSIONS
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 1
#endif
) uniform TransformationProjection {
highp mat3 transformationProjectionMatrices[DRAW_COUNT];
};
#elif defined(THREE_DIMENSIONS)
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 0
#endif
) uniform Projection {
highp mat4 projectionMatrix;
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 1
#endif
) uniform Transformation {
highp mat4 transformationMatrices[DRAW_COUNT];
};
#else
#error
#endif
/* Keep in sync with MeshVisualizer.geom and MeshVisualizer.frag. Can't
"outsource" to a common file because the #extension directives need to be
always before any code. */
struct DrawUniform {
#ifdef THREE_DIMENSIONS
highp mat3 normalMatrix; /* actually mat3x4 */
#elif !defined(TWO_DIMENSIONS)
#error
#endif
highp uvec4 materialIdReservedReservedReservedReserved;
#define draw_materialIdReserved materialIdReservedReservedReservedReserved.x
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
/* Keep in sync with MeshVisualizer.geom and MeshVisualizer.frag. Can't
"outsource" to a common file because the #extension directives need to be
always before any code. */
struct MaterialUniform {
lowp vec4 color;
lowp vec4 wireframeColor;
lowp vec4 wireframeWidthColorMapOffsetColorMapScaleLineWidth;
#define material_wireframeWidth wireframeWidthColorMapOffsetColorMapScaleLineWidth.x
#define material_colorMapOffset wireframeWidthColorMapOffsetColorMapScaleLineWidth.y
#define material_colorMapScale wireframeWidthColorMapOffsetColorMapScaleLineWidth.z
#define material_lineWidth wireframeWidthColorMapOffsetColorMapScaleLineWidth.w
lowp vec4 lineLengthSmoothnessReservedReserved;
#define material_lineLength lineLengthSmoothnessReservedReserved.x
#define material_smoothness lineLengthSmoothnessReservedReserved.y
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
};
#endif
/* Inputs */
#ifdef EXPLICIT_ATTRIB_LOCATION
@ -189,6 +280,23 @@ out highp vec4 normalEndpoint;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
#ifdef TWO_DIMENSIONS
highp const mat3 transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
#elif defined(THREE_DIMENSIONS)
highp const mat4 transformationMatrix = transformationMatrices[drawOffset];
#else
#error
#endif
#if defined(TANGENT_DIRECTION) || defined(BITANGENT_DIRECTION) || defined(BITANGENT_FROM_TANGENT_DIRECTION) || defined(NORMAL_DIRECTION)
mediump const mat3 normalMatrix = draws[drawOffset].normalMatrix;
#endif
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu;
lowp float colorMapOffset = materials[materialId].material_colorMapOffset;
lowp float colorMapScale = materials[materialId].material_colorMapScale;
highp float lineLength = materials[materialId].material_lineLength;
#endif
#ifdef TWO_DIMENSIONS
gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0);
#elif defined(THREE_DIMENSIONS)

532
src/Magnum/Shaders/MeshVisualizerGL.cpp

@ -39,6 +39,10 @@
#include "Magnum/GL/Shader.h"
#include "Magnum/GL/Texture.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/Buffer.h"
#endif
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
namespace Magnum { namespace Shaders {
@ -48,11 +52,36 @@ namespace {
/* First four taken by Phong (A/D/S/N) */
ColorMapTextureUnit = 4
};
#ifndef MAGNUM_TARGET_GLES2
enum: Int {
ProjectionBufferBinding = 0,
/* Not using the zero binding to avoid conflicts with
ProjectionBufferBinding from the 3D variant which can likely stay
bound to the same buffer for the whole time */
TransformationProjectionBufferBinding = 1,
TransformationBufferBinding = 1,
DrawBufferBinding = 2,
/* Binding 3 is commonly used by TextureTransformationBufferBinding,
leave it reserved */
MaterialBufferBinding = 4,
};
#endif
}
namespace Implementation {
MeshVisualizerGLBase::MeshVisualizerGLBase(FlagsBase flags): _flags{flags} {
MeshVisualizerGLBase::MeshVisualizerGLBase(FlagsBase flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt materialCount, const UnsignedInt drawCount
#endif
):
_flags{flags}
#ifndef MAGNUM_TARGET_GLES2
, _materialCount{materialCount},
_drawCount{drawCount}
#endif
{
#ifndef MAGNUM_TARGET_GLES2
#ifndef CORRADE_NO_ASSERT
Int countMutuallyExclusive = 0;
@ -64,6 +93,11 @@ MeshVisualizerGLBase::MeshVisualizerGLBase(FlagsBase flags): _flags{flags} {
"Shaders::MeshVisualizerGL: Flag::InstancedObjectId, Flag::VertexId and Flag::PrimitiveId are mutually exclusive", );
#endif
#ifndef MAGNUM_TARGET_GLES
if(flags >= FlagBase::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#ifndef MAGNUM_TARGET_GLES2
if(_flags & FlagBase::Wireframe && !(_flags & FlagBase::NoGeometryShader)) {
#ifndef MAGNUM_TARGET_GLES
@ -126,6 +160,16 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
"#define SUBSCRIPTING_WORKAROUND\n" : "")
#endif
;
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= FlagBase::UniformBuffers) {
vert.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
_drawCount,
_materialCount));
}
#endif
frag.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
#ifndef MAGNUM_TARGET_GLES2
.addSource(_flags & FlagBase::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
@ -136,11 +180,25 @@ GL::Version MeshVisualizerGLBase::setupShaders(GL::Shader& vert, GL::Shader& fra
"#define PRIMITIVE_ID\n") : "")
#endif
;
#ifndef MAGNUM_TARGET_GLES2
if(_flags >= FlagBase::UniformBuffers) {
frag.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
_drawCount,
_materialCount));
}
#endif
return version;
}
MeshVisualizerGLBase& MeshVisualizerGLBase::setColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= FlagBase::UniformBuffers),
"Shaders::MeshVisualizerGL::setColor(): the shader was created with uniform buffers enabled", *this);
#endif
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(_flags & (FlagBase::Wireframe|FlagBase::InstancedObjectId|FlagBase::VertexId|FlagBase::PrimitiveId),
"Shaders::MeshVisualizerGL::setColor(): the shader was not created with wireframe or object/vertex/primitive ID enabled", *this);
@ -153,6 +211,10 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::setColor(const Color4& color) {
}
MeshVisualizerGLBase& MeshVisualizerGLBase::setWireframeColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= FlagBase::UniformBuffers),
"Shaders::MeshVisualizerGL::setWireframeColor(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & FlagBase::Wireframe,
"Shaders::MeshVisualizerGL::setWireframeColor(): the shader was not created with wireframe enabled", *this);
setUniform(_wireframeColorUniform, color);
@ -160,6 +222,10 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::setWireframeColor(const Color4& colo
}
MeshVisualizerGLBase& MeshVisualizerGLBase::setWireframeWidth(const Float width) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= FlagBase::UniformBuffers),
"Shaders::MeshVisualizerGL::setWireframeWidth(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & FlagBase::Wireframe,
"Shaders::MeshVisualizerGL::setWireframeWidth(): the shader was not created with wireframe enabled", *this);
setUniform(_wireframeWidthUniform, width);
@ -168,12 +234,41 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::setWireframeWidth(const Float width)
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGLBase& MeshVisualizerGLBase::setColorMapTransformation(const Float offset, const Float scale) {
CORRADE_ASSERT(!(_flags >= FlagBase::UniformBuffers),
"Shaders::MeshVisualizerGL::setColorMapTransformation(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & (FlagBase::InstancedObjectId|FlagBase::VertexId|FlagBase::PrimitiveId),
"Shaders::MeshVisualizerGL::setColorMapTransformation(): the shader was not created with object/vertex/primitive ID enabled", *this);
setUniform(_colorMapOffsetScaleUniform, Vector2{offset, scale});
return *this;
}
#endif
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGLBase& MeshVisualizerGLBase::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(offset < _drawCount,
"Shaders::MeshVisualizerGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
setUniform(_drawOffsetUniform, offset);
return *this;
}
MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
MeshVisualizerGLBase& MeshVisualizerGLBase::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= FlagBase::UniformBuffers,
"Shaders::MeshVisualizerGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
#endif
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGLBase& MeshVisualizerGLBase::bindColorMapTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(_flags & (FlagBase::InstancedObjectId|FlagBase::VertexId|FlagBase::PrimitiveId),
"Shaders::MeshVisualizerGL::bindColorMapTexture(): the shader was not created with object/vertex/primitive ID enabled", *this);
@ -184,7 +279,15 @@ MeshVisualizerGLBase& MeshVisualizerGLBase::bindColorMapTexture(GL::Texture2D& t
}
MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): Implementation::MeshVisualizerGLBase{Implementation::MeshVisualizerGLBase::FlagBase(UnsignedShort(flags))} {
MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt materialCount, const UnsignedInt drawCount
#endif
): Implementation::MeshVisualizerGLBase{Implementation::MeshVisualizerGLBase::FlagBase(UnsignedShort(flags))
#ifndef MAGNUM_TARGET_GLES2
, materialCount, drawCount
#endif
} {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(flags & ((Flag::Wireframe|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId) & ~Flag::NoGeometryShader),
"Shaders::MeshVisualizerGL2D: at least one visualization feature has to be enabled", );
@ -193,6 +296,16 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): Implementation::MeshV
"Shaders::MeshVisualizerGL2D: at least Flag::Wireframe has to be enabled", );
#endif
/* Has to be here and not in the base class in order to have it exit the
constructor when testing for asserts -- GLSL compilation would fail
otherwise */
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount,
"Shaders::MeshVisualizerGL2D: material count can't be zero", );
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::MeshVisualizerGL2D: draw count can't be zero", );
#endif
#ifndef MAGNUM_TARGET_GLES
const GL::Context& context = GL::Context::current();
#endif
@ -215,8 +328,12 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): Implementation::MeshV
nothing actually needs it, as that makes checks much simpler in
the shader code */
.addSource((flags & Flag::NoGeometryShader) || !(flags & Flag::Wireframe) ?
"#define NO_GEOMETRY_SHADER\n" : "")
.addSource(rs.get("generic.glsl"))
"#define NO_GEOMETRY_SHADER\n" : "");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers)
frag.addSource("#define TWO_DIMENSIONS\n");
#endif
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.frag"));
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
@ -230,8 +347,19 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): Implementation::MeshV
.addSource(_flags & FlagBase::PrimitiveId ?
(_flags >= FlagBase::PrimitiveIdFromVertexId ?
"#define PRIMITIVE_ID_FROM_VERTEX_ID\n" :
"#define PRIMITIVE_ID\n") : "")
.addSource(rs.get("MeshVisualizer.geom"));
"#define PRIMITIVE_ID\n") : "");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
geom->addSource(Utility::formatString(
"#define TWO_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
_drawCount,
_materialCount));
}
#endif
geom->addSource(rs.get("MeshVisualizer.geom"));
}
#else
static_cast<void>(version);
@ -276,25 +404,35 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): Implementation::MeshV
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
if(flags & (Flag::Wireframe
/* This one is used also in the UBO case as it's usually a global
setting */
if((flags & Flag::Wireframe) && !(flags & Flag::NoGeometryShader))
_viewportSizeUniform = uniformLocation("viewportSize");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
_drawOffsetUniform = uniformLocation("drawOffset");
} else
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
#endif
))
_colorUniform = uniformLocation("color");
if(flags & Flag::Wireframe) {
_wireframeColorUniform = uniformLocation("wireframeColor");
_wireframeWidthUniform = uniformLocation("wireframeWidth");
_smoothnessUniform = uniformLocation("smoothness");
}
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId)) {
_colorMapOffsetScaleUniform = uniformLocation("colorMapOffsetScale");
}
#endif
))
_colorUniform = uniformLocation("color");
if(flags & Flag::Wireframe) {
_wireframeColorUniform = uniformLocation("wireframeColor");
_wireframeWidthUniform = uniformLocation("wireframeWidth");
_smoothnessUniform = uniformLocation("smoothness");
if(!(flags & Flag::NoGeometryShader))
_viewportSizeUniform = uniformLocation("viewportSize");
}
#ifndef MAGNUM_TARGET_GLES2
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId)) {
_colorMapOffsetScaleUniform = uniformLocation("colorMapOffsetScale");
}
#endif
}
#ifndef MAGNUM_TARGET_GLES2
@ -305,31 +443,50 @@ MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): Implementation::MeshV
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId)) {
setUniform(uniformLocation("colorMapTexture"), ColorMapTextureUnit);
}
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding);
}
#endif
}
#endif
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix(Matrix3{Math::IdentityInit});
if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
/* Viewport size is zero by default */
/* Draw offset is zero by default */
} else
#endif
{
setTransformationProjectionMatrix(Matrix3{Math::IdentityInit});
if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
#endif
))
setColor(Color3(1.0f));
if(flags & Flag::Wireframe) {
/* Viewport size is zero by default */
setWireframeColor(Color3{0.0f});
setWireframeWidth(1.0f);
setSmoothness(2.0f);
}
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId))
setColorMapTransformation(1.0f/512.0f, 1.0f/256.0f);
#endif
))
setColor(Color3(1.0f));
if(flags & Flag::Wireframe) {
/* Viewport size is zero by default */
setWireframeColor(Color3{0.0f});
setWireframeWidth(1.0f);
setSmoothness(2.0f);
}
#ifndef MAGNUM_TARGET_GLES2
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId))
setColorMapTransformation(1.0f/512.0f, 1.0f/256.0f);
#endif
#endif
}
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL2D::MeshVisualizerGL2D(const Flags flags): MeshVisualizerGL2D{flags, 1, 1} {}
#endif
MeshVisualizerGL2D& MeshVisualizerGL2D::setViewportSize(const Vector2& size) {
/* Not asserting here, since the relation to wireframe is a bit vague.
Also it's an ugly hack that should be removed, ideally. */
@ -339,11 +496,19 @@ MeshVisualizerGL2D& MeshVisualizerGL2D::setViewportSize(const Vector2& size) {
}
MeshVisualizerGL2D& MeshVisualizerGL2D::setTransformationProjectionMatrix(const Matrix3& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL2D::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_transformationProjectionMatrixUniform, matrix);
return *this;
}
MeshVisualizerGL2D& MeshVisualizerGL2D::setSmoothness(const Float smoothness) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL2D::setSmoothness(): the shader was created with uniform buffers enabled", *this);
#endif
/* This is a bit vaguely related but less vague than setViewportSize() so
asserting in this case. */
CORRADE_ASSERT(flags() & Flag::Wireframe,
@ -352,7 +517,45 @@ MeshVisualizerGL2D& MeshVisualizerGL2D::setSmoothness(const Float smoothness) {
return *this;
}
MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): Implementation::MeshVisualizerGLBase{Implementation::MeshVisualizerGLBase::FlagBase(UnsignedShort(flags))} {
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
MeshVisualizerGL2D& MeshVisualizerGL2D::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
MeshVisualizerGL2D& MeshVisualizerGL2D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL2D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
#endif
MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt materialCount, const UnsignedInt drawCount
#endif
): Implementation::MeshVisualizerGLBase{Implementation::MeshVisualizerGLBase::FlagBase(UnsignedShort(flags))
#ifndef MAGNUM_TARGET_GLES2
, materialCount, drawCount
#endif
} {
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
CORRADE_ASSERT(flags & ((Flag::Wireframe|Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId) & ~Flag::NoGeometryShader),
"Shaders::MeshVisualizerGL3D: at least one visualization feature has to be enabled", );
@ -368,6 +571,16 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): Implementation::MeshV
"Shaders::MeshVisualizerGL3D: at least Flag::Wireframe has to be enabled", );
#endif
/* Has to be here and not in the base class in order to have it exit the
constructor when testing for asserts -- GLSL compilation would fail
otherwise */
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount,
"Shaders::MeshVisualizerGL3D: material count can't be zero", );
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::MeshVisualizerGL3D: draw count can't be zero", );
#endif
#ifndef MAGNUM_TARGET_GLES
const GL::Context& context = GL::Context::current();
#endif
@ -399,7 +612,8 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): Implementation::MeshV
.addSource(flags & Flag::BitangentDirection ? "#define BITANGENT_DIRECTION\n" : "")
.addSource(flags & Flag::NormalDirection ? "#define NORMAL_DIRECTION\n" : "")
#endif
.addSource(rs.get("generic.glsl"))
;
vert.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.vert"));
frag
/* Pass NO_GEOMETRY_SHADER not only when NoGeometryShader but also when
@ -413,7 +627,12 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): Implementation::MeshV
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
.addSource(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection) ? "#define TBN_DIRECTION\n" : "")
#endif
.addSource(rs.get("generic.glsl"))
;
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers)
frag.addSource("#define THREE_DIMENSIONS\n");
#endif
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.frag"));
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
@ -438,8 +657,19 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): Implementation::MeshV
"#define PRIMITIVE_ID\n") : "")
.addSource(flags & Flag::TangentDirection ? "#define TANGENT_DIRECTION\n" : "")
.addSource(flags & (Flag::BitangentDirection|Flag::BitangentFromTangentDirection) ? "#define BITANGENT_DIRECTION\n" : "")
.addSource(flags & Flag::NormalDirection ? "#define NORMAL_DIRECTION\n" : "")
.addSource(rs.get("MeshVisualizer.geom"));
.addSource(flags & Flag::NormalDirection ? "#define NORMAL_DIRECTION\n" : "");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
geom->addSource(Utility::formatString(
"#define THREE_DIMENSIONS\n"
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n",
_drawCount,
_materialCount));
}
#endif
geom->addSource(rs.get("MeshVisualizer.geom"));
}
#else
static_cast<void>(version);
@ -495,39 +725,53 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): Implementation::MeshV
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#endif
{
_transformationMatrixUniform = uniformLocation("transformationMatrix");
_projectionMatrixUniform = uniformLocation("projectionMatrix");
if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
#endif
))
_colorUniform = uniformLocation("color");
if(flags & Flag::Wireframe) {
_wireframeColorUniform = uniformLocation("wireframeColor");
_wireframeWidthUniform = uniformLocation("wireframeWidth");
}
if(flags & (Flag::Wireframe
/* This one is used also in the UBO case as it's usually a global
setting */
if(((flags & Flag::Wireframe) && !(flags & Flag::NoGeometryShader))
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
|Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection
|| (flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection))
#endif
)) {
_smoothnessUniform = uniformLocation("smoothness");
if(!(flags & Flag::NoGeometryShader))
_viewportSizeUniform = uniformLocation("viewportSize");
}
)
_viewportSizeUniform = uniformLocation("viewportSize");
#ifndef MAGNUM_TARGET_GLES2
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId)) {
_colorMapOffsetScaleUniform = uniformLocation("colorMapOffsetScale");
}
if(flags >= Flag::UniformBuffers) {
_drawOffsetUniform = uniformLocation("drawOffset");
} else
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection)) {
_normalMatrixUniform = uniformLocation("normalMatrix");
_lineWidthUniform = uniformLocation("lineWidth");
_lineLengthUniform = uniformLocation("lineLength");
{
_transformationMatrixUniform = uniformLocation("transformationMatrix");
_projectionMatrixUniform = uniformLocation("projectionMatrix");
if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
#endif
))
_colorUniform = uniformLocation("color");
if(flags & Flag::Wireframe) {
_wireframeColorUniform = uniformLocation("wireframeColor");
_wireframeWidthUniform = uniformLocation("wireframeWidth");
}
if(flags & (Flag::Wireframe
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
|Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection
#endif
)) {
_smoothnessUniform = uniformLocation("smoothness");
}
#ifndef MAGNUM_TARGET_GLES2
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId)) {
_colorMapOffsetScaleUniform = uniformLocation("colorMapOffsetScale");
}
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection)) {
_normalMatrixUniform = uniformLocation("normalMatrix");
_lineWidthUniform = uniformLocation("lineWidth");
_lineLengthUniform = uniformLocation("lineLength");
}
#endif
}
#endif
}
#ifndef MAGNUM_TARGET_GLES2
@ -538,57 +782,87 @@ MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): Implementation::MeshV
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId)) {
setUniform(uniformLocation("colorMapTexture"), ColorMapTextureUnit);
}
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
setUniformBlockBinding(uniformBlockIndex("Projection"), ProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Transformation"), TransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding);
}
#endif
}
#endif
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationMatrix(Matrix4{Math::IdentityInit});
setProjectionMatrix(Matrix4{Math::IdentityInit});
if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
/* Viewport size is zero by default */
/* Draw offset is zero by default */
} else
#endif
{
setTransformationMatrix(Matrix4{Math::IdentityInit});
setProjectionMatrix(Matrix4{Math::IdentityInit});
if(flags & (Flag::Wireframe
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
#endif
))
setColor(Color3(1.0f));
if(flags & Flag::Wireframe) {
/* Viewport size is zero by default */
setWireframeColor(Color3{0.0f});
setWireframeWidth(1.0f);
}
if(flags & (Flag::Wireframe
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
|Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection
#endif
)) {
setSmoothness(2.0f);
}
#ifndef MAGNUM_TARGET_GLES2
|Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId))
setColorMapTransformation(1.0f/512.0f, 1.0f/256.0f);
#endif
))
setColor(Color3(1.0f));
if(flags & Flag::Wireframe) {
/* Viewport size is zero by default */
setWireframeColor(Color3{0.0f});
setWireframeWidth(1.0f);
}
if(flags & (Flag::Wireframe
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
|Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection
if(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection)) {
setNormalMatrix(Matrix3x3{Math::IdentityInit});
setLineWidth(1.0f);
setLineLength(1.0f);
}
#endif
)) {
setSmoothness(2.0f);
}
#ifndef MAGNUM_TARGET_GLES2
if(flags & (Flag::InstancedObjectId|Flag::VertexId|Flag::PrimitiveIdFromVertexId))
setColorMapTransformation(1.0f/512.0f, 1.0f/256.0f);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(flags & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection)) {
setNormalMatrix(Matrix3x3{Math::IdentityInit});
setLineWidth(1.0f);
setLineLength(1.0f);
}
#endif
#endif
}
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL3D::MeshVisualizerGL3D(const Flags flags): MeshVisualizerGL3D{flags, 1, 1} {}
#endif
MeshVisualizerGL3D& MeshVisualizerGL3D::setTransformationMatrix(const Matrix4& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL3D::setTransformationMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_transformationMatrixUniform, matrix);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::setProjectionMatrix(const Matrix4& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL3D::setProjectionMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_projectionMatrixUniform, matrix);
return *this;
}
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
MeshVisualizerGL3D& MeshVisualizerGL3D::setNormalMatrix(const Matrix3x3& matrix) {
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL3D::setNormalMatrix(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(flags() & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection),
"Shaders::MeshVisualizerGL3D::setNormalMatrix(): the shader was not created with TBN direction enabled", *this);
setUniform(_normalMatrixUniform, matrix);
@ -610,6 +884,8 @@ MeshVisualizerGL3D& MeshVisualizerGL3D::setViewportSize(const Vector2& size) {
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
MeshVisualizerGL3D& MeshVisualizerGL3D::setLineWidth(const Float width) {
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL3D::setLineWidth(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(flags() & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection),
"Shaders::MeshVisualizerGL3D::setLineWidth(): the shader was not created with TBN direction enabled", *this);
setUniform(_lineWidthUniform, width);
@ -617,6 +893,8 @@ MeshVisualizerGL3D& MeshVisualizerGL3D::setLineWidth(const Float width) {
}
MeshVisualizerGL3D& MeshVisualizerGL3D::setLineLength(const Float length) {
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL3D::setLineLength(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(flags() & (Flag::TangentDirection|Flag::BitangentFromTangentDirection|Flag::BitangentDirection|Flag::NormalDirection),
"Shaders::MeshVisualizerGL3D::setLineLength(): the shader was not created with TBN direction enabled", *this);
setUniform(_lineLengthUniform, length);
@ -625,6 +903,10 @@ MeshVisualizerGL3D& MeshVisualizerGL3D::setLineLength(const Float length) {
#endif
MeshVisualizerGL3D& MeshVisualizerGL3D::setSmoothness(const Float smoothness) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags() >= Flag::UniformBuffers),
"Shaders::MeshVisualizerGL3D::setSmoothness(): the shader was created with uniform buffers enabled", *this);
#endif
#ifndef CORRADE_NO_ASSERT
/* This is a bit vaguely related but less vague than setViewportSize() so
asserting in this case. */
@ -640,6 +922,50 @@ MeshVisualizerGL3D& MeshVisualizerGL3D::setSmoothness(const Float smoothness) {
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding, offset, size);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding, offset, size);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
MeshVisualizerGL3D& MeshVisualizerGL3D::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(flags() >= Flag::UniformBuffers,
"Shaders::MeshVisualizerGL3D::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
#endif
Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
debug << "Shaders::MeshVisualizerGL2D::Flag" << Debug::nospace;
@ -656,6 +982,9 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flag value) {
#endif
_c(PrimitiveIdFromVertexId)
#endif
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#endif
#undef _c
/* LCOV_EXCL_STOP */
}
@ -685,6 +1014,9 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flag value) {
#endif
_c(PrimitiveIdFromVertexId)
#endif
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#endif
#undef _c
/* LCOV_EXCL_STOP */
}
@ -703,7 +1035,10 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL2D::Flags value) {
MeshVisualizerGL2D::Flag::VertexId,
MeshVisualizerGL2D::Flag::PrimitiveIdFromVertexId, /* Superset of PrimitiveId */
#ifndef MAGNUM_TARGET_WEBGL
MeshVisualizerGL2D::Flag::PrimitiveId
MeshVisualizerGL2D::Flag::PrimitiveId,
#endif
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL2D::Flag::UniformBuffers
#endif
#endif
});
@ -726,7 +1061,10 @@ Debug& operator<<(Debug& debug, const MeshVisualizerGL3D::Flags value) {
MeshVisualizerGL3D::Flag::VertexId,
MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId, /* Superset of PrimitiveId */
#ifndef MAGNUM_TARGET_WEBGL
MeshVisualizerGL3D::Flag::PrimitiveId
MeshVisualizerGL3D::Flag::PrimitiveId,
#endif
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGL3D::Flag::UniformBuffers
#endif
#endif
});

479
src/Magnum/Shaders/MeshVisualizerGL.h

@ -53,14 +53,20 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr
InstancedObjectId = 1 << 2,
VertexId = 1 << 3,
PrimitiveId = 1 << 4,
PrimitiveIdFromVertexId = (1 << 5)|PrimitiveId
PrimitiveIdFromVertexId = (1 << 5)|PrimitiveId,
/* bit 6, 7, 8, 9 used by 3D-specific TBN visualization */
UniformBuffers = 1 << 10
#endif
};
typedef Containers::EnumSet<FlagBase> FlagsBase;
CORRADE_ENUMSET_FRIEND_OPERATORS(FlagsBase)
explicit MeshVisualizerGLBase(FlagsBase flags);
explicit MeshVisualizerGLBase(FlagsBase flags
#ifndef MAGNUM_TARGET_GLES2
, UnsignedInt materialCount, UnsignedInt drawCount
#endif
);
explicit MeshVisualizerGLBase(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {}
MAGNUM_SHADERS_LOCAL GL::Version setupShaders(GL::Shader& vert, GL::Shader& frag, const Utility::Resource& rs) const;
@ -73,6 +79,12 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr
MeshVisualizerGLBase& bindColorMapTexture(GL::Texture2D& texture);
#endif
#ifndef MAGNUM_TARGET_GLES2
MeshVisualizerGLBase& setDrawOffset(UnsignedInt offset);
MeshVisualizerGLBase& bindMaterialBuffer(GL::Buffer& buffer);
MeshVisualizerGLBase& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
#endif
/* Prevent accidentally calling irrelevant functions */
#ifndef MAGNUM_TARGET_GLES
using GL::AbstractShaderProgram::drawTransformFeedback;
@ -82,6 +94,9 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr
#endif
FlagsBase _flags;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _materialCount{}, _drawCount{};
#endif
Int _colorUniform{1},
_wireframeColorUniform{2},
_wireframeWidthUniform{3},
@ -89,6 +104,9 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGLBase: public GL::AbstractShaderProgr
_viewportSizeUniform{5};
#ifndef MAGNUM_TARGET_GLES2
Int _colorMapOffsetScaleUniform{6};
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */
Int _drawOffsetUniform{0};
#endif
};
@ -200,11 +218,26 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
/** @copydoc MeshVisualizerGL3D::Flag::PrimitiveIdFromVertexId */
#ifndef MAGNUM_TARGET_WEBGL
PrimitiveIdFromVertexId = (1 << 5)|PrimitiveId
PrimitiveIdFromVertexId = (1 << 5)|PrimitiveId,
#else
PrimitiveIdFromVertexId = (1 << 5)|(1 << 4)
PrimitiveIdFromVertexId = (1 << 5)|(1 << 4),
#endif
#endif
#ifndef MAGNUM_TARGET_GLES2
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(), @ref bindDrawBuffer()
* and @ref bindMaterialBuffer() instead of direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL
* 1.0.
* @m_since_latest
*/
UniformBuffers = 1 << 10
#endif
};
/** @brief Flags */
@ -215,9 +248,50 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* @param flags Flags
*
* At least @ref Flag::Wireframe is expected to be enabled.
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref MeshVisualizerGL2D(Flags, UnsignedInt, UnsignedInt) with
* @p materialCount and @p drawCount set to @cpp 1 @ce.
*/
explicit MeshVisualizerGL2D(Flags flags);
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param materialCount Size of a @ref MeshVisualizerMaterialUniform
* buffer bound with @ref bindMaterialBuffer()
* @param drawCount Size of a @ref TransformationProjectionUniform2D
* / @ref MeshVisualizerMaterialUniform buffer bound with
* @ref bindTransformationProjectionBuffer() and
* @ref bindDrawBuffer()
*
* At least @ref Flag::Wireframe is expected to be enabled.
*
* If @p flags contains @ref Flag::UniformBuffers, @p materialCount and
* @p drawCount describe the uniform buffer sizes as these are required
* to have a statically defined size. The draw offset is then set via
* @ref setDrawOffset() and the per-draw materials are specified via
* @ref MeshVisualizerDrawUniform2D::materialId.
*
* If @p flags don't contain @ref Flag::UniformBuffers,
* @p materialCount and @p drawCount is ignored and the constructor
* behaves the same as @ref MeshVisualizerGL2D(Flags).
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
/** @todo this constructor will eventually need to have also joint
count, per-vertex weight count, view count for multiview and clip
plane count ... and putting them in arbitrary order next to each
other is too error-prone, so it needs some other solution
(accepting pairs of parameter type and value like in GL context
creation, e.g., which will probably need a new enum as reusing Flag
for this might be too confusing) */
explicit MeshVisualizerGL2D(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount);
#endif
/**
* @brief Construct without creating the underlying OpenGL object
*
@ -249,8 +323,37 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
return Flag(UnsignedShort(Implementation::MeshVisualizerGLBase::_flags));
}
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Material count
* @m_since_latest
*
* Statically defined size of the @ref MeshVisualizerMaterialUniform
* uniform buffer. Has use only if @ref Flag::UniformBuffers is set.
* @see @ref bindMaterialBuffer()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt materialCount() const { return _materialCount; }
/**
* @brief Draw count
* @m_since_latest
*
* Statically defined size of each of the
* @ref TransformationProjectionUniform2D and
* @ref MeshVisualizerDrawUniform2D uniform buffers. Has use only if
* @ref Flag::UniformBuffers is set.
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt drawCount() const { return _drawCount; }
#endif
/** @{
* @name Uniform setters
*
* Used only if @ref Flag::UniformBuffers is not set.
*/
/**
@ -258,6 +361,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* @return Reference to self (for method chaining)
*
* Initial value is an identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix
* and call @ref bindTransformationProjectionBuffer() instead.
*/
MeshVisualizerGL2D& setTransformationProjectionMatrix(const Matrix3& matrix);
@ -280,6 +387,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* @ref Flag::PrimitiveId / @ref Flag::PrimitiveIdFromVertexId is
* enabled. In case of the latter, the color is multiplied with the
* color map coming from @ref bindColorMapTexture().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::color and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL2D& setColor(const Color4& color) {
return static_cast<MeshVisualizerGL2D&>(Implementation::MeshVisualizerGLBase::setColor(color));
@ -291,6 +402,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
*
* Initial value is @cpp 0x000000ff_rgbaf @ce. Expects that
* @ref Flag::Wireframe is enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::wireframeColor and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL2D& setWireframeColor(const Color4& color) {
return static_cast<MeshVisualizerGL2D&>(Implementation::MeshVisualizerGLBase::setWireframeColor(color));
@ -303,6 +418,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* The value is in screen space (depending on @ref setViewportSize()),
* initial value is @cpp 1.0f @ce. Expects that @ref Flag::Wireframe is
* enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::wireframeWidth and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL2D& setWireframeWidth(Float width) {
return static_cast<MeshVisualizerGL2D&>(Implementation::MeshVisualizerGLBase::setWireframeWidth(width));
@ -322,6 +441,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* Value is in screen space (depending on @ref setViewportSize()),
* initial value is @cpp 2.0f @ce. Expects that @ref Flag::Wireframe is
* enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::smoothness and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL2D& setSmoothness(Float smoothness);
@ -329,6 +452,103 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL2D: public Implementation::MeshVisua
* @}
*/
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
/**
* @brief Set a draw offset
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Specifies which item in the @ref TransformationProjectionUniform2D
* and @ref MeshVisualizerDrawUniform2D buffers bound with
* @ref bindTransformationProjectionBuffer() and @ref bindDrawBuffer()
* should be used for current draw. Expects that
* @ref Flag::UniformBuffers is set and @p offset is less than
* @ref drawCount(). Initial value is @cpp 0 @ce.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL2D& setDrawOffset(UnsignedInt offset) {
return static_cast<MeshVisualizerGL2D&>(Implementation::MeshVisualizerGLBase::setDrawOffset(offset));
}
/**
* @brief Set a transformation and projection uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref TransformationUniform3D. At the very least you need to call
* also @ref bindDrawBuffer() and @ref bindMaterialBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL2D& bindTransformationProjectionBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
MeshVisualizerGL2D& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a draw uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref MeshVisualizerDrawUniform2D. At the very least you need to call
* also @ref bindTransformationProjectionBuffer() and
* @ref bindMaterialBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL2D& bindDrawBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
MeshVisualizerGL2D& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a material uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref materialCount() instances of
* @ref MeshVisualizerMaterialUniform. At the very least you need to
* call also @ref bindTransformationProjectionBuffer() and
* @ref bindDrawBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL2D& bindMaterialBuffer(GL::Buffer& buffer) {
return static_cast<MeshVisualizerGL2D&>(Implementation::MeshVisualizerGLBase::bindMaterialBuffer(buffer));
}
/**
* @overload
* @m_since_latest
*/
MeshVisualizerGL2D& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size) {
return static_cast<MeshVisualizerGL2D&>(Implementation::MeshVisualizerGLBase::bindMaterialBuffer(buffer, offset, size));
}
/**
* @}
*/
#endif
/** @{
* @name Texture binding
*/
@ -761,7 +981,23 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @requires_gles Geometry shaders are not available in WebGL.
* @m_since{2020,06}
*/
NormalDirection = 1 << 9
NormalDirection = 1 << 9,
#endif
#ifndef MAGNUM_TARGET_GLES2
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer(),
* @ref bindDrawBuffer() and @ref bindMaterialBuffer() instead of
* direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL
* 1.0.
* @m_since_latest
*/
UniformBuffers = 1 << 10
#endif
};
@ -776,6 +1012,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref Flag::BitangentFromTangentDirection,
* @ref Flag::BitangentDirection, @ref Flag::NormalDirection is
* expected to be enabled.
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref MeshVisualizerGL3D(Flags, UnsignedInt, UnsignedInt) with
* @p materialCount and @p drawCount set to @cpp 1 @ce.
*/
explicit MeshVisualizerGL3D(Flags flags);
@ -788,6 +1029,46 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
explicit CORRADE_DEPRECATED("use MeshVisualizerGL3D(Flags) instead") MeshVisualizerGL3D(): MeshVisualizerGL3D{{}} {}
#endif
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param materialCount Size of a @ref MeshVisualizerMaterialUniform
* buffer bound with @ref bindMaterialBuffer()
* @param drawCount Size of a @ref ProjectionUniform3D /
* @ref TransformationUniform3D /
* @ref MeshVisualizerMaterialUniform buffer bound with
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer()
* and @ref bindDrawBuffer()
*
* At least @ref Flag::Wireframe or one of @ref Flag::TangentDirection,
* @ref Flag::BitangentFromTangentDirection,
* @ref Flag::BitangentDirection, @ref Flag::NormalDirection is
* expected to be enabled.
*
* If @p flags contains @ref Flag::UniformBuffers, @p materialCount and
* @p drawCount describe the uniform buffer sizes as these are required
* to have a statically defined size. The draw offset is then set via
* @ref setDrawOffset() and the per-draw materials are specified via
* @ref MeshVisualizerDrawUniform3D::materialId.
*
* If @p flags don't contain @ref Flag::UniformBuffers,
* @p materialCount and @p drawCount is ignored and the constructor
* behaves the same as @ref MeshVisualizerGL3D(Flags).
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
/** @todo this constructor will eventually need to have also joint
count, per-vertex weight count, view count for multiview and clip
plane count ... and putting them in arbitrary order next to each
other is too error-prone, so it needs some other solution
(accepting pairs of parameter type and value like in GL context
creation, e.g., which will probably need a new enum as reusing Flag
for this might be too confusing) */
explicit MeshVisualizerGL3D(Flags flags, UnsignedInt materialCount, UnsignedInt drawCount);
#endif
/**
* @brief Construct without creating the underlying OpenGL object
*
@ -819,8 +1100,37 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
return Flag(UnsignedShort(Implementation::MeshVisualizerGLBase::_flags));
}
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Material count
* @m_since_latest
*
* Statically defined size of the @ref MeshVisualizerMaterialUniform
* uniform buffer. Has use only if @ref Flag::UniformBuffers is set.
* @see @ref bindMaterialBuffer()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt materialCount() const { return _materialCount; }
/**
* @brief Draw count
* @m_since_latest
*
* Statically defined size of each of the
* @ref TransformationProjectionUniform3D and
* @ref MeshVisualizerDrawUniform3D uniform buffers. Has use only if
* @ref Flag::UniformBuffers is set.
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt drawCount() const { return _drawCount; }
#endif
/** @{
* @name Uniform setters
*
* Used only if @ref Flag::UniformBuffers is not set.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
@ -841,6 +1151,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @return Reference to self (for method chaining)
*
* Initial value is an identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationUniform3D::transformationMatrix and call
* @ref bindTransformationBuffer() instead.
*/
MeshVisualizerGL3D& setTransformationMatrix(const Matrix4& matrix);
@ -851,6 +1165,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* Initial value is an identity matrix. (i.e., an orthographic
* projection of the default @f$ [ -\boldsymbol{1} ; \boldsymbol{1} ] @f$
* cube).
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref ProjectionUniform3D::projectionMatrix and call
* @ref bindProjectionBuffer() instead.
*/
MeshVisualizerGL3D& setProjectionMatrix(const Matrix4& matrix);
@ -865,6 +1183,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* enabled. The matrix doesn't need to be normalized, as
* renormalization is done per-fragment anyway.
* Initial value is an identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerDrawUniform3D::normalMatrix and call
* @ref bindDrawBuffer() instead.
* @requires_gl32 Extension @gl_extension{ARB,geometry_shader4}
* @requires_gles30 Not defined in OpenGL ES 2.0.
* @requires_gles32 Extension @gl_extension{ANDROID,extension_pack_es31a} /
@ -894,6 +1216,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref Flag::PrimitiveId / @ref Flag::PrimitiveIdFromVertexId is
* enabled. In case of the latter, the color is multiplied with the
* color map coming from @ref bindColorMapTexture().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::color and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL3D& setColor(const Color4& color) {
return static_cast<MeshVisualizerGL3D&>(Implementation::MeshVisualizerGLBase::setColor(color));
@ -905,6 +1231,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
*
* Initial value is @cpp 0x000000ff_rgbaf @ce. Expects that
* @ref Flag::Wireframe is enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::wireframeColor and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL3D& setWireframeColor(const Color4& color) {
return static_cast<MeshVisualizerGL3D&>(Implementation::MeshVisualizerGLBase::setWireframeColor(color));
@ -917,6 +1247,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* The value is in screen space (depending on @ref setViewportSize()),
* initial value is @cpp 1.0f @ce. Expects that @ref Flag::Wireframe is
* enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::wireframeWidth and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL3D& setWireframeWidth(Float width) {
return static_cast<MeshVisualizerGL3D&>(Implementation::MeshVisualizerGLBase::setWireframeWidth(width));
@ -943,6 +1277,11 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref FlatGL::setObjectId() "setObjectId()" uniform that's used to
* offset the per-vertex / per-instance ID. Instead, you need to encode
* the base offset into the @p offset parameter.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::colorMapOffset and
* @ref MeshVisualizerMaterialUniform::colorMapScale and call
* @ref bindMaterialBuffer() instead.
* @requires_gles30 Object ID visualization requires integer attributes
* while primitive ID visualization requires the `gl_VertexID` /
* `gl_PrimitiveID` builtins, neither of which is available in
@ -969,6 +1308,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref Flag::BitangentFromTangentDirection,
* @ref Flag::BitangentDirection or @ref Flag::NormalDirection is
* enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::lineWidth and call
* @ref bindMaterialBuffer() instead.
* @requires_gl32 Extension @gl_extension{ARB,geometry_shader4}
* @requires_gles30 Not defined in OpenGL ES 2.0.
* @requires_gles32 Extension @gl_extension{ANDROID,extension_pack_es31a} /
@ -987,6 +1330,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref Flag::BitangentFromTangentDirection,
* @ref Flag::BitangentDirection or @ref Flag::NormalDirection is
* enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::lineLength and call
* @ref bindMaterialBuffer() instead.
* @requires_gl32 Extension @gl_extension{ARB,geometry_shader4}
* @requires_gles30 Not defined in OpenGL ES 2.0.
* @requires_gles32 Extension @gl_extension{ANDROID,extension_pack_es31a} /
@ -1006,6 +1353,10 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @ref Flag::BitangentFromTangentDirection,
* @ref Flag::BitangentDirection or @ref Flag::NormalDirection is
* enabled.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref MeshVisualizerMaterialUniform::smoothness and call
* @ref bindMaterialBuffer() instead.
*/
MeshVisualizerGL3D& setSmoothness(Float smoothness);
@ -1013,6 +1364,124 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizerGL3D: public Implementation::MeshVisua
* @}
*/
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
/**
* @brief Set a draw offset
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Specifies which item in the @ref TransformationUniform3D and
* @ref MeshVisualizerDrawUniform3D buffers bound with
* @ref bindTransformationBuffer() and @ref bindDrawBuffer() should be
* used for current draw. Expects that @ref Flag::UniformBuffers is set
* and @p offset is less than @ref drawCount(). Initial value is
* @cpp 0 @ce.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL3D& setDrawOffset(UnsignedInt offset) {
return static_cast<MeshVisualizerGL3D&>(Implementation::MeshVisualizerGLBase::setDrawOffset(offset));
}
/**
* @brief Set a projection uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain at least one instance of
* @ref ProjectionUniform3D. At the very least you need to call also
* @ref bindTransformationBuffer(), @ref bindDrawBuffer() and
* @ref bindMaterialBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL3D& bindProjectionBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
MeshVisualizerGL3D& bindProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a transformation uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref TransformationUniform3D. At the very least you need to call
* also @ref bindDrawBuffer() and @ref bindMaterialBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL3D& bindTransformationBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
MeshVisualizerGL3D& bindTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a draw uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref MeshVisualizerDrawUniform3D. At the very least you need to call
* also @ref bindProjectionBuffer(), @ref bindTransformationBuffer()
* and @ref bindMaterialBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL3D& bindDrawBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
MeshVisualizerGL3D& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a material uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref materialCount() instances of
* @ref MeshVisualizerMaterialUniform. At the very least you need to
* call also @ref bindProjectionBuffer(),
* @ref bindTransformationBuffer() and @ref bindDrawBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
MeshVisualizerGL3D& bindMaterialBuffer(GL::Buffer& buffer) {
return static_cast<MeshVisualizerGL3D&>(Implementation::MeshVisualizerGLBase::bindMaterialBuffer(buffer));
}
/**
* @overload
* @m_since_latest
*/
MeshVisualizerGL3D& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size) {
return static_cast<MeshVisualizerGL3D&>(Implementation::MeshVisualizerGLBase::bindMaterialBuffer(buffer, offset, size));
}
/**
* @}
*/
#endif
/** @{
* @name Texture binding
*/

137
src/Magnum/Shaders/Phong.frag

@ -39,6 +39,7 @@
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 4)
#endif
@ -53,7 +54,6 @@ uniform lowp vec4 ambientColor
;
#if LIGHT_COUNT
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 5)
#endif
@ -145,6 +145,78 @@ uniform lowp float lightRanges[LIGHT_COUNT]
;
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
/* Keep in sync with Phong.vert. Can't "outsource" to a common file because
the #extension directive needs to be always before any code. */
struct DrawUniform {
mediump mat3 normalMatrix; /* actually mat3x4 */
highp uvec4 materialIdReservedObjectIdLightOffsetLightCount;
#define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCount.x
#define draw_objectId materialIdReservedObjectIdLightOffsetLightCount.y
#define draw_lightOffset materialIdReservedObjectIdLightOffsetLightCount.z
#define draw_lightCount materialIdReservedObjectIdLightOffsetLightCount.w
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
struct MaterialUniform {
lowp vec4 ambientColor;
lowp vec4 diffuseColor;
lowp vec4 specularColor;
mediump vec4 normalTextureScaleShininessAlphaMaskReserved;
#define material_normalTextureScale normalTextureScaleShininessAlphaMaskReserved.x
#define material_shininess normalTextureScaleShininessAlphaMaskReserved.y
#define material_alphaMask normalTextureScaleShininessAlphaMaskReserved.z
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 4
#endif
) uniform Material {
MaterialUniform materials[MATERIAL_COUNT];
};
/* Keep in sync with Phong.vert. Can't "outsource" to a common file because
the #extension directive needs to be always before any code. */
struct LightUniform {
highp vec4 position;
lowp vec3 colorReserved;
#define light_color colorReserved.xyz
lowp vec4 specularColorReserved;
#define light_specularColor specularColorReserved.xyz
lowp vec4 rangeReservedReservedReserved;
#define light_range rangeReservedReservedReserved.x
};
#if LIGHT_COUNT
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 5
#endif
) uniform Light {
LightUniform lights[LIGHT_COUNT];
};
#endif
#endif
/* Textures */
#ifdef AMBIENT_TEXTURE
@ -222,6 +294,28 @@ out highp uint fragmentObjectId;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
#ifdef OBJECT_ID
highp const uint objectId = draws[drawOffset].draw_objectId;
#endif
mediump const uint materialId = draws[drawOffset].draw_materialIdReserved & 0xffffu;
lowp const vec4 ambientColor = materials[materialId].ambientColor;
#if LIGHT_COUNT
lowp const vec4 diffuseColor = materials[materialId].diffuseColor;
lowp const vec4 specularColor = materials[materialId].specularColor;
mediump const float shininess = materials[materialId].material_shininess;
#endif
#ifdef NORMAL_TEXTURE
mediump float normalTextureScale = materials[materialId].material_normalTextureScale;
#endif
#ifdef ALPHA_MASK
lowp const float alphaMask = materials[materialId].material_alphaMask;
#endif
#if LIGHT_COUNT
mediump const uint lightOffset = draws[drawOffset].draw_lightOffset;
#endif
#endif
lowp const vec4 finalAmbientColor =
#ifdef AMBIENT_TEXTURE
texture(ambientTexture, interpolatedTextureCoordinates)*
@ -273,7 +367,34 @@ void main() {
#endif
/* Add diffuse color for each light */
for(int i = 0; i < LIGHT_COUNT; ++i) {
#ifndef UNIFORM_BUFFERS
for(int i = 0; i < LIGHT_COUNT; ++i)
#else
for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawOffset].draw_lightCount); i < actualLightCount; ++i)
#endif
{
lowp const vec3 lightColor =
#ifndef UNIFORM_BUFFERS
lightColors[i]
#else
lights[lightOffset + i].light_color
#endif
;
lowp const vec3 lightSpecularColor =
#ifndef UNIFORM_BUFFERS
lightSpecularColors[i]
#else
lights[lightOffset + i].light_specularColor
#endif
;
lowp const float lightRange =
#ifndef UNIFORM_BUFFERS
lightRanges[i]
#else
lights[lightOffset + i].light_range
#endif
;
/* Attenuation. Directional lights have the .w component set to 0, use
that to make the distance zero -- which will then ensure the
attenuation is always 1.0 */
@ -281,19 +402,25 @@ void main() {
/* If range is 0 for whatever reason, clamp it to a small value to
avoid a NaN when dist is 0 as well (which is the case for
directional lights). */
highp float attenuation = clamp(1.0 - pow(dist/max(lightRanges[i], 0.0001), 4.0), 0.0, 1.0);
highp float attenuation = clamp(1.0 - pow(dist/max(lightRange, 0.0001), 4.0), 0.0, 1.0);
attenuation = attenuation*attenuation/(1.0 + dist*dist);
highp vec3 normalizedLightDirection = normalize(lightDirections[i].xyz);
lowp float intensity = max(0.0, dot(normalizedTransformedNormal, normalizedLightDirection))*attenuation;
fragmentColor += vec4(finalDiffuseColor.rgb*lightColors[i]*intensity, finalDiffuseColor.a/float(LIGHT_COUNT));
fragmentColor += vec4(finalDiffuseColor.rgb*lightColor*intensity, finalDiffuseColor.a/float(
#ifndef UNIFORM_BUFFERS
LIGHT_COUNT
#else
actualLightCount
#endif
));
/* Add specular color, if needed */
if(intensity > 0.001) {
highp vec3 reflection = reflect(-normalizedLightDirection, normalizedTransformedNormal);
/* Use attenuation for the specularity as well */
mediump float specularity = clamp(pow(max(0.0, dot(normalize(cameraDirection), reflection)), shininess), 0.0, 1.0)*attenuation;
fragmentColor += vec4(finalSpecularColor.rgb*lightSpecularColors[i].rgb*specularity, finalSpecularColor.a);
fragmentColor += vec4(finalSpecularColor.rgb*lightSpecularColor.rgb*specularity, finalSpecularColor.a);
}
}
#endif

449
src/Magnum/Shaders/Phong.h

@ -25,33 +25,460 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file
* @brief Typedef @ref Magnum::Shaders::Phong
* @m_deprecated_since_latest Use @ref Magnum/Shaders/PhongGL.h and the
* @ref Magnum::Shaders::PhongGL "PhongGL" class instead
* @brief Struct @ref Magnum::Shaders::PhongDrawUniform, @ref Magnum::Shaders::PhongMaterialUniform, @ref Magnum::Shaders::PhongLightUniform
*/
#endif
#include "Magnum/configure.h"
#include "Magnum/Magnum.h"
#include "Magnum/Tags.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Matrix.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#include "Magnum/Shaders/PhongGL.h"
CORRADE_DEPRECATED_FILE("use Magnum/Shaders/PhongGL.h and the PhongGL class instead")
#endif
namespace Magnum { namespace Shaders {
/**
@brief Per-draw uniform for Phong shaders
@m_since_latest
Together with the generic @ref TransformationUniform3D contains parameters that
are specific to each draw call. Texture transformation, if needed, is supplied
separately in a @ref TextureTransformationUniform; material-related properties
are expected to be shared among multiple draw calls and thus are provided in a
separate @ref PhongMaterialUniform structure, referenced by @ref materialId.
@see @ref PhongGL::bindDrawBuffer()
*/
struct PhongDrawUniform {
/** @brief Construct with default parameters */
constexpr explicit PhongDrawUniform(DefaultInitT = DefaultInit) noexcept: normalMatrix{Math::IdentityInit}, materialId{0}, objectId{0}, lightOffset{0}, lightCount{0xffffffffu} {}
/** @brief Construct without initializing the contents */
explicit PhongDrawUniform(NoInitT) noexcept: normalMatrix{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref normalMatrix field
* @return Reference to self (for method chaining)
*
* The matrix is expanded to @relativeref{Magnum,Matrix3x4}, with the
* bottom row being zeros.
*/
PhongDrawUniform& setNormalMatrix(const Matrix3x3& matrix) {
normalMatrix = Matrix3x4{matrix};
return *this;
}
/**
* @brief Set the @ref materialId field
* @return Reference to self (for method chaining)
*/
PhongDrawUniform& setMaterialId(UnsignedInt id) {
materialId = id;
return *this;
}
/**
* @brief Set the @ref objectId field
* @return Reference to self (for method chaining)
*/
PhongDrawUniform& setObjectId(UnsignedInt id) {
objectId = id;
return *this;
}
/**
* @brief Set the @ref lightOffset and @ref lightCount fields
* @return Reference to self (for method chaining)
*/
PhongDrawUniform& setLightOffsetCount(UnsignedInt offset, UnsignedInt count) {
lightOffset = offset;
lightCount = count;
return *this;
}
/**
* @}
*/
/**
* @brief Normal matrix
*
* Default value is an identity matrix. The bottom row is unused and acts
* only as a padding to match uniform buffer packing rules.
*
* If @ref PhongGL::Flag::InstancedTransformation is enabled, the
* per-instance normal matrix coming from the @ref PhongGL::NormalMatrix
* attribute is applied first, before this one.
* @see @ref PhongGL::setNormalMatrix()
*/
Matrix3x4 normalMatrix;
/** @var materialId
* @brief Material ID
*
* References a particular material from a @ref PhongMaterialUniform array.
* Useful when a UBO with more than one material is supplied or in a
* multi-draw scenario. Should be less than the material count passed to
* the @ref PhongGL::PhongGL(Flags, UnsignedInt, UnsignedInt, UnsignedInt)
* constructor. Default value is @cpp 0 @ce, meaning the first material
* gets used.
*/
/* This field is an UnsignedInt in the shader and materialId is extracted
as (value & 0xffff), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort materialId;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
UnsignedShort:16; /* reserved for skinOffset */
#endif
#else
UnsignedShort:16; /* reserved for skinOffset */
UnsignedShort materialId;
#endif
/**
* @brief Object ID
*
* Unlike @ref materialId, this index is used only for the object ID
* framebuffer output, not to access any other uniform data. Default value
* is @cpp 0 @ce.
*
* Used only if @ref PhongGL::Flag::ObjectId is enabled, ignored otherwise.
* If @ref PhongGL::Flag::InstancedObjectId is enabled as well, this value
* is added to the ID coming from the @ref PhongGL::ObjectId attribute.
* @see @ref PhongGL::setObjectId()
*/
UnsignedInt objectId;
/**
* @brief Light offset
*
* References the first light in the @ref PhongLightUniform array. Should
* be less than the light count passed to @ref PhongGL constructor. Default
* value is @cpp 0 @ce.
*/
UnsignedInt lightOffset;
/**
* @brief Light count
*
* Specifies how many lights after the @p lightOffset are used from the
* @ref PhongLightUniform array. Gets clamped by the shader so it's
* together with @ref lightOffset not larger than the light count passed to
* @ref PhongGL constructor. Default value is @cpp 0xffffffffu @ce.
*/
UnsignedInt lightCount;
};
/**
@brief Material uniform for Phong shaders
@m_since_latest
Describes material properties referenced from
@ref PhongDrawUniform::materialId.
@see @ref PhongGL::bindMaterialBuffer()
*/
struct PhongMaterialUniform {
/** @brief Construct with default parameters */
constexpr explicit PhongMaterialUniform(DefaultInitT = DefaultInit) noexcept: ambientColor{0.0f, 0.0f, 0.0f, 0.0f}, diffuseColor{1.0f, 1.0f, 1.0f, 1.0f}, specularColor{1.0f, 1.0f, 1.0f, 0.0f}, normalTextureScale{1.0f}, shininess{80.0f}, alphaMask{0.5f} {}
/** @brief Construct without initializing the contents */
explicit PhongMaterialUniform(NoInitT) noexcept: ambientColor{NoInit}, diffuseColor{NoInit}, specularColor{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref ambientColor field
* @return Reference to self (for method chaining)
*/
PhongMaterialUniform& setAmbientColor(const Color4& color) {
ambientColor = color;
return *this;
}
/**
* @brief Set the @ref diffuseColor field
* @return Reference to self (for method chaining)
*/
PhongMaterialUniform& setDiffuseColor(const Color4& color) {
diffuseColor = color;
return *this;
}
/**
* @brief Set the @ref specularColor field
* @return Reference to self (for method chaining)
*/
PhongMaterialUniform& setSpecularColor(const Color4& color) {
specularColor = color;
return *this;
}
/**
* @brief Set the @ref normalTextureScale field
* @return Reference to self (for method chaining)
*/
PhongMaterialUniform& setNormalTextureScale(Float scale) {
normalTextureScale = scale;
return *this;
}
/**
* @brief Set the @ref shininess field
* @return Reference to self (for method chaining)
*/
PhongMaterialUniform& setShininess(Float shininess) {
this->shininess = shininess;
return *this;
}
/**
* @brief Set the @ref alphaMask field
* @return Reference to self (for method chaining)
*/
PhongMaterialUniform& setAlphaMask(Float alphaMask) {
this->alphaMask = alphaMask;
return *this;
}
/**
* @}
*/
/**
* @brief Ambient color
*
* Default value is @cpp 0x00000000_rgbaf @ce. If
* @ref PhongGL::Flag::AmbientTexture is enabled, be sure to set this field
* to @cpp 0xffffffff_rgbaf @ce, otherwise the texture will be ignored.
*
* If @ref PhongGL::Flag::VertexColor is enabled, the color is multiplied
* with a color coming from the @ref PhongGL::Color3 / @ref PhongGL::Color4
* attribute.
* @see @ref PhongGL::setAmbientColor()
*/
Color4 ambientColor;
/**
* @brief Diffuse color
*
* Default value is @cpp 0xffffffff_rgbaf @ce.
*
* Used only if @ref PhongDrawUniform::lightCount is not zero, ignored
* otherwise. If @ref PhongGL::Flag::VertexColor is enabled, the color is
* multiplied with a color coming from the @ref PhongGL::Color3 /
* @ref PhongGL::Color4 attribute.
* @see @ref PhongGL::setDiffuseColor()
*/
Color4 diffuseColor;
/**
* @brief Specular color
*
* Default value is @cpp 0xffffff00_rgbaf @ce.
*
* Used only if @ref PhongDrawUniform::lightCount is not zero, ignored
* otherwise.
* @see @ref PhongGL::setSpecularColor()
*/
Color4 specularColor;
/**
* @brief Normal texture scale
*
* Affects strength of the normal mapping. Default value is @cpp 1.0f @ce,
* meaning the normal texture is not changed in any way; a value of
* @cpp 0.0f @ce disables the normal texture effect altogether.
*
* Used only if @ref PhongGL::Flag::NormalTexture is enabled and
* @ref PhongDrawUniform::lightCount is not zero, ignored otherwise.
* @see @ref PhongGL::setNormalTextureScale()
*/
Float normalTextureScale;
/**
* @brief Shininess
*
* The larger value, the harder surface (smaller specular highlight).
* Default value is @cpp 80.0f @ce.
*
* Used only if @ref PhongDrawUniform::lightCount is not zero, ignored
* otherwise.
* @see @ref PhongGL::setShininess()
*/
Float shininess;
/**
* @brief Alpha mask value
*
* Fragments with alpha values smaller than the mask value will be
* discarded. Default value is @cpp 0.5f @ce.
*
* Used only if @ref PhongGL::Flag::AlphaMask is enabled, ignored
* otherwise.
* @see @ref PhongGL::setAlphaMask()
*/
Float alphaMask;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32;
#endif
};
/**
@brief Light parameters for Phong shaders
@m_since_latest
Describes light properties referenced by the @ref PhongDrawUniform::lightOffset
and @ref PhongDrawUniform::lightCount range.
@see @ref PhongGL::bindLightBuffer()
*/
struct PhongLightUniform {
/** @brief Construct with default parameters */
constexpr explicit PhongLightUniform(DefaultInitT = DefaultInit) noexcept: position{0.0f, 0.0f, 1.0f, 0.0f}, color{1.0f, 1.0f, 1.0f}, specularColor{1.0f, 1.0f, 1.0f}, range{Constants::inf()} {}
/** @brief Construct without initializing the contents */
explicit PhongLightUniform(NoInitT) noexcept: position{NoInit}, color{NoInit}, specularColor{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref position field
* @return Reference to self (for method chaining)
*/
PhongLightUniform& setPosition(const Vector4& position) {
this->position = position;
return *this;
}
/**
* @brief Set the @ref color field
* @return Reference to self (for method chaining)
*/
PhongLightUniform& setColor(const Color3& color) {
this->color = color;
return *this;
}
/**
* @brief Set the @ref specularColor field
* @return Reference to self (for method chaining)
*/
PhongLightUniform& setSpecularColor(const Color3& specularColor) {
this->specularColor = specularColor;
return *this;
}
/**
* @brief Set the @ref range field
* @return Reference to self (for method chaining)
*/
PhongLightUniform& setRange(Float range) {
this->range = range;
return *this;
}
/**
* @}
*/
/**
* @brief Position
*
* Depending on the fourth component, the value is treated as either a
* camera-relative position of a point light, if the fourth component is
* @cpp 1.0f @ce; or a direction *to* a directional light, if the fourth
* component is @cpp 0.0f @ce. Default value is
* @cpp {0.0f, 0.0f, 1.0f, 0.0f} @ce --- a directional "fill" light coming
* from the camera.
* @see @ref PhongGL::setLightPositions()
*/
Vector4 position;
/**
* @brief Color
*
* Default value is @cpp 0xffffff_rgbf @ce.
* @see @ref PhongGL::setLightColors()
*/
Color3 color;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32; /* reserved for cone inner angle */
#endif
/**
* @brief Specular color
*
* Usually you'd set this value to the same as @ref color, but it allows
* for greater flexibility such as disabling specular highlights on certain
* lights. Default value is @cpp 0xffffff_rgbf @ce.
* @see @ref PhongGL::setLightColors()
*/
Color3 specularColor;
/* warning: Member __pad1__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32; /* reserved for cone outer angle */
#endif
/**
* @brief Attenuation range
*
* Default value is @ref Constants::inf().
* @see @ref PhongGL::setLightRanges()
*/
Float range;
/* warning: Member __pad2__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
Int:32; /* reserved for cone direction */
Int:32;
Int:32;
#endif
};
#ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief PhongGL
* @m_deprecated_since_latest Use @ref PhongGL instead.
*/
typedef CORRADE_DEPRECATED("use PhongGL instead") PhongGL Phong;
#endif
}}
#else
#error use Magnum/Shaders/PhongGL.h and the PhongGL class instead
#endif
#endif

119
src/Magnum/Shaders/Phong.vert

@ -32,8 +32,13 @@
#define out varying
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -86,6 +91,92 @@ uniform highp vec4 lightPositions[LIGHT_COUNT]
;
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
/* Keep in sync with Phong.frag. Can't "outsource" to a common file because
the #extension directive needs to be always before any code. */
struct DrawUniform {
mediump mat3 normalMatrix; /* actually mat3x4 */
highp uvec4 materialIdReservedObjectIdLightOffsetLightCount;
#define draw_materialIdReserved materialIdReservedObjectIdLightOffsetLightCount.x
#define draw_objectId materialIdReservedObjectIdLightOffsetLightCount.y
#define draw_lightOffset materialIdReservedObjectIdLightOffsetLightCount.z
#define draw_lightCount materialIdReservedObjectIdLightOffsetLightCount.w
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 0
#endif
) uniform Projection {
highp mat4 projectionMatrix;
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 1
#endif
) uniform Transformation {
highp mat4 transformationMatrices[DRAW_COUNT];
};
#ifdef TEXTURE_TRANSFORMATION
struct TextureTransformationUniform {
highp vec4 rotationScaling;
highp vec4 offsetReservedReserved;
#define textureTransformation_offset offsetReservedReserved.xy
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 3
#endif
) uniform TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT];
};
#endif
#if LIGHT_COUNT
/* Keep in sync with Phong.frag. Can't "outsource" to a common file because
the #extension directive needs to be always before any code. */
struct LightUniform {
highp vec4 position;
lowp vec3 colorReserved;
#define light_color colorReserved.xyz
lowp vec4 specularColorReserved;
#define light_specularColor specularColorReserved.xyz
lowp vec4 rangeReservedReservedReserved;
#define light_range rangeReservedReservedReserved.x
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 5
#endif
) uniform Light {
LightUniform lights[LIGHT_COUNT];
};
#endif
#endif
/* Inputs */
#ifdef EXPLICIT_ATTRIB_LOCATION
@ -183,6 +274,19 @@ out highp vec3 cameraDirection;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
highp const mat4 transformationMatrix = transformationMatrices[drawOffset];
#if LIGHT_COUNT
mediump const mat3 normalMatrix = draws[drawOffset].normalMatrix;
#endif
#ifdef TEXTURE_TRANSFORMATION
mediump const mat3 textureMatrix = mat3(textureTransformations[drawOffset].rotationScaling.xy, 0.0, textureTransformations[drawOffset].rotationScaling.zw, 0.0, textureTransformations[drawOffset].textureTransformation_offset, 1.0);
#endif
#if LIGHT_COUNT
mediump const uint lightOffset = draws[drawOffset].draw_lightOffset;
#endif
#endif
/* Transformed vertex position */
highp vec4 transformedPosition4 = transformationMatrix*
#ifdef INSTANCED_TRANSFORMATION
@ -221,8 +325,21 @@ void main() {
/* Direction to the light. Directional lights have the last component set
to 0, which gets used to ignore the transformed position. */
#ifndef UNIFORM_BUFFERS
for(int i = 0; i < LIGHT_COUNT; ++i)
lightDirections[i] = vec4(lightPositions[i].xyz - transformedPosition*lightPositions[i].w, lightPositions[i].w);
#else
for(uint i = 0u, actualLightCount = min(uint(LIGHT_COUNT), draws[drawOffset].draw_lightCount); i < actualLightCount; ++i)
#endif
{
highp const vec4 lightPosition =
#ifndef UNIFORM_BUFFERS
lightPositions[i]
#else
lights[lightOffset + i].position
#endif
;
lightDirections[i] = vec4(lightPosition.xyz - transformedPosition*lightPosition.w, lightPosition.w);
}
/* Direction to the camera */
cameraDirection = -transformedPosition;

377
src/Magnum/Shaders/PhongGL.cpp

@ -43,6 +43,10 @@
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/Buffer.h"
#endif
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
namespace Magnum { namespace Shaders {
@ -54,12 +58,49 @@ namespace {
SpecularTextureUnit = 2,
NormalTextureUnit = 3
};
#ifndef MAGNUM_TARGET_GLES2
enum: Int {
ProjectionBufferBinding = 0,
TransformationBufferBinding = 1,
DrawBufferBinding = 2,
TextureTransformationBufferBinding = 3,
MaterialBufferBinding = 4,
LightBufferBinding = 5
};
#endif
}
PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}, _lightCount{lightCount}, _lightColorsUniform{_lightPositionsUniform + Int(lightCount)}, _lightSpecularColorsUniform{_lightPositionsUniform + 2*Int(lightCount)}, _lightRangesUniform{_lightPositionsUniform + 3*Int(lightCount)} {
PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt materialCount, const UnsignedInt drawCount
#endif
):
_flags{flags},
_lightCount{lightCount},
#ifndef MAGNUM_TARGET_GLES2
_materialCount{materialCount},
_drawCount{drawCount},
#endif
_lightColorsUniform{_lightPositionsUniform + Int(lightCount)},
_lightSpecularColorsUniform{_lightPositionsUniform + 2*Int(lightCount)},
_lightRangesUniform{_lightPositionsUniform + 3*Int(lightCount)}
{
CORRADE_ASSERT(!(flags & Flag::TextureTransformation) || (flags & (Flag::AmbientTexture|Flag::DiffuseTexture|Flag::SpecularTexture|Flag::NormalTexture)),
"Shaders::PhongGL: texture transformation enabled but the shader is not textured", );
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || materialCount,
"Shaders::PhongGL: material count can't be zero", );
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::PhongGL: draw count can't be zero", );
#endif
#ifndef MAGNUM_TARGET_GLES
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShadersGL"))
@ -69,6 +110,11 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}
const GL::Context& context = GL::Context::current();
#ifndef MAGNUM_TARGET_GLES
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || context.isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>(),
"Shaders::PhongGL: uniform buffers require" << GL::Extensions::ARB::uniform_buffer_object::string(), );
#endif
#ifndef MAGNUM_TARGET_GLES
const GL::Version version = context.supportedVersion({GL::Version::GL320, GL::Version::GL310, GL::Version::GL300, GL::Version::GL210});
#else
@ -80,7 +126,7 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}
#ifndef MAGNUM_TARGET_GLES
std::string lightInitializerVertex, lightInitializerFragment;
if(lightCount) {
if(!(flags >= Flag::UniformBuffers) && lightCount) {
using namespace Containers::Literals;
/* Initializer for the light color / position / range arrays -- we need
@ -140,8 +186,19 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}
#endif
.addSource(flags & Flag::InstancedTransformation ? "#define INSTANCED_TRANSFORMATION\n" : "")
.addSource(flags >= Flag::InstancedTextureOffset ? "#define INSTANCED_TEXTURE_OFFSET\n" : "");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
vert.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define LIGHT_COUNT {}\n",
drawCount,
lightCount));
}
#endif
#ifndef MAGNUM_TARGET_GLES
if(lightCount) vert.addSource(std::move(lightInitializerVertex));
if(!(flags >= Flag::UniformBuffers) && lightCount)
vert.addSource(std::move(lightInitializerVertex));
#endif
vert.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Phong.vert"));
@ -156,7 +213,21 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}
.addSource(flags & Flag::ObjectId ? "#define OBJECT_ID\n" : "")
.addSource(flags >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
#endif
.addSource(Utility::formatString(
;
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
frag.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n"
"#define MATERIAL_COUNT {}\n"
"#define LIGHT_COUNT {}\n",
drawCount,
materialCount,
lightCount));
} else
#endif
{
frag.addSource(Utility::formatString(
"#define LIGHT_COUNT {}\n"
"#define LIGHT_COLORS_LOCATION {}\n"
"#define LIGHT_SPECULAR_COLORS_LOCATION {}\n"
@ -165,8 +236,10 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}
_lightPositionsUniform + lightCount,
_lightPositionsUniform + 2*lightCount,
_lightPositionsUniform + 3*lightCount));
}
#ifndef MAGNUM_TARGET_GLES
if(lightCount) frag.addSource(std::move(lightInitializerFragment));
if(!(flags >= Flag::UniformBuffers) && lightCount)
frag.addSource(std::move(lightInitializerFragment));
#endif
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Phong.frag"));
@ -215,27 +288,34 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#endif
{
_transformationMatrixUniform = uniformLocation("transformationMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_projectionMatrixUniform = uniformLocation("projectionMatrix");
_ambientColorUniform = uniformLocation("ambientColor");
if(lightCount) {
_normalMatrixUniform = uniformLocation("normalMatrix");
_diffuseColorUniform = uniformLocation("diffuseColor");
_specularColorUniform = uniformLocation("specularColor");
_shininessUniform = uniformLocation("shininess");
if(flags & Flag::NormalTexture)
_normalTextureScaleUniform = uniformLocation("normalTextureScale");
_lightPositionsUniform = uniformLocation("lightPositions");
_lightColorsUniform = uniformLocation("lightColors");
_lightSpecularColorsUniform = uniformLocation("lightSpecularColors");
_lightRangesUniform = uniformLocation("lightRanges");
}
if(flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask");
#ifndef MAGNUM_TARGET_GLES2
if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId");
if(flags >= Flag::UniformBuffers) {
_drawOffsetUniform = uniformLocation("drawOffset");
} else
#endif
{
_transformationMatrixUniform = uniformLocation("transformationMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_projectionMatrixUniform = uniformLocation("projectionMatrix");
_ambientColorUniform = uniformLocation("ambientColor");
if(lightCount) {
_normalMatrixUniform = uniformLocation("normalMatrix");
_diffuseColorUniform = uniformLocation("diffuseColor");
_specularColorUniform = uniformLocation("specularColor");
_shininessUniform = uniformLocation("shininess");
if(flags & Flag::NormalTexture)
_normalTextureScaleUniform = uniformLocation("normalTextureScale");
_lightPositionsUniform = uniformLocation("lightPositions");
_lightColorsUniform = uniformLocation("lightColors");
_lightSpecularColorsUniform = uniformLocation("lightSpecularColors");
_lightRangesUniform = uniformLocation("lightRanges");
}
if(flags & Flag::AlphaMask) _alphaMaskUniform = uniformLocation("alphaMask");
#ifndef MAGNUM_TARGET_GLES2
if(flags & Flag::ObjectId) _objectIdUniform = uniformLocation("objectId");
#endif
}
}
#ifndef MAGNUM_TARGET_GLES
@ -248,57 +328,100 @@ PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): _flags{flags}
if(flags & Flag::SpecularTexture) setUniform(uniformLocation("specularTexture"), SpecularTextureUnit);
if(flags & Flag::NormalTexture) setUniform(uniformLocation("normalTexture"), NormalTextureUnit);
}
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
setUniformBlockBinding(uniformBlockIndex("Projection"), ProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Transformation"), TransformationBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Material"), MaterialBufferBinding);
if(flags & Flag::TextureTransformation)
setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding);
if(lightCount)
setUniformBlockBinding(uniformBlockIndex("Light"), LightBufferBinding);
}
#endif
}
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
/* Default to fully opaque white so we can see the textures */
if(flags & Flag::AmbientTexture) setAmbientColor(Magnum::Color4{1.0f});
else setAmbientColor(Magnum::Color4{0.0f});
setTransformationMatrix(Matrix4{Math::IdentityInit});
setProjectionMatrix(Matrix4{Math::IdentityInit});
if(lightCount) {
setDiffuseColor(Magnum::Color4{1.0f});
setSpecularColor(Magnum::Color4{1.0f, 0.0f});
setShininess(80.0f);
if(flags & Flag::NormalTexture)
setNormalTextureScale(1.0f);
setLightPositions(Containers::Array<Vector4>{DirectInit, lightCount, Vector4{0.0f, 0.0f, 1.0f, 0.0f}});
Containers::Array<Magnum::Color3> colors{DirectInit, lightCount, Magnum::Color3{1.0f}};
setLightColors(colors);
setLightSpecularColors(colors);
setLightRanges(Containers::Array<Float>{DirectInit, lightCount, Constants::inf()});
/* Light position is zero by default */
setNormalMatrix(Matrix3x3{Math::IdentityInit});
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
/* Draw offset is zero by default */
} else
#endif
{
/* Default to fully opaque white so we can see the textures */
if(flags & Flag::AmbientTexture) setAmbientColor(Magnum::Color4{1.0f});
else setAmbientColor(Magnum::Color4{0.0f});
setTransformationMatrix(Matrix4{Math::IdentityInit});
setProjectionMatrix(Matrix4{Math::IdentityInit});
if(lightCount) {
setDiffuseColor(Magnum::Color4{1.0f});
setSpecularColor(Magnum::Color4{1.0f, 0.0f});
setShininess(80.0f);
if(flags & Flag::NormalTexture)
setNormalTextureScale(1.0f);
setLightPositions(Containers::Array<Vector4>{DirectInit, lightCount, Vector4{0.0f, 0.0f, 1.0f, 0.0f}});
Containers::Array<Magnum::Color3> colors{DirectInit, lightCount, Magnum::Color3{1.0f}};
setLightColors(colors);
setLightSpecularColors(colors);
setLightRanges(Containers::Array<Float>{DirectInit, lightCount, Constants::inf()});
/* Light position is zero by default */
setNormalMatrix(Matrix3x3{Math::IdentityInit});
}
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
}
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
if(flags & Flag::AlphaMask) setAlphaMask(0.5f);
/* Object ID is zero by default */
#endif
}
#ifndef MAGNUM_TARGET_GLES2
PhongGL::PhongGL(const Flags flags, const UnsignedInt lightCount): PhongGL{flags, lightCount, 1, 1} {}
#endif
PhongGL& PhongGL::setAmbientColor(const Magnum::Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setAmbientColor(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_ambientColorUniform, color);
return *this;
}
PhongGL& PhongGL::setDiffuseColor(const Magnum::Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setDiffuseColor(): the shader was created with uniform buffers enabled", *this);
#endif
if(_lightCount) setUniform(_diffuseColorUniform, color);
return *this;
}
PhongGL& PhongGL::setSpecularColor(const Magnum::Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setSpecularColor(): the shader was created with uniform buffers enabled", *this);
#endif
if(_lightCount) setUniform(_specularColorUniform, color);
return *this;
}
PhongGL& PhongGL::setShininess(Float shininess) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setShininess(): the shader was created with uniform buffers enabled", *this);
#endif
if(_lightCount) setUniform(_shininessUniform, shininess);
return *this;
}
PhongGL& PhongGL::setNormalTextureScale(const Float scale) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setNormalTextureScale(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & Flag::NormalTexture,
"Shaders::PhongGL::setNormalTextureScale(): the shader was not created with normal texture enabled", *this);
if(_lightCount) setUniform(_normalTextureScaleUniform, scale);
@ -306,6 +429,10 @@ PhongGL& PhongGL::setNormalTextureScale(const Float scale) {
}
PhongGL& PhongGL::setAlphaMask(Float mask) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setAlphaMask(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & Flag::AlphaMask,
"Shaders::PhongGL::setAlphaMask(): the shader was not created with alpha mask enabled", *this);
setUniform(_alphaMaskUniform, mask);
@ -314,6 +441,8 @@ PhongGL& PhongGL::setAlphaMask(Float mask) {
#ifndef MAGNUM_TARGET_GLES2
PhongGL& PhongGL::setObjectId(UnsignedInt id) {
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setObjectId(): the shader was created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::ObjectId,
"Shaders::PhongGL::setObjectId(): the shader was not created with object ID enabled", *this);
setUniform(_objectIdUniform, id);
@ -322,21 +451,37 @@ PhongGL& PhongGL::setObjectId(UnsignedInt id) {
#endif
PhongGL& PhongGL::setTransformationMatrix(const Matrix4& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setTransformationMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_transformationMatrixUniform, matrix);
return *this;
}
PhongGL& PhongGL::setNormalMatrix(const Matrix3x3& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setNormalMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
if(_lightCount) setUniform(_normalMatrixUniform, matrix);
return *this;
}
PhongGL& PhongGL::setProjectionMatrix(const Matrix4& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setProjectionMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_projectionMatrixUniform, matrix);
return *this;
}
PhongGL& PhongGL::setTextureMatrix(const Matrix3& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setTextureMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::PhongGL::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
setUniform(_textureMatrixUniform, matrix);
@ -344,6 +489,10 @@ PhongGL& PhongGL::setTextureMatrix(const Matrix3& matrix) {
}
PhongGL& PhongGL::setLightPositions(const Containers::ArrayView<const Vector4> positions) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightPositions(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_lightCount == positions.size(),
"Shaders::PhongGL::setLightPositions(): expected" << _lightCount << "items but got" << positions.size(), *this);
if(_lightCount) setUniform(_lightPositionsUniform, positions);
@ -373,6 +522,10 @@ PhongGL& PhongGL::setLightPositions(const std::initializer_list<Vector3> positio
#endif
PhongGL& PhongGL::setLightPosition(const UnsignedInt id, const Vector4& position) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightPosition(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(id < _lightCount,
"Shaders::PhongGL::setLightPosition(): light ID" << id << "is out of bounds for" << _lightCount << "lights", *this);
setUniform(_lightPositionsUniform + id, position);
@ -391,6 +544,10 @@ PhongGL& PhongGL::setLightPosition(const Vector3& position) {
#endif
PhongGL& PhongGL::setLightColors(const Containers::ArrayView<const Magnum::Color3> colors) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightColors(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_lightCount == colors.size(),
"Shaders::PhongGL::setLightColors(): expected" << _lightCount << "items but got" << colors.size(), *this);
if(_lightCount) setUniform(_lightColorsUniform, colors);
@ -418,6 +575,10 @@ PhongGL& PhongGL::setLightColors(const std::initializer_list<Magnum::Color3> col
}
PhongGL& PhongGL::setLightColor(const UnsignedInt id, const Magnum::Color3& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightColor(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(id < _lightCount,
"Shaders::PhongGL::setLightColor(): light ID" << id << "is out of bounds for" << _lightCount << "lights", *this);
setUniform(_lightColorsUniform + id, color);
@ -436,6 +597,10 @@ PhongGL& PhongGL::setLightColor(const Magnum::Color4& color) {
#endif
PhongGL& PhongGL::setLightSpecularColors(const Containers::ArrayView<const Magnum::Color3> colors) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightSpecularColors(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_lightCount == colors.size(),
"Shaders::PhongGL::setLightSpecularColors(): expected" << _lightCount << "items but got" << colors.size(), *this);
if(_lightCount) setUniform(_lightSpecularColorsUniform, colors);
@ -447,6 +612,10 @@ PhongGL& PhongGL::setLightSpecularColors(const std::initializer_list<Magnum::Col
}
PhongGL& PhongGL::setLightSpecularColor(const UnsignedInt id, const Magnum::Color3& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightSpecularColor(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(id < _lightCount,
"Shaders::PhongGL::setLightSpecularColor(): light ID" << id << "is out of bounds for" << _lightCount << "lights", *this);
setUniform(_lightSpecularColorsUniform + id, color);
@ -454,6 +623,10 @@ PhongGL& PhongGL::setLightSpecularColor(const UnsignedInt id, const Magnum::Colo
}
PhongGL& PhongGL::setLightRanges(const Containers::ArrayView<const Float> ranges) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightRanges(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_lightCount == ranges.size(),
"Shaders::PhongGL::setLightRanges(): expected" << _lightCount << "items but got" << ranges.size(), *this);
if(_lightCount) setUniform(_lightRangesUniform, ranges);
@ -465,12 +638,115 @@ PhongGL& PhongGL::setLightRanges(const std::initializer_list<Float> ranges) {
}
PhongGL& PhongGL::setLightRange(const UnsignedInt id, const Float range) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::PhongGL::setLightRange(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(id < _lightCount,
"Shaders::PhongGL::setLightRange(): light ID" << id << "is out of bounds for" << _lightCount << "lights", *this);
setUniform(_lightRangesUniform + id, range);
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
PhongGL& PhongGL::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(offset < _drawCount,
"Shaders::PhongGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
setUniform(_drawOffsetUniform, offset);
return *this;
}
PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding);
return *this;
}
PhongGL& PhongGL::bindProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, ProjectionBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding);
return *this;
}
PhongGL& PhongGL::bindTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
PhongGL& PhongGL::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindTextureTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
PhongGL& PhongGL::bindTextureTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::PhongGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding);
return *this;
}
PhongGL& PhongGL::bindMaterialBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindMaterialBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, MaterialBufferBinding, offset, size);
return *this;
}
PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindLightBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, LightBufferBinding);
return *this;
}
PhongGL& PhongGL::bindLightBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::PhongGL::bindLightBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, LightBufferBinding, offset, size);
return *this;
}
#endif
PhongGL& PhongGL::bindAmbientTexture(GL::Texture2D& texture) {
CORRADE_ASSERT(_flags & Flag::AmbientTexture,
"Shaders::PhongGL::bindAmbientTexture(): the shader was not created with ambient texture enabled", *this);
@ -526,6 +802,9 @@ Debug& operator<<(Debug& debug, const PhongGL::Flag value) {
#endif
_c(InstancedTransformation)
_c(InstancedTextureOffset)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#endif
#undef _c
/* LCOV_EXCL_STOP */
}
@ -548,7 +827,11 @@ Debug& operator<<(Debug& debug, const PhongGL::Flags value) {
PhongGL::Flag::InstancedObjectId, /* Superset of ObjectId */
PhongGL::Flag::ObjectId,
#endif
PhongGL::Flag::InstancedTransformation});
PhongGL::Flag::InstancedTransformation,
#ifndef MAGNUM_TARGET_GLES2
PhongGL::Flag::UniformBuffers
#endif
});
}
}}

357
src/Magnum/Shaders/PhongGL.h

@ -509,9 +509,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
/**
* Instanced object ID. Retrieves a per-instance / per-vertex
* object ID from the @ref ObjectId attribute, outputting a sum of
* the per-vertex ID and ID coming from @ref setObjectId().
* Implicitly enables @ref Flag::ObjectId. See
* @ref Shaders-PhongGL-object-id for more information.
* the per-vertex ID and ID coming from @ref setObjectId() or
* @ref PhongDrawUniform::objectId. Implicitly enables
* @ref Flag::ObjectId. See @ref Shaders-PhongGL-object-id for more
* information.
* @requires_gl30 Extension @gl_extension{EXT,gpu_shader4}
* @requires_gles30 Object ID output requires integer support in
* shaders, which is not available in OpenGL ES 2.0 or WebGL
@ -526,9 +527,11 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* transformation and normal matrix from the
* @ref TransformationMatrix / @ref NormalMatrix attributes and
* uses them together with matrices coming from
* @ref setTransformationMatrix() and @ref setNormalMatrix() (first
* the per-instance, then the uniform matrix). See
* @ref Shaders-PhongGL-instancing for more information.
* @ref setTransformationMatrix() and @ref setNormalMatrix() or
* @ref TransformationUniform3D::transformationMatrix and
* @ref PhongDrawUniform::normalMatrix (first the per-instance,
* then the uniform matrix). See @ref Shaders-PhongGL-instancing
* for more information.
* @requires_gl33 Extension @gl_extension{ARB,instanced_arrays}
* @requires_gles30 Extension @gl_extension{ANGLE,instanced_arrays},
* @gl_extension{EXT,instanced_arrays} or
@ -542,7 +545,9 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
/**
* Instanced texture offset. Retrieves a per-instance offset vector
* from the @ref TextureOffset attribute and uses it together with
* the matrix coming from @ref setTextureMatrix() (first the
* the matrix coming from @ref setTextureMatrix() or
* @ref TextureTransformationUniform::rotationScaling and
* @ref TextureTransformationUniform::offset (first the
* per-instance vector, then the uniform matrix). Instanced texture
* scaling and rotation is not supported at the moment, you can
* specify that only via the uniform @ref setTextureMatrix().
@ -556,7 +561,24 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* in WebGL 1.0.
* @m_since{2020,06}
*/
InstancedTextureOffset = (1 << 10)|TextureTransformation
InstancedTextureOffset = (1 << 10)|TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer(),
* @ref bindDrawBuffer(), @ref bindTextureTransformationBuffer(),
* @ref bindMaterialBuffer() and @ref bindLightBuffer() instead of
* direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL
* 1.0.
* @m_since_latest
*/
UniformBuffers = 1 << 12
#endif
};
/**
@ -570,9 +592,54 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @brief Constructor
* @param flags Flags
* @param lightCount Count of light sources
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref PhongGL(Flags, UnsignedInt, UnsignedInt, UnsignedInt) with
* @p materialCount and @p drawCount set to @cpp 1 @ce.
*/
explicit PhongGL(Flags flags = {}, UnsignedInt lightCount = 1);
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param lightCount Size of a @ref PhongLightUniform buffer bound
* with @ref bindLightBuffer()
* @param materialCount Size of a @ref PhongMaterialUniform buffer
* bound with @ref bindMaterialBuffer()
* @param drawCount Size of a @ref ProjectionUniform3D /
* @ref TransformationUniform3D / @ref PhongDrawUniform /
* @ref TextureTransformationUniform buffer bound with
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer()
*
* If @p flags contains @ref Flag::UniformBuffers, @p lightCount,
* @p materialCount and @p drawCount describe the uniform buffer sizes
* as these are required to have a statically defined size. The draw
* offset is then set via @ref setDrawOffset() and the per-draw
* materials and lights are specified via
* @ref PhongDrawUniform::materialId,
* @ref PhongDrawUniform::lightOffset and
* @ref PhongDrawUniform::lightCount.
*
* If @p flags don't contain @ref Flag::UniformBuffers,
* @p materialCount and @p drawCount is ignored and the constructor
* behaves the same as @ref PhongGL(Flags, UnsignedInt).
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
/** @todo this constructor will eventually need to have also joint
count, per-vertex weight count, view count for multiview and clip
plane count ... and putting them in arbitrary order next to each
other is too error-prone, so it needs some other solution
(accepting pairs of parameter type and value like in GL context
creation, e.g., which will probably need a new enum as reusing Flag
for this might be too confusing) */
explicit PhongGL(Flags flags, UnsignedInt lightCount, UnsignedInt materialCount, UnsignedInt drawCount);
#endif
/**
* @brief Construct without creating the underlying OpenGL object
*
@ -602,11 +669,46 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
/** @brief Flags */
Flags flags() const { return _flags; }
/** @brief Light count */
/**
* @brief Light count
*
* If @ref Flag::UniformBuffers is set, this is the statically defined
* size of the @ref PhongLightUniform uniform buffer.
* @see @ref bindLightBuffer()
*/
UnsignedInt lightCount() const { return _lightCount; }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Material count
* @m_since_latest
*
* Statically defined size of the @ref PhongMaterialUniform uniform
* buffer. Has use only if @ref Flag::UniformBuffers is set.
* @see @ref bindMaterialBuffer()
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt materialCount() const { return _materialCount; }
/**
* @brief Draw count
* @m_since_latest
*
* Statically defined size of each of the @ref ProjectionUniform3D,
* @ref TransformationUniform3D, @ref PhongDrawUniform and
* @ref TextureTransformationUniform uniform buffers. Has use only if
* @ref Flag::UniformBuffers is set.
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt drawCount() const { return _drawCount; }
#endif
/** @{
* @name Uniform setters
*
* Used only if @ref Flag::UniformBuffers is not set.
*/
/**
@ -618,6 +720,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* ambient texture, otherwise default value is @cpp 0x00000000_rgbaf @ce.
* If @ref Flag::VertexColor is set, the color is multiplied with a
* color coming from the @ref Color3 / @ref Color4 attribute.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::ambientColor and call
* @ref bindMaterialBuffer() instead.
* @see @ref bindAmbientTexture(), @ref Shaders-PhongGL-lights-ambient
*/
PhongGL& setAmbientColor(const Magnum::Color4& color);
@ -632,6 +738,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* as diffuse color doesn't contribute to the output in that case.
* If @ref Flag::VertexColor is set, the color is multiplied with a
* color coming from the @ref Color3 / @ref Color4 attribute.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::diffuseColor and call
* @ref bindMaterialBuffer() instead.
* @see @ref bindDiffuseTexture()
*/
PhongGL& setDiffuseColor(const Magnum::Color4& color);
@ -649,6 +759,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* Expects that the shader was created with @ref Flag::NormalTexture
* enabled. If @ref lightCount() is zero, this function is a no-op, as
* normals don't contribute to the output in that case.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::normalTextureScale and call
* @ref bindDrawBuffer() instead.
* @see @ref Shaders-PhongGL-normal-mapping, @ref bindNormalTexture(),
* @ref Trade::MaterialAttribute::NormalTextureScale
*/
@ -664,6 +778,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* the specular color to @cpp 0x00000000_rgbaf @ce. If
* @ref lightCount() is zero, this function is a no-op, as specular
* color doesn't contribute to the output in that case.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::specularColor and call
* @ref bindMaterialBuffer() instead.
* @see @ref bindSpecularTexture()
*/
PhongGL& setSpecularColor(const Magnum::Color4& color);
@ -676,6 +794,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* Initial value is @cpp 80.0f @ce. If @ref lightCount() is zero, this
* function is a no-op, as specular color doesn't contribute to the
* output in that case.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::shininess and call
* @ref bindMaterialBuffer() instead.
*/
PhongGL& setShininess(Float shininess);
@ -690,6 +812,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*
* This corresponds to @m_class{m-doc-external} [glAlphaFunc()](https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glAlphaFunc.xml)
* in classic OpenGL.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongMaterialUniform::alphaMask and call
* @ref bindMaterialBuffer() instead.
* @m_keywords{glAlphaFunc()}
*/
PhongGL& setAlphaMask(Float mask);
@ -704,6 +830,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @ref Shaders-PhongGL-object-id for more information. Default is
* @cpp 0 @ce. If @ref Flag::InstancedObjectId is enabled as well, this
* value is added to the ID coming from the @ref ObjectId attribute.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongDrawUniform::objectId and call @ref bindDrawBuffer()
* instead.
* @requires_gl30 Extension @gl_extension{EXT,gpu_shader4}
* @requires_gles30 Object ID output requires integer support in
* shaders, which is not available in OpenGL ES 2.0 or WebGL 1.0.
@ -720,6 +850,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @ref Flag::InstancedTransformation is set, the per-instance
* transformation coming from the @ref TransformationMatrix attribute
* is applied first, before this one.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationUniform3D::transformationMatrix and call
* @ref bindTransformationBuffer() instead.
*/
PhongGL& setTransformationMatrix(const Matrix4& matrix);
@ -735,6 +869,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* that case. If @ref Flag::InstancedTransformation is set, the
* per-instance normal matrix coming from the @ref NormalMatrix
* attribute is applied first, before this one.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongDrawUniform::normalMatrix and call
* @ref bindDrawBuffer() instead.
* @see @ref Math::Matrix4::normalMatrix()
*/
PhongGL& setNormalMatrix(const Matrix3x3& matrix);
@ -746,6 +884,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* Initial value is an identity matrix (i.e., an orthographic
* projection of the default @f$ [ -\boldsymbol{1} ; \boldsymbol{1} ] @f$
* cube).
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref ProjectionUniform3D::projectionMatrix and call
* @ref bindProjectionBuffer() instead.
*/
PhongGL& setProjectionMatrix(const Matrix4& matrix);
@ -759,6 +901,11 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* identity matrix. If @ref Flag::InstancedTextureOffset is set, the
* per-instance offset coming from the @ref TextureOffset atttribute is
* applied first, before this matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TextureTransformationUniform::rotationScaling and
* @ref TextureTransformationUniform::offset and call
* @ref bindTextureTransformationBuffer() instead.
*/
PhongGL& setTextureMatrix(const Matrix3& matrix);
@ -774,6 +921,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @p positions array is the same as @ref lightCount(). Initial values
* are @cpp {0.0f, 0.0f, 1.0f, 0.0f} @ce --- a directional "fill" light
* coming from the camera.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::position and call
* @ref bindLightBuffer() instead
* @see @ref Shaders-PhongGL-lights, @ref setLightPosition()
*/
PhongGL& setLightPositions(Containers::ArrayView<const Vector4> positions);
@ -813,6 +964,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* position. If updating more than one light, prefer the batch function
* instead to reduce the count of GL API calls. Expects that @p id is
* less than @ref lightCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::position and call @ref bindLightBuffer()
* instead.
*/
PhongGL& setLightPosition(UnsignedInt id, const Vector4& position);
@ -844,6 +999,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*
* Initial values are @cpp 0xffffff_rgbf @ce. Expects that the size
* of the @p colors array is the same as @ref lightCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::color and call @ref bindLightBuffer()
* instead.
* @see @ref Shaders-PhongGL-lights, @ref setLightColor()
*/
PhongGL& setLightColors(Containers::ArrayView<const Magnum::Color3> colors);
@ -879,6 +1038,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* updating more than one light, prefer the batch function instead to
* reduce the count of GL API calls. Expects that @p id is less than
* @ref lightCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::color and call @ref bindLightBuffer()
* instead.
*/
PhongGL& setLightColor(UnsignedInt id, const Magnum::Color3& color);
@ -910,6 +1073,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* highlights on certain lights. Initial values are
* @cpp 0xffffff_rgbf @ce. Expects that the size of the @p colors array
* is the same as @ref lightCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::specularColor and call @ref bindLightBuffer()
* instead.
* @see @ref Shaders-PhongGL-lights, @ref setLightColor()
*/
PhongGL& setLightSpecularColors(Containers::ArrayView<const Magnum::Color3> colors);
@ -929,6 +1096,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* color. If updating more than one light, prefer the batch function
* instead to reduce the count of GL API calls. Expects that @p id is
* less than @ref lightCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::specularColor and call
* @ref bindLightBuffer() instead.
*/
PhongGL& setLightSpecularColor(UnsignedInt id, const Magnum::Color3& color);
@ -939,6 +1110,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
*
* Initial values are @ref Constants::inf(). Expects that the size of
* the @p ranges array is the same as @ref lightCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::range and call @ref bindLightBuffer()
* instead.
* @see @ref Shaders-PhongGL-lights, @ref setLightRange()
*/
PhongGL& setLightRanges(Containers::ArrayView<const Float> ranges);
@ -958,6 +1133,10 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* updating more than one light, prefer the batch function instead to
* reduce the count of GL API calls. Expects that @p id is less than
* @ref lightCount().
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref PhongLightUniform::range and call @ref bindLightBuffer()
* instead.
*/
PhongGL& setLightRange(UnsignedInt id, Float range);
@ -965,6 +1144,158 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
* @}
*/
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
/**
* @brief Set a draw offset
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Specifies which item in the @ref TransformationUniform3D,
* @ref PhongDrawUniform and @ref TextureTransformationUniform buffers
* bound with @ref bindTransformationBuffer(), @ref bindDrawBuffer()
* and @ref bindTextureTransformationBuffer() should be used for
* current draw. Expects that @ref Flag::UniformBuffers is set and
* @p offset is less than @ref drawCount(). Initial value is @cpp 0 @ce.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
PhongGL& setDrawOffset(UnsignedInt offset);
/**
* @brief Set a projection uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain at least one instance of
* @ref ProjectionUniform3D. At the very least you need to call also
* @ref bindTransformationBuffer(), @ref bindDrawBuffer() and
* @ref bindMaterialBuffer(), usually @ref bindLightBuffer() as well.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
PhongGL& bindProjectionBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
PhongGL& bindProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a transformation uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref TransformationUniform3D. At the very least you need to call
* also @ref bindProjectionBuffer(), @ref bindDrawBuffer() and
* @ref bindMaterialBuffer(), usually @ref bindLightBuffer() as well.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
PhongGL& bindTransformationBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
PhongGL& bindTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a draw uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref PhongDrawUniform. At the very least you need to call also
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer() and
* @ref bindMaterialBuffer(), usually @ref bindLightBuffer() as well.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
PhongGL& bindDrawBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
PhongGL& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a texture transformation uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that both @ref Flag::UniformBuffers and
* @ref Flag::TextureTransformation is set. The buffer is expected to
* contain @ref drawCount() instances of
* @ref TextureTransformationUniform.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
PhongGL& bindTextureTransformationBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
PhongGL& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a material uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref materialCount() instances of
* @ref PhongMaterialUniform. At the very least you need to call also
* @ref bindProjectionBuffer(), @ref bindTransformationBuffer() and
* @ref bindDrawBuffer(), usually @ref bindLightBuffer() as well.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
PhongGL& bindMaterialBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
PhongGL& bindMaterialBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a light uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref lightCount() instances of
* @ref PhongLightUniform.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
PhongGL& bindLightBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
PhongGL& bindLightBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @}
*/
#endif
/** @{
* @name Texture binding
*/
@ -1050,6 +1381,9 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
Flags _flags;
UnsignedInt _lightCount{};
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _materialCount{}, _drawCount{};
#endif
Int _transformationMatrixUniform{0},
_projectionMatrixUniform{1},
_normalMatrixUniform{2},
@ -1067,6 +1401,11 @@ class MAGNUM_SHADERS_EXPORT PhongGL: public GL::AbstractShaderProgram {
_lightColorsUniform, /* 11 + lightCount, set in the constructor */
_lightSpecularColorsUniform, /* 11 + 2*lightCount */
_lightRangesUniform; /* 11 + 3*lightCount */
#ifndef MAGNUM_TARGET_GLES2
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */
Int _drawOffsetUniform{0};
#endif
};
/** @debugoperatorclassenum{PhongGL,PhongGL::Flag} */

45
src/Magnum/Shaders/Test/CMakeLists.txt

@ -23,6 +23,22 @@
# DEALINGS IN THE SOFTWARE.
#
corrade_add_test(ShadersDistanceFieldVectorTest DistanceFieldVectorTest.cpp LIBRARIES MagnumShaders)
corrade_add_test(ShadersFlatTest FlatTest.cpp LIBRARIES MagnumShaders)
corrade_add_test(ShadersGenericTest GenericTest.cpp LIBRARIES MagnumShaders)
corrade_add_test(ShadersMeshVisualizerTest MeshVisualizerTest.cpp LIBRARIES MagnumShaders)
corrade_add_test(ShadersPhongTest PhongTest.cpp LIBRARIES MagnumShaders)
corrade_add_test(ShadersVectorTest VectorTest.cpp LIBRARIES MagnumShaders)
set_target_properties(
ShadersDistanceFieldVectorTest
ShadersFlatTest
ShadersGenericTest
ShadersMeshVisualizerTest
ShadersPhongTest
ShadersVectorTest
PROPERTIES FOLDER "Magnum/Shaders/Test")
# There's an underscore between GL and Test to disambiguate from GLTest, which
# is a common suffix used to mark tests that need a GL context. Ugly, I know.
corrade_add_test(ShadersDistanceFieldVectorGL_Test DistanceFieldVectorGL_Test.cpp LIBRARIES MagnumShaders)
@ -94,7 +110,9 @@ if(BUILD_GL_TESTS)
VectorTestFiles/smooth0.2-2D.tga
VectorTestFiles/smooth0.2-3D.tga
VectorTestFiles/outline2D.tga
VectorTestFiles/outline3D.tga)
VectorTestFiles/outline3D.tga
VectorTestFiles/multidraw2D-distancefield.tga
VectorTestFiles/multidraw3D-distancefield.tga)
target_include_directories(ShadersDistanceFieldVectorGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
if(BUILD_PLUGINS_STATIC)
if(WITH_ANYIMAGEIMPORTER)
@ -133,7 +151,11 @@ if(BUILD_GL_TESTS)
FlatTestFiles/textured2D-alpha-mask0.5.tga
FlatTestFiles/textured3D-alpha-mask0.5.tga
FlatTestFiles/vertexColor2D.tga
FlatTestFiles/vertexColor3D.tga)
FlatTestFiles/vertexColor3D.tga
FlatTestFiles/multidraw2D.tga
FlatTestFiles/multidraw3D.tga
FlatTestFiles/multidraw-textured2D.tga
FlatTestFiles/multidraw-textured3D.tga)
target_include_directories(ShadersFlatGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
if(BUILD_PLUGINS_STATIC)
if(WITH_ANYIMAGEIMPORTER)
@ -189,7 +211,14 @@ if(BUILD_GL_TESTS)
MeshVisualizerTestFiles/wireframe-wide2D.tga
MeshVisualizerTestFiles/wireframe-wide3D.tga
MeshVisualizerTestFiles/wireframe2D.tga
MeshVisualizerTestFiles/wireframe3D.tga)
MeshVisualizerTestFiles/wireframe3D.tga
MeshVisualizerTestFiles/multidraw-wireframe2D.tga
MeshVisualizerTestFiles/multidraw-wireframe3D.tga
MeshVisualizerTestFiles/multidraw-wireframe-tbn3D.tga
MeshVisualizerTestFiles/multidraw-wireframe-nogeo2D.tga
MeshVisualizerTestFiles/multidraw-wireframe-nogeo3D.tga
MeshVisualizerTestFiles/multidraw-vertexid2D.tga
MeshVisualizerTestFiles/multidraw-vertexid3D.tga)
target_include_directories(ShadersMeshVisualizerGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
if(BUILD_PLUGINS_STATIC)
if(WITH_ANYIMAGEIMPORTER)
@ -251,6 +280,8 @@ if(BUILD_GL_TESTS)
PhongTestFiles/light-point-range1.5.tga
PhongTestFiles/light-point-specular-color.tga
PhongTestFiles/light-point.tga
PhongTestFiles/multidraw.tga
PhongTestFiles/multidraw-textured.tga
# For zero lights test (equivalency to Flat3D)
FlatTestFiles/textured3D-alpha-mask0.5.tga)
@ -280,7 +311,9 @@ if(BUILD_GL_TESTS)
VectorTestFiles/defaults.tga
VectorTestFiles/vector2D.tga
VectorTestFiles/vector3D.tga)
VectorTestFiles/vector3D.tga
VectorTestFiles/multidraw2D.tga
VectorTestFiles/multidraw3D.tga)
target_include_directories(ShadersVectorGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
if(BUILD_PLUGINS_STATIC)
if(WITH_ANYIMAGEIMPORTER)
@ -306,7 +339,9 @@ if(BUILD_GL_TESTS)
FlatTestFiles/defaults.tga
VertexColorTestFiles/vertexColor2D.tga
VertexColorTestFiles/vertexColor3D.tga)
VertexColorTestFiles/vertexColor3D.tga
VertexColorTestFiles/multidraw2D.tga
VertexColorTestFiles/multidraw3D.tga)
target_include_directories(ShadersVertexColorGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
if(BUILD_PLUGINS_STATIC)
if(WITH_ANYIMAGEIMPORTER)

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

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,195 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <new>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Shaders/DistanceFieldVector.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
struct DistanceFieldVectorTest: TestSuite::Tester {
explicit DistanceFieldVectorTest();
template<class T> void uniformSize();
void drawUniformConstructDefault();
void drawUniformConstructNoInit();
void drawUniformSetters();
void drawUniformMaterialIdPacking();
void materialUniformConstructDefault();
void materialUniformConstructNoInit();
void materialUniformSetters();
};
DistanceFieldVectorTest::DistanceFieldVectorTest() {
addTests({&DistanceFieldVectorTest::uniformSize<DistanceFieldVectorDrawUniform>,
&DistanceFieldVectorTest::uniformSize<DistanceFieldVectorMaterialUniform>,
&DistanceFieldVectorTest::drawUniformConstructDefault,
&DistanceFieldVectorTest::drawUniformConstructNoInit,
&DistanceFieldVectorTest::drawUniformSetters,
&DistanceFieldVectorTest::drawUniformMaterialIdPacking,
&DistanceFieldVectorTest::materialUniformConstructDefault,
&DistanceFieldVectorTest::materialUniformConstructNoInit,
&DistanceFieldVectorTest::materialUniformSetters});
}
using namespace Math::Literals;
template<class> struct UniformTraits;
template<> struct UniformTraits<DistanceFieldVectorDrawUniform> {
static const char* name() { return "DistanceFieldVectorDrawUniform"; }
};
template<> struct UniformTraits<DistanceFieldVectorMaterialUniform> {
static const char* name() { return "DistanceFieldVectorMaterialUniform"; }
};
template<class T> void DistanceFieldVectorTest::uniformSize() {
setTestCaseTemplateName(UniformTraits<T>::name());
CORRADE_FAIL_IF(sizeof(T) % sizeof(Vector4) != 0, sizeof(T) << "is not a multiple of vec4 for UBO alignment.");
/* 48-byte structures are fine, we'll align them to 768 bytes and not
256, but warn about that */
CORRADE_FAIL_IF(768 % sizeof(T) != 0, sizeof(T) << "can't fit exactly into 768-byte UBO alignment.");
if(256 % sizeof(T) != 0)
CORRADE_WARN(sizeof(T) << "can't fit exactly into 256-byte UBO alignment, only 768.");
}
void DistanceFieldVectorTest::drawUniformConstructDefault() {
DistanceFieldVectorDrawUniform a;
DistanceFieldVectorDrawUniform b{DefaultInit};
CORRADE_COMPARE(a.materialId, 0);
CORRADE_COMPARE(b.materialId, 0);
constexpr DistanceFieldVectorDrawUniform ca;
constexpr DistanceFieldVectorDrawUniform cb{DefaultInit};
CORRADE_COMPARE(ca.materialId, 0);
CORRADE_COMPARE(cb.materialId, 0);
CORRADE_VERIFY(std::is_nothrow_default_constructible<DistanceFieldVectorDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<DistanceFieldVectorDrawUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, DistanceFieldVectorDrawUniform>::value);
}
void DistanceFieldVectorTest::drawUniformConstructNoInit() {
/* Testing only some fields, should be enough */
DistanceFieldVectorDrawUniform a;
a.materialId = 76;
new(&a) DistanceFieldVectorDrawUniform{NoInit};
CORRADE_COMPARE(a.materialId, 76);
CORRADE_VERIFY(std::is_nothrow_constructible<DistanceFieldVectorDrawUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, DistanceFieldVectorDrawUniform>::value);
}
void DistanceFieldVectorTest::drawUniformSetters() {
DistanceFieldVectorDrawUniform a;
a.setMaterialId(76);
CORRADE_COMPARE(a.materialId, 76);
}
void DistanceFieldVectorTest::drawUniformMaterialIdPacking() {
DistanceFieldVectorDrawUniform a;
a.setMaterialId(13765);
/* materialId should be right at the beginning, in the low 16 bits on both
LE and BE */
CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&a)[0] & 0xffff, 13765);
}
void DistanceFieldVectorTest::materialUniformConstructDefault() {
DistanceFieldVectorMaterialUniform a;
DistanceFieldVectorMaterialUniform b{DefaultInit};
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(a.outlineColor, 0x00000000_rgbaf);
CORRADE_COMPARE(b.outlineColor, 0x00000000_rgbaf);
CORRADE_COMPARE(a.outlineStart, 0.5f);
CORRADE_COMPARE(b.outlineStart, 0.5f);
CORRADE_COMPARE(a.outlineEnd, 1.0f);
CORRADE_COMPARE(b.outlineEnd, 1.0f);
CORRADE_COMPARE(a.smoothness, 0.04f);
CORRADE_COMPARE(b.smoothness, 0.04f);
constexpr DistanceFieldVectorMaterialUniform ca;
constexpr DistanceFieldVectorMaterialUniform cb{DefaultInit};
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(ca.outlineColor, 0x00000000_rgbaf);
CORRADE_COMPARE(cb.outlineColor, 0x00000000_rgbaf);
CORRADE_COMPARE(ca.outlineStart, 0.5f);
CORRADE_COMPARE(cb.outlineStart, 0.5f);
CORRADE_COMPARE(ca.outlineEnd, 1.0f);
CORRADE_COMPARE(cb.outlineEnd, 1.0f);
CORRADE_COMPARE(ca.smoothness, 0.04f);
CORRADE_COMPARE(cb.smoothness, 0.04f);
CORRADE_VERIFY(std::is_nothrow_default_constructible<DistanceFieldVectorMaterialUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<DistanceFieldVectorMaterialUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, DistanceFieldVectorMaterialUniform>::value);
}
void DistanceFieldVectorTest::materialUniformConstructNoInit() {
/* Testing only some fields, should be enough */
DistanceFieldVectorMaterialUniform a;
a.color = 0x354565fc_rgbaf;
a.outlineEnd = 0.37f;
new(&a) DistanceFieldVectorMaterialUniform{NoInit};
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.outlineEnd, 0.37f);
CORRADE_VERIFY(std::is_nothrow_constructible<DistanceFieldVectorMaterialUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, DistanceFieldVectorMaterialUniform>::value);
}
void DistanceFieldVectorTest::materialUniformSetters() {
DistanceFieldVectorMaterialUniform a;
a.setColor(0x354565fc_rgbaf)
.setOutlineColor(0x9876facd_rgbaf)
.setOutlineRange(0.6f, 0.1f)
.setSmoothness(0.37f);
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.outlineColor, 0x9876facd_rgbaf);
CORRADE_COMPARE(a.outlineStart, 0.6f);
CORRADE_COMPARE(a.outlineEnd, 0.1f);
CORRADE_COMPARE(a.smoothness, 0.37f);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::DistanceFieldVectorTest)

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

File diff suppressed because it is too large Load Diff

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

@ -78,8 +78,8 @@ template<UnsignedInt dimensions> void FlatGL_Test::constructCopy() {
void FlatGL_Test::debugFlag() {
std::ostringstream out;
Debug{&out} << FlatGL3D::Flag::Textured << FlatGL3D::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::Textured Shaders::FlatGL::Flag(0xf0)\n");
Debug{&out} << FlatGL3D::Flag::Textured << FlatGL3D::Flag(0xf00d);
CORRADE_COMPARE(out.str(), "Shaders::FlatGL::Flag::Textured Shaders::FlatGL::Flag(0xf00d)\n");
}
void FlatGL_Test::debugFlags() {

124
src/Magnum/Shaders/Test/FlatTest.cpp

@ -0,0 +1,124 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <new>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Shaders/Flat.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
struct FlatTest: TestSuite::Tester {
explicit FlatTest();
template<class T> void uniformSize();
void drawUniformConstructDefault();
void drawUniformConstructNoInit();
void drawUniformSetters();
};
FlatTest::FlatTest() {
addTests({&FlatTest::uniformSize<FlatDrawUniform>,
&FlatTest::drawUniformConstructDefault,
&FlatTest::drawUniformConstructNoInit,
&FlatTest::drawUniformSetters});
}
using namespace Math::Literals;
template<class> struct UniformTraits;
template<> struct UniformTraits<FlatDrawUniform> {
static const char* name() { return "FlatDrawUniform"; }
};
template<class T> void FlatTest::uniformSize() {
setTestCaseTemplateName(UniformTraits<T>::name());
CORRADE_FAIL_IF(sizeof(T) % sizeof(Vector4) != 0, sizeof(T) << "is not a multiple of vec4 for UBO alignment.");
/* 48-byte structures are fine, we'll align them to 768 bytes and not
256, but warn about that */
CORRADE_FAIL_IF(768 % sizeof(T) != 0, sizeof(T) << "can't fit exactly into 768-byte UBO alignment.");
if(256 % sizeof(T) != 0)
CORRADE_WARN(sizeof(T) << "can't fit exactly into 256-byte UBO alignment, only 768.");
}
void FlatTest::drawUniformConstructDefault() {
FlatDrawUniform a;
FlatDrawUniform b{DefaultInit};
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(a.objectId, 0);
CORRADE_COMPARE(b.objectId, 0);
CORRADE_COMPARE(a.alphaMask, 0.5f);
CORRADE_COMPARE(b.alphaMask, 0.5f);
constexpr FlatDrawUniform ca;
constexpr FlatDrawUniform cb{DefaultInit};
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(ca.objectId, 0);
CORRADE_COMPARE(cb.objectId, 0);
CORRADE_COMPARE(ca.alphaMask, 0.5f);
CORRADE_COMPARE(cb.alphaMask, 0.5f);
CORRADE_VERIFY(std::is_nothrow_default_constructible<FlatDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, FlatDrawUniform>::value);
}
void FlatTest::drawUniformConstructNoInit() {
/* Testing only some fields, should be enough */
FlatDrawUniform a;
a.color = 0x354565fc_rgbaf;
a.alphaMask = 0.7f;
new(&a) FlatDrawUniform{NoInit};
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.alphaMask, 0.7f);
CORRADE_VERIFY(std::is_nothrow_constructible<FlatDrawUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, FlatDrawUniform>::value);
}
void FlatTest::drawUniformSetters() {
FlatDrawUniform a;
a.setColor(0x354565fc_rgbaf)
.setObjectId(7)
.setAlphaMask(0.7f);
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.objectId, 7);
CORRADE_COMPARE(a.alphaMask, 0.7f);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::FlatTest)

BIN
src/Magnum/Shaders/Test/FlatTestFiles/multidraw-textured2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/FlatTestFiles/multidraw-textured3D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/FlatTestFiles/multidraw2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/FlatTestFiles/multidraw3D.tga

Binary file not shown.

408
src/Magnum/Shaders/Test/GenericTest.cpp

@ -0,0 +1,408 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <new>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Shaders/Generic.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
struct GenericTest: TestSuite::Tester {
explicit GenericTest();
template<class T> void uniformSize();
void projectionUniform2DConstructDefault();
void projectionUniform2DConstructNoInit();
void projectionUniform2DSetters();
void projectionUniform3DConstructDefault();
void projectionUniform3DConstructNoInit();
void projectionUniform3DSetters();
void transformationUniform2DConstructDefault();
void transformationUniform2DConstructNoInit();
void transformationUniform2DSetters();
void transformationUniform3DConstructDefault();
void transformationUniform3DConstructNoInit();
void transformationUniform3DSetters();
void textureTransformationUniformConstructDefault();
void textureTransformationUniformConstructNoInit();
void textureTransformationUniformSetters();
};
GenericTest::GenericTest() {
addTests({&GenericTest::uniformSize<ProjectionUniform2D>,
&GenericTest::uniformSize<ProjectionUniform3D>,
&GenericTest::uniformSize<TransformationUniform2D>,
&GenericTest::uniformSize<TransformationUniform3D>,
&GenericTest::uniformSize<TextureTransformationUniform>,
&GenericTest::projectionUniform2DConstructDefault,
&GenericTest::projectionUniform2DConstructNoInit,
&GenericTest::projectionUniform2DSetters,
&GenericTest::projectionUniform3DConstructDefault,
&GenericTest::projectionUniform3DConstructNoInit,
&GenericTest::projectionUniform3DSetters,
&GenericTest::transformationUniform2DConstructDefault,
&GenericTest::transformationUniform2DConstructNoInit,
&GenericTest::transformationUniform2DSetters,
&GenericTest::transformationUniform3DConstructDefault,
&GenericTest::transformationUniform3DConstructNoInit,
&GenericTest::transformationUniform3DSetters,
&GenericTest::textureTransformationUniformConstructDefault,
&GenericTest::textureTransformationUniformConstructNoInit,
&GenericTest::textureTransformationUniformSetters});
}
using namespace Math::Literals;
template<class> struct UniformTraits;
template<> struct UniformTraits<ProjectionUniform2D> {
static const char* name() { return "ProjectionUniform2D"; }
};
template<> struct UniformTraits<ProjectionUniform3D> {
static const char* name() { return "ProjectionUniform3D"; }
};
template<> struct UniformTraits<TransformationUniform2D> {
static const char* name() { return "TransformationUniform2D"; }
};
template<> struct UniformTraits<TransformationUniform3D> {
static const char* name() { return "TransformationUniform3D"; }
};
template<> struct UniformTraits<TextureTransformationUniform> {
static const char* name() { return "TextureTransformationUniform"; }
};
template<class T> void GenericTest::uniformSize() {
setTestCaseTemplateName(UniformTraits<T>::name());
CORRADE_FAIL_IF(sizeof(T) % sizeof(Vector4) != 0, sizeof(T) << "is not a multiple of vec4 for UBO alignment.");
/* 48-byte structures are fine, we'll align them to 768 bytes and not
256, but warn about that */
CORRADE_FAIL_IF(768 % sizeof(T) != 0, sizeof(T) << "can't fit exactly into 768-byte UBO alignment.");
if(256 % sizeof(T) != 0)
CORRADE_WARN(sizeof(T) << "can't fit exactly into 256-byte UBO alignment, only 768.");
}
void GenericTest::projectionUniform2DConstructDefault() {
ProjectionUniform2D a;
ProjectionUniform2D b{DefaultInit};
CORRADE_COMPARE(a.projectionMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(b.projectionMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
constexpr ProjectionUniform2D ca;
constexpr ProjectionUniform2D cb{DefaultInit};
CORRADE_COMPARE(ca.projectionMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(cb.projectionMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_VERIFY(std::is_nothrow_default_constructible<ProjectionUniform2D>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<ProjectionUniform2D, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, ProjectionUniform2D>::value);
}
void GenericTest::projectionUniform2DConstructNoInit() {
ProjectionUniform2D a;
a.projectionMatrix[2] = {1.5f, 0.3f, 3.1f, 0.5f};
new(&a) ProjectionUniform2D{NoInit};
CORRADE_COMPARE(a.projectionMatrix[2], (Vector4{1.5f, 0.3f, 3.1f, 0.5f}));
CORRADE_VERIFY(std::is_nothrow_constructible<ProjectionUniform2D, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, ProjectionUniform2D>::value);
}
void GenericTest::projectionUniform2DSetters() {
ProjectionUniform2D a;
a.setProjectionMatrix(Matrix3::projection({2.5f, 3.0f}));
CORRADE_COMPARE(a.projectionMatrix, (Matrix3x4{
Vector4{0.8f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.666667f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
}
void GenericTest::projectionUniform3DConstructDefault() {
ProjectionUniform3D a;
ProjectionUniform3D b{DefaultInit};
CORRADE_COMPARE(a.projectionMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
CORRADE_COMPARE(b.projectionMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
constexpr ProjectionUniform3D ca;
constexpr ProjectionUniform3D cb{DefaultInit};
CORRADE_COMPARE(ca.projectionMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
CORRADE_COMPARE(cb.projectionMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
CORRADE_VERIFY(std::is_nothrow_default_constructible<ProjectionUniform3D>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<ProjectionUniform3D, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, ProjectionUniform3D>::value);
}
void GenericTest::projectionUniform3DConstructNoInit() {
ProjectionUniform3D a;
a.projectionMatrix[2] = {1.5f, 0.3f, 3.1f, 0.5f};
new(&a) ProjectionUniform3D{NoInit};
CORRADE_COMPARE(a.projectionMatrix[2], (Vector4{1.5f, 0.3f, 3.1f, 0.5f}));
CORRADE_VERIFY(std::is_nothrow_constructible<ProjectionUniform3D, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, ProjectionUniform3D>::value);
}
void GenericTest::projectionUniform3DSetters() {
ProjectionUniform3D a;
a.setProjectionMatrix(Matrix4::perspectiveProjection(35.0_degf, 1.5f, 0.1f, 100.0f));
CORRADE_COMPARE(a.projectionMatrix, Matrix4::perspectiveProjection(35.0_degf, 1.5f, 0.1f, 100.0f));
}
void GenericTest::transformationUniform2DConstructDefault() {
TransformationUniform2D a;
TransformationUniform2D b{DefaultInit};
CORRADE_COMPARE(a.transformationMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(b.transformationMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
constexpr TransformationUniform2D ca;
constexpr TransformationUniform2D cb{DefaultInit};
CORRADE_COMPARE(ca.transformationMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(cb.transformationMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_VERIFY(std::is_nothrow_default_constructible<TransformationUniform2D>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<TransformationUniform2D, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, TransformationUniform2D>::value);
}
void GenericTest::transformationUniform2DConstructNoInit() {
TransformationUniform2D a;
a.transformationMatrix[2] = {1.5f, 0.3f, 3.1f, 0.5f};
new(&a) TransformationUniform2D{NoInit};
CORRADE_COMPARE(a.transformationMatrix[2], (Vector4{1.5f, 0.3f, 3.1f, 0.5f}));
CORRADE_VERIFY(std::is_nothrow_constructible<TransformationUniform2D, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, TransformationUniform2D>::value);
}
void GenericTest::transformationUniform2DSetters() {
TransformationUniform2D a;
a.setTransformationMatrix(Matrix3::translation({2.5f, 3.0f}));
CORRADE_COMPARE(a.transformationMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{2.5f, 3.0f, 1.0f, 0.0f}
}));
}
void GenericTest::transformationUniform3DConstructDefault() {
TransformationUniform3D a;
TransformationUniform3D b{DefaultInit};
CORRADE_COMPARE(a.transformationMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
CORRADE_COMPARE(b.transformationMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
constexpr TransformationUniform3D ca;
constexpr TransformationUniform3D cb{DefaultInit};
CORRADE_COMPARE(ca.transformationMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
CORRADE_COMPARE(cb.transformationMatrix, (Matrix4{
{1.0f, 0.0f, 0.0f, 0.0f},
{0.0f, 1.0f, 0.0f, 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{0.0f, 0.0f, 0.0f, 1.0f}
}));
CORRADE_VERIFY(std::is_nothrow_default_constructible<TransformationUniform3D>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<TransformationUniform3D, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, TransformationUniform3D>::value);
}
void GenericTest::transformationUniform3DConstructNoInit() {
TransformationUniform3D a;
a.transformationMatrix[2] = {1.5f, 0.3f, 3.1f, 0.5f};
new(&a) TransformationUniform3D{NoInit};
CORRADE_COMPARE(a.transformationMatrix[2], (Vector4{1.5f, 0.3f, 3.1f, 0.5f}));
CORRADE_VERIFY(std::is_nothrow_constructible<TransformationUniform3D, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, TransformationUniform3D>::value);
}
void GenericTest::transformationUniform3DSetters() {
TransformationUniform3D a;
a.setTransformationMatrix(Matrix4::translation({3.5f, 2.0f, -1.0f}));
CORRADE_COMPARE(a.transformationMatrix, Matrix4::translation({3.5f, 2.0f, -1.0f}));
}
void GenericTest::textureTransformationUniformConstructDefault() {
TextureTransformationUniform a;
TextureTransformationUniform b{DefaultInit};
CORRADE_COMPARE(a.rotationScaling, (Matrix2x2{
Vector2{1.0f, 0.0f},
Vector2{0.0f, 1.0f}
}));
CORRADE_COMPARE(b.rotationScaling, (Matrix2x2{
Vector2{1.0f, 0.0f},
Vector2{0.0f, 1.0f}
}));
CORRADE_COMPARE(a.offset, (Vector2{0.0f, 0.0f}));
CORRADE_COMPARE(b.offset, (Vector2{0.0f, 0.0f}));
constexpr TextureTransformationUniform ca;
constexpr TextureTransformationUniform cb{DefaultInit};
CORRADE_COMPARE(ca.rotationScaling, (Matrix2x2{
Vector2{1.0f, 0.0f},
Vector2{0.0f, 1.0f}
}));
CORRADE_COMPARE(cb.rotationScaling, (Matrix2x2{
Vector2{1.0f, 0.0f},
Vector2{0.0f, 1.0f}
}));
CORRADE_COMPARE(ca.offset, (Vector2{0.0f, 0.0f}));
CORRADE_COMPARE(cb.offset, (Vector2{0.0f, 0.0f}));
CORRADE_VERIFY(std::is_nothrow_default_constructible<TextureTransformationUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<TextureTransformationUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, TextureTransformationUniform>::value);
}
void GenericTest::textureTransformationUniformConstructNoInit() {
TextureTransformationUniform a;
a.rotationScaling[1] = {2.5f, -3.0f};
a.offset = {2.7f, 0.3f};
new(&a) TextureTransformationUniform{NoInit};
CORRADE_COMPARE(a.rotationScaling[1], (Vector2{2.5f, -3.0f}));
CORRADE_COMPARE(a.offset, (Vector2{2.7f, 0.3f}));
CORRADE_VERIFY(std::is_nothrow_constructible<TextureTransformationUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, TextureTransformationUniform>::value);
}
void GenericTest::textureTransformationUniformSetters() {
TextureTransformationUniform a;
a.setTextureMatrix(Matrix3::translation({2.6f, 0.3f})*
Matrix3::rotation(90.0_degf));
CORRADE_COMPARE(a.rotationScaling, (Matrix2x2{
Vector2{ 0.0f, 1.0f},
Vector2{-1.0f, 0.0f}
}));
CORRADE_COMPARE(a.offset, (Vector2{2.6f, 0.3f}));
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::GenericTest)

1959
src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp

File diff suppressed because it is too large Load Diff

302
src/Magnum/Shaders/Test/MeshVisualizerTest.cpp

@ -0,0 +1,302 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <new>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Math/Matrix4.h"
#include "Magnum/Shaders/MeshVisualizer.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
struct MeshVisualizerTest: TestSuite::Tester {
explicit MeshVisualizerTest();
template<class T> void uniformSize();
void drawUniform2DConstructDefault();
void drawUniform2DConstructNoInit();
void drawUniform2DSetters();
void drawUniform2DMaterialIdPacking();
void drawUniform3DConstructDefault();
void drawUniform3DConstructNoInit();
void drawUniform3DSetters();
void drawUniform3DMaterialIdPacking();
void materialUniformConstructDefault();
void materialUniformConstructNoInit();
void materialUniformSetters();
};
MeshVisualizerTest::MeshVisualizerTest() {
addTests({&MeshVisualizerTest::uniformSize<MeshVisualizerDrawUniform2D>,
&MeshVisualizerTest::uniformSize<MeshVisualizerDrawUniform3D>,
&MeshVisualizerTest::uniformSize<MeshVisualizerMaterialUniform>,
&MeshVisualizerTest::drawUniform2DConstructDefault,
&MeshVisualizerTest::drawUniform2DConstructNoInit,
&MeshVisualizerTest::drawUniform2DSetters,
&MeshVisualizerTest::drawUniform2DMaterialIdPacking,
&MeshVisualizerTest::drawUniform3DConstructDefault,
&MeshVisualizerTest::drawUniform3DConstructNoInit,
&MeshVisualizerTest::drawUniform3DSetters,
&MeshVisualizerTest::drawUniform3DMaterialIdPacking,
&MeshVisualizerTest::materialUniformConstructDefault,
&MeshVisualizerTest::materialUniformConstructNoInit,
&MeshVisualizerTest::materialUniformSetters});
}
using namespace Math::Literals;
template<class> struct UniformTraits;
template<> struct UniformTraits<MeshVisualizerDrawUniform2D> {
static const char* name() { return "MeshVisualizerDrawUniform2D"; }
};
template<> struct UniformTraits<MeshVisualizerDrawUniform3D> {
static const char* name() { return "MeshVisualizerDrawUniform3D"; }
};
template<> struct UniformTraits<MeshVisualizerMaterialUniform> {
static const char* name() { return "MeshVisualizerMaterialUniform"; }
};
template<class T> void MeshVisualizerTest::uniformSize() {
setTestCaseTemplateName(UniformTraits<T>::name());
CORRADE_FAIL_IF(sizeof(T) % sizeof(Vector4) != 0, sizeof(T) << "is not a multiple of vec4 for UBO alignment");
/* 48-byte structures are fine, we'll align them to 768 bytes and not
256, but warn about that */
CORRADE_FAIL_IF(768 % sizeof(T) != 0, sizeof(T) << "can't fit exactly into 768-byte UBO alignment");
if(256 % sizeof(T) != 0)
CORRADE_WARN(sizeof(T) << "can't fit exactly into 256-byte UBO alignment, only 768");
}
void MeshVisualizerTest::drawUniform2DConstructDefault() {
MeshVisualizerDrawUniform2D a;
MeshVisualizerDrawUniform2D b{DefaultInit};
CORRADE_COMPARE(a.materialId, 0);
CORRADE_COMPARE(b.materialId, 0);
constexpr MeshVisualizerDrawUniform2D ca;
constexpr MeshVisualizerDrawUniform2D cb{DefaultInit};
CORRADE_COMPARE(ca.materialId, 0);
CORRADE_COMPARE(cb.materialId, 0);
CORRADE_VERIFY(std::is_nothrow_default_constructible<MeshVisualizerDrawUniform2D>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<MeshVisualizerDrawUniform2D, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, MeshVisualizerDrawUniform2D>::value);
}
void MeshVisualizerTest::drawUniform2DConstructNoInit() {
/* Testing only some fields, should be enough */
MeshVisualizerDrawUniform2D a;
a.materialId = 73;
new(&a) MeshVisualizerDrawUniform2D{NoInit};
CORRADE_COMPARE(a.materialId, 73);
CORRADE_VERIFY(std::is_nothrow_constructible<MeshVisualizerDrawUniform2D, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, MeshVisualizerDrawUniform2D>::value);
}
void MeshVisualizerTest::drawUniform2DSetters() {
MeshVisualizerDrawUniform2D a;
a.setMaterialId(73);
CORRADE_COMPARE(a.materialId, 73);
}
void MeshVisualizerTest::drawUniform2DMaterialIdPacking() {
MeshVisualizerDrawUniform2D a;
a.setMaterialId(13765);
/* materialId should be right at the beginning, in the low 16 bits on both
LE and BE */
CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&a)[0] & 0xffff, 13765);
}
void MeshVisualizerTest::drawUniform3DConstructDefault() {
MeshVisualizerDrawUniform3D a;
MeshVisualizerDrawUniform3D b{DefaultInit};
CORRADE_COMPARE(a.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(b.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(a.materialId, 0);
CORRADE_COMPARE(b.materialId, 0);
constexpr MeshVisualizerDrawUniform3D ca;
constexpr MeshVisualizerDrawUniform3D cb{DefaultInit};
CORRADE_COMPARE(ca.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(cb.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(ca.materialId, 0);
CORRADE_COMPARE(cb.materialId, 0);
CORRADE_VERIFY(std::is_nothrow_default_constructible<MeshVisualizerDrawUniform3D>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<MeshVisualizerDrawUniform3D, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, MeshVisualizerDrawUniform2D>::value);
}
void MeshVisualizerTest::drawUniform3DConstructNoInit() {
/* Testing only some fields, should be enough */
MeshVisualizerDrawUniform3D a;
a.normalMatrix[2] = {1.5f, 0.3f, 3.1f, 0.5f};
a.materialId = 5;
new(&a) MeshVisualizerDrawUniform3D{NoInit};
CORRADE_COMPARE(a.normalMatrix[2], (Vector4{1.5f, 0.3f, 3.1f, 0.5f}));
CORRADE_COMPARE(a.materialId, 5);
CORRADE_VERIFY(std::is_nothrow_constructible<MeshVisualizerDrawUniform3D, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, MeshVisualizerDrawUniform3D>::value);
}
void MeshVisualizerTest::drawUniform3DSetters() {
MeshVisualizerDrawUniform3D a;
a.setNormalMatrix(Matrix4::rotationX(90.0_degf).normalMatrix())
.setMaterialId(5);
CORRADE_COMPARE(a.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f},
Vector4{0.0f, -1.0f, 0.0f, 0.0f}
}));
CORRADE_COMPARE(a.materialId, 5);
}
void MeshVisualizerTest::drawUniform3DMaterialIdPacking() {
MeshVisualizerDrawUniform3D a;
a.setMaterialId(13765);
/* The normalMatrix field is 3x4 floats, materialId should be right after
in the low 16 bits on both LE and BE */
CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&a)[12] & 0xffff, 13765);
}
void MeshVisualizerTest::materialUniformConstructDefault() {
MeshVisualizerMaterialUniform a;
MeshVisualizerMaterialUniform b{DefaultInit};
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(a.wireframeColor, 0x000000ff_rgbaf);
CORRADE_COMPARE(b.wireframeColor, 0x000000ff_rgbaf);
CORRADE_COMPARE(a.wireframeWidth, 1.0f);
CORRADE_COMPARE(b.wireframeWidth, 1.0f);
CORRADE_COMPARE(a.colorMapOffset, 1.0f/512.0f);
CORRADE_COMPARE(b.colorMapOffset, 1.0f/512.0f);
CORRADE_COMPARE(a.colorMapScale, 1.0f/256.0f);
CORRADE_COMPARE(b.colorMapScale, 1.0f/256.0f);
CORRADE_COMPARE(a.lineWidth, 1.0f);
CORRADE_COMPARE(b.lineWidth, 1.0f);
CORRADE_COMPARE(a.lineLength, 1.0f);
CORRADE_COMPARE(b.lineLength, 1.0f);
CORRADE_COMPARE(a.smoothness, 2.0f);
CORRADE_COMPARE(b.smoothness, 2.0f);
constexpr MeshVisualizerMaterialUniform ca;
constexpr MeshVisualizerMaterialUniform cb{DefaultInit};
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(ca.wireframeColor, 0x000000ff_rgbaf);
CORRADE_COMPARE(cb.wireframeColor, 0x000000ff_rgbaf);
CORRADE_COMPARE(ca.wireframeWidth, 1.0f);
CORRADE_COMPARE(cb.wireframeWidth, 1.0f);
CORRADE_COMPARE(ca.colorMapOffset, 1.0f/512.0f);
CORRADE_COMPARE(cb.colorMapOffset, 1.0f/512.0f);
CORRADE_COMPARE(ca.colorMapScale, 1.0f/256.0f);
CORRADE_COMPARE(cb.colorMapScale, 1.0f/256.0f);
CORRADE_COMPARE(ca.lineWidth, 1.0f);
CORRADE_COMPARE(cb.lineWidth, 1.0f);
CORRADE_COMPARE(ca.lineLength, 1.0f);
CORRADE_COMPARE(cb.lineLength, 1.0f);
CORRADE_COMPARE(ca.smoothness, 2.0f);
CORRADE_COMPARE(cb.smoothness, 2.0f);
CORRADE_VERIFY(std::is_nothrow_default_constructible<MeshVisualizerMaterialUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<MeshVisualizerMaterialUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, MeshVisualizerMaterialUniform>::value);
}
void MeshVisualizerTest::materialUniformConstructNoInit() {
/* Testing only some fields, should be enough */
MeshVisualizerMaterialUniform a;
a.color = 0x354565fc_rgbaf;
a.lineWidth = 0.765f;
new(&a) MeshVisualizerMaterialUniform{NoInit};
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.lineWidth, 0.765f);
CORRADE_VERIFY(std::is_nothrow_constructible<MeshVisualizerMaterialUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, MeshVisualizerMaterialUniform>::value);
}
void MeshVisualizerTest::materialUniformSetters() {
MeshVisualizerMaterialUniform a;
a.setColor(0x354565fc_rgbaf)
.setWireframeColor(0x9876fadc_rgbaf)
.setWireframeWidth(3.5f)
.setColorMapTransformation(35.5f, 0.5f)
.setLineWidth(3.0f)
.setLineLength(4.0f)
.setSmoothness(5.0f);
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.wireframeColor, 0x9876fadc_rgbaf);
CORRADE_COMPARE(a.wireframeWidth, 3.5f);
CORRADE_COMPARE(a.colorMapOffset, 35.5f);
CORRADE_COMPARE(a.colorMapScale, 0.5f);
CORRADE_COMPARE(a.lineWidth, 3.0f);
CORRADE_COMPARE(a.lineLength, 4.0f);
CORRADE_COMPARE(a.smoothness, 5.0f);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::MeshVisualizerTest)

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-vertexid2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-vertexid3D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe-nogeo2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe-nogeo3D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe-tbn3D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/multidraw-wireframe3D.tga

Binary file not shown.

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

File diff suppressed because it is too large Load Diff

322
src/Magnum/Shaders/Test/PhongTest.cpp

@ -0,0 +1,322 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <new>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Math/Matrix4.h"
#include "Magnum/Shaders/Phong.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
struct PhongTest: TestSuite::Tester {
explicit PhongTest();
template<class T> void uniformSize();
void drawUniformConstructDefault();
void drawUniformConstructNoInit();
void drawUniformSetters();
void drawUniformMaterialIdPacking();
void materialUniformConstructDefault();
void materialUniformConstructNoInit();
void materialUniformSetters();
void lightUniformConstructDefault();
void lightUniformConstructNoInit();
void lightUniformSetters();
};
PhongTest::PhongTest() {
addTests({&PhongTest::uniformSize<PhongDrawUniform>,
&PhongTest::uniformSize<PhongMaterialUniform>,
&PhongTest::uniformSize<PhongLightUniform>,
&PhongTest::drawUniformConstructDefault,
&PhongTest::drawUniformConstructNoInit,
&PhongTest::drawUniformSetters,
&PhongTest::drawUniformMaterialIdPacking,
&PhongTest::materialUniformConstructDefault,
&PhongTest::materialUniformConstructNoInit,
&PhongTest::materialUniformSetters,
&PhongTest::lightUniformConstructDefault,
&PhongTest::lightUniformConstructNoInit,
&PhongTest::lightUniformSetters});
}
using namespace Math::Literals;
template<class> struct UniformTraits;
template<> struct UniformTraits<PhongDrawUniform> {
static const char* name() { return "PhongDrawUniform"; }
};
template<> struct UniformTraits<PhongMaterialUniform> {
static const char* name() { return "PhongMaterialUniform"; }
};
template<> struct UniformTraits<PhongLightUniform> {
static const char* name() { return "PhongLightUniform"; }
};
template<class T> void PhongTest::uniformSize() {
setTestCaseTemplateName(UniformTraits<T>::name());
CORRADE_FAIL_IF(sizeof(T) % sizeof(Vector4) != 0, sizeof(T) << "is not a multiple of vec4 for UBO alignment.");
/* 48-byte structures are fine, we'll align them to 768 bytes and not
256, but warn about that */
CORRADE_FAIL_IF(768 % sizeof(T) != 0, sizeof(T) << "can't fit exactly into 768-byte UBO alignment.");
if(256 % sizeof(T) != 0)
CORRADE_WARN(sizeof(T) << "can't fit exactly into 256-byte UBO alignment, only 768.");
}
void PhongTest::drawUniformConstructDefault() {
PhongDrawUniform a;
PhongDrawUniform b{DefaultInit};
CORRADE_COMPARE(a.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(b.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(a.materialId, 0);
CORRADE_COMPARE(b.materialId, 0);
CORRADE_COMPARE(a.objectId, 0);
CORRADE_COMPARE(b.objectId, 0);
CORRADE_COMPARE(a.lightOffset, 0);
CORRADE_COMPARE(b.lightOffset, 0);
CORRADE_COMPARE(a.lightCount, 0xffffffffu);
CORRADE_COMPARE(b.lightCount, 0xffffffffu);
constexpr PhongDrawUniform ca;
constexpr PhongDrawUniform cb{DefaultInit};
CORRADE_COMPARE(ca.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(cb.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 1.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f}
}));
CORRADE_COMPARE(ca.materialId, 0);
CORRADE_COMPARE(cb.materialId, 0);
CORRADE_COMPARE(ca.objectId, 0);
CORRADE_COMPARE(cb.objectId, 0);
CORRADE_COMPARE(ca.lightOffset, 0);
CORRADE_COMPARE(cb.lightOffset, 0);
CORRADE_COMPARE(ca.lightCount, 0xffffffffu);
CORRADE_COMPARE(cb.lightCount, 0xffffffffu);
CORRADE_VERIFY(std::is_nothrow_default_constructible<PhongDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongDrawUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, PhongDrawUniform>::value);
}
void PhongTest::drawUniformConstructNoInit() {
/* Testing only some fields, should be enough */
PhongDrawUniform a;
a.normalMatrix[2] = {1.5f, 0.3f, 3.1f, 0.5f};
a.materialId = 5;
a.lightCount = 7;
new(&a) PhongDrawUniform{NoInit};
CORRADE_COMPARE(a.normalMatrix[2], (Vector4{1.5f, 0.3f, 3.1f, 0.5f}));
CORRADE_COMPARE(a.materialId, 5);
CORRADE_COMPARE(a.lightCount, 7);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongDrawUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, PhongDrawUniform>::value);
}
void PhongTest::drawUniformSetters() {
PhongDrawUniform a;
a.setNormalMatrix(Matrix4::rotationX(90.0_degf).normalMatrix())
.setMaterialId(5)
.setObjectId(7)
.setLightOffsetCount(9, 13);
CORRADE_COMPARE(a.normalMatrix, (Matrix3x4{
Vector4{1.0f, 0.0f, 0.0f, 0.0f},
Vector4{0.0f, 0.0f, 1.0f, 0.0f},
Vector4{0.0f, -1.0f, 0.0f, 0.0f}
}));
CORRADE_COMPARE(a.materialId, 5);
CORRADE_COMPARE(a.objectId, 7);
CORRADE_COMPARE(a.lightOffset, 9);
CORRADE_COMPARE(a.lightCount, 13);
}
void PhongTest::drawUniformMaterialIdPacking() {
PhongDrawUniform a;
a.setMaterialId(13765);
/* The normalMatrix field is 3x4 floats, materialId should be right after
in the low 16 bits on both LE and BE */
CORRADE_COMPARE(reinterpret_cast<UnsignedInt*>(&a)[12] & 0xffff, 13765);
}
void PhongTest::materialUniformConstructDefault() {
PhongMaterialUniform a;
PhongMaterialUniform b{DefaultInit};
CORRADE_COMPARE(a.ambientColor, 0x00000000_rgbaf);
CORRADE_COMPARE(b.ambientColor, 0x00000000_rgbaf);
CORRADE_COMPARE(a.diffuseColor, 0xffffffff_rgbaf);
CORRADE_COMPARE(b.diffuseColor, 0xffffffff_rgbaf);
CORRADE_COMPARE(a.specularColor, 0xffffff00_rgbaf);
CORRADE_COMPARE(b.specularColor, 0xffffff00_rgbaf);
CORRADE_COMPARE(a.normalTextureScale, 1.0f);
CORRADE_COMPARE(b.normalTextureScale, 1.0f);
CORRADE_COMPARE(a.shininess, 80.0f);
CORRADE_COMPARE(b.shininess, 80.0f);
CORRADE_COMPARE(a.alphaMask, 0.5f);
CORRADE_COMPARE(b.alphaMask, 0.5f);
constexpr PhongMaterialUniform ca;
constexpr PhongMaterialUniform cb{DefaultInit};
CORRADE_COMPARE(ca.ambientColor, 0x00000000_rgbaf);
CORRADE_COMPARE(cb.ambientColor, 0x00000000_rgbaf);
CORRADE_COMPARE(ca.diffuseColor, 0xffffffff_rgbaf);
CORRADE_COMPARE(cb.diffuseColor, 0xffffffff_rgbaf);
CORRADE_COMPARE(ca.specularColor, 0xffffff00_rgbaf);
CORRADE_COMPARE(cb.specularColor, 0xffffff00_rgbaf);
CORRADE_COMPARE(ca.normalTextureScale, 1.0f);
CORRADE_COMPARE(cb.normalTextureScale, 1.0f);
CORRADE_COMPARE(ca.shininess, 80.0f);
CORRADE_COMPARE(cb.shininess, 80.0f);
CORRADE_COMPARE(ca.alphaMask, 0.5f);
CORRADE_COMPARE(cb.alphaMask, 0.5f);
CORRADE_VERIFY(std::is_nothrow_default_constructible<PhongMaterialUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongMaterialUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, PhongMaterialUniform>::value);
}
void PhongTest::materialUniformConstructNoInit() {
/* Testing only some fields, should be enough */
PhongMaterialUniform a;
a.diffuseColor = 0x354565fc_rgbaf;
a.normalTextureScale = 0.4f;
a.alphaMask = 7.0f;
new(&a) PhongMaterialUniform{NoInit};
CORRADE_COMPARE(a.diffuseColor, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.normalTextureScale, 0.4f);
CORRADE_COMPARE(a.alphaMask, 7.0f);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongMaterialUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, PhongMaterialUniform>::value);
}
void PhongTest::materialUniformSetters() {
PhongMaterialUniform a;
a.setAmbientColor(0xff3366cc_rgbaf)
.setDiffuseColor(0x996600aa_rgbaf)
.setSpecularColor(0x0044ffdd_rgbaf)
.setNormalTextureScale(0.4f)
.setShininess(37.0f)
.setAlphaMask(2.5f);
CORRADE_COMPARE(a.ambientColor, 0xff3366cc_rgbaf);
CORRADE_COMPARE(a.diffuseColor, 0x996600aa_rgbaf);
CORRADE_COMPARE(a.specularColor, 0x0044ffdd_rgbaf);
CORRADE_COMPARE(a.normalTextureScale, 0.4f);
CORRADE_COMPARE(a.shininess, 37.0f);
CORRADE_COMPARE(a.alphaMask, 2.5f);
}
void PhongTest::lightUniformConstructDefault() {
PhongLightUniform a;
PhongLightUniform b{DefaultInit};
CORRADE_COMPARE(a.position, (Vector4{0.0f, 0.0f, 1.0f, 0.0f}));
CORRADE_COMPARE(b.position, (Vector4{0.0f, 0.0f, 1.0f, 0.0f}));
CORRADE_COMPARE(a.color, 0xffffff_rgbf);
CORRADE_COMPARE(b.color, 0xffffff_rgbf);
CORRADE_COMPARE(a.specularColor, 0xffffff_rgbf);
CORRADE_COMPARE(b.specularColor, 0xffffff_rgbf);
CORRADE_COMPARE(a.range, Constants::inf());
CORRADE_COMPARE(b.range, Constants::inf());
constexpr PhongLightUniform ca;
constexpr PhongLightUniform cb{DefaultInit};
CORRADE_COMPARE(ca.position, (Vector4{0.0f, 0.0f, 1.0f, 0.0f}));
CORRADE_COMPARE(cb.position, (Vector4{0.0f, 0.0f, 1.0f, 0.0f}));
CORRADE_COMPARE(ca.color, 0xffffff_rgbf);
CORRADE_COMPARE(cb.color, 0xffffff_rgbf);
CORRADE_COMPARE(ca.specularColor, 0xffffff_rgbf);
CORRADE_COMPARE(cb.specularColor, 0xffffff_rgbf);
CORRADE_COMPARE(ca.range, Constants::inf());
CORRADE_COMPARE(cb.range, Constants::inf());
CORRADE_VERIFY(std::is_nothrow_default_constructible<PhongLightUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongLightUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, PhongLightUniform>::value);
}
void PhongTest::lightUniformConstructNoInit() {
/* Testing only some fields, should be enough */
PhongLightUniform a;
a.color = 0x354565_rgbf;
a.range = 7.0f;
new(&a) PhongLightUniform{NoInit};
CORRADE_COMPARE(a.color, 0x354565_rgbf);
CORRADE_COMPARE(a.range, 7.0f);
CORRADE_VERIFY(std::is_nothrow_constructible<PhongLightUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, PhongLightUniform>::value);
}
void PhongTest::lightUniformSetters() {
PhongLightUniform a;
a.setPosition({2.5f, 3.6f, 0.7f, 1.1f})
.setColor(0x354565_rgbf)
.setSpecularColor(0x996600_rgbf)
.setRange(7.0f);
CORRADE_COMPARE(a.position, (Vector4{2.5f, 3.6f, 0.7f, 1.1f}));
CORRADE_COMPARE(a.color, 0x354565_rgbf);
CORRADE_COMPARE(a.specularColor, 0x996600_rgbf);
CORRADE_COMPARE(a.range, 7.0f);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::PhongTest)

BIN
src/Magnum/Shaders/Test/PhongTestFiles/multidraw-textured.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/PhongTestFiles/multidraw.tga

Binary file not shown.

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

@ -52,6 +52,21 @@
#include "Magnum/Trade/ImageData.h"
#include "Magnum/Trade/MeshData.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/Extensions.h"
#include "Magnum/GL/MeshView.h"
#include "Magnum/MeshTools/Concatenate.h"
#include "Magnum/MeshTools/GenerateIndices.h"
#include "Magnum/Primitives/Circle.h"
#include "Magnum/Primitives/Cone.h"
#include "Magnum/Primitives/Plane.h"
#include "Magnum/Primitives/Square.h"
#include "Magnum/Primitives/UVSphere.h"
#include "Magnum/Shaders/Generic.h"
#include "Magnum/Shaders/Generic.h"
#include "Magnum/Shaders/Vector.h"
#endif
#include "configure.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
@ -60,17 +75,43 @@ struct VectorGLTest: GL::OpenGLTester {
explicit VectorGLTest();
template<UnsignedInt dimensions> void construct();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void constructUniformBuffers();
#endif
template<UnsignedInt dimensions> void constructMove();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void constructMoveUniformBuffers();
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void constructUniformBuffersZeroDraws();
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setUniformUniformBuffersEnabled();
template<UnsignedInt dimensions> void bindBufferUniformBuffersNotEnabled();
#endif
template<UnsignedInt dimensions> void setTextureMatrixNotEnabled();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void bindTextureTransformBufferNotEnabled();
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setWrongDrawOffset();
#endif
void renderSetup();
void renderTeardown();
void renderDefaults2D();
void renderDefaults3D();
void render2D();
void render3D();
template<VectorGL2D::Flag flag = VectorGL2D::Flag{}> void renderDefaults2D();
template<VectorGL3D::Flag flag = VectorGL3D::Flag{}> void renderDefaults3D();
template<VectorGL2D::Flag flag = VectorGL2D::Flag{}> void render2D();
template<VectorGL3D::Flag flag = VectorGL3D::Flag{}> void render3D();
#ifndef MAGNUM_TARGET_GLES2
void renderMulti2D();
void renderMulti3D();
#endif
private:
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"};
@ -105,6 +146,19 @@ constexpr struct {
{"texture transformation", VectorGL2D::Flag::TextureTransformation}
};
#ifndef MAGNUM_TARGET_GLES2
constexpr struct {
const char* name;
VectorGL2D::Flags flags;
UnsignedInt drawCount;
} ConstructUniformBuffersData[]{
{"classic fallback", {}, 1},
{"", VectorGL2D::Flag::UniformBuffers, 1},
{"texture transformation", VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, 1},
{"multiple draws", VectorGL2D::Flag::UniformBuffers, 128},
};
#endif
const struct {
const char* name;
VectorGL2D::Flags flags;
@ -122,30 +176,102 @@ const struct {
"vector2D.tga", "vector3D.tga", false}
};
#ifndef MAGNUM_TARGET_GLES2
constexpr struct {
const char* name;
const char* expected2D;
const char* expected3D;
UnsignedInt drawCount;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga",
1, 16, 0.0f, 0.0f},
{"draw offset", "multidraw2D.tga", "multidraw3D.tga",
3, 1, 0.0f, 0.0f},
};
#endif
VectorGLTest::VectorGLTest() {
addInstancedTests<VectorGLTest>({
&VectorGLTest::construct<2>,
&VectorGLTest::construct<3>},
Containers::arraySize(ConstructData));
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests<VectorGLTest>({
&VectorGLTest::constructUniformBuffers<2>,
&VectorGLTest::constructUniformBuffers<3>},
Containers::arraySize(ConstructUniformBuffersData));
#endif
addTests<VectorGLTest>({
&VectorGLTest::constructMove<2>,
&VectorGLTest::constructMove<3>,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::constructMoveUniformBuffers<2>,
&VectorGLTest::constructMoveUniformBuffers<3>,
#endif
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::constructUniformBuffersZeroDraws<2>,
&VectorGLTest::constructUniformBuffersZeroDraws<3>,
#endif
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::setUniformUniformBuffersEnabled<2>,
&VectorGLTest::setUniformUniformBuffersEnabled<3>,
&VectorGLTest::bindBufferUniformBuffersNotEnabled<2>,
&VectorGLTest::bindBufferUniformBuffersNotEnabled<3>,
#endif
&VectorGLTest::setTextureMatrixNotEnabled<2>,
&VectorGLTest::setTextureMatrixNotEnabled<3>});
&VectorGLTest::setTextureMatrixNotEnabled<3>,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::bindTextureTransformBufferNotEnabled<2>,
&VectorGLTest::bindTextureTransformBufferNotEnabled<3>,
#endif
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::setWrongDrawOffset<2>,
&VectorGLTest::setWrongDrawOffset<3>
#endif
});
addTests({&VectorGLTest::renderDefaults2D,
&VectorGLTest::renderDefaults3D},
addTests({
&VectorGLTest::renderDefaults2D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::renderDefaults2D<VectorGL2D::Flag::UniformBuffers>,
#endif
&VectorGLTest::renderDefaults3D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::renderDefaults3D<VectorGL3D::Flag::UniformBuffers>,
#endif
},
&VectorGLTest::renderSetup,
&VectorGLTest::renderTeardown);
addInstancedTests({&VectorGLTest::render2D,
&VectorGLTest::render3D},
addInstancedTests({
&VectorGLTest::render2D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::render2D<VectorGL2D::Flag::UniformBuffers>,
#endif
&VectorGLTest::render3D,
#ifndef MAGNUM_TARGET_GLES2
&VectorGLTest::render3D<VectorGL3D::Flag::UniformBuffers>,
#endif
},
Containers::arraySize(RenderData),
&VectorGLTest::renderSetup,
&VectorGLTest::renderTeardown);
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests({&VectorGLTest::renderMulti2D,
&VectorGLTest::renderMulti3D},
Containers::arraySize(RenderMultiData),
&VectorGLTest::renderSetup,
&VectorGLTest::renderTeardown);
#endif
/* Load the plugins directly from the build tree. Otherwise they're either
static and already loaded or not present in the build tree */
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME
@ -189,6 +315,33 @@ template<UnsignedInt dimensions> void VectorGLTest::construct() {
MAGNUM_VERIFY_NO_GL_ERROR();
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VectorGLTest::constructUniformBuffers() {
setTestCaseTemplateName(std::to_string(dimensions));
auto&& data = ConstructUniformBuffersData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES
if((data.flags & VectorGL<dimensions>::Flag::UniformBuffers) && !GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
VectorGL<dimensions> shader{data.flags, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.drawCount(), data.drawCount);
CORRADE_VERIFY(shader.id());
{
#ifdef CORRADE_TARGET_APPLE
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly.");
#endif
CORRADE_VERIFY(shader.validate().first);
}
MAGNUM_VERIFY_NO_GL_ERROR();
}
#endif
template<UnsignedInt dimensions> void VectorGLTest::constructMove() {
setTestCaseTemplateName(std::to_string(dimensions));
@ -210,6 +363,115 @@ template<UnsignedInt dimensions> void VectorGLTest::constructMove() {
CORRADE_VERIFY(!b.id());
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VectorGLTest::constructMoveUniformBuffers() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
VectorGL<dimensions> a{VectorGL<dimensions>::Flag::UniformBuffers, 5};
const GLuint id = a.id();
CORRADE_VERIFY(id);
MAGNUM_VERIFY_NO_GL_ERROR();
VectorGL<dimensions> b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), VectorGL<dimensions>::Flag::UniformBuffers);
CORRADE_COMPARE(b.drawCount(), 5);
CORRADE_VERIFY(!a.id());
VectorGL<dimensions> c{NoCreate};
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), VectorGL<dimensions>::Flag::UniformBuffers);
CORRADE_COMPARE(c.drawCount(), 5);
CORRADE_VERIFY(!b.id());
}
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VectorGLTest::constructUniformBuffersZeroDraws() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
std::ostringstream out;
Error redirectError{&out};
VectorGL<dimensions>{VectorGL<dimensions>::Flag::UniformBuffers, 0};
CORRADE_COMPARE(out.str(),
"Shaders::VectorGL: draw count can't be zero\n");
}
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VectorGLTest::setUniformUniformBuffersEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
std::ostringstream out;
Error redirectError{&out};
VectorGL<dimensions> shader{VectorGL<dimensions>::Flag::UniformBuffers};
shader.setTransformationProjectionMatrix({})
.setTextureMatrix({})
.setBackgroundColor({})
.setColor({});
CORRADE_COMPARE(out.str(),
"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::setBackgroundColor(): the shader was created with uniform buffers enabled\n"
"Shaders::VectorGL::setColor(): the shader was created with uniform buffers enabled\n");
}
template<UnsignedInt dimensions> void VectorGLTest::bindBufferUniformBuffersNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
std::ostringstream out;
Error redirectError{&out};
GL::Buffer buffer;
VectorGL<dimensions> shader;
shader.bindTransformationProjectionBuffer(buffer)
.bindTransformationProjectionBuffer(buffer, 0, 16)
.bindDrawBuffer(buffer)
.bindDrawBuffer(buffer, 0, 16)
.bindTextureTransformationBuffer(buffer)
.bindTextureTransformationBuffer(buffer, 0, 16)
.setDrawOffset(0);
CORRADE_COMPARE(out.str(),
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled\n");
}
#endif
template<UnsignedInt dimensions> void VectorGLTest::setTextureMatrixNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
@ -227,6 +489,54 @@ template<UnsignedInt dimensions> void VectorGLTest::setTextureMatrixNotEnabled()
"Shaders::VectorGL::setTextureMatrix(): the shader was not created with texture transformation enabled\n");
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VectorGLTest::bindTextureTransformBufferNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
std::ostringstream out;
Error redirectError{&out};
GL::Buffer buffer{GL::Buffer::TargetHint::Uniform};
VectorGL<dimensions> shader{VectorGL<dimensions>::Flag::UniformBuffers};
shader.bindTextureTransformationBuffer(buffer)
.bindTextureTransformationBuffer(buffer, 0, 16);
CORRADE_COMPARE(out.str(),
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled\n"
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled\n");
}
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VectorGLTest::setWrongDrawOffset() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
std::ostringstream out;
Error redirectError{&out};
VectorGL<dimensions>{VectorGL<dimensions>::Flag::UniformBuffers, 5}
.setDrawOffset(5);
CORRADE_COMPARE(out.str(),
"Shaders::VectorGL::setDrawOffset(): draw offset 5 is out of bounds for 5 draws\n");
}
#endif
constexpr Vector2i RenderSize{80, 80};
void VectorGLTest::renderSetup() {
@ -262,7 +572,18 @@ constexpr GL::TextureFormat TextureFormatR =
#endif
;
void VectorGLTest::renderDefaults2D() {
template<VectorGL2D::Flag flag> void VectorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2
if(flag == VectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
}
#endif
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -288,9 +609,26 @@ void VectorGLTest::renderDefaults2D() {
.setSubImage(0, {}, *image);
#endif
VectorGL2D{}
.bindVectorTexture(texture)
.draw(square);
VectorGL2D shader{flag};
shader.bindVectorTexture(texture);
if(flag == VectorGL2D::Flag{}) {
shader.draw(square);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL2D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
VectorDrawUniform{}
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.draw(square);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -309,7 +647,18 @@ void VectorGLTest::renderDefaults2D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void VectorGLTest::renderDefaults3D() {
template<VectorGL3D::Flag flag> void VectorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2
if(flag == VectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
}
#endif
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -335,9 +684,26 @@ void VectorGLTest::renderDefaults3D() {
.setSubImage(0, {}, *image);
#endif
VectorGL3D{}
.bindVectorTexture(texture)
.draw(plane);
VectorGL3D shader{flag};
shader.bindVectorTexture(texture);
if(flag == VectorGL3D::Flag{}) {
shader.draw(plane);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL2D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
VectorDrawUniform{}
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.draw(plane);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -356,10 +722,21 @@ void VectorGLTest::renderDefaults3D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void VectorGLTest::render2D() {
template<VectorGL2D::Flag flag> void VectorGLTest::render2D() {
auto&& data = RenderData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2
if(flag == VectorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
}
#endif
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -385,18 +762,46 @@ void VectorGLTest::render2D() {
.setSubImage(0, {}, *image);
#endif
VectorGL2D 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);
VectorGL2D shader{data.flags|flag};
shader.bindVectorTexture(texture);
if(flag == VectorGL2D::Flag{}) {
shader.setBackgroundColor(data.backgroundColor)
.setColor(data.color);
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);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL2D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
data.textureTransformation == Matrix3{} ?
Matrix3::projection({2.1f, 2.1f})*
Matrix3::rotation(5.0_degf) : Matrix3{}
)
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
VectorDrawUniform{}
.setBackgroundColor(data.backgroundColor)
.setColor(data.color)
}};
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
}};
if(data.flags & VectorGL2D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.draw(square);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -418,10 +823,21 @@ void VectorGLTest::render2D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void VectorGLTest::render3D() {
template<VectorGL3D::Flag flag> void VectorGLTest::render3D() {
auto&& data = RenderData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES2
if(flag == VectorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
}
#endif
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
@ -447,20 +863,50 @@ void VectorGLTest::render3D() {
.setSubImage(0, {}, *image);
#endif
VectorGL3D 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);
VectorGL3D shader{data.flags|flag};
shader.bindVectorTexture(texture);
if(flag == VectorGL3D::Flag{}) {
shader.setBackgroundColor(data.backgroundColor)
.setColor(data.color);
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);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VectorGL3D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
data.textureTransformation == Matrix3{} ?
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) : Matrix4{}
)
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
VectorDrawUniform{}
.setBackgroundColor(data.backgroundColor)
.setColor(data.color)
}};
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, {
TextureTransformationUniform{}
.setTextureMatrix(data.textureTransformation)
}};
if(data.flags & VectorGL3D::Flag::TextureTransformation)
shader.bindTextureTransformationBuffer(textureTransformationUniform);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.draw(plane);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -482,6 +928,333 @@ void VectorGLTest::render3D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
#ifndef MAGNUM_TARGET_GLES2
void VectorGLTest::renderMulti2D() {
auto&& data = RenderMultiData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Directory::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 */
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}));
GL::MeshView circle{mesh};
circle.setCount(circleData.indexCount());
GL::MeshView square{mesh};
square.setCount(squareData.indexCount())
.setIndexRange(circleData.indexCount());
GL::MeshView triangle{mesh};
triangle.setCount(triangleData.indexCount())
.setIndexRange(circleData.indexCount() + squareData.indexCount());
/* Some drivers have uniform offset alignment as high as 256, which means
the subsequent sets of uniforms have to be aligned to a multiply of it.
The data.uniformIncrement is set high enough to ensure that, in the
non-offset-bind case this value is 1. */
Containers::Array<TransformationProjectionUniform2D> transformationProjectionData{2*data.uniformIncrement + 1};
transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::scaling(Vector2{0.4f})*
Matrix3::translation({-1.25f, -1.25f})
);
transformationProjectionData[1*data.uniformIncrement] = TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::scaling(Vector2{0.4f})*
Matrix3::translation({ 1.25f, -1.25f})
);
transformationProjectionData[2*data.uniformIncrement] = TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::scaling(Vector2{0.4f})*
Matrix3::translation({ 0.00f, 1.25f})
);
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData};
Containers::Array<TextureTransformationUniform> textureTransformationData{2*data.uniformIncrement + 1};
textureTransformationData[0*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
Matrix3::translation({0.5f, 0.5f})*
Matrix3::rotation(180.0_degf)*
Matrix3::translation({-0.5f, -0.5f})
);
textureTransformationData[1*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
Matrix3::translation(Vector2::xAxis(1.0f))*
Matrix3::scaling(Vector2::xScale(-1.0f))
);
textureTransformationData[2*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(Matrix3{});
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<VectorDrawUniform> drawData{2*data.uniformIncrement + 1};
drawData[0*data.uniformIncrement] = VectorDrawUniform{}
.setColor(0x00ff00_rgbf)
.setBackgroundColor(0xccffcc_rgbf);
drawData[1*data.uniformIncrement] = VectorDrawUniform{}
.setColor(0xff0000_rgbf)
.setBackgroundColor(0xffcccc_rgbf);
drawData[2*data.uniformIncrement] = VectorDrawUniform{}
.setColor(0x00ff00_rgbf)
.setBackgroundColor(0xccffcc_rgbf);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL2D shader{VectorGL2D::Flag::UniformBuffers|VectorGL2D::Flag::TextureTransformation, data.drawCount};
shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
shader.bindDrawBuffer(drawUniform,
0*data.uniformIncrement*sizeof(VectorDrawUniform),
sizeof(VectorDrawUniform));
shader.bindTextureTransformationBuffer(textureTransformationUniform,
0*data.uniformIncrement*sizeof(TextureTransformationUniform),
sizeof(TextureTransformationUniform));
shader.draw(circle);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
1*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
shader.bindDrawBuffer(drawUniform,
1*data.uniformIncrement*sizeof(VectorDrawUniform),
sizeof(VectorDrawUniform));
shader.bindTextureTransformationBuffer(textureTransformationUniform,
1*data.uniformIncrement*sizeof(TextureTransformationUniform),
sizeof(TextureTransformationUniform));
shader.draw(square);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
2*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
shader.bindDrawBuffer(drawUniform,
2*data.uniformIncrement*sizeof(VectorDrawUniform),
sizeof(VectorDrawUniform));
shader.bindTextureTransformationBuffer(textureTransformationUniform,
2*data.uniformIncrement*sizeof(TextureTransformationUniform),
sizeof(TextureTransformationUniform));
shader.draw(triangle);
/* Otherwise using the draw offset */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
/*
- Circle lower left, green, upside down
- Square lower right, red, mirrored
- Triangle up center, green
*/
MAGNUM_VERIFY_NO_GL_ERROR();
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", data.expected2D}),
(DebugTools::CompareImageToFile{_manager, data.maxThreshold, data.meanThreshold}));
}
void VectorGLTest::renderMulti3D() {
auto&& data = RenderMultiData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
Containers::Pointer<Trade::AbstractImporter> importer = _manager.loadAndInstantiate("AnyImageImporter");
CORRADE_VERIFY(importer);
Containers::Optional<Trade::ImageData2D> image;
CORRADE_VERIFY(importer->openFile(Utility::Directory::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);
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereFlag::TextureCoordinates);
/* Plane is a strip, make it indexed first */
Trade::MeshData planeData = MeshTools::generateIndices(Primitives::planeSolid(
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}));
GL::MeshView sphere{mesh};
sphere.setCount(sphereData.indexCount());
GL::MeshView plane{mesh};
plane.setCount(planeData.indexCount())
.setIndexRange(sphereData.indexCount());
GL::MeshView cone{mesh};
cone.setCount(coneData.indexCount())
.setIndexRange(sphereData.indexCount() + planeData.indexCount());
/* Some drivers have uniform offset alignment as high as 256, which means
the subsequent sets of uniforms have to be aligned to a multiply of it.
The data.uniformIncrement is set high enough to ensure that, in the
non-offset-bind case this value is 1. */
Containers::Array<TransformationProjectionUniform3D> transformationProjectionData{2*data.uniformIncrement + 1};
transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::scaling(Vector3{0.4f})*
Matrix4::translation({-1.25f, -1.25f, 0.0f})*
Matrix4::rotationY(180.0_degf) /* so the texture is visible */
);
transformationProjectionData[1*data.uniformIncrement] = TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::scaling(Vector3{0.4f})*
Matrix4::translation({ 1.25f, -1.25f, 0.0f})
);
transformationProjectionData[2*data.uniformIncrement] = TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::scaling(Vector3{0.4f})*
Matrix4::translation({ 0.0f, 1.0f, 1.0f})*
Matrix4::rotationY(180.0_degf) /* so the texture is visible */
);
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData};
Containers::Array<TextureTransformationUniform> textureTransformationData{2*data.uniformIncrement + 1};
textureTransformationData[0*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
Matrix3::translation({0.5f, 0.5f})*
Matrix3::rotation(180.0_degf)*
Matrix3::translation({-0.5f, -0.5f})
);
textureTransformationData[1*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(
Matrix3::translation(Vector2::xAxis(1.0f))*
Matrix3::scaling(Vector2::xScale(-1.0f))
);
textureTransformationData[2*data.uniformIncrement] = TextureTransformationUniform{}
.setTextureMatrix(Matrix3{});
GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, textureTransformationData};
Containers::Array<VectorDrawUniform> drawData{2*data.uniformIncrement + 1};
drawData[0*data.uniformIncrement] = VectorDrawUniform{}
.setColor(0x00ff00_rgbf)
.setBackgroundColor(0xccffcc_rgbf);
drawData[1*data.uniformIncrement] = VectorDrawUniform{}
.setColor(0xff0000_rgbf)
.setBackgroundColor(0xffcccc_rgbf);
drawData[2*data.uniformIncrement] = VectorDrawUniform{}
.setColor(0x00ff00_rgbf)
.setBackgroundColor(0xccffcc_rgbf);
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, drawData};
VectorGL3D shader{VectorGL3D::Flag::UniformBuffers|VectorGL3D::Flag::TextureTransformation, data.drawCount};
shader.bindVectorTexture(vector);
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));
shader.bindDrawBuffer(drawUniform,
0*data.uniformIncrement*sizeof(VectorDrawUniform),
sizeof(VectorDrawUniform));
shader.bindTextureTransformationBuffer(textureTransformationUniform,
0*data.uniformIncrement*sizeof(TextureTransformationUniform),
sizeof(TextureTransformationUniform));
shader.draw(sphere);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
1*data.uniformIncrement*sizeof(TransformationUniform3D),
sizeof(TransformationUniform3D));
shader.bindDrawBuffer(drawUniform,
1*data.uniformIncrement*sizeof(VectorDrawUniform),
sizeof(VectorDrawUniform));
shader.bindTextureTransformationBuffer(textureTransformationUniform,
1*data.uniformIncrement*sizeof(TextureTransformationUniform),
sizeof(TextureTransformationUniform));
shader.draw(plane);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
2*data.uniformIncrement*sizeof(TransformationUniform3D),
sizeof(TransformationUniform3D));
shader.bindDrawBuffer(drawUniform,
2*data.uniformIncrement*sizeof(VectorDrawUniform),
sizeof(VectorDrawUniform));
shader.bindTextureTransformationBuffer(textureTransformationUniform,
2*data.uniformIncrement*sizeof(TextureTransformationUniform),
sizeof(TextureTransformationUniform));
shader.draw(cone);
/* Otherwise using the draw offset */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindTextureTransformationBuffer(textureTransformationUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
/*
- Sphere lower left, green, upside down
- Plane lower right, red, mirrored
- Cone up center, green
*/
MAGNUM_VERIFY_NO_GL_ERROR();
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", data.expected3D}),
(DebugTools::CompareImageToFile{_manager, data.maxThreshold, data.meanThreshold}));
}
#endif
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::VectorGLTest)

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

@ -0,0 +1,118 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <new>
#include <Corrade/TestSuite/Tester.h>
#include "Magnum/Shaders/Vector.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
struct VectorTest: TestSuite::Tester {
explicit VectorTest();
template<class T> void uniformSize();
void drawUniformConstructDefault();
void drawUniformConstructNoInit();
void drawUniformSetters();
};
VectorTest::VectorTest() {
addTests({&VectorTest::uniformSize<VectorDrawUniform>,
&VectorTest::drawUniformConstructDefault,
&VectorTest::drawUniformConstructNoInit,
&VectorTest::drawUniformSetters});
}
using namespace Math::Literals;
template<class> struct UniformTraits;
template<> struct UniformTraits<VectorDrawUniform> {
static const char* name() { return "VectorDrawUniform"; }
};
template<class T> void VectorTest::uniformSize() {
setTestCaseTemplateName(UniformTraits<T>::name());
CORRADE_FAIL_IF(sizeof(T) % sizeof(Vector4) != 0, sizeof(T) << "is not a multiple of vec4 for UBO alignment.");
/* 48-byte structures are fine, we'll align them to 768 bytes and not
256, but warn about that */
CORRADE_FAIL_IF(768 % sizeof(T) != 0, sizeof(T) << "can't fit exactly into 768-byte UBO alignment.");
if(256 % sizeof(T) != 0)
CORRADE_WARN(sizeof(T) << "can't fit exactly into 256-byte UBO alignment, only 768.");
}
void VectorTest::drawUniformConstructDefault() {
VectorDrawUniform a;
VectorDrawUniform b{DefaultInit};
CORRADE_COMPARE(a.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(b.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(a.backgroundColor, 0x00000000_rgbaf);
CORRADE_COMPARE(b.backgroundColor, 0x00000000_rgbaf);
constexpr VectorDrawUniform ca;
constexpr VectorDrawUniform cb{DefaultInit};
CORRADE_COMPARE(ca.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(cb.color, 0xffffffff_rgbaf);
CORRADE_COMPARE(ca.backgroundColor, 0x00000000_rgbaf);
CORRADE_COMPARE(cb.backgroundColor, 0x00000000_rgbaf);
CORRADE_VERIFY(std::is_nothrow_default_constructible<VectorDrawUniform>::value);
CORRADE_VERIFY(std::is_nothrow_constructible<VectorDrawUniform, DefaultInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<DefaultInitT, VectorDrawUniform>::value);
}
void VectorTest::drawUniformConstructNoInit() {
/* Testing only some fields, should be enough */
VectorDrawUniform a;
a.color = 0x354565fc_rgbaf;
a.backgroundColor = 0x98769facb_rgbaf;
new(&a) VectorDrawUniform{NoInit};
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.backgroundColor, 0x98769facb_rgbaf);
CORRADE_VERIFY(std::is_nothrow_constructible<VectorDrawUniform, NoInitT>::value);
/* Implicit construction is not allowed */
CORRADE_VERIFY(!std::is_convertible<NoInitT, VectorDrawUniform>::value);
}
void VectorTest::drawUniformSetters() {
VectorDrawUniform a;
a.setColor(0x354565fc_rgbaf)
.setBackgroundColor(0x98769facb_rgbaf);
CORRADE_COMPARE(a.color, 0x354565fc_rgbaf);
CORRADE_COMPARE(a.backgroundColor, 0x98769facb_rgbaf);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::VectorTest)

BIN
src/Magnum/Shaders/Test/VectorTestFiles/multidraw2D-distancefield.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/VectorTestFiles/multidraw2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/VectorTestFiles/multidraw3D-distancefield.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/VectorTestFiles/multidraw3D.tga

Binary file not shown.

650
src/Magnum/Shaders/Test/VertexColorGLTest.cpp

@ -23,9 +23,11 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/Containers/StridedArrayView.h>
#include <Corrade/PluginManager/Manager.h>
#include <Corrade/Utility/Directory.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/DebugTools/CompareImage.h"
#include "Magnum/Image.h"
@ -46,6 +48,17 @@
#include "Magnum/Trade/AbstractImporter.h"
#include "Magnum/Trade/MeshData.h"
#ifndef MAGNUM_TARGET_GLES2
#include "Magnum/GL/Extensions.h"
#include "Magnum/GL/MeshView.h"
#include "Magnum/MeshTools/Concatenate.h"
#include "Magnum/MeshTools/GenerateIndices.h"
#include "Magnum/Primitives/Cone.h"
#include "Magnum/Primitives/Plane.h"
#include "Magnum/Primitives/Square.h"
#include "Magnum/Shaders/Generic.h"
#endif
#include "configure.h"
namespace Magnum { namespace Shaders { namespace Test { namespace {
@ -54,16 +67,38 @@ struct VertexColorGLTest: GL::OpenGLTester {
explicit VertexColorGLTest();
template<UnsignedInt dimensions> void construct();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void constructUniformBuffers();
#endif
template<UnsignedInt dimensions> void constructMove();
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void constructMoveUniformBuffers();
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void constructUniformBuffersZeroDraws();
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void setUniformUniformBuffersEnabled();
template<UnsignedInt dimensions> void bindBufferUniformBuffersNotEnabled();
template<UnsignedInt dimensions> void setWrongDrawOffset();
#endif
void renderSetup();
void renderTeardown();
template<class T> void renderDefaults2D();
template<class T> void renderDefaults3D();
template<class T, VertexColorGL2D::Flag flag = VertexColorGL2D::Flag{}> void renderDefaults2D();
template<class T, VertexColorGL3D::Flag flag = VertexColorGL3D::Flag{}> void renderDefaults3D();
template<class T, VertexColorGL2D::Flag flag = VertexColorGL2D::Flag{}> void render2D();
template<class T, VertexColorGL3D::Flag flag = VertexColorGL3D::Flag{}> void render3D();
template<class T> void render2D();
template<class T> void render3D();
#ifndef MAGNUM_TARGET_GLES2
void renderMulti2D();
void renderMulti3D();
#endif
private:
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"};
@ -89,24 +124,115 @@ struct VertexColorGLTest: GL::OpenGLTester {
using namespace Math::Literals;
#ifndef MAGNUM_TARGET_GLES2
constexpr struct {
const char* name;
VertexColorGL2D::Flags flags;
UnsignedInt drawCount;
} ConstructUniformBuffersData[]{
{"classic fallback", {}, 1},
{"", VertexColorGL2D::Flag::UniformBuffers, 1},
{"multiple draws", VertexColorGL2D::Flag::UniformBuffers, 128}
};
#endif
#ifndef MAGNUM_TARGET_GLES2
constexpr struct {
const char* name;
const char* expected2D;
const char* expected3D;
UnsignedInt drawCount;
UnsignedInt uniformIncrement;
Float maxThreshold, meanThreshold;
} RenderMultiData[] {
{"bind with offset", "multidraw2D.tga", "multidraw3D.tga",
1, 16, 0.0f, 0.0f},
{"draw offset", "multidraw2D.tga", "multidraw3D.tga",
3, 1, 0.0f, 0.0f}
};
#endif
VertexColorGLTest::VertexColorGLTest() {
addTests<VertexColorGLTest>({
&VertexColorGLTest::construct<2>,
&VertexColorGLTest::construct<3>,
&VertexColorGLTest::construct<3>});
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests<VertexColorGLTest>({
&VertexColorGLTest::constructUniformBuffers<2>,
&VertexColorGLTest::constructUniformBuffers<3>},
Containers::arraySize(ConstructUniformBuffersData));
#endif
addTests<VertexColorGLTest>({
&VertexColorGLTest::constructMove<2>,
&VertexColorGLTest::constructMove<3>});
&VertexColorGLTest::constructMove<3>,
addTests({&VertexColorGLTest::renderDefaults2D<Color3>,
&VertexColorGLTest::renderDefaults2D<Color4>,
&VertexColorGLTest::renderDefaults3D<Color3>,
&VertexColorGLTest::renderDefaults3D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::constructMoveUniformBuffers<2>,
&VertexColorGLTest::constructMoveUniformBuffers<3>,
#endif
&VertexColorGLTest::render2D<Color3>,
&VertexColorGLTest::render2D<Color4>,
&VertexColorGLTest::render3D<Color3>,
&VertexColorGLTest::render3D<Color4>},
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::constructUniformBuffersZeroDraws<2>,
&VertexColorGLTest::constructUniformBuffersZeroDraws<3>,
#endif
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::setUniformUniformBuffersEnabled<2>,
&VertexColorGLTest::setUniformUniformBuffersEnabled<3>,
&VertexColorGLTest::bindBufferUniformBuffersNotEnabled<2>,
&VertexColorGLTest::bindBufferUniformBuffersNotEnabled<3>,
&VertexColorGLTest::setWrongDrawOffset<2>,
&VertexColorGLTest::setWrongDrawOffset<3>
#endif
});
addTests({
&VertexColorGLTest::renderDefaults2D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults2D<Color3, VertexColorGL2D::Flag::UniformBuffers>,
#endif
&VertexColorGLTest::renderDefaults2D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults2D<Color4, VertexColorGL2D::Flag::UniformBuffers>,
#endif
&VertexColorGLTest::renderDefaults3D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults3D<Color3, VertexColorGL3D::Flag::UniformBuffers>,
#endif
&VertexColorGLTest::renderDefaults3D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::renderDefaults3D<Color4, VertexColorGL3D::Flag::UniformBuffers>,
#endif
&VertexColorGLTest::render2D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render2D<Color3, VertexColorGL2D::Flag::UniformBuffers>,
#endif
&VertexColorGLTest::render2D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render2D<Color4, VertexColorGL2D::Flag::UniformBuffers>,
#endif
&VertexColorGLTest::render3D<Color3>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render3D<Color3, VertexColorGL3D::Flag::UniformBuffers>,
#endif
&VertexColorGLTest::render3D<Color4>,
#ifndef MAGNUM_TARGET_GLES2
&VertexColorGLTest::render3D<Color4, VertexColorGL3D::Flag::UniformBuffers>,
#endif
},
&VertexColorGLTest::renderSetup,
&VertexColorGLTest::renderTeardown);
#ifndef MAGNUM_TARGET_GLES2
addInstancedTests({&VertexColorGLTest::renderMulti2D,
&VertexColorGLTest::renderMulti3D},
Containers::arraySize(RenderMultiData),
&VertexColorGLTest::renderSetup,
&VertexColorGLTest::renderTeardown);
#endif
/* Load the plugins directly from the build tree. Otherwise they're either
static and already loaded or not present in the build tree */
@ -147,6 +273,33 @@ template<UnsignedInt dimensions> void VertexColorGLTest::construct() {
MAGNUM_VERIFY_NO_GL_ERROR();
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VertexColorGLTest::constructUniformBuffers() {
setTestCaseTemplateName(std::to_string(dimensions));
auto&& data = ConstructUniformBuffersData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES
if((data.flags & VertexColorGL<dimensions>::Flag::UniformBuffers) && !GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
VertexColorGL<dimensions> shader{data.flags, data.drawCount};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_COMPARE(shader.drawCount(), data.drawCount);
CORRADE_VERIFY(shader.id());
{
#ifdef CORRADE_TARGET_APPLE
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly.");
#endif
CORRADE_VERIFY(shader.validate().first);
}
MAGNUM_VERIFY_NO_GL_ERROR();
}
#endif
template<UnsignedInt dimensions> void VertexColorGLTest::constructMove() {
setTestCaseTemplateName(std::to_string(dimensions));
@ -166,6 +319,121 @@ template<UnsignedInt dimensions> void VertexColorGLTest::constructMove() {
CORRADE_VERIFY(!b.id());
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VertexColorGLTest::constructMoveUniformBuffers() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
VertexColorGL<dimensions> a{VertexColorGL<dimensions>::Flag::UniformBuffers, 5};
const GLuint id = a.id();
CORRADE_VERIFY(id);
MAGNUM_VERIFY_NO_GL_ERROR();
VertexColorGL<dimensions> b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), VertexColorGL<dimensions>::Flag::UniformBuffers);
CORRADE_COMPARE(b.drawCount(), 5);
CORRADE_VERIFY(!a.id());
VertexColorGL<dimensions> c{NoCreate};
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), VertexColorGL<dimensions>::Flag::UniformBuffers);
CORRADE_COMPARE(c.drawCount(), 5);
CORRADE_VERIFY(!b.id());
}
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VertexColorGLTest::constructUniformBuffersZeroDraws() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
std::ostringstream out;
Error redirectError{&out};
VertexColorGL<dimensions>{VertexColorGL<dimensions>::Flag::UniformBuffers, 0};
CORRADE_COMPARE(out.str(),
"Shaders::VertexColorGL: draw count can't be zero\n");
}
#endif
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> void VertexColorGLTest::setUniformUniformBuffersEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
std::ostringstream out;
Error redirectError{&out};
VertexColorGL<dimensions> shader{VertexColorGL<dimensions>::Flag::UniformBuffers};
shader.setTransformationProjectionMatrix({});
CORRADE_COMPARE(out.str(),
"Shaders::VertexColorGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled\n");
}
template<UnsignedInt dimensions> void VertexColorGLTest::bindBufferUniformBuffersNotEnabled() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
std::ostringstream out;
Error redirectError{&out};
GL::Buffer buffer;
VertexColorGL<dimensions> shader;
shader.bindTransformationProjectionBuffer(buffer)
.bindTransformationProjectionBuffer(buffer, 0, 16)
.setDrawOffset(0);
CORRADE_COMPARE(out.str(),
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled\n"
"Shaders::VertexColorGL::setDrawOffset(): the shader was not created with uniform buffers enabled\n");
}
template<UnsignedInt dimensions> void VertexColorGLTest::setWrongDrawOffset() {
setTestCaseTemplateName(std::to_string(dimensions));
#ifdef CORRADE_NO_ASSERT
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
#endif
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
std::ostringstream out;
Error redirectError{&out};
VertexColorGL<dimensions>{VertexColorGL<dimensions>::Flag::UniformBuffers, 5}
.setDrawOffset(5);
CORRADE_COMPARE(out.str(),
"Shaders::VertexColorGL::setDrawOffset(): draw offset 5 is out of bounds for 5 draws\n");
}
#endif
constexpr Vector2i RenderSize{80, 80};
void VertexColorGLTest::renderSetup() {
@ -193,8 +461,20 @@ void VertexColorGLTest::renderTeardown() {
_color = GL::Renderbuffer{NoCreate};
}
template<class T> void VertexColorGLTest::renderDefaults2D() {
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2
if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
} else
#endif
{
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
}
Trade::MeshData circleData = Primitives::circle2DSolid(32,
Primitives::Circle2DFlag::TextureCoordinates);
@ -207,8 +487,21 @@ template<class T> void VertexColorGLTest::renderDefaults2D() {
GL::Mesh circle = MeshTools::compile(circleData);
circle.addVertexBuffer(colors, 0, GL::Attribute<VertexColorGL2D::Color3::Location, T>{});
VertexColorGL2D{}
.draw(circle);
VertexColorGL2D shader{flag};
if(flag == VertexColorGL2D::Flag{}) {
shader.draw(circle);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL2D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.draw(circle);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -230,8 +523,20 @@ template<class T> void VertexColorGLTest::renderDefaults2D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
template<class T> void VertexColorGLTest::renderDefaults3D() {
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::renderDefaults3D() {
#ifndef MAGNUM_TARGET_GLES2
if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
} else
#endif
{
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
}
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
@ -248,8 +553,21 @@ template<class T> void VertexColorGLTest::renderDefaults3D() {
GL::Mesh sphere = MeshTools::compile(sphereData);
sphere.addVertexBuffer(colors, 0, GL::Attribute<VertexColorGL3D::Color4::Location, T>{});
VertexColorGL3D{}
.draw(sphere);
VertexColorGL3D shader{flag};
if(flag == VertexColorGL3D::Flag{}) {
shader.draw(sphere);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL3D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.draw(sphere);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -267,8 +585,20 @@ template<class T> void VertexColorGLTest::renderDefaults3D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
template<class T> void VertexColorGLTest::render2D() {
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
template<class T, VertexColorGL2D::Flag flag> void VertexColorGLTest::render2D() {
#ifndef MAGNUM_TARGET_GLES2
if(flag == VertexColorGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
} else
#endif
{
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
}
Trade::MeshData circleData = Primitives::circle2DSolid(32,
Primitives::Circle2DFlag::TextureCoordinates);
@ -283,9 +613,23 @@ template<class T> void VertexColorGLTest::render2D() {
GL::Mesh circle = MeshTools::compile(circleData);
circle.addVertexBuffer(colors, 0, GL::Attribute<VertexColorGL2D::Color3::Location, T>{});
VertexColorGL2D{}
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
VertexColorGL2D shader{flag};
if(flag == VertexColorGL2D::Flag{}) {
shader.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
.draw(circle);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL2D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.draw(circle);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -308,8 +652,20 @@ template<class T> void VertexColorGLTest::render2D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
template<class T> void VertexColorGLTest::render3D() {
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
template<class T, VertexColorGL3D::Flag flag> void VertexColorGLTest::render3D() {
#ifndef MAGNUM_TARGET_GLES2
if(flag == VertexColorGL3D::Flag::UniformBuffers) {
setTestCaseTemplateName({T::Size == 3 ? "Color3" : "Color4", "Flag::UniformBuffers"});
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
} else
#endif
{
setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4");
}
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32,
Primitives::UVSphereFlag::TextureCoordinates);
@ -324,13 +680,32 @@ template<class T> void VertexColorGLTest::render3D() {
GL::Mesh sphere = MeshTools::compile(sphereData);
sphere.addVertexBuffer(colors, 0, GL::Attribute<VertexColorGL3D::Color4::Location, T>{});
VertexColorGL3D{}
.setTransformationProjectionMatrix(
VertexColorGL3D shader{flag};
if(flag == VertexColorGL3D::Flag{}) {
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))
.draw(sphere);
}
#ifndef MAGNUM_TARGET_GLES2
else if(flag == VertexColorGL3D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform3D{}
.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)
)
}};
shader.bindTransformationProjectionBuffer(transformationProjectionUniform)
.draw(sphere);
}
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
@ -353,6 +728,221 @@ template<class T> void VertexColorGLTest::render3D() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
#ifndef MAGNUM_TARGET_GLES2
void VertexColorGLTest::renderMulti2D() {
auto&& data = RenderMultiData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
/* Circle is a fan, plane is a strip, make it indexed first */
Trade::MeshData circleData = MeshTools::generateIndices(Primitives::circle2DSolid(32));
Trade::MeshData squareData = MeshTools::generateIndices(Primitives::squareSolid());
Trade::MeshData triangleData = MeshTools::generateIndices(Primitives::circle2DSolid(3));
/* Concatenate the meshes, reserve a vertex color attribute and fill it
with a ... RAINBOW! */
Trade::MeshData colored = MeshTools::interleave(MeshTools::concatenate({circleData, squareData, triangleData}), {
Trade::MeshAttributeData{Trade::MeshAttribute::Color, VertexFormat::Vector3, nullptr}
});
Deg angle = 0.0_degf;
for(Vector3& i: colored.mutableAttribute<Vector3>(Trade::MeshAttribute::Color))
i = Color3::fromHsv({angle += 360.0_degf/colored.vertexCount(), 1.0f, 1.0f});
GL::Mesh mesh = MeshTools::compile(colored);
GL::MeshView circle{mesh};
circle.setCount(circleData.indexCount());
GL::MeshView square{mesh};
square.setCount(squareData.indexCount())
.setIndexRange(circleData.indexCount());
GL::MeshView triangle{mesh};
triangle.setCount(triangleData.indexCount())
.setIndexRange(circleData.indexCount() + squareData.indexCount());
/* Some drivers have uniform offset alignment as high as 256, which means
the subsequent sets of uniforms have to be aligned to a multiply of it.
The data.uniformIncrement is set high enough to ensure that, in the
non-offset-bind case this value is 1. */
Containers::Array<TransformationProjectionUniform2D> transformationProjectionData{2*data.uniformIncrement + 1};
transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::scaling(Vector2{0.4f})*
Matrix3::translation({-1.25f, -1.25f})
);
transformationProjectionData[1*data.uniformIncrement] = TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::scaling(Vector2{0.4f})*
Matrix3::translation({ 1.25f, -1.25f})
);
transformationProjectionData[2*data.uniformIncrement] = TransformationProjectionUniform2D{}
.setTransformationProjectionMatrix(
Matrix3::projection({2.1f, 2.1f})*
Matrix3::scaling(Vector2{0.4f})*
Matrix3::translation({ 0.00f, 1.25f})
);
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData};
VertexColorGL2D shader{VertexColorGL2D::Flag::UniformBuffers, data.drawCount};
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
shader.draw(circle);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
1*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
shader.draw(square);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
2*data.uniformIncrement*sizeof(TransformationProjectionUniform2D),
sizeof(TransformationProjectionUniform2D));
shader.draw(triangle);
/* Otherwise using the draw offset */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform);
shader.setDrawOffset(0)
.draw(circle);
shader.setDrawOffset(1)
.draw(square);
shader.setDrawOffset(2)
.draw(triangle);
}
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
/*
- Circle should be lower left
- Square lower right
- Triangle up center
*/
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, "VertexColorTestFiles", data.expected2D}),
(DebugTools::CompareImageToFile{_manager, data.maxThreshold, data.meanThreshold}));
}
void VertexColorGLTest::renderMulti3D() {
auto&& data = RenderMultiData[testCaseInstanceId()];
setTestCaseDescription(data.name);
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
Trade::MeshData sphereData = Primitives::uvSphereSolid(16, 32);
/* Plane is a strip, make it indexed first */
Trade::MeshData planeData = MeshTools::generateIndices(Primitives::planeSolid());
Trade::MeshData coneData = Primitives::coneSolid(1, 32, 1.0f);
/* Concatenate the meshes, reserve a vertex color attribute and fill it
with a ... RAINBOW! */
Trade::MeshData colored = MeshTools::interleave(MeshTools::concatenate({sphereData, planeData, coneData}), {
Trade::MeshAttributeData{Trade::MeshAttribute::Color, VertexFormat::Vector3, nullptr}
});
Deg angle = 0.0_degf;
for(Vector3& i: colored.mutableAttribute<Vector3>(Trade::MeshAttribute::Color))
i = Color3::fromHsv({angle += 360.0_degf/colored.vertexCount(), 1.0f, 1.0f});
GL::Mesh mesh = MeshTools::compile(colored);
GL::MeshView sphere{mesh};
sphere.setCount(sphereData.indexCount());
GL::MeshView plane{mesh};
plane.setCount(planeData.indexCount())
.setIndexRange(sphereData.indexCount());
GL::MeshView cone{mesh};
cone.setCount(coneData.indexCount())
.setIndexRange(sphereData.indexCount() + planeData.indexCount());
/* Some drivers have uniform offset alignment as high as 256, which means
the subsequent sets of uniforms have to be aligned to a multiply of it.
The data.uniformIncrement is set high enough to ensure that, in the
non-offset-bind case this value is 1. */
Containers::Array<TransformationProjectionUniform3D> transformationProjectionData{2*data.uniformIncrement + 1};
transformationProjectionData[0*data.uniformIncrement] = TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::scaling(Vector3{0.4f})*
Matrix4::translation({-1.25f, -1.25f, 0.0f})
);
transformationProjectionData[1*data.uniformIncrement] = TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::scaling(Vector3{0.4f})*
Matrix4::translation({ 1.25f, -1.25f, 0.0f})
);
transformationProjectionData[2*data.uniformIncrement] = TransformationProjectionUniform3D{}
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
Matrix4::translation(Vector3::zAxis(-2.15f))*
Matrix4::scaling(Vector3{0.4f})*
Matrix4::translation({ 0.0f, 1.0f, 1.0f})
);
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, transformationProjectionData};
VertexColorGL3D shader{VertexColorGL3D::Flag::UniformBuffers, data.drawCount};
/* Just one draw, rebinding UBOs each time */
if(data.drawCount == 1) {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
0*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));
shader.draw(sphere);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
1*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));
shader.draw(plane);
shader.bindTransformationProjectionBuffer(transformationProjectionUniform,
2*data.uniformIncrement*sizeof(TransformationProjectionUniform3D),
sizeof(TransformationProjectionUniform3D));
shader.draw(cone);
/* Otherwise using the draw offset */
} else {
shader.bindTransformationProjectionBuffer(transformationProjectionUniform);
shader.setDrawOffset(0)
.draw(sphere);
shader.setDrawOffset(1)
.draw(plane);
shader.setDrawOffset(2)
.draw(cone);
}
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
/*
- Sphere should be lower left
- Plane lower right
- Cone up center
*/
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, "VertexColorTestFiles", data.expected3D}),
(DebugTools::CompareImageToFile{_manager, data.maxThreshold, data.meanThreshold}));
}
#endif
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::VertexColorGLTest)

34
src/Magnum/Shaders/Test/VertexColorGL_Test.cpp

@ -23,7 +23,9 @@
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Shaders/VertexColorGL.h"
@ -36,6 +38,9 @@ struct VertexColorGL_Test: TestSuite::Tester {
template<UnsignedInt dimensions> void constructNoCreate();
template<UnsignedInt dimensions> void constructCopy();
void debugFlag();
void debugFlags();
};
VertexColorGL_Test::VertexColorGL_Test() {
@ -44,7 +49,10 @@ VertexColorGL_Test::VertexColorGL_Test() {
&VertexColorGL_Test::constructNoCreate<3>,
&VertexColorGL_Test::constructCopy<2>,
&VertexColorGL_Test::constructCopy<3>});
&VertexColorGL_Test::constructCopy<3>,
&VertexColorGL_Test::debugFlag,
&VertexColorGL_Test::debugFlags});
}
template<UnsignedInt dimensions> void VertexColorGL_Test::constructNoCreate() {
@ -65,6 +73,30 @@ template<UnsignedInt dimensions> void VertexColorGL_Test::constructCopy() {
CORRADE_VERIFY(!std::is_copy_assignable<VertexColorGL<dimensions>>{});
}
void VertexColorGL_Test::debugFlag() {
std::ostringstream out;
#ifndef MAGNUM_TARGET_GLES2
Debug{&out} << VertexColorGL3D::Flag::UniformBuffers << VertexColorGL3D::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag::UniformBuffers Shaders::VertexColorGL::Flag(0xf0)\n");
#else
Debug{&out} << VertexColorGL3D::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag(0xf0)\n");
#endif
}
void VertexColorGL_Test::debugFlags() {
std::ostringstream out;
#ifndef MAGNUM_TARGET_GLES2
Debug{&out} << (VertexColorGL3D::Flag::UniformBuffers|VertexColorGL3D::Flag(0xf0)) << VertexColorGL3D::Flags{};
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag::UniformBuffers|Shaders::VertexColorGL::Flag(0xf0) Shaders::VertexColorGL::Flags{}\n");
#else
Debug{&out} << VertexColorGL3D::Flag(0xf0) << VertexColorGL3D::Flags{};
CORRADE_COMPARE(out.str(), "Shaders::VertexColorGL::Flag(0xf0) Shaders::VertexColorGL::Flags{}\n");
#endif
}
}}}}
CORRADE_TEST_MAIN(Magnum::Shaders::Test::VertexColorGL_Test)

BIN
src/Magnum/Shaders/Test/VertexColorTestFiles/multidraw2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/VertexColorTestFiles/multidraw3D.tga

Binary file not shown.

37
src/Magnum/Shaders/Vector.frag

@ -29,8 +29,13 @@
#define texture texture2D
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 2)
#endif
@ -45,6 +50,33 @@ uniform lowp vec4 color
#endif
;
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
struct DrawUniform {
lowp vec4 color;
lowp vec4 backgroundColor;
lowp uvec4 reserved;
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 2
#endif
) uniform Draw {
DrawUniform draws[DRAW_COUNT];
};
#endif
/* Textures */
#ifdef EXPLICIT_BINDING
@ -66,6 +98,11 @@ out lowp vec4 fragmentColor;
#endif
void main() {
#ifdef UNIFORM_BUFFERS
lowp const vec4 color = draws[drawOffset].color;
lowp const vec4 backgroundColor = draws[drawOffset].backgroundColor;
#endif
lowp float intensity = texture(vectorTexture, interpolatedTextureCoordinates).r;
fragmentColor = mix(backgroundColor, color, intensity);
}

100
src/Magnum/Shaders/Vector.h

@ -25,26 +25,104 @@
DEALINGS IN THE SOFTWARE.
*/
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file
* @brief Typedef @ref Magnum::Shaders::Vector, alias @ref Magnum::Shaders::Vector2D, @ref Magnum::Shaders::Vector3D
* @m_deprecated_since_latest Use @ref Magnum/Shaders/VectorGL.h, the
* @ref Magnum::Shaders::VectorGL "VectorGL" class and
* related typedefs instead.
* @brief Struct @ref Magnum::Shaders::VectorDrawUniform
*/
#endif
#include "Magnum/configure.h"
#include "Magnum/Magnum.h"
#include "Magnum/Math/Color.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#include "Magnum/Shaders/VectorGL.h"
CORRADE_DEPRECATED_FILE("use Magnum/Shaders/VectorGL.h, the VectorGL class and related typedefs instead")
#endif
namespace Magnum { namespace Shaders {
/**
@brief Per-draw uniform for vector shaders
@m_since_latest
Together with the generic @ref TransformationProjectionUniform2D /
@ref TransformationProjectionUniform3D contains parameters that are specific to
each draw call. Texture transformation, if needed, is supplied separately in a
@ref TextureTransformationUniform.
@see @ref VectorGL::bindDrawBuffer()
*/
struct VectorDrawUniform {
/** @brief Construct with default parameters */
constexpr explicit VectorDrawUniform(DefaultInitT = DefaultInit) noexcept: color{1.0f, 1.0f, 1.0f, 1.0f}, backgroundColor{0.0f, 0.0f, 0.0f, 0.0f} {}
/** @brief Construct without initializing the contents */
explicit VectorDrawUniform(NoInitT) noexcept: color{NoInit}, backgroundColor{NoInit} {}
/** @{
* @name Convenience setters
*
* Provided to allow the use of method chaining for populating a structure
* in a single expression, otherwise equivalent to accessing the fields
* directly. Also guaranteed to provide backwards compatibility when
* packing of the actual fields changes.
*/
/**
* @brief Set the @ref color field
* @return Reference to self (for method chaining)
*/
VectorDrawUniform& setColor(const Color4& color) {
this->color = color;
return *this;
}
/**
* @brief Set the @ref backgroundColor field
* @return Reference to self (for method chaining)
*/
VectorDrawUniform& setBackgroundColor(const Color4& color) {
backgroundColor = color;
return *this;
}
/**
* @}
*/
/**
* @brief Fill color
*
* Default is @cpp 0xffffffff_rgbaf @ce.
* @see @ref VectorGL::setColor()
*/
Color4 color;
/**
* @brief Background color
*
* Default is @cpp 0x00000000_rgbaf @ce.
* @see @ref VectorGL::setBackgroundColor()
*/
Color4 backgroundColor;
/* warning: Member __pad0__ is not documented. FFS DOXYGEN WHY DO YOU THINK
I MADE THOSE UNNAMED, YOU DUMB FOOL */
#ifndef DOXYGEN_GENERATING_OUTPUT
/* This field is an UnsignedInt in the shader and skinOffset is extracted
as (value >> 16), so the order has to be different on BE */
#ifndef CORRADE_TARGET_BIG_ENDIAN
UnsignedShort:16;
UnsignedShort:16; /* reserved for skinOffset */
#else
UnsignedShort:16; /* reserved for skinOffset */
UnsignedShort:16;
#endif
Int:32; /* reserved for objectId */
Int:32; /* reserved for alphaMask */
Int:32;
#endif
};
#ifdef MAGNUM_BUILD_DEPRECATED
/** @brief @copybrief Shaders::VectorGL
* @m_deprecated_since_latest Use @ref Shaders::VectorGL "VectorGL" instead.
*/
@ -61,10 +139,8 @@ typedef CORRADE_DEPRECATED("use VectorGL2D instead") VectorGL2D Vector2D;
* @m_deprecated_since_latest Use @ref VectorGL3D instead.
*/
typedef CORRADE_DEPRECATED("use VectorGL3D instead") VectorGL3D Vector3D;
#endif
}}
#else
#error use Magnum/Shaders/VectorGL.h, the VectorGL class and related typedefs instead
#endif
#endif

65
src/Magnum/Shaders/Vector.vert

@ -28,8 +28,13 @@
#define out varying
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -60,6 +65,51 @@ uniform mediump mat3 textureMatrix
;
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 1
#endif
) uniform TransformationProjection {
highp
#ifdef TWO_DIMENSIONS
mat3
#elif defined(THREE_DIMENSIONS)
mat4
#else
#error
#endif
transformationProjectionMatrices[DRAW_COUNT];
};
#ifdef TEXTURE_TRANSFORMATION
struct TextureTransformationUniform {
highp vec4 rotationScaling;
highp vec4 offsetReservedReserved;
#define textureTransformation_offset offsetReservedReserved.xy
};
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 3
#endif
) uniform TextureTransformation {
TextureTransformationUniform textureTransformations[DRAW_COUNT];
};
#endif
#endif
/* Inputs */
#ifdef EXPLICIT_ATTRIB_LOCATION
@ -83,6 +133,21 @@ in mediump vec2 textureCoordinates;
out mediump vec2 interpolatedTextureCoordinates;
void main() {
#ifdef UNIFORM_BUFFERS
highp const
#ifdef TWO_DIMENSIONS
mat3
#elif defined(THREE_DIMENSIONS)
mat4
#else
#error
#endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
#ifdef TEXTURE_TRANSFORMATION
mediump const mat3 textureMatrix = mat3(textureTransformations[drawOffset].rotationScaling.xy, 0.0, textureTransformations[drawOffset].rotationScaling.zw, 0.0, textureTransformations[drawOffset].textureTransformation_offset, 1.0);
#endif
#endif
#ifdef TWO_DIMENSIONS
gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0);
#elif defined(THREE_DIMENSIONS)

186
src/Magnum/Shaders/VectorGL.cpp

@ -37,15 +37,51 @@
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include "Magnum/GL/Buffer.h"
#endif
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
namespace Magnum { namespace Shaders {
namespace {
enum: Int { TextureUnit = 6 };
#ifndef MAGNUM_TARGET_GLES2
enum: Int {
/* Not using the zero binding to avoid conflicts with
ProjectionBufferBinding from other shaders which can likely stay
bound to the same buffer for the whole time */
TransformationProjectionBufferBinding = 1,
DrawBufferBinding = 2,
TextureTransformationBufferBinding = 3
};
#endif
}
template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flags): _flags{flags} {
template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt drawCount
#endif
):
_flags{flags}
#ifndef MAGNUM_TARGET_GLES2
, _drawCount{drawCount}
#endif
{
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::VectorGL: draw count can't be zero", );
#endif
#ifndef MAGNUM_TARGET_GLES
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShadersGL"))
@ -65,9 +101,25 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
vert.addSource(flags & Flag::TextureTransformation ? "#define TEXTURE_TRANSFORMATION\n" : "")
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n")
.addSource(rs.get("generic.glsl"))
.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
vert.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
}
#endif
vert.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Vector.vert"));
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
frag.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
}
#endif
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("Vector.frag"));
@ -92,11 +144,18 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_backgroundColorUniform = uniformLocation("backgroundColor");
_colorUniform = uniformLocation("color");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
_drawOffsetUniform = uniformLocation("drawOffset");
} else
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
if(flags & Flag::TextureTransformation)
_textureMatrixUniform = uniformLocation("textureMatrix");
_backgroundColorUniform = uniformLocation("backgroundColor");
_colorUniform = uniformLocation("color");
}
}
#ifndef MAGNUM_TARGET_GLES
@ -104,23 +163,51 @@ template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flag
#endif
{
setUniform(uniformLocation("vectorTexture"), TextureUnit);
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding);
setUniformBlockBinding(uniformBlockIndex("Draw"), DrawBufferBinding);
if(flags & Flag::TextureTransformation)
setUniformBlockBinding(uniformBlockIndex("TextureTransformation"), TextureTransformationBufferBinding);
}
#endif
}
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
setColor(Color4{1.0f}); /* Background color is zero by default */
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
/* Draw offset is zero by default */
} else
#endif
{
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
if(flags & Flag::TextureTransformation)
setTextureMatrix(Matrix3{Math::IdentityInit});
/* Background color is zero by default */
setColor(Color4{1.0f});
}
#endif
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> VectorGL<dimensions>::VectorGL(const Flags flags): VectorGL{flags, 1} {}
#endif
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::VectorGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_transformationProjectionMatrixUniform, matrix);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setTextureMatrix(const Matrix3& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::VectorGL::setTextureMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::VectorGL::setTextureMatrix(): the shader was not created with texture transformation enabled", *this);
setUniform(_textureMatrixUniform, matrix);
@ -128,15 +215,80 @@ template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::set
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setBackgroundColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::VectorGL::setBackgroundColor(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_backgroundColorUniform, color);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setColor(const Color4& color) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::VectorGL::setColor(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_colorUniform, color);
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(offset < _drawCount,
"Shaders::VectorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindDrawBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindDrawBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, DrawBufferBinding, offset, size);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTextureTransformationBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindTextureTransformationBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(_flags & Flag::TextureTransformation,
"Shaders::VectorGL::bindTextureTransformationBuffer(): the shader was not created with texture transformation enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TextureTransformationBufferBinding, offset, size);
return *this;
}
#endif
template<UnsignedInt dimensions> VectorGL<dimensions>& VectorGL<dimensions>::bindVectorTexture(GL::Texture2D& texture) {
texture.bind(TextureUnit);
return *this;
@ -154,6 +306,9 @@ Debug& operator<<(Debug& debug, const VectorGLFlag value) {
/* LCOV_EXCL_START */
#define _c(v) case VectorGLFlag::v: return debug << "::" #v;
_c(TextureTransformation)
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#endif
#undef _c
/* LCOV_EXCL_STOP */
}
@ -163,8 +318,11 @@ Debug& operator<<(Debug& debug, const VectorGLFlag value) {
Debug& operator<<(Debug& debug, const VectorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VectorGL::Flags{}", {
VectorGLFlag::TextureTransformation
});
VectorGLFlag::TextureTransformation,
#ifndef MAGNUM_TARGET_GLES2
VectorGLFlag::UniformBuffers
#endif
});
}
}

194
src/Magnum/Shaders/VectorGL.h

@ -39,7 +39,10 @@ namespace Magnum { namespace Shaders {
namespace Implementation {
enum class VectorGLFlag: UnsignedByte {
TextureTransformation = 1 << 0
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 1
#endif
};
typedef Containers::EnumSet<VectorGLFlag> VectorGLFlags;
}
@ -117,7 +120,23 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @see @ref setTextureMatrix()
* @m_since{2020,06}
*/
TextureTransformation = 1 << 0
TextureTransformation = 1 << 0,
#ifndef MAGNUM_TARGET_GLES2
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer()
* instead of direct uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL
* 1.0.
* @m_since_latest
*/
UniformBuffers = 1 << 1
#endif
};
/**
@ -137,9 +156,44 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
/**
* @brief Constructor
* @param flags Flags
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref VectorGL(Flags, UnsignedInt) with @p drawCount set to @cpp 1 @ce.
*/
explicit VectorGL(Flags flags = {});
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param drawCount Size of a @ref TransformationProjectionUniform2D
* / @ref TransformationProjectionUniform3D /
* @ref VectorDrawUniform / @ref TextureTransformationUniform
* buffer bound with @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer()
*
* If @p flags contains @ref Flag::UniformBuffers @p drawCount
* describes the uniform buffer sizes as these are required to have a
* statically defined size. The draw offset is then set via
* @ref setDrawOffset().
*
* If @p flags don't contain @ref Flag::UniformBuffers, @p drawCount is
* ignored and the constructor behaves the same as @ref VectorGL(Flags).
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
/** @todo this constructor will eventually need to have also joint
count, per-vertex weight count, view count for multiview and clip
plane count ... and putting them in arbitrary order next to each
other is too error-prone, so it needs some other solution
(accepting pairs of parameter type and value like in GL context
creation, e.g., which will probably need a new enum as reusing Flag
for this might be too confusing) */
explicit VectorGL(Flags flags, UnsignedInt drawCount);
#endif
/**
* @brief Construct without creating the underlying OpenGL object
*
@ -172,8 +226,26 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
*/
Flags flags() const { return _flags; }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Draw count
* @m_since_latest
*
* Statically defined size of each of the
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D, @ref VectorDrawUniform and
* @ref TextureTransformationUniform uniform buffers. Has use only if
* @ref Flag::UniformBuffers is set.
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt drawCount() const { return _drawCount; }
#endif
/** @{
* @name Uniform setters
*
* Used only if @ref Flag::UniformBuffers is not set.
*/
/**
@ -181,6 +253,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @return Reference to self (for method chaining)
*
* Initial value is an identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix /
* @ref TransformationProjectionUniform3D::transformationProjectionMatrix
* and call @ref bindTransformationProjectionBuffer() instead.
*/
VectorGL<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix);
@ -192,6 +269,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* Expects that the shader was created with
* @ref Flag::TextureTransformation enabled. Initial value is an
* identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TextureTransformationUniform::rotationScaling and
* @ref TextureTransformationUniform::offset and call
* @ref bindTextureTransformationBuffer() instead.
*/
VectorGL<dimensions>& setTextureMatrix(const Matrix3& matrix);
@ -200,6 +282,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 0x00000000_rgbaf @ce.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref VectorDrawUniform::backgroundColor and call
* @ref bindDrawBuffer() instead.
* @see @ref setColor()
*/
VectorGL<dimensions>& setBackgroundColor(const Color4& color);
@ -209,6 +295,10 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 0xffffffff_rgbaf @ce.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref VectorDrawUniform::color and call @ref bindDrawBuffer()
* instead.
* @see @ref setBackgroundColor()
*/
VectorGL<dimensions>& setColor(const Color4& color);
@ -217,6 +307,98 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
* @}
*/
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
/**
* @brief Set a draw offset
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Specifies which item in the @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D,
* @ref VectorDrawUniform and @ref TextureTransformationUniform buffers
* bound with @ref bindTransformationProjectionBuffer(),
* @ref bindDrawBuffer() and @ref bindTextureTransformationBuffer()
* should be used for current draw. Expects that
* @ref Flag::UniformBuffers is set and @p offset is less than
* @ref drawCount(). Initial value is @cpp 0 @ce.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
VectorGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Set a transformation and projection uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D. At the very least you need
* to call also @ref bindDrawBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
VectorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
VectorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a draw uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref VectorDrawUniform. At the very least you need to call also
* @ref bindTransformationProjectionBuffer().
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
VectorGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
VectorGL<dimensions>& bindDrawBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @brief Set a texture transformation uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that both @ref Flag::UniformBuffers and
* @ref Flag::TextureTransformation is set. The buffer is expected to
* contain @ref drawCount() instances of
* @ref TextureTransformationUniform.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
VectorGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
VectorGL<dimensions>& bindTextureTransformationBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @}
*/
#endif
/** @{
* @name Texture binding
*/
@ -243,10 +425,18 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VectorGL: public GL
#endif
Flags _flags;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _drawCount{};
#endif
Int _transformationProjectionMatrixUniform{0},
_textureMatrixUniform{1},
_backgroundColorUniform{2},
_colorUniform{3};
#ifndef MAGNUM_TARGET_GLES2
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */
Int _drawOffsetUniform{0};
#endif
};
/**

46
src/Magnum/Shaders/VertexColor.vert

@ -28,8 +28,13 @@
#define out varying
#endif
#ifndef RUNTIME_CONST
#define const
#endif
/* Uniforms */
#ifndef UNIFORM_BUFFERS
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
@ -49,6 +54,35 @@ uniform highp mat4 transformationProjectionMatrix
#error
#endif
/* Uniform buffers */
#else
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
uniform highp uint drawOffset
#ifndef GL_ES
= 0u
#endif
;
layout(std140
#ifdef EXPLICIT_BINDING
, binding = 1
#endif
) uniform TransformationProjection {
highp
#ifdef TWO_DIMENSIONS
mat3
#elif defined(THREE_DIMENSIONS)
mat4
#else
#error
#endif
transformationProjectionMatrices[DRAW_COUNT];
};
#endif
/* Inputs */
#ifdef EXPLICIT_ATTRIB_LOCATION
@ -72,6 +106,18 @@ in lowp vec4 color;
out lowp vec4 interpolatedColor;
void main() {
#ifdef UNIFORM_BUFFERS
highp const
#ifdef TWO_DIMENSIONS
mat3
#elif defined(THREE_DIMENSIONS)
mat4
#else
#error
#endif
transformationProjectionMatrix = transformationProjectionMatrices[drawOffset];
#endif
#ifdef TWO_DIMENSIONS
gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0);
#elif defined(THREE_DIMENSIONS)

140
src/Magnum/Shaders/VertexColorGL.cpp

@ -25,6 +25,7 @@
#include "VertexColorGL.h"
#include <Corrade/Containers/EnumSet.hpp>
#include <Corrade/Containers/Reference.h>
#include <Corrade/Utility/Resource.h>
@ -35,11 +36,47 @@
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#ifndef MAGNUM_TARGET_GLES2
#include <Corrade/Utility/FormatStl.h>
#include "Magnum/GL/Buffer.h"
#endif
#include "Magnum/Shaders/Implementation/CreateCompatibilityShader.h"
namespace Magnum { namespace Shaders {
template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL() {
namespace {
#ifndef MAGNUM_TARGET_GLES2
enum: Int {
/* Not using the zero binding to avoid conflicts with
ProjectionBufferBinding from other shaders which can likely stay
bound to the same buffer for the whole time */
TransformationProjectionBufferBinding = 1
};
#endif
}
template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(const Flags flags
#ifndef MAGNUM_TARGET_GLES2
, const UnsignedInt drawCount
#endif
):
_flags{flags}
#ifndef MAGNUM_TARGET_GLES2
, _drawCount{drawCount}
#endif
{
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(flags >= Flag::UniformBuffers) || drawCount,
"Shaders::VertexColorGL: draw count can't be zero", );
#endif
#ifndef MAGNUM_TARGET_GLES
if(flags >= Flag::UniformBuffers)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::uniform_buffer_object);
#endif
#ifdef MAGNUM_BUILD_STATIC
/* Import resources on static build, if not already */
if(!Utility::Resource::hasGroup("MagnumShadersGL"))
@ -58,8 +95,16 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL() {
GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex);
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
vert.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n")
.addSource(rs.get("generic.glsl"))
vert.addSource(dimensions == 2 ? "#define TWO_DIMENSIONS\n" : "#define THREE_DIMENSIONS\n");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
vert.addSource(Utility::formatString(
"#define UNIFORM_BUFFERS\n"
"#define DRAW_COUNT {}\n",
drawCount));
}
#endif
vert.addSource(rs.get("generic.glsl"))
.addSource(rs.get("VertexColor.vert"));
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("VertexColor.frag"));
@ -85,21 +130,106 @@ template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL() {
if(!context.isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
_drawOffsetUniform = uniformLocation("drawOffset");
} else
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
}
}
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers
#ifndef MAGNUM_TARGET_GLES
&& !context.isExtensionSupported<GL::Extensions::ARB::shading_language_420pack>(version)
#endif
) {
setUniformBlockBinding(uniformBlockIndex("TransformationProjection"), TransformationProjectionBufferBinding);
}
#endif
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
#ifndef MAGNUM_TARGET_GLES2
if(flags >= Flag::UniformBuffers) {
/* Draw offset is zero by default */
} else
#endif
{
setTransformationProjectionMatrix(MatrixTypeFor<dimensions, Float>{Math::IdentityInit});
}
#endif
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> VertexColorGL<dimensions>::VertexColorGL(const Flags flags): VertexColorGL{flags, 1} {}
#endif
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix) {
#ifndef MAGNUM_TARGET_GLES2
CORRADE_ASSERT(!(_flags >= Flag::UniformBuffers),
"Shaders::VertexColorGL::setTransformationProjectionMatrix(): the shader was created with uniform buffers enabled", *this);
#endif
setUniform(_transformationProjectionMatrixUniform, matrix);
return *this;
}
#ifndef MAGNUM_TARGET_GLES2
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::setDrawOffset(const UnsignedInt offset) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::setDrawOffset(): the shader was not created with uniform buffers enabled", *this);
CORRADE_ASSERT(offset < _drawCount,
"Shaders::VertexColorGL::setDrawOffset(): draw offset" << offset << "is out of bounds for" << _drawCount << "draws", *this);
setUniform(_drawOffsetUniform, offset);
return *this;
}
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding);
return *this;
}
template<UnsignedInt dimensions> VertexColorGL<dimensions>& VertexColorGL<dimensions>::bindTransformationProjectionBuffer(GL::Buffer& buffer, const GLintptr offset, const GLsizeiptr size) {
CORRADE_ASSERT(_flags >= Flag::UniformBuffers,
"Shaders::VertexColorGL::bindTransformationProjectionBuffer(): the shader was not created with uniform buffers enabled", *this);
buffer.bind(GL::Buffer::Target::Uniform, TransformationProjectionBufferBinding, offset, size);
return *this;
}
#endif
template class MAGNUM_SHADERS_EXPORT VertexColorGL<2>;
template class MAGNUM_SHADERS_EXPORT VertexColorGL<3>;
namespace Implementation {
Debug& operator<<(Debug& debug, const VertexColorGLFlag value) {
debug << "Shaders::VertexColorGL::Flag" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case VertexColorGLFlag::v: return debug << "::" #v;
#ifndef MAGNUM_TARGET_GLES2
_c(UniformBuffers)
#endif
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const VertexColorGLFlags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::VertexColorGL::Flags{}", {
#ifndef MAGNUM_TARGET_GLES2
VertexColorGLFlag::UniformBuffers
#endif
});
}
}
}}

184
src/Magnum/Shaders/VertexColorGL.h

@ -37,6 +37,15 @@
namespace Magnum { namespace Shaders {
namespace Implementation {
enum class VertexColorGLFlag: UnsignedByte {
#ifndef MAGNUM_TARGET_GLES2
UniformBuffers = 1 << 0
#endif
};
typedef Containers::EnumSet<VertexColorGLFlag> VertexColorGLFlags;
}
/**
@brief Vertex color OpenGL shader
@m_since_latest
@ -107,7 +116,84 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
ColorOutput = GenericGL<dimensions>::ColorOutput
};
explicit VertexColorGL();
#ifdef DOXYGEN_GENERATING_OUTPUT
/**
* @brief Flag
* @m_since{2020,06}
*
* @see @ref Flags, @ref flags()
*/
enum class Flag: UnsignedByte {
#ifndef MAGNUM_TARGET_GLES2
/**
* Use uniform buffers. Expects that uniform data are supplied via
* @ref bindTransformationProjectionBuffer() instead of direct
* uniform setters.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES
* 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL
* 1.0.
* @m_since_latest
*/
UniformBuffers = 1 << 0
#endif
};
/**
* @brief Flags
* @m_since{2020,06}
*
* @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::VertexColorGLFlag Flag;
typedef Implementation::VertexColorGLFlags Flags;
#endif
/**
* @brief Constructor
* @param flags Flags
*
* While this function is meant mainly for the classic uniform
* scenario (without @ref Flag::UniformBuffers set), it's equivalent to
* @ref VertexColorGL(Flags, UnsignedInt) with @p drawCount set to
* @cpp 1 @ce.
*/
explicit VertexColorGL(Flags flags = {});
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Construct for a multi-draw scenario
* @param flags Flags
* @param drawCount Size of a @ref TransformationProjectionUniform2D
* / @ref TransformationProjectionUniform3D buffer bound with
* @ref bindTransformationProjectionBuffer()
*
* If @p flags contains @ref Flag::UniformBuffers, @p drawCount
* describes the uniform buffer sizes as these are required to have a
* statically defined size. The draw offset is then set via
* @ref setDrawOffset().
*
* If @p flags don't contain @ref Flag::UniformBuffers, @p drawCount is
* ignored and the constructor behaves the same as
* @ref VertexColorGL(Flags).
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
/** @todo this constructor will eventually need to have also joint
count, per-vertex weight count, view count for multiview and clip
plane count ... and putting them in arbitrary order next to each
other is too error-prone, so it needs some other solution
(accepting pairs of parameter type and value like in GL context
creation, e.g., which will probably need a new enum as reusing Flag
for this might be too confusing) */
explicit VertexColorGL(Flags flags, UnsignedInt drawCount);
#endif
/**
* @brief Construct without creating the underlying OpenGL object
@ -135,8 +221,28 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
/** @brief Move assignment */
VertexColorGL<dimensions>& operator=(VertexColorGL<dimensions>&&) noexcept = default;
/** @brief Flags */
Flags flags() const { return _flags; }
#ifndef MAGNUM_TARGET_GLES2
/**
* @brief Draw count
* @m_since_latest
*
* Statically defined size of each of the
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D uniform buffers. Has use only
* if @ref Flag::UniformBuffers is set.
* @requires_gles30 Not defined on OpenGL ES 2.0 builds.
* @requires_webgl20 Not defined on WebGL 1.0 builds.
*/
UnsignedInt drawCount() const { return _drawCount; }
#endif
/** @{
* @name Uniform setters
*
* Used only if @ref Flag::UniformBuffers is not set.
*/
/**
@ -144,6 +250,11 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* @return Reference to self (for method chaining)
*
* Default is an identity matrix.
*
* Expects that @ref Flag::UniformBuffers is not set, in that case fill
* @ref TransformationProjectionUniform2D::transformationProjectionMatrix /
* @ref TransformationProjectionUniform3D::transformationProjectionMatrix
* and call @ref bindTransformationProjectionBuffer() instead.
*/
VertexColorGL<dimensions>& setTransformationProjectionMatrix(const MatrixTypeFor<dimensions, Float>& matrix);
@ -151,6 +262,54 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
* @}
*/
#ifndef MAGNUM_TARGET_GLES2
/** @{
* @name Uniform buffer binding and related uniform setters
*
* Used if @ref Flag::UniformBuffers is set.
*/
/**
* @brief Set a draw offset
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Specifies which item in the @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D buffers bound with
* @ref bindTransformationProjectionBuffer() should be used for current
* draw. Expects that @ref Flag::UniformBuffers is set and @p offset is
* less than @ref drawCount(). Initial value is @cpp 0 @ce.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
VertexColorGL<dimensions>& setDrawOffset(UnsignedInt offset);
/**
* @brief Set a transformation and projection uniform buffer
* @return Reference to self (for method chaining)
* @m_since_latest
*
* Expects that @ref Flag::UniformBuffers is set. The buffer is
* expected to contain @ref drawCount() instances of
* @ref TransformationProjectionUniform2D /
* @ref TransformationProjectionUniform3D.
* @requires_gl31 Extension @gl_extension{ARB,uniform_buffer_object}
* @requires_gles30 Uniform buffers are not available in OpenGL ES 2.0.
* @requires_webgl20 Uniform buffers are not available in WebGL 1.0.
*/
VertexColorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer);
/**
* @overload
* @m_since_latest
*/
VertexColorGL<dimensions>& bindTransformationProjectionBuffer(GL::Buffer& buffer, GLintptr offset, GLsizeiptr size);
/**
* @}
*/
#endif
private:
/* Prevent accidentally calling irrelevant functions */
#ifndef MAGNUM_TARGET_GLES
@ -160,7 +319,16 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT VertexColorGL: publ
using GL::AbstractShaderProgram::dispatchCompute;
#endif
Flags _flags;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _drawCount{};
#endif
Int _transformationProjectionMatrixUniform{0};
#ifndef MAGNUM_TARGET_GLES2
/* Used instead of all other uniforms when Flag::UniformBuffers is set,
so it can alias them */
Int _drawOffsetUniform{0};
#endif
};
/**
@ -175,6 +343,20 @@ typedef VertexColorGL<2> VertexColorGL2D;
*/
typedef VertexColorGL<3> VertexColorGL3D;
#ifdef DOXYGEN_GENERATING_OUTPUT
/** @debugoperatorclassenum{VertexColorGL,VertexColorGL::Flag} */
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, VertexColorGL<dimensions>::Flag value);
/** @debugoperatorclassenum{VertexColorGL,VertexColorGL::Flags} */
template<UnsignedInt dimensions> Debug& operator<<(Debug& debug, VertexColorGL<dimensions>::Flags value);
#else
namespace Implementation {
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, VertexColorGLFlag value);
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, VertexColorGLFlags value);
CORRADE_ENUMSET_OPERATORS(VertexColorGLFlags)
}
#endif
}}
#endif

Loading…
Cancel
Save