Browse Source

Shaders: add a 2D variant of MeshVisualizer.

pull/430/head
Vladimír Vondruš 6 years ago
parent
commit
74c75178de
  1. 3
      doc/changelog.dox
  2. 11
      doc/generated/primitives.cpp
  3. 28
      doc/generated/shaders.cpp
  4. 39
      doc/namespaces.dox
  5. BIN
      doc/shaders-meshvisualizer2d.png
  6. BIN
      doc/shaders-meshvisualizer3d.png
  7. 15
      doc/snippets/MagnumShaders.cpp
  8. 224
      src/Magnum/Shaders/MeshVisualizer.cpp
  9. 331
      src/Magnum/Shaders/MeshVisualizer.h
  10. 22
      src/Magnum/Shaders/MeshVisualizer.vert
  11. 11
      src/Magnum/Shaders/Shaders.h
  12. 12
      src/Magnum/Shaders/Test/CMakeLists.txt
  13. 445
      src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp
  14. 91
      src/Magnum/Shaders/Test/MeshVisualizerTest.cpp
  15. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/defaults-wireframe2D.tga
  16. 0
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/defaults-wireframe3D.tga
  17. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-nogeo2D.tga
  18. 0
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-nogeo3D.tga
  19. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide2D.tga
  20. 0
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide3D.tga
  21. BIN
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe2D.tga
  22. 0
      src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe3D.tga
  23. 2
      src/Magnum/Shaders/visibility.h

3
doc/changelog.dox

@ -204,6 +204,7 @@ See also:
@subsubsection changelog-latest-new-shaders Shaders library
- New @ref Shaders::MeshVisualizer2D for 2D mesh visualization
- Texture coordinate transformation in @ref Shaders::DistanceFieldVector,
@ref Shaders::Flat, @ref Shaders::Phong and @ref Shaders::Vector
- New attribute definitions and an location allocation scheme in
@ -495,6 +496,8 @@ See also:
@ref MeshTools::compressIndices(), @ref MeshTools::duplicate(),
@ref MeshTools::removeDuplicatesInPlace() and @ref MeshTools::subdivide() /
@ref MeshTools::subdivideInPlace() overloads instead
- @cpp Shaders::MeshVisualizer @ce is deprecated as the shader can now handle
both 2D and 3D, use @ref Shaders::MeshVisualizer3D instead
@subsection changelog-latest-compatibility Potential compatibility breakages, removed APIs

11
doc/generated/primitives.cpp

@ -275,17 +275,12 @@ int PrimitiveVisualizer::exec() {
}
}
Shaders::MeshVisualizer wireframe2D{Shaders::MeshVisualizer::Flag::Wireframe};
Shaders::MeshVisualizer2D wireframe2D{Shaders::MeshVisualizer2D::Flag::Wireframe};
wireframe2D.setColor(0x00000000_srgbaf)
.setWireframeColor(OutlineColor)
.setWireframeWidth(2.0f)
.setViewportSize(Vector2{ImageSize})
.setTransformationProjectionMatrix(Matrix4{
/** @todo clean up once Matrix4 from Matrix3 constructor exists */
{(Projection2D*Transformation2D)[0], 0.0f},
{(Projection2D*Transformation2D)[1], 0.0f},
{0.0f, 0.0f, 1.0f, 0.0f},
{{(Projection2D*Transformation2D)[2].xy(), 0.0f}, 1.0f}});
.setTransformationProjectionMatrix(Projection2D*Transformation2D);
{
Shaders::Flat2D flat;
@ -312,7 +307,7 @@ int PrimitiveVisualizer::exec() {
}
}
Shaders::MeshVisualizer wireframe3D{Shaders::MeshVisualizer::Flag::Wireframe};
Shaders::MeshVisualizer3D wireframe3D{Shaders::MeshVisualizer3D::Flag::Wireframe};
wireframe3D.setColor(0x00000000_srgbaf)
.setWireframeColor(OutlineColor)
.setWireframeWidth(2.0f)

28
doc/generated/shaders.cpp

@ -78,7 +78,8 @@ struct ShaderVisualizer: Platform::WindowlessApplication {
int exec() override;
std::string phong();
std::string meshVisualizer();
std::string meshVisualizer2D();
std::string meshVisualizer3D();
std::string flat();
std::string vertexColor();
@ -127,7 +128,8 @@ int ShaderVisualizer::exec() {
GL::Renderer::setClearColor(0x000000_srgbaf);
for(auto fun: {&ShaderVisualizer::phong,
&ShaderVisualizer::meshVisualizer,
&ShaderVisualizer::meshVisualizer2D,
&ShaderVisualizer::meshVisualizer3D,
&ShaderVisualizer::flat,
&ShaderVisualizer::vertexColor,
&ShaderVisualizer::vector,
@ -167,12 +169,28 @@ std::string ShaderVisualizer::phong() {
return "phong.png";
}
std::string ShaderVisualizer::meshVisualizer() {
std::string ShaderVisualizer::meshVisualizer2D() {
const Matrix3 projection =
Matrix3::projection(Vector2{3.0f})*
Matrix3::rotation(13.7_degf);
Shaders::MeshVisualizer2D{Shaders::MeshVisualizer2D::Flag::Wireframe}
.setColor(BaseColor)
.setWireframeColor(OutlineColor)
.setWireframeWidth(2.0f)
.setViewportSize(Vector2{ImageSize})
.setTransformationProjectionMatrix(projection)
.draw(MeshTools::compile(Primitives::circle2DSolid(8)));
return "meshvisualizer2d.png";
}
std::string ShaderVisualizer::meshVisualizer3D() {
const Matrix4 projection = Projection*Transformation*
Matrix4::rotationZ(13.7_degf)*
Matrix4::rotationX(-12.6_degf);
Shaders::MeshVisualizer{Shaders::MeshVisualizer::Flag::Wireframe}
Shaders::MeshVisualizer3D{Shaders::MeshVisualizer3D::Flag::Wireframe}
.setColor(BaseColor)
.setWireframeColor(OutlineColor)
.setWireframeWidth(2.0f)
@ -180,7 +198,7 @@ std::string ShaderVisualizer::meshVisualizer() {
.setTransformationProjectionMatrix(projection)
.draw(MeshTools::compile(Primitives::icosphereSolid(1)));
return "meshvisualizer.png";
return "meshvisualizer3d.png";
}
std::string ShaderVisualizer::flat() {

39
doc/namespaces.dox

@ -449,24 +449,21 @@ See @ref building, @ref cmake and @ref shaders for more information.
@parblock
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-flat.png
@m_div{m-col-m-4 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-flat.png width=256px
@ref Flat @m_class{m-label m-success} **2D** @m_class{m-label m-primary} **3D**
@m_enddiv
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-phong.png
@m_div{m-col-m-4 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-phong.png width=256px
@ref Phong @m_class{m-label m-primary} **3D**
@m_enddiv
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-vertexcolor.png
@ref VertexColor @m_class{m-label m-success} **2D** @m_class{m-label m-primary} **3D**
@m_enddiv
@m_div{m-clearfix-t} @m_enddiv
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-meshvisualizer.png
@ref MeshVisualizer @m_class{m-label m-primary} **3D**
@m_div{m-col-m-4 m-push-t-3 m-push-m-0 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-vertexcolor.png width=256px
@ref VertexColor @m_class{m-label m-success} **2D** @m_class{m-label m-primary} **3D**
@m_enddiv
@endparblock
@ -475,13 +472,25 @@ See @ref building, @ref cmake and @ref shaders for more information.
@parblock
@m_div{m-col-m-3 m-push-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-vector.png
@m_div{m-clearfix-m} @m_enddiv
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-meshvisualizer2d.png width=256px
@ref MeshVisualizer2D "MeshVisualizer2D" @m_class{m-label m-success} **2D**
@m_enddiv
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-meshvisualizer3d.png width=256px
@ref MeshVisualizer3D "MeshVisualizer3D" @m_class{m-label m-primary} **3D**
@m_enddiv
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-vector.png width=256px
@ref Vector @m_class{m-label m-success} **2D** @m_class{m-label m-primary} **3D**
@m_enddiv
@m_div{m-col-m-3 m-push-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-distancefieldvector.png
@m_div{m-col-m-3 m-col-t-6 m-text-center m-nopadt m-nopadx}
@image html shaders-distancefieldvector.png width=256px
@ref DistanceFieldVector @m_class{m-label m-success} **2D** @m_class{m-label m-primary} **3D**
@m_enddiv

BIN
doc/shaders-meshvisualizer2d.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
doc/shaders-meshvisualizer.png → doc/shaders-meshvisualizer3d.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

15
doc/snippets/MagnumShaders.cpp

@ -95,7 +95,7 @@ mesh.addVertexBuffer(vertices, 0,
/* [shaders-generic] */
/* [shaders-meshvisualizer] */
Shaders::MeshVisualizer visualizerShader{Shaders::MeshVisualizer::Flag::Wireframe};
Shaders::MeshVisualizer3D visualizerShader{Shaders::MeshVisualizer3D::Flag::Wireframe};
visualizerShader
.setColor(0x2f83cc_rgbf)
.setWireframeColor(0xdcdcdc_rgbf)
@ -254,7 +254,7 @@ GL::Buffer vertices;
vertices.setData(data, GL::BufferUsage::StaticDraw);
GL::Mesh mesh;
mesh.addVertexBuffer(vertices, 0, Shaders::MeshVisualizer::Position{});
mesh.addVertexBuffer(vertices, 0, Shaders::MeshVisualizer3D::Position{});
/* [MeshVisualizer-usage-geom1] */
/* [MeshVisualizer-usage-geom2] */
@ -262,7 +262,7 @@ Matrix4 transformationMatrix = Matrix4::translation(Vector3::zAxis(-5.0f));
Matrix4 projectionMatrix =
Matrix4::perspectiveProjection(35.0_degf, 1.0f, 0.001f, 100.0f);
Shaders::MeshVisualizer shader{Shaders::MeshVisualizer::Flag::Wireframe};
Shaders::MeshVisualizer3D shader{Shaders::MeshVisualizer3D::Flag::Wireframe};
shader.setColor(0x2f83cc_rgbf)
.setWireframeColor(0xdcdcdc_rgbf)
.setViewportSize(Vector2{GL::defaultFramebuffer.viewport().size()})
@ -277,7 +277,7 @@ std::iota(vertexIndex.begin(), vertexIndex.end(), 0.0f);
GL::Buffer vertexIndices;
vertexIndices.setData(vertexIndex, GL::BufferUsage::StaticDraw);
mesh.addVertexBuffer(vertexIndices, 0, Shaders::MeshVisualizer::VertexIndex{});
mesh.addVertexBuffer(vertexIndices, 0, Shaders::MeshVisualizer3D::VertexIndex{});
/* [MeshVisualizer-usage-no-geom-old] */
}
#endif
@ -291,7 +291,7 @@ Containers::StridedArrayView1D<const Vector3> indexedPositions;
GL::Buffer vertices{MeshTools::duplicate(indices, indexedPositions)};
GL::Mesh mesh;
mesh.addVertexBuffer(vertices, 0, Shaders::MeshVisualizer::Position{});
mesh.addVertexBuffer(vertices, 0, Shaders::MeshVisualizer3D::Position{});
/* [MeshVisualizer-usage-no-geom1] */
}
@ -300,8 +300,9 @@ GL::Mesh mesh;
/* [MeshVisualizer-usage-no-geom2] */
Matrix4 transformationMatrix, projectionMatrix;
Shaders::MeshVisualizer shader{Shaders::MeshVisualizer::Flag::Wireframe|
Shaders::MeshVisualizer::Flag::NoGeometryShader};
Shaders::MeshVisualizer3D shader{
Shaders::MeshVisualizer3D::Flag::Wireframe|
Shaders::MeshVisualizer3D::Flag::NoGeometryShader};
shader.setColor(0x2f83cc_rgbf)
.setWireframeColor(0xdcdcdc_rgbf)
.setTransformationProjectionMatrix(projectionMatrix*transformationMatrix)

224
src/Magnum/Shaders/MeshVisualizer.cpp

@ -31,6 +31,7 @@
#include <Corrade/Utility/Resource.h>
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#include "Magnum/GL/Context.h"
#include "Magnum/GL/Extensions.h"
@ -40,9 +41,11 @@
namespace Magnum { namespace Shaders {
MeshVisualizer::MeshVisualizer(const Flags flags): _flags{flags} {
namespace Implementation {
MeshVisualizerBase::MeshVisualizerBase(FlagsBase flags): _flags{flags} {
#ifndef MAGNUM_TARGET_GLES2
if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) {
if(_flags & FlagBase::Wireframe && !(_flags & FlagBase::NoGeometryShader)) {
#ifndef MAGNUM_TARGET_GLES
MAGNUM_ASSERT_GL_VERSION_SUPPORTED(GL::Version::GL320);
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::ARB::geometry_shader4);
@ -51,7 +54,7 @@ MeshVisualizer::MeshVisualizer(const Flags flags): _flags{flags} {
#endif
}
#else
if(_flags & Flag::Wireframe)
if(_flags & FlagBase::Wireframe)
MAGNUM_ASSERT_GL_EXTENSION_SUPPORTED(GL::Extensions::OES::standard_derivatives);
#endif
@ -60,34 +63,85 @@ MeshVisualizer::MeshVisualizer(const Flags flags): _flags{flags} {
if(!Utility::Resource::hasGroup("MagnumShaders"))
importShaderResources();
#endif
Utility::Resource rs("MagnumShaders");
}
GL::Version MeshVisualizerBase::setupShaders(GL::Shader& vert, GL::Shader& frag, const Utility::Resource& rs) const {
#ifndef MAGNUM_TARGET_GLES
const GL::Version version = GL::Context::current().supportedVersion({GL::Version::GL320, GL::Version::GL310, GL::Version::GL300, GL::Version::GL210});
CORRADE_INTERNAL_ASSERT(!flags || flags & Flag::NoGeometryShader || version >= GL::Version::GL320);
CORRADE_INTERNAL_ASSERT(!_flags || _flags & FlagBase::NoGeometryShader || version >= GL::Version::GL320);
#elif !defined(MAGNUM_TARGET_WEBGL)
const GL::Version version = GL::Context::current().supportedVersion({GL::Version::GLES310, GL::Version::GLES300, GL::Version::GLES200});
CORRADE_INTERNAL_ASSERT(!flags || flags & Flag::NoGeometryShader || version >= GL::Version::GLES310);
CORRADE_INTERNAL_ASSERT(!_flags || _flags & FlagBase::NoGeometryShader || version >= GL::Version::GLES310);
#else
const GL::Version version = GL::Context::current().supportedVersion({GL::Version::GLES300, GL::Version::GLES200});
#endif
GL::Shader vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex);
GL::Shader frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
vert = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Vertex);
frag = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Fragment);
vert.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
.addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "")
vert.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
.addSource(_flags & FlagBase::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "")
#ifdef MAGNUM_TARGET_WEBGL
.addSource("#define SUBSCRIPTING_WORKAROUND\n")
#elif defined(MAGNUM_TARGET_GLES2)
.addSource(GL::Context::current().detectedDriver() & GL::Context::DetectedDriver::Angle ?
"#define SUBSCRIPTING_WORKAROUND\n" : "")
#endif
;
frag.addSource(_flags & FlagBase::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
.addSource(_flags & FlagBase::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "");
return version;
}
MeshVisualizerBase& MeshVisualizerBase::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. */
if(_flags & FlagBase::Wireframe && !(_flags & FlagBase::NoGeometryShader))
setUniform(_viewportSizeUniform, size);
return *this;
}
MeshVisualizerBase& MeshVisualizerBase::setColor(const Color4& color) {
setUniform(_colorUniform, color);
return *this;
}
MeshVisualizerBase& MeshVisualizerBase::setWireframeColor(const Color4& color) {
CORRADE_ASSERT(_flags & FlagBase::Wireframe,
"Shaders::MeshVisualizer::setWireframeColor(): the shader was not created with wireframe enabled", *this);
setUniform(_wireframeColorUniform, color);
return *this;
}
MeshVisualizerBase& MeshVisualizerBase::setWireframeWidth(const Float width) {
CORRADE_ASSERT(_flags & FlagBase::Wireframe,
"Shaders::MeshVisualizer::setWireframeWidth(): the shader was not created with wireframe enabled", *this);
setUniform(_wireframeWidthUniform, width);
return *this;
}
MeshVisualizerBase& MeshVisualizerBase::setSmoothness(const Float smoothness) {
/* This is a bit vaguely related too, but less vague than setViewportSize()
so asserting. */
CORRADE_ASSERT(_flags & FlagBase::Wireframe,
"Shaders::MeshVisualizer::setSmoothness(): the shader was not created with wireframe enabled", *this);
setUniform(_smoothnessUniform, smoothness);
return *this;
}
}
MeshVisualizer2D::MeshVisualizer2D(const Flags flags): Implementation::MeshVisualizerBase{Implementation::MeshVisualizerBase::FlagBase(UnsignedByte(flags))} {
Utility::Resource rs{"MagnumShaders"};
GL::Shader vert{NoCreate};
GL::Shader frag{NoCreate};
const GL::Version version = setupShaders(vert, frag, rs);
vert.addSource("#define TWO_DIMENSIONS\n")
.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.vert"));
frag.addSource(flags & Flag::Wireframe ? "#define WIREFRAME_RENDERING\n" : "")
.addSource(flags & Flag::NoGeometryShader ? "#define NO_GEOMETRY_SHADER\n" : "")
.addSource(rs.get("generic.glsl"))
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.frag"));
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
@ -96,6 +150,8 @@ MeshVisualizer::MeshVisualizer(const Flags flags): _flags{flags} {
geom = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Geometry);
geom->addSource(rs.get("MeshVisualizer.geom"));
}
#else
static_cast<void>(version);
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
@ -149,7 +205,7 @@ MeshVisualizer::MeshVisualizer(const Flags flags): _flags{flags} {
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix({});
setColor(Color3(1.0f));
if(_flags & Flag::Wireframe) {
if(flags & Flag::Wireframe) {
/* Viewport size is zero by default */
setWireframeColor(Color3{0.0f});
setWireframeWidth(1.0f);
@ -158,53 +214,104 @@ MeshVisualizer::MeshVisualizer(const Flags flags): _flags{flags} {
#endif
}
MeshVisualizer& MeshVisualizer::setTransformationProjectionMatrix(const Matrix4& matrix) {
MeshVisualizer2D& MeshVisualizer2D::setTransformationProjectionMatrix(const Matrix3& matrix) {
setUniform(_transformationProjectionMatrixUniform, matrix);
return *this;
}
MeshVisualizer& MeshVisualizer::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. */
if(_flags & Flag::Wireframe && !(_flags & Flag::NoGeometryShader))
setUniform(_viewportSizeUniform, size);
return *this;
MeshVisualizer3D::MeshVisualizer3D(const Flags flags): Implementation::MeshVisualizerBase{Implementation::MeshVisualizerBase::FlagBase(UnsignedByte(flags))} {
Utility::Resource rs{"MagnumShaders"};
GL::Shader vert{NoCreate};
GL::Shader frag{NoCreate};
const GL::Version version = setupShaders(vert, frag, rs);
vert.addSource("#define THREE_DIMENSIONS\n")
.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.vert"));
frag.addSource(rs.get("generic.glsl"))
.addSource(rs.get("MeshVisualizer.frag"));
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
Containers::Optional<GL::Shader> geom;
if(flags & Flag::Wireframe && !(flags & Flag::NoGeometryShader)) {
geom = Implementation::createCompatibilityShader(rs, version, GL::Shader::Type::Geometry);
geom->addSource(rs.get("MeshVisualizer.geom"));
}
#else
static_cast<void>(version);
#endif
MeshVisualizer& MeshVisualizer::setColor(const Color4& color) {
setUniform(_colorUniform, color);
return *this;
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(geom) CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, *geom, frag}));
else
#endif
CORRADE_INTERNAL_ASSERT_OUTPUT(GL::Shader::compile({vert, frag}));
attachShaders({vert, frag});
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
if(geom) attachShader(*geom);
#endif
/* ES3 has this done in the shader directly */
#if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2)
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::explicit_attrib_location>(version))
#endif
{
bindAttributeLocation(Position::Location, "position");
#if !defined(MAGNUM_TARGET_GLES) || defined(MAGNUM_TARGET_GLES2)
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isVersionSupported(GL::Version::GL310))
#endif
{
bindAttributeLocation(VertexIndex::Location, "vertexIndex");
}
#endif
}
#endif
MeshVisualizer& MeshVisualizer::setWireframeColor(const Color4& color) {
CORRADE_ASSERT(_flags & Flag::Wireframe,
"Shaders::MeshVisualizer::setWireframeColor(): the shader was not created with wireframe enabled", *this);
setUniform(_wireframeColorUniform, color);
return *this;
CORRADE_INTERNAL_ASSERT_OUTPUT(link());
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::explicit_uniform_location>(version))
#endif
{
_transformationProjectionMatrixUniform = uniformLocation("transformationProjectionMatrix");
_colorUniform = uniformLocation("color");
if(flags & Flag::Wireframe) {
_wireframeColorUniform = uniformLocation("wireframeColor");
_wireframeWidthUniform = uniformLocation("wireframeWidth");
_smoothnessUniform = uniformLocation("smoothness");
if(!(flags & Flag::NoGeometryShader))
_viewportSizeUniform = uniformLocation("viewportSize");
}
}
MeshVisualizer& MeshVisualizer::setWireframeWidth(const Float width) {
CORRADE_ASSERT(_flags & Flag::Wireframe,
"Shaders::MeshVisualizer::setWireframeWidth(): the shader was not created with wireframe enabled", *this);
setUniform(_wireframeWidthUniform, width);
return *this;
/* Set defaults in OpenGL ES (for desktop they are set in shader code itself) */
#ifdef MAGNUM_TARGET_GLES
setTransformationProjectionMatrix({});
setColor(Color3(1.0f));
if(flags & Flag::Wireframe) {
/* Viewport size is zero by default */
setWireframeColor(Color3{0.0f});
setWireframeWidth(1.0f);
setSmoothness(2.0f);
}
#endif
}
MeshVisualizer& MeshVisualizer::setSmoothness(const Float smoothness) {
/* This is a bit vaguely related too, but less vague than setViewportSize()
so asserting. */
CORRADE_ASSERT(_flags & Flag::Wireframe,
"Shaders::MeshVisualizer::setSmoothness(): the shader was not created with wireframe enabled", *this);
setUniform(_smoothnessUniform, smoothness);
MeshVisualizer3D& MeshVisualizer3D::setTransformationProjectionMatrix(const Matrix4& matrix) {
setUniform(_transformationProjectionMatrixUniform, matrix);
return *this;
}
Debug& operator<<(Debug& debug, const MeshVisualizer::Flag value) {
debug << "Shaders::MeshVisualizer::Flag" << Debug::nospace;
Debug& operator<<(Debug& debug, const MeshVisualizer2D::Flag value) {
debug << "Shaders::MeshVisualizer2D::Flag" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case MeshVisualizer::Flag::v: return debug << "::" #v;
#define _c(v) case MeshVisualizer2D::Flag::v: return debug << "::" #v;
_c(NoGeometryShader)
_c(Wireframe)
#undef _c
@ -214,11 +321,34 @@ Debug& operator<<(Debug& debug, const MeshVisualizer::Flag value) {
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const MeshVisualizer::Flags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::MeshVisualizer::Flags{}", {
MeshVisualizer::Flag::Wireframe,
Debug& operator<<(Debug& debug, const MeshVisualizer3D::Flag value) {
debug << "Shaders::MeshVisualizer3D::Flag" << Debug::nospace;
switch(value) {
/* LCOV_EXCL_START */
#define _c(v) case MeshVisualizer3D::Flag::v: return debug << "::" #v;
_c(NoGeometryShader)
_c(Wireframe)
#undef _c
/* LCOV_EXCL_STOP */
}
return debug << "(" << Debug::nospace << reinterpret_cast<void*>(UnsignedByte(value)) << Debug::nospace << ")";
}
Debug& operator<<(Debug& debug, const MeshVisualizer2D::Flags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::MeshVisualizer2D::Flags{}", {
MeshVisualizer2D::Flag::Wireframe,
/* Wireframe contains this on ES2 so it's not reported there */
MeshVisualizer2D::Flag::NoGeometryShader
});
}
Debug& operator<<(Debug& debug, const MeshVisualizer3D::Flags value) {
return Containers::enumSetDebugOutput(debug, value, "Shaders::MeshVisualizer3D::Flags{}", {
MeshVisualizer3D::Flag::Wireframe,
/* Wireframe contains this on ES2 so it's not reported there */
MeshVisualizer::Flag::NoGeometryShader
MeshVisualizer3D::Flag::NoGeometryShader
});
}

331
src/Magnum/Shaders/MeshVisualizer.h

@ -26,25 +26,248 @@
*/
/** @file
* @brief Class @ref Magnum::Shaders::MeshVisualizer
* @brief Class @ref Magnum::Shaders::MeshVisualizer2D, @ref Magnum::Shaders::MeshVisualizer3D
*/
#include <Corrade/Utility/Utility.h>
#include "Magnum/DimensionTraits.h"
#include "Magnum/GL/AbstractShaderProgram.h"
#include "Magnum/Shaders/Generic.h"
#include "Magnum/Shaders/visibility.h"
namespace Magnum { namespace Shaders {
namespace Implementation {
class MAGNUM_SHADERS_EXPORT MeshVisualizerBase: public GL::AbstractShaderProgram {
protected:
enum class FlagBase: UnsignedByte {
#ifndef MAGNUM_TARGET_GLES2
Wireframe = 1 << 0,
#else
Wireframe = (1 << 0) | (1 << 1),
#endif
NoGeometryShader = 1 << 1
};
typedef Containers::EnumSet<FlagBase> FlagsBase;
CORRADE_ENUMSET_FRIEND_OPERATORS(FlagsBase)
explicit MeshVisualizerBase(FlagsBase flags);
explicit MeshVisualizerBase(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {}
MAGNUM_SHADERS_LOCAL GL::Version setupShaders(GL::Shader& vert, GL::Shader& frag, const Utility::Resource& rs) const;
MeshVisualizerBase& setViewportSize(const Vector2& size);
MeshVisualizerBase& setColor(const Color4& color);
MeshVisualizerBase& setWireframeColor(const Color4& color);
MeshVisualizerBase& setWireframeWidth(Float width);
MeshVisualizerBase& setSmoothness(Float smoothness);
/* Prevent accidentally calling irrelevant functions */
#ifndef MAGNUM_TARGET_GLES
using GL::AbstractShaderProgram::drawTransformFeedback;
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
using GL::AbstractShaderProgram::dispatchCompute;
#endif
FlagsBase _flags;
Int _colorUniform{1},
_wireframeColorUniform{2},
_wireframeWidthUniform{3},
_smoothnessUniform{4},
_viewportSizeUniform{5};
};
}
/**
@brief Mesh visualization shader
@brief 2D mesh visualization shader
@m_since_latest
Uses geometry shader to visualize wireframe of 3D meshes. You need to provide
the @ref Position attribute in your triangle mesh. By default, the shader
renders the mesh with a white color in an identity transformation. Use
Uses the geometry shader to visualize wireframe of 3D meshes. You need to
provide the @ref Position attribute in your triangle mesh. By default, the
shader renders the mesh with a white color in an identity transformation. Use
@ref setTransformationProjectionMatrix(), @ref setColor() and others to
configure the shader.
@image html shaders-meshvisualizer.png width=256px
@image html shaders-meshvisualizer2d.png width=256px
This shader is a 2D variant of @ref MeshVisualizer3D with mostly identical
workflow. See its documentation for more information.
*/
class MAGNUM_SHADERS_EXPORT MeshVisualizer2D: public Implementation::MeshVisualizerBase {
public:
/**
* @brief Vertex position
*
* @ref shaders-generic "Generic attribute",
* @ref Magnum::Vector2 "Vector2".
*/
typedef typename Generic2D::Position Position;
/**
* @brief Vertex index
*
* See @ref MeshVisualizer3D::VertexIndex for more information.
*/
typedef GL::Attribute<4, Float> VertexIndex;
enum: UnsignedInt {
/**
* Color shader output. @ref shaders-generic "Generic output",
* present always. Expects three- or four-component floating-point
* or normalized buffer attachment.
*/
ColorOutput = Generic2D::ColorOutput
};
/**
* @brief Flag
*
* @see @ref Flags, @ref MeshVisualizer2D()
*/
enum class Flag: UnsignedByte {
/**
* Visualize wireframe. On OpenGL ES 2.0 this also enables
* @ref Flag::NoGeometryShader.
*/
#ifndef MAGNUM_TARGET_GLES2
Wireframe = 1 << 0,
#else
Wireframe = (1 << 0) | (1 << 1),
#endif
/**
* Don't use a geometry shader for wireframe visualization. If
* enabled, you might need to provide also the @ref VertexIndex
* attribute in the mesh. In OpenGL ES 2.0 enabled alongside
* @ref Flag::Wireframe.
*/
NoGeometryShader = 1 << 1
};
/** @brief Flags */
typedef Containers::EnumSet<Flag> Flags;
/**
* @brief Constructor
* @param flags Flags
*/
explicit MeshVisualizer2D(Flags flags = {});
/**
* @brief Construct without creating the underlying OpenGL object
*
* The constructed instance is equivalent to a moved-from state. Useful
* in cases where you will overwrite the instance later anyway. Move
* another object over it to make it useful.
*
* This function can be safely used for constructing (and later
* destructing) objects even without any OpenGL context being active.
* However note that this is a low-level and a potentially dangerous
* API, see the documentation of @ref NoCreate for alternatives.
*/
explicit MeshVisualizer2D(NoCreateT) noexcept: Implementation::MeshVisualizerBase{NoCreate} {}
/** @brief Copying is not allowed */
MeshVisualizer2D(const MeshVisualizer2D&) = delete;
/** @brief Move constructor */
MeshVisualizer2D(MeshVisualizer2D&&) noexcept = default;
/** @brief Copying is not allowed */
MeshVisualizer2D& operator=(const MeshVisualizer2D&) = delete;
/** @brief Move assignment */
MeshVisualizer2D& operator=(MeshVisualizer2D&&) noexcept = default;
/** @brief Flags */
Flags flags() const {
return reinterpret_cast<const Flags&>(Implementation::MeshVisualizerBase::_flags);
}
/**
* @brief Set transformation and projection matrix
* @return Reference to self (for method chaining)
*
* Initial value is an identity matrix.
*/
MeshVisualizer2D& setTransformationProjectionMatrix(const Matrix3& matrix);
/**
* @brief Set viewport size
* @return Reference to self (for method chaining)
*
* Has effect only if @ref Flag::Wireframe is enabled and geometry
* shaders are used, otherwise it does nothing. Initial value is a zero
* vector.
*/
MeshVisualizer2D& setViewportSize(const Vector2& size) {
return static_cast<MeshVisualizer2D&>(Implementation::MeshVisualizerBase::setViewportSize(size));
}
/**
* @brief Set base object color
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 0xffffffff_rgbaf @ce.
*/
MeshVisualizer2D& setColor(const Color4& color) {
return static_cast<MeshVisualizer2D&>(Implementation::MeshVisualizerBase::setColor(color));
}
/**
* @brief Set wireframe color
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 0x000000ff_rgbaf @ce. Expects that
* @ref Flag::Wireframe is enabled.
*/
MeshVisualizer2D& setWireframeColor(const Color4& color) {
return static_cast<MeshVisualizer2D&>(Implementation::MeshVisualizerBase::setWireframeColor(color));
}
/**
* @brief Set wireframe width
* @return Reference to self (for method chaining)
*
* Value is in screen space (depending on @ref setViewportSize()),
* initial value is @cpp 1.0f @ce. Expects that @ref Flag::Wireframe is
* enabled.
*/
MeshVisualizer2D& setWireframeWidth(Float width) {
return static_cast<MeshVisualizer2D&>(Implementation::MeshVisualizerBase::setWireframeWidth(width));
}
/**
* @brief Set line smoothness
* @return Reference to self (for method chaining)
*
* Value is in screen space (depending on @ref setViewportSize()),
* initial value is @cpp 2.0f @ce. Expects that @ref Flag::Wireframe is
* enabled.
*/
MeshVisualizer2D& setSmoothness(Float smoothness) {
return static_cast<MeshVisualizer2D&>(Implementation::MeshVisualizerBase::setSmoothness(smoothness));
}
private:
Int _transformationProjectionMatrixUniform{0};
};
/**
@brief 3D mesh visualization shader
Uses the geometry shader to visualize wireframe of 3D meshes. You need to
provide the @ref Position attribute in your triangle mesh. By default, the
shader renders the mesh with a white color in an identity transformation. Use
@ref setTransformationProjectionMatrix(), @ref setColor() and others to
configure the shader.
@image html shaders-meshvisualizer3d.png width=256px
@section Shaders-MeshVisualizer-wireframe Wireframe visualization
@ -100,10 +323,10 @@ addition to the above*:
Rendering setup the same as above.
@see @ref shaders
@see @ref shaders, @ref MeshVisualizer2D
@todo Understand and add support wireframe width/smoothness without GS
*/
class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
class MAGNUM_SHADERS_EXPORT MeshVisualizer3D: public Implementation::MeshVisualizerBase {
public:
/**
* @brief Vertex position
@ -111,7 +334,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
* @ref shaders-generic "Generic attribute",
* @ref Magnum::Vector3 "Vector3".
*/
typedef Generic3D::Position Position;
typedef typename Generic3D::Position Position;
/**
* @brief Vertex index
@ -157,8 +380,8 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
#endif
/**
* Don't use geometry shader for wireframe visualization. If
* enabled, you might need to provide also @ref VertexIndex
* Don't use a geometry shader for wireframe visualization. If
* enabled, you might need to provide also the @ref VertexIndex
* attribute in the mesh. In OpenGL ES 2.0 enabled alongside
* @ref Flag::Wireframe.
*/
@ -172,7 +395,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
* @brief Constructor
* @param flags Flags
*/
explicit MeshVisualizer(Flags flags = {});
explicit MeshVisualizer3D(Flags flags = {});
/**
* @brief Construct without creating the underlying OpenGL object
@ -186,22 +409,24 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
* However note that this is a low-level and a potentially dangerous
* API, see the documentation of @ref NoCreate for alternatives.
*/
explicit MeshVisualizer(NoCreateT) noexcept: GL::AbstractShaderProgram{NoCreate} {}
explicit MeshVisualizer3D(NoCreateT) noexcept: Implementation::MeshVisualizerBase{NoCreate} {}
/** @brief Copying is not allowed */
MeshVisualizer(const MeshVisualizer&) = delete;
MeshVisualizer3D(const MeshVisualizer3D&) = delete;
/** @brief Move constructor */
MeshVisualizer(MeshVisualizer&&) noexcept = default;
MeshVisualizer3D(MeshVisualizer3D&&) noexcept = default;
/** @brief Copying is not allowed */
MeshVisualizer& operator=(const MeshVisualizer&) = delete;
MeshVisualizer3D& operator=(const MeshVisualizer3D&) = delete;
/** @brief Move assignment */
MeshVisualizer& operator=(MeshVisualizer&&) noexcept = default;
MeshVisualizer3D& operator=(MeshVisualizer3D&&) noexcept = default;
/** @brief Flags */
Flags flags() const { return _flags; }
Flags flags() const {
return reinterpret_cast<const Flags&>(Implementation::MeshVisualizerBase::_flags);
}
/**
* @brief Set transformation and projection matrix
@ -209,7 +434,7 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
*
* Initial value is an identity matrix.
*/
MeshVisualizer& setTransformationProjectionMatrix(const Matrix4& matrix);
MeshVisualizer3D& setTransformationProjectionMatrix(const Matrix4& matrix);
/**
* @brief Set viewport size
@ -218,7 +443,9 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
* Has effect only if @ref Flag::Wireframe is enabled and geometry
* shaders are used. Initial value is a zero vector.
*/
MeshVisualizer& setViewportSize(const Vector2& size);
MeshVisualizer3D& setViewportSize(const Vector2& size) {
return static_cast<MeshVisualizer3D&>(Implementation::MeshVisualizerBase::setViewportSize(size));
}
/**
* @brief Set base object color
@ -226,60 +453,70 @@ class MAGNUM_SHADERS_EXPORT MeshVisualizer: public GL::AbstractShaderProgram {
*
* Initial value is @cpp 0xffffffff_rgbaf @ce.
*/
MeshVisualizer& setColor(const Color4& color);
MeshVisualizer3D& setColor(const Color4& color) {
return static_cast<MeshVisualizer3D&>(Implementation::MeshVisualizerBase::setColor(color));
}
/**
* @brief Set wireframe color
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 0x000000ff_rgbaf @ce. Has effect only if
* Initial value is @cpp 0x000000ff_rgbaf @ce. Expects that
* @ref Flag::Wireframe is enabled.
*/
MeshVisualizer& setWireframeColor(const Color4& color);
MeshVisualizer3D& setWireframeColor(const Color4& color) {
return static_cast<MeshVisualizer3D&>(Implementation::MeshVisualizerBase::setWireframeColor(color));
}
/**
* @brief Set wireframe width
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 1.0f @ce. Has effect only if @ref Flag::Wireframe
* is enabled.
* Initial value is @cpp 1.0f @ce. Has effect only if
* @ref Flag::Wireframe is enabled.
*/
MeshVisualizer& setWireframeWidth(Float width);
MeshVisualizer3D& setWireframeWidth(Float width) {
return static_cast<MeshVisualizer3D&>(Implementation::MeshVisualizerBase::setWireframeWidth(width));
}
/**
* @brief Set line smoothness
* @return Reference to self (for method chaining)
*
* Initial value is @cpp 2.0f @ce. Has effect only if @ref Flag::Wireframe
* Value is in screen space (depending on @ref setViewportSize()),
* initial value is @cpp 2.0f @ce. Expects that @ref Flag::Wireframe
* is enabled.
*/
MeshVisualizer& setSmoothness(Float smoothness);
MeshVisualizer3D& setSmoothness(Float smoothness) {
return static_cast<MeshVisualizer3D&>(Implementation::MeshVisualizerBase::setSmoothness(smoothness));
}
private:
/* Prevent accidentally calling irrelevant functions */
#ifndef MAGNUM_TARGET_GLES
using GL::AbstractShaderProgram::drawTransformFeedback;
#endif
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
using GL::AbstractShaderProgram::dispatchCompute;
Int _transformationProjectionMatrixUniform{0};
};
#ifdef MAGNUM_BUILD_DEPRECATED
/**
@brief 3D mesh visualizer shader
@m_deprecated_since_latest Use @ref MeshVisualizer3D instead.
*/
typedef CORRADE_DEPRECATED("use MeshVisualizer3D instead") MeshVisualizer3D MeshVisualizer;
#endif
Flags _flags;
Int _transformationProjectionMatrixUniform{0},
_colorUniform{1},
_wireframeColorUniform{2},
_wireframeWidthUniform{3},
_smoothnessUniform{4},
_viewportSizeUniform{5};
};
/** @debugoperatorclassenum{MeshVisualizer2D,MeshVisualizer2D::Flag} */
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, MeshVisualizer2D::Flag value);
/** @debugoperatorclassenum{MeshVisualizer3D,MeshVisualizer3D::Flag} */
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, MeshVisualizer3D::Flag value);
/** @debugoperatorclassenum{MeshVisualizer,MeshVisualizer::Flag} */
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, MeshVisualizer::Flag value);
/** @debugoperatorclassenum{MeshVisualizer2D,MeshVisualizer2D::Flags} */
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, MeshVisualizer2D::Flags value);
/** @debugoperatorclassenum{MeshVisualizer,MeshVisualizer::Flags} */
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, MeshVisualizer::Flags value);
/** @debugoperatorclassenum{MeshVisualizer3D,MeshVisualizer3D::Flags} */
MAGNUM_SHADERS_EXPORT Debug& operator<<(Debug& debug, MeshVisualizer3D::Flags value);
CORRADE_ENUMSET_OPERATORS(MeshVisualizer::Flags)
CORRADE_ENUMSET_OPERATORS(MeshVisualizer2D::Flags)
CORRADE_ENUMSET_OPERATORS(MeshVisualizer3D::Flags)
}}

22
src/Magnum/Shaders/MeshVisualizer.vert

@ -31,16 +31,32 @@
#ifdef EXPLICIT_UNIFORM_LOCATION
layout(location = 0)
#endif
#ifdef TWO_DIMENSIONS
uniform highp mat3 transformationProjectionMatrix
#ifndef GL_ES
= mat3(1.0)
#endif
;
#elif defined(THREE_DIMENSIONS)
uniform highp mat4 transformationProjectionMatrix
#ifndef GL_ES
= mat4(1.0)
#endif
;
#else
#error
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = POSITION_ATTRIBUTE_LOCATION)
#endif
#ifdef TWO_DIMENSIONS
in highp vec2 position;
#elif defined(THREE_DIMENSIONS)
in highp vec4 position;
#else
#error
#endif
#if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER)
#if (!defined(GL_ES) && __VERSION__ < 140) || (defined(GL_ES) && __VERSION__ < 300)
@ -55,7 +71,13 @@ out vec3 barycentric;
#endif
void main() {
#ifdef TWO_DIMENSIONS
gl_Position.xywz = vec4(transformationProjectionMatrix*vec3(position, 1.0), 0.0);
#elif defined(THREE_DIMENSIONS)
gl_Position = transformationProjectionMatrix*position;
#else
#error
#endif
#if defined(WIREFRAME_RENDERING) && defined(NO_GEOMETRY_SHADER)
barycentric = vec3(0.0);

11
src/Magnum/Shaders/Shaders.h

@ -31,6 +31,10 @@
#include "Magnum/Types.h"
#ifdef MAGNUM_BUILD_DEPRECATED
#include <Corrade/Utility/Macros.h>
#endif
namespace Magnum { namespace Shaders {
#ifndef DOXYGEN_GENERATING_OUTPUT
@ -48,7 +52,12 @@ typedef Flat<3> Flat3D;
/* Generic is used only statically */
class MeshVisualizer;
class MeshVisualizer2D;
class MeshVisualizer3D;
#ifdef MAGNUM_BUILD_DEPRECATED
typedef CORRADE_DEPRECATED("use MeshVisualizer3D instead") MeshVisualizer3D MeshVisualizer;
#endif
class Phong;
template<UnsignedInt> class Vector;

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

@ -153,10 +153,14 @@ if(BUILD_GL_TESTS)
FILES
FlatTestFiles/defaults.tga
FlatTestFiles/colored3D.tga
MeshVisualizerTestFiles/defaults-wireframe.tga
MeshVisualizerTestFiles/wireframe.tga
MeshVisualizerTestFiles/wireframe-nogeo.tga
MeshVisualizerTestFiles/wireframe-wide.tga)
MeshVisualizerTestFiles/defaults-wireframe2D.tga
MeshVisualizerTestFiles/defaults-wireframe3D.tga
MeshVisualizerTestFiles/wireframe2D.tga
MeshVisualizerTestFiles/wireframe3D.tga
MeshVisualizerTestFiles/wireframe-nogeo2D.tga
MeshVisualizerTestFiles/wireframe-nogeo3D.tga
MeshVisualizerTestFiles/wireframe-wide2D.tga
MeshVisualizerTestFiles/wireframe-wide3D.tga)
target_include_directories(ShadersMeshVisualizerGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>)
if(BUILD_PLUGINS_STATIC)
if(WITH_ANYIMAGEIMPORTER)

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

@ -43,9 +43,11 @@
#include "Magnum/ImageView.h"
#include "Magnum/PixelFormat.h"
#include "Magnum/Math/Color.h"
#include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h"
#include "Magnum/MeshTools/Compile.h"
#include "Magnum/MeshTools/Duplicate.h"
#include "Magnum/MeshTools/GenerateIndices.h"
#include "Magnum/Primitives/Circle.h"
#include "Magnum/Primitives/Icosphere.h"
#include "Magnum/Primitives/UVSphere.h"
@ -60,25 +62,33 @@ namespace Magnum { namespace Shaders { namespace Test { namespace {
struct MeshVisualizerGLTest: GL::OpenGLTester {
explicit MeshVisualizerGLTest();
void construct();
void construct2D();
void construct3D();
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
void constructWireframeGeometryShader();
void constructWireframeGeometryShader2D();
void constructWireframeGeometryShader3D();
#endif
void constructWireframeNoGeometryShader();
void constructMove();
void constructMove2D();
void constructMove3D();
void setWireframeNotEnabled();
void setWireframeNotEnabled2D();
void setWireframeNotEnabled3D();
void renderSetup();
void renderTeardown();
void renderDefaults();
void renderDefaults2D();
void renderDefaults3D();
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
void renderDefaultsWireframe();
void renderDefaultsWireframe2D();
void renderDefaultsWireframe3D();
#endif
void render();
void renderWireframe();
void render2D();
void render3D();
void renderWireframe2D();
void renderWireframe3D();
private:
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"};
@ -106,40 +116,97 @@ using namespace Math::Literals;
constexpr struct {
const char* name;
MeshVisualizer::Flags flags;
MeshVisualizer2D::Flags flags;
} ConstructData2D[] {
{"", {}},
{"wireframe w/o GS", MeshVisualizer2D::Flag::Wireframe|MeshVisualizer2D::Flag::NoGeometryShader},
};
constexpr struct {
const char* name;
MeshVisualizer3D::Flags flags;
} ConstructData3D[] {
{"", {}},
{"wireframe w/o GS", MeshVisualizer3D::Flag::Wireframe|MeshVisualizer3D::Flag::NoGeometryShader}
};
constexpr struct {
const char* name;
MeshVisualizer2D::Flags flags;
Float width, smoothness;
const char* file;
const char* fileXfail;
} WireframeData2D[] {
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
{"", MeshVisualizer2D::Flags{},
1.0f, 2.0f, "wireframe2D.tga", nullptr},
{"wide/sharp", MeshVisualizer2D::Flags{},
3.0f, 1.0f, "wireframe-wide2D.tga", nullptr},
#endif
{"no geometry shader", MeshVisualizer2D::Flag::NoGeometryShader,
1.0f, 2.0f, "wireframe2D.tga", "wireframe-nogeo2D.tga"},
{"no geometry shader, wide/sharp", MeshVisualizer2D::Flag::NoGeometryShader,
3.0f, 1.0f, "wireframe-wide2D.tga", "wireframe-nogeo2D.tga"}
};
constexpr struct {
const char* name;
MeshVisualizer3D::Flags flags;
Float width, smoothness;
const char* file;
const char* fileXfail;
} WireframeData[] {
} WireframeData3D[] {
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
{"", MeshVisualizer::Flags{}, 1.0f, 2.0f, "wireframe.tga", nullptr},
{"wide/sharp", MeshVisualizer::Flags{}, 3.0f, 1.0f, "wireframe-wide.tga", nullptr},
{"", MeshVisualizer3D::Flags{},
1.0f, 2.0f, "wireframe3D.tga", nullptr},
{"wide/sharp", MeshVisualizer3D::Flags{},
3.0f, 1.0f, "wireframe-wide3D.tga", nullptr},
#endif
{"no geometry shader", MeshVisualizer::Flag::NoGeometryShader, 1.0f, 2.0f, "wireframe.tga", "wireframe-nogeo.tga"},
{"no geometry shader, wide/sharp", MeshVisualizer::Flag::NoGeometryShader, 3.0f, 1.0f, "wireframe-wide.tga", "wireframe-nogeo.tga"}
{"no geometry shader",
MeshVisualizer3D::Flag::NoGeometryShader,
1.0f, 2.0f, "wireframe3D.tga", "wireframe-nogeo3D.tga"},
{"no geometry shader, wide/sharp",
MeshVisualizer3D::Flag::NoGeometryShader,
3.0f, 1.0f, "wireframe-wide3D.tga", "wireframe-nogeo3D.tga"}
};
MeshVisualizerGLTest::MeshVisualizerGLTest() {
addTests({&MeshVisualizerGLTest::construct,
addInstancedTests({&MeshVisualizerGLTest::construct2D},
Containers::arraySize(ConstructData2D));
addInstancedTests({&MeshVisualizerGLTest::construct3D},
Containers::arraySize(ConstructData3D));
addTests({
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
&MeshVisualizerGLTest::constructWireframeGeometryShader,
&MeshVisualizerGLTest::constructWireframeGeometryShader2D,
&MeshVisualizerGLTest::constructWireframeGeometryShader3D,
#endif
&MeshVisualizerGLTest::constructWireframeNoGeometryShader,
&MeshVisualizerGLTest::constructMove,
&MeshVisualizerGLTest::constructMove2D,
&MeshVisualizerGLTest::constructMove3D,
&MeshVisualizerGLTest::setWireframeNotEnabled});
&MeshVisualizerGLTest::setWireframeNotEnabled2D,
&MeshVisualizerGLTest::setWireframeNotEnabled3D});
addTests({&MeshVisualizerGLTest::renderDefaults,
addTests({&MeshVisualizerGLTest::renderDefaults2D,
&MeshVisualizerGLTest::renderDefaults3D,
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
&MeshVisualizerGLTest::renderDefaultsWireframe,
&MeshVisualizerGLTest::renderDefaultsWireframe2D,
&MeshVisualizerGLTest::renderDefaultsWireframe3D,
#endif
&MeshVisualizerGLTest::render},
&MeshVisualizerGLTest::render2D,
&MeshVisualizerGLTest::render3D},
&MeshVisualizerGLTest::renderSetup,
&MeshVisualizerGLTest::renderTeardown);
addInstancedTests({&MeshVisualizerGLTest::renderWireframe2D},
Containers::arraySize(WireframeData2D),
&MeshVisualizerGLTest::renderSetup,
&MeshVisualizerGLTest::renderTeardown);
addInstancedTests({&MeshVisualizerGLTest::renderWireframe},
Containers::arraySize(WireframeData),
addInstancedTests({&MeshVisualizerGLTest::renderWireframe3D},
Containers::arraySize(WireframeData3D),
&MeshVisualizerGLTest::renderSetup,
&MeshVisualizerGLTest::renderTeardown);
@ -167,9 +234,29 @@ MeshVisualizerGLTest::MeshVisualizerGLTest() {
}
}
void MeshVisualizerGLTest::construct() {
MeshVisualizer shader;
CORRADE_COMPARE(shader.flags(), MeshVisualizer::Flags{});
void MeshVisualizerGLTest::construct2D() {
auto&& data = ConstructData2D[testCaseInstanceId()];
setTestCaseDescription(data.name);
MeshVisualizer2D shader{data.flags};
CORRADE_COMPARE(shader.flags(), data.flags);
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();
}
void MeshVisualizerGLTest::construct3D() {
auto&& data = ConstructData3D[testCaseInstanceId()];
setTestCaseDescription(data.name);
MeshVisualizer3D shader{data.flags};
CORRADE_COMPARE(shader.flags(), data.flags);
CORRADE_VERIFY(shader.id());
{
#ifdef CORRADE_TARGET_APPLE
@ -182,7 +269,7 @@ void MeshVisualizerGLTest::construct() {
}
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
void MeshVisualizerGLTest::constructWireframeGeometryShader() {
void MeshVisualizerGLTest::constructWireframeGeometryShader2D() {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>())
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported"));
@ -196,8 +283,8 @@ void MeshVisualizerGLTest::constructWireframeGeometryShader() {
Debug() << "Using" << GL::Extensions::NV::shader_noperspective_interpolation::string();
#endif
MeshVisualizer shader{MeshVisualizer::Flag::Wireframe};
CORRADE_COMPARE(shader.flags(), MeshVisualizer::Flag::Wireframe);
MeshVisualizer2D shader{MeshVisualizer2D::Flag::Wireframe};
CORRADE_COMPARE(shader.flags(), MeshVisualizer2D::Flag::Wireframe);
{
#ifdef CORRADE_TARGET_APPLE
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly.");
@ -206,11 +293,23 @@ void MeshVisualizerGLTest::constructWireframeGeometryShader() {
CORRADE_VERIFY(shader.validate().first);
}
}
void MeshVisualizerGLTest::constructWireframeGeometryShader3D() {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>())
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported"));
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>())
CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() + std::string(" is not supported"));
#endif
void MeshVisualizerGLTest::constructWireframeNoGeometryShader() {
MeshVisualizer shader{MeshVisualizer::Flag::Wireframe|MeshVisualizer::Flag::NoGeometryShader};
CORRADE_COMPARE(shader.flags(), MeshVisualizer::Flag::Wireframe|MeshVisualizer::Flag::NoGeometryShader);
#ifdef MAGNUM_TARGET_GLES
if(GL::Context::current().isExtensionSupported<GL::Extensions::NV::shader_noperspective_interpolation>())
Debug() << "Using" << GL::Extensions::NV::shader_noperspective_interpolation::string();
#endif
MeshVisualizer3D shader{MeshVisualizer3D::Flag::Wireframe};
CORRADE_COMPARE(shader.flags(), MeshVisualizer3D::Flag::Wireframe);
{
#ifdef CORRADE_TARGET_APPLE
CORRADE_EXPECT_FAIL("macOS drivers need insane amount of state to validate properly.");
@ -219,31 +318,66 @@ void MeshVisualizerGLTest::constructWireframeNoGeometryShader() {
CORRADE_VERIFY(shader.validate().first);
}
}
#endif
void MeshVisualizerGLTest::constructMove() {
MeshVisualizer a{MeshVisualizer::Flag::Wireframe|MeshVisualizer::Flag::NoGeometryShader};
void MeshVisualizerGLTest::constructMove2D() {
MeshVisualizer2D a{MeshVisualizer2D::Flag::Wireframe|MeshVisualizer2D::Flag::NoGeometryShader};
const GLuint id = a.id();
CORRADE_VERIFY(id);
MAGNUM_VERIFY_NO_GL_ERROR();
MeshVisualizer b{std::move(a)};
MeshVisualizer2D b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), MeshVisualizer::Flag::Wireframe|MeshVisualizer::Flag::NoGeometryShader);
CORRADE_COMPARE(b.flags(), MeshVisualizer2D::Flag::Wireframe|MeshVisualizer2D::Flag::NoGeometryShader);
CORRADE_VERIFY(!a.id());
MeshVisualizer c{NoCreate};
MeshVisualizer2D c{NoCreate};
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), MeshVisualizer::Flag::Wireframe|MeshVisualizer::Flag::NoGeometryShader);
CORRADE_COMPARE(c.flags(), MeshVisualizer2D::Flag::Wireframe|MeshVisualizer2D::Flag::NoGeometryShader);
CORRADE_VERIFY(!b.id());
}
void MeshVisualizerGLTest::setWireframeNotEnabled() {
void MeshVisualizerGLTest::constructMove3D() {
MeshVisualizer3D a{MeshVisualizer3D::Flag::Wireframe|MeshVisualizer3D::Flag::NoGeometryShader};
const GLuint id = a.id();
CORRADE_VERIFY(id);
MAGNUM_VERIFY_NO_GL_ERROR();
MeshVisualizer3D b{std::move(a)};
CORRADE_COMPARE(b.id(), id);
CORRADE_COMPARE(b.flags(), MeshVisualizer3D::Flag::Wireframe|MeshVisualizer3D::Flag::NoGeometryShader);
CORRADE_VERIFY(!a.id());
MeshVisualizer3D c{NoCreate};
c = std::move(b);
CORRADE_COMPARE(c.id(), id);
CORRADE_COMPARE(c.flags(), MeshVisualizer3D::Flag::Wireframe|MeshVisualizer3D::Flag::NoGeometryShader);
CORRADE_VERIFY(!b.id());
}
void MeshVisualizerGLTest::setWireframeNotEnabled2D() {
std::ostringstream out;
Error redirectError{&out};
MeshVisualizer shader;
MeshVisualizer2D shader;
shader.setWireframeColor({})
.setWireframeWidth({})
.setSmoothness({});
CORRADE_COMPARE(out.str(),
"Shaders::MeshVisualizer::setWireframeColor(): the shader was not created with wireframe enabled\n"
"Shaders::MeshVisualizer::setWireframeWidth(): the shader was not created with wireframe enabled\n"
"Shaders::MeshVisualizer::setSmoothness(): the shader was not created with wireframe enabled\n");
}
void MeshVisualizerGLTest::setWireframeNotEnabled3D() {
std::ostringstream out;
Error redirectError{&out};
MeshVisualizer3D shader;
shader.setWireframeColor({})
.setWireframeWidth({})
.setSmoothness({});
@ -281,10 +415,36 @@ void MeshVisualizerGLTest::renderTeardown() {
_color = GL::Renderbuffer{NoCreate};
}
void MeshVisualizerGLTest::renderDefaults() {
void MeshVisualizerGLTest::renderDefaults2D() {
GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32));
MeshVisualizer2D{}
.draw(circle);
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels */
const Float maxThreshold = 238.0f, meanThreshold = 0.298f;
#else
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 238.0f, meanThreshold = 0.298f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Directory::join(_testDir, "FlatTestFiles/defaults.tga"),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void MeshVisualizerGLTest::renderDefaults3D() {
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32));
MeshVisualizer{}
MeshVisualizer3D{}
.draw(sphere);
MAGNUM_VERIFY_NO_GL_ERROR();
@ -308,7 +468,56 @@ void MeshVisualizerGLTest::renderDefaults() {
}
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
void MeshVisualizerGLTest::renderDefaultsWireframe() {
void MeshVisualizerGLTest::renderDefaultsWireframe2D() {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>())
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported"));
#else
if(!GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>())
CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() + std::string(" is not supported"));
#endif
#ifdef MAGNUM_TARGET_GLES
if(GL::Context::current().isExtensionSupported<GL::Extensions::NV::shader_noperspective_interpolation>())
Debug() << "Using" << GL::Extensions::NV::shader_noperspective_interpolation::string();
#endif
GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(16));
MeshVisualizer2D shader{MeshVisualizer2D::Flag::Wireframe};
shader.draw(circle);
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
{
CORRADE_EXPECT_FAIL("Defaults don't work for wireframe as line width is derived from viewport size.");
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, "MeshVisualizerTestFiles/defaults-wireframe2D.tga"),
(DebugTools::CompareImageToFile{_manager}));
}
/** @todo make this unnecessary */
shader
.setViewportSize({80, 80})
.draw(circle);
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, "MeshVisualizerTestFiles/defaults-wireframe2D.tga"),
/* AMD has off-by-one errors on edges compared to Intel */
(DebugTools::CompareImageToFile{_manager, 1.0f, 0.082f}));
}
void MeshVisualizerGLTest::renderDefaultsWireframe3D() {
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>())
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported"));
@ -324,7 +533,7 @@ void MeshVisualizerGLTest::renderDefaultsWireframe() {
GL::Mesh sphere = MeshTools::compile(Primitives::icosphereSolid(1));
MeshVisualizer shader{MeshVisualizer::Flag::Wireframe};
MeshVisualizer3D shader{MeshVisualizer3D::Flag::Wireframe};
shader.draw(sphere);
MAGNUM_VERIFY_NO_GL_ERROR();
@ -338,7 +547,7 @@ void MeshVisualizerGLTest::renderDefaultsWireframe() {
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, "MeshVisualizerTestFiles/defaults-wireframe.tga"),
Utility::Directory::join(_testDir, "MeshVisualizerTestFiles/defaults-wireframe3D.tga"),
(DebugTools::CompareImageToFile{_manager}));
}
@ -352,16 +561,44 @@ void MeshVisualizerGLTest::renderDefaultsWireframe() {
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, "MeshVisualizerTestFiles/defaults-wireframe.tga"),
Utility::Directory::join(_testDir, "MeshVisualizerTestFiles/defaults-wireframe3D.tga"),
/* AMD has off-by-one errors on edges compared to Intel */
(DebugTools::CompareImageToFile{_manager, 1.0f, 0.06f}));
}
#endif
void MeshVisualizerGLTest::render() {
void MeshVisualizerGLTest::render2D() {
GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32));
MeshVisualizer2D{}
.setColor(0x9999ff_rgbf)
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
.draw(circle);
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels */
const Float maxThreshold = 170.0f, meanThreshold = 0.133f;
#else
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 170.0f, meanThreshold = 0.456f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Directory::join(_testDir, "FlatTestFiles/colored2D.tga"),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void MeshVisualizerGLTest::render3D() {
GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32));
MeshVisualizer{}
MeshVisualizer3D{}
.setColor(0x9999ff_rgbf)
.setTransformationProjectionMatrix(
Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)*
@ -390,13 +627,105 @@ void MeshVisualizerGLTest::render() {
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
void MeshVisualizerGLTest::renderWireframe() {
auto&& data = WireframeData[testCaseInstanceId()];
void MeshVisualizerGLTest::renderWireframe2D() {
auto&& data = WireframeData2D[testCaseInstanceId()];
setTestCaseDescription(data.name);
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
#ifndef MAGNUM_TARGET_GLES
if(!(data.flags & MeshVisualizer2D::Flag::NoGeometryShader) && !GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>())
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported"));
#else
if(!(data.flags & MeshVisualizer2D::Flag::NoGeometryShader) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>())
CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() + std::string(" is not supported"));
#endif
#ifdef MAGNUM_TARGET_GLES
if(GL::Context::current().isExtensionSupported<GL::Extensions::NV::shader_noperspective_interpolation>())
Debug() << "Using" << GL::Extensions::NV::shader_noperspective_interpolation::string();
#endif
#endif
const Trade::MeshData circleData = Primitives::circle2DSolid(16);
GL::Mesh circle{NoCreate};
if(data.flags & MeshVisualizer2D::Flag::NoGeometryShader) {
/* Duplicate the vertices. The circle primitive is */
const Trade::MeshData circleDataIndexed =
MeshTools::generateIndices(circleData);
circle = MeshTools::compile(MeshTools::duplicate(circleDataIndexed));
/* Supply also the vertex ID, if needed */
#ifndef MAGNUM_TARGET_GLES2
if(!GL::Context::current().isExtensionSupported<GL::Extensions::MAGNUM::shader_vertex_id>())
#endif
{
Containers::Array<Float> vertexIndex{circleDataIndexed.indexCount()};
std::iota(vertexIndex.begin(), vertexIndex.end(), 0.0f);
GL::Buffer vertexId;
vertexId.setData(vertexIndex);
circle.addVertexBuffer(std::move(vertexId), 0, MeshVisualizer2D::VertexIndex{});
}
} else circle = MeshTools::compile(circleData);
MeshVisualizer2D{data.flags|MeshVisualizer2D::Flag::Wireframe}
.setColor(0xffff99_rgbf)
.setWireframeColor(0x9999ff_rgbf)
.setWireframeWidth(data.width)
.setSmoothness(data.smoothness)
.setViewportSize({80, 80})
.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f}))
.draw(circle);
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
{
CORRADE_EXPECT_FAIL_IF(data.flags & MeshVisualizer2D::Flag::NoGeometryShader,
"Line width is currently not configurable w/o geometry shader.");
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels */
const Float maxThreshold = 170.0f, meanThreshold = 0.327f;
#else
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 170.0f, meanThreshold = 1.699f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Directory::join({_testDir, "MeshVisualizerTestFiles", data.file}),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
/* Test it's not *too* off, at least */
if(data.flags & MeshVisualizer2D::Flag::NoGeometryShader) {
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels. Apple
A8 on more. */
const Float maxThreshold = 170.0f, meanThreshold = 0.330f;
#else
/* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */
const Float maxThreshold = 170.0f, meanThreshold = 2.077f;
#endif
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Directory::join({_testDir, "MeshVisualizerTestFiles", data.fileXfail}),
(DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold}));
}
}
void MeshVisualizerGLTest::renderWireframe3D() {
auto&& data = WireframeData3D[testCaseInstanceId()];
setTestCaseDescription(data.name);
#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL)
#ifndef MAGNUM_TARGET_GLES
if(!(data.flags & MeshVisualizer::Flag::NoGeometryShader) && !GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>())
if(!(data.flags & MeshVisualizer3D::Flag::NoGeometryShader) && !GL::Context::current().isExtensionSupported<GL::Extensions::ARB::geometry_shader4>())
CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported"));
#else
if(!(data.flags & MeshVisualizer::Flag::NoGeometryShader) && !GL::Context::current().isExtensionSupported<GL::Extensions::EXT::geometry_shader>())
@ -412,7 +741,7 @@ void MeshVisualizerGLTest::renderWireframe() {
const Trade::MeshData sphereData = Primitives::icosphereSolid(1);
GL::Mesh sphere{NoCreate};
if(data.flags & MeshVisualizer::Flag::NoGeometryShader) {
if(data.flags & MeshVisualizer3D::Flag::NoGeometryShader) {
/* Duplicate the vertices */
sphere = MeshTools::compile(MeshTools::duplicate(sphereData));
@ -426,11 +755,11 @@ void MeshVisualizerGLTest::renderWireframe() {
GL::Buffer vertexId;
vertexId.setData(vertexIndex);
sphere.addVertexBuffer(std::move(vertexId), 0, MeshVisualizer::VertexIndex{});
sphere.addVertexBuffer(std::move(vertexId), 0, MeshVisualizer3D::VertexIndex{});
}
} else sphere = MeshTools::compile(sphereData);
MeshVisualizer{data.flags|MeshVisualizer::Flag::Wireframe}
MeshVisualizer3D{data.flags|MeshVisualizer3D::Flag::Wireframe}
.setColor(0xffff99_rgbf)
.setWireframeColor(0x9999ff_rgbf)
.setWireframeWidth(data.width)
@ -450,7 +779,7 @@ void MeshVisualizerGLTest::renderWireframe() {
CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found.");
{
CORRADE_EXPECT_FAIL_IF(data.flags & MeshVisualizer::Flag::NoGeometryShader,
CORRADE_EXPECT_FAIL_IF(data.flags & MeshVisualizer3D::Flag::NoGeometryShader,
"Line width is currently not configurable w/o geometry shader.");
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels */
@ -467,7 +796,7 @@ void MeshVisualizerGLTest::renderWireframe() {
}
/* Test it's not *too* off, at least */
if(data.flags & MeshVisualizer::Flag::NoGeometryShader) {
if(data.flags & MeshVisualizer3D::Flag::NoGeometryShader) {
#if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL))
/* SwiftShader has differently rasterized edges on four pixels. Apple
A8 on more. */

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

@ -34,62 +34,111 @@ namespace Magnum { namespace Shaders { namespace Test { namespace {
struct MeshVisualizerTest: TestSuite::Tester {
explicit MeshVisualizerTest();
void constructNoCreate();
void constructCopy();
void constructNoCreate2D();
void constructNoCreate3D();
void constructCopy2D();
void constructCopy3D();
void vertexIndexSameAsObjectId();
void debugFlag();
void debugFlags();
void debugFlag2D();
void debugFlag3D();
void debugFlags2D();
void debugFlags3D();
};
MeshVisualizerTest::MeshVisualizerTest() {
addTests({&MeshVisualizerTest::constructNoCreate,
&MeshVisualizerTest::constructCopy,
addTests({&MeshVisualizerTest::constructNoCreate2D,
&MeshVisualizerTest::constructNoCreate3D,
&MeshVisualizerTest::constructCopy2D,
&MeshVisualizerTest::constructCopy3D,
&MeshVisualizerTest::vertexIndexSameAsObjectId,
&MeshVisualizerTest::debugFlag,
&MeshVisualizerTest::debugFlags});
&MeshVisualizerTest::debugFlag2D,
&MeshVisualizerTest::debugFlag3D,
&MeshVisualizerTest::debugFlags2D,
&MeshVisualizerTest::debugFlags3D});
}
void MeshVisualizerTest::constructNoCreate2D() {
{
MeshVisualizer2D shader{NoCreate};
CORRADE_COMPARE(shader.id(), 0);
}
CORRADE_VERIFY(true);
}
void MeshVisualizerTest::constructNoCreate() {
void MeshVisualizerTest::constructNoCreate3D() {
{
MeshVisualizer shader{NoCreate};
MeshVisualizer3D shader{NoCreate};
CORRADE_COMPARE(shader.id(), 0);
}
CORRADE_VERIFY(true);
}
void MeshVisualizerTest::constructCopy() {
CORRADE_VERIFY(!(std::is_constructible<MeshVisualizer, const MeshVisualizer&>{}));
CORRADE_VERIFY(!(std::is_assignable<MeshVisualizer, const MeshVisualizer&>{}));
void MeshVisualizerTest::constructCopy2D() {
CORRADE_VERIFY((std::is_constructible<MeshVisualizer2D, MeshVisualizer2D&&>{}));
CORRADE_VERIFY(!(std::is_constructible<MeshVisualizer2D, const MeshVisualizer2D&>{}));
CORRADE_VERIFY((std::is_assignable<MeshVisualizer2D, MeshVisualizer2D&&>{}));
CORRADE_VERIFY(!(std::is_assignable<MeshVisualizer2D, const MeshVisualizer2D&>{}));
}
void MeshVisualizerTest::constructCopy3D() {
CORRADE_VERIFY((std::is_constructible<MeshVisualizer3D, MeshVisualizer3D&&>{}));
CORRADE_VERIFY(!(std::is_constructible<MeshVisualizer3D, const MeshVisualizer3D&>{}));
CORRADE_VERIFY((std::is_assignable<MeshVisualizer3D, MeshVisualizer3D&&>{}));
CORRADE_VERIFY(!(std::is_assignable<MeshVisualizer3D, const MeshVisualizer3D&>{}));
}
void MeshVisualizerTest::vertexIndexSameAsObjectId() {
#ifdef MAGNUM_TARGET_GLES2
CORRADE_SKIP("Object ID is not available on ES2.");
#else
CORRADE_COMPARE(MeshVisualizer::VertexIndex::Location, Generic3D::ObjectId::Location);
CORRADE_COMPARE(MeshVisualizer2D::VertexIndex::Location, Generic2D::ObjectId::Location);
CORRADE_COMPARE(MeshVisualizer3D::VertexIndex::Location, Generic3D::ObjectId::Location);
#endif
}
void MeshVisualizerTest::debugFlag() {
void MeshVisualizerTest::debugFlag2D() {
std::ostringstream out;
Debug{&out} << MeshVisualizer2D::Flag::Wireframe << MeshVisualizer2D::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer2D::Flag::Wireframe Shaders::MeshVisualizer2D::Flag(0xf0)\n");
}
void MeshVisualizerTest::debugFlag3D() {
std::ostringstream out;
Debug{&out} << MeshVisualizer3D::Flag::Wireframe << MeshVisualizer3D::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer3D::Flag::Wireframe Shaders::MeshVisualizer3D::Flag(0xf0)\n");
}
void MeshVisualizerTest::debugFlags2D() {
std::ostringstream out;
Debug{&out} << MeshVisualizer::Flag::Wireframe << MeshVisualizer::Flag(0xf0);
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer::Flag::Wireframe Shaders::MeshVisualizer::Flag(0xf0)\n");
Debug{&out} << (MeshVisualizer2D::Flag::Wireframe|MeshVisualizer2D::Flag::NoGeometryShader) << MeshVisualizer2D::Flags{};
#ifndef MAGNUM_TARGET_GLES2
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer2D::Flag::Wireframe|Shaders::MeshVisualizer2D::Flag::NoGeometryShader Shaders::MeshVisualizer2D::Flags{}\n");
#else
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer2D::Flag::Wireframe Shaders::MeshVisualizer2D::Flags{}\n");
#endif
}
void MeshVisualizerTest::debugFlags() {
void MeshVisualizerTest::debugFlags3D() {
std::ostringstream out;
Debug{&out} << (MeshVisualizer::Flag::Wireframe|MeshVisualizer::Flag::NoGeometryShader) << MeshVisualizer::Flags{};
Debug{&out} << (MeshVisualizer3D::Flag::Wireframe|MeshVisualizer3D::Flag::NoGeometryShader) << MeshVisualizer3D::Flags{};
#ifndef MAGNUM_TARGET_GLES2
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer::Flag::Wireframe|Shaders::MeshVisualizer::Flag::NoGeometryShader Shaders::MeshVisualizer::Flags{}\n");
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer3D::Flag::Wireframe|Shaders::MeshVisualizer3D::Flag::NoGeometryShader Shaders::MeshVisualizer3D::Flags{}\n");
#else
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer::Flag::Wireframe Shaders::MeshVisualizer::Flags{}\n");
CORRADE_COMPARE(out.str(), "Shaders::MeshVisualizer3D::Flag::Wireframe Shaders::MeshVisualizer3D::Flags{}\n");
#endif
}

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

Binary file not shown.

0
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/defaults-wireframe.tga → src/Magnum/Shaders/Test/MeshVisualizerTestFiles/defaults-wireframe3D.tga

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

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

Binary file not shown.

0
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-nogeo.tga → src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-nogeo3D.tga

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

BIN
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide2D.tga

Binary file not shown.

0
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide.tga → src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide3D.tga

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

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

Binary file not shown.

0
src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe.tga → src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe3D.tga

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

2
src/Magnum/Shaders/visibility.h

@ -39,8 +39,10 @@
#else
#define MAGNUM_SHADERS_EXPORT CORRADE_VISIBILITY_STATIC
#endif
#define MAGNUM_SHADERS_LOCAL CORRADE_VISIBILITY_LOCAL
#else
#define MAGNUM_SHADERS_EXPORT
#define MAGNUM_SHADERS_LOCAL
#endif
#endif

Loading…
Cancel
Save