From a515bdf29725c8f9466126344a2978bf05cfc861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Tue, 1 Oct 2019 00:20:06 +0200 Subject: [PATCH] Shaders: rendering tests for all remaining builtin shaders. --- src/Magnum/Shaders/Test/CMakeLists.txt | 106 +++++- .../Test/DistanceFieldVectorGLTest.cpp | 348 ++++++++++++++++++ .../Shaders/Test/MeshVisualizerGLTest.cpp | 325 ++++++++++++++++ .../defaults-wireframe.tga | Bin 0 -> 19218 bytes .../wireframe-nogeo.tga | Bin 0 -> 19218 bytes .../wireframe-wide.tga | Bin 0 -> 19218 bytes .../MeshVisualizerTestFiles/wireframe.tga | Bin 0 -> 19218 bytes src/Magnum/Shaders/Test/TestFiles/README.md | 22 ++ .../Test/TestFiles/vector-distancefield.tga | Bin 0 -> 4114 bytes src/Magnum/Shaders/Test/TestFiles/vector.tga | Bin 0 -> 16402 bytes src/Magnum/Shaders/Test/VectorGLTest.cpp | 304 +++++++++++++++ .../defaults-distancefield.tga | Bin 0 -> 19218 bytes .../Shaders/Test/VectorTestFiles/defaults.tga | Bin 0 -> 19218 bytes .../Test/VectorTestFiles/outline2D.tga | Bin 0 -> 19218 bytes .../Test/VectorTestFiles/outline3D.tga | Bin 0 -> 19218 bytes .../Test/VectorTestFiles/smooth0.1-2D.tga | Bin 0 -> 19218 bytes .../Test/VectorTestFiles/smooth0.1-3D.tga | Bin 0 -> 19218 bytes .../Test/VectorTestFiles/smooth0.2-2D.tga | Bin 0 -> 19218 bytes .../Test/VectorTestFiles/smooth0.2-3D.tga | Bin 0 -> 19218 bytes .../Shaders/Test/VectorTestFiles/vector2D.tga | Bin 0 -> 19218 bytes .../Shaders/Test/VectorTestFiles/vector3D.tga | Bin 0 -> 19218 bytes src/Magnum/Shaders/Test/VertexColorGLTest.cpp | 258 +++++++++++++ .../VertexColorTestFiles/vertexColor2D.tga | Bin 0 -> 19218 bytes .../VertexColorTestFiles/vertexColor3D.tga | Bin 0 -> 19218 bytes 24 files changed, 1359 insertions(+), 4 deletions(-) create mode 100644 src/Magnum/Shaders/Test/MeshVisualizerTestFiles/defaults-wireframe.tga create mode 100644 src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-nogeo.tga create mode 100644 src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-wide.tga create mode 100644 src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe.tga create mode 100644 src/Magnum/Shaders/Test/TestFiles/README.md create mode 100644 src/Magnum/Shaders/Test/TestFiles/vector-distancefield.tga create mode 100644 src/Magnum/Shaders/Test/TestFiles/vector.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/defaults-distancefield.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/defaults.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/outline2D.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/outline3D.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/smooth0.1-2D.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/smooth0.1-3D.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/smooth0.2-2D.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/smooth0.2-3D.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/vector2D.tga create mode 100644 src/Magnum/Shaders/Test/VectorTestFiles/vector3D.tga create mode 100644 src/Magnum/Shaders/Test/VertexColorTestFiles/vertexColor2D.tga create mode 100644 src/Magnum/Shaders/Test/VertexColorTestFiles/vertexColor3D.tga diff --git a/src/Magnum/Shaders/Test/CMakeLists.txt b/src/Magnum/Shaders/Test/CMakeLists.txt index 8bcfc27b1..6b3f439a3 100644 --- a/src/Magnum/Shaders/Test/CMakeLists.txt +++ b/src/Magnum/Shaders/Test/CMakeLists.txt @@ -72,7 +72,35 @@ if(BUILD_GL_TESTS) ${CMAKE_CURRENT_BINARY_DIR}/configure.h) endif() - corrade_add_test(ShadersDistanceFieldVectorGLTest DistanceFieldVectorGLTest.cpp LIBRARIES MagnumShaders MagnumOpenGLTester) + corrade_add_test(ShadersDistanceFieldVectorGLTest DistanceFieldVectorGLTest.cpp + LIBRARIES + MagnumDebugTools + MagnumMeshTools + MagnumPrimitives + MagnumShadersTestLib + MagnumOpenGLTester + FILES + TestFiles/vector-distancefield.tga + + VectorTestFiles/defaults.tga + VectorTestFiles/defaults-distancefield.tga + VectorTestFiles/smooth0.1-2D.tga + VectorTestFiles/smooth0.1-3D.tga + VectorTestFiles/smooth0.2-2D.tga + VectorTestFiles/smooth0.2-3D.tga + VectorTestFiles/outline2D.tga + VectorTestFiles/outline3D.tga) + if(NOT BUILD_PLUGINS_STATIC) + target_include_directories(ShadersDistanceFieldVectorGLTest PRIVATE $) + else() + target_include_directories(ShadersDistanceFieldVectorGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + if(WITH_ANYIMAGEIMPORTER) + target_link_libraries(ShadersDistanceFieldVectorGLTest PRIVATE AnyImageImporter) + endif() + if(WITH_TGAIMPORTER) + target_link_libraries(ShadersDistanceFieldVectorGLTest PRIVATE TgaImporter) + endif() + endif() corrade_add_test(ShadersFlatGLTest FlatGLTest.cpp LIBRARIES @@ -109,7 +137,31 @@ if(BUILD_GL_TESTS) endif() endif() - corrade_add_test(ShadersMeshVisualizerGLTest MeshVisualizerGLTest.cpp LIBRARIES MagnumShaders MagnumOpenGLTester) + corrade_add_test(ShadersMeshVisualizerGLTest MeshVisualizerGLTest.cpp + LIBRARIES + MagnumDebugTools + MagnumMeshTools + MagnumPrimitives + MagnumShadersTestLib + MagnumOpenGLTester + FILES + FlatTestFiles/defaults.tga + FlatTestFiles/colored3D.tga + MeshVisualizerTestFiles/defaults-wireframe.tga + MeshVisualizerTestFiles/wireframe.tga + MeshVisualizerTestFiles/wireframe-nogeo.tga + MeshVisualizerTestFiles/wireframe-wide.tga) + if(NOT BUILD_PLUGINS_STATIC) + target_include_directories(ShadersMeshVisualizerGLTest PRIVATE $) + else() + target_include_directories(ShadersMeshVisualizerGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + if(WITH_ANYIMAGEIMPORTER) + target_link_libraries(ShadersMeshVisualizerGLTest PRIVATE AnyImageImporter) + endif() + if(WITH_TGAIMPORTER) + target_link_libraries(ShadersMeshVisualizerGLTest PRIVATE TgaImporter) + endif() + endif() corrade_add_test(ShadersPhongGLTest PhongGLTest.cpp LIBRARIES @@ -158,8 +210,54 @@ if(BUILD_GL_TESTS) endif() endif() - corrade_add_test(ShadersVectorGLTest VectorGLTest.cpp LIBRARIES MagnumShaders MagnumOpenGLTester) - corrade_add_test(ShadersVertexColorGLTest VertexColorGLTest.cpp LIBRARIES MagnumShaders MagnumOpenGLTester) + corrade_add_test(ShadersVectorGLTest VectorGLTest.cpp + LIBRARIES + MagnumDebugTools + MagnumMeshTools + MagnumPrimitives + MagnumShadersTestLib + MagnumOpenGLTester + FILES + TestFiles/vector.tga + + VectorTestFiles/defaults.tga + VectorTestFiles/vector2D.tga + VectorTestFiles/vector3D.tga) + if(NOT BUILD_PLUGINS_STATIC) + target_include_directories(ShadersVectorGLTest PRIVATE $) + else() + target_include_directories(ShadersVectorGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + if(WITH_ANYIMAGEIMPORTER) + target_link_libraries(ShadersVectorGLTest PRIVATE AnyImageImporter) + endif() + if(WITH_TGAIMPORTER) + target_link_libraries(ShadersVectorGLTest PRIVATE TgaImporter) + endif() + endif() + + corrade_add_test(ShadersVertexColorGLTest VertexColorGLTest.cpp + LIBRARIES + MagnumDebugTools + MagnumMeshTools + MagnumPrimitives + MagnumShadersTestLib + MagnumOpenGLTester + FILES + FlatTestFiles/defaults.tga + + VertexColorTestFiles/vertexColor2D.tga + VertexColorTestFiles/vertexColor3D.tga) + if(NOT BUILD_PLUGINS_STATIC) + target_include_directories(ShadersVertexColorGLTest PRIVATE $) + else() + target_include_directories(ShadersVertexColorGLTest PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) + if(WITH_ANYIMAGEIMPORTER) + target_link_libraries(ShadersVertexColorGLTest PRIVATE AnyImageImporter) + endif() + if(WITH_TGAIMPORTER) + target_link_libraries(ShadersVertexColorGLTest PRIVATE TgaImporter) + endif() + endif() set_target_properties( ShadersDistanceFieldVectorGLTest diff --git a/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp b/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp index 7ac598038..9e14eab6d 100644 --- a/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp +++ b/src/Magnum/Shaders/Test/DistanceFieldVectorGLTest.cpp @@ -23,8 +23,32 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include +#include +#include + +#include "Magnum/DebugTools/CompareImage.h" #include "Magnum/GL/OpenGLTester.h" +#include "Magnum/GL/Framebuffer.h" +#include "Magnum/GL/Mesh.h" +#include "Magnum/GL/Renderbuffer.h" +#include "Magnum/GL/RenderbufferFormat.h" +#include "Magnum/GL/Texture.h" +#include "Magnum/GL/TextureFormat.h" +#include "Magnum/Image.h" +#include "Magnum/ImageView.h" +#include "Magnum/PixelFormat.h" +#include "Magnum/MeshTools/Compile.h" +#include "Magnum/Primitives/Plane.h" +#include "Magnum/Primitives/Square.h" #include "Magnum/Shaders/DistanceFieldVector.h" +#include "Magnum/Trade/AbstractImporter.h" +#include "Magnum/Trade/ImageData.h" +#include "Magnum/Trade/MeshData2D.h" +#include "Magnum/Trade/MeshData3D.h" + +#include "configure.h" namespace Magnum { namespace Shaders { namespace Test { namespace { @@ -33,6 +57,46 @@ struct DistanceFieldVectorGLTest: GL::OpenGLTester { template void construct(); template void constructMove(); + + void renderSetup(); + void renderTeardown(); + + void renderDefaults2D(); + void renderDefaults3D(); + void render2D(); + void render3D(); + + private: + PluginManager::Manager _manager{"nonexistent"}; + + GL::Renderbuffer _color{NoCreate}; + #ifndef MAGNUM_TARGET_GLES2 + GL::Renderbuffer _objectId{NoCreate}; + #endif + GL::Framebuffer _framebuffer{NoCreate}; +}; + +/* + Rendering tests done on: + + - Mesa Intel + - Mesa AMD + - SwiftShader ES2/ES3 + - ARM Mali (Huawei P10) ES2/ES3 + - WebGL 1 / 2 (on Mesa Intel) +*/ + +using namespace Math::Literals; + +constexpr struct { + const char* name; + Float outlineRangeStart, outlineRangeEnd, smoothness; + const char* file2D; + const char* file3D; +} RenderData[] { + {"smooth0.1", 0.5f, 1.0f, 0.1f, "smooth0.1-2D.tga", "smooth0.1-3D.tga"}, + {"smooth0.2", 0.5f, 1.0f, 0.2f, "smooth0.2-2D.tga", "smooth0.2-3D.tga"}, + {"outline", 0.6f, 0.45f, 0.05f, "outline2D.tga", "outline3D.tga"} }; DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() { @@ -41,6 +105,26 @@ DistanceFieldVectorGLTest::DistanceFieldVectorGLTest() { &DistanceFieldVectorGLTest::construct<3>, &DistanceFieldVectorGLTest::constructMove<2>, &DistanceFieldVectorGLTest::constructMove<3>}); + + addTests({&DistanceFieldVectorGLTest::renderDefaults2D, + &DistanceFieldVectorGLTest::renderDefaults3D}, + &DistanceFieldVectorGLTest::renderSetup, + &DistanceFieldVectorGLTest::renderTeardown); + + addInstancedTests({&DistanceFieldVectorGLTest::render2D, + &DistanceFieldVectorGLTest::render3D}, + Containers::arraySize(RenderData), + &DistanceFieldVectorGLTest::renderSetup, + &DistanceFieldVectorGLTest::renderTeardown); + + /* 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 + CORRADE_INTERNAL_ASSERT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif + #ifdef TGAIMPORTER_PLUGIN_FILENAME + CORRADE_INTERNAL_ASSERT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif } template void DistanceFieldVectorGLTest::construct() { @@ -77,6 +161,270 @@ template void DistanceFieldVectorGLTest::constructMove() CORRADE_VERIFY(!b.id()); } +constexpr Vector2i RenderSize{80, 80}; + +void DistanceFieldVectorGLTest::renderSetup() { + /* Pick a color that's directly representable on RGBA4 as well to reduce + artifacts */ + GL::Renderer::setClearColor(0x111111_rgbf); + GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); + + _color = GL::Renderbuffer{}; + _color.setStorage( + #if !defined(MAGNUM_TARGET_GLES2) || !defined(MAGNUM_TARGET_WEBGL) + GL::RenderbufferFormat::RGBA8, + #else + GL::RenderbufferFormat::RGBA4, + #endif + RenderSize); + _framebuffer = GL::Framebuffer{{{}, RenderSize}}; + _framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color) + .clear(GL::FramebufferClear::Color) + .bind(); +} + +void DistanceFieldVectorGLTest::renderTeardown() { + _framebuffer = GL::Framebuffer{NoCreate}; + _color = GL::Renderbuffer{NoCreate}; +} + +constexpr GL::TextureFormat TextureFormatR = + #ifndef MAGNUM_TARGET_GLES2 + GL::TextureFormat::R8 + #else + GL::TextureFormat::Luminance + #endif + ; + +void DistanceFieldVectorGLTest::renderDefaults2D() { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + DistanceFieldVector2D shader; + shader.bindVectorTexture(texture); + square.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + /* Should be almost the same as Shaders::Vector output, but due to various + differences in the SDF output and too sharp default shininess it can't + be exact */ + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/defaults.tga"), + (DebugTools::CompareImageToFile{_manager, 189.0f, 6.1f})); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has off-by-one differences on edges, ARM Mali off-by-one in + all channels. */ + const Float maxThreshold = 3.0f, meanThreshold = 0.076f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 17.0f, meanThreshold = 0.480f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/defaults-distancefield.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void DistanceFieldVectorGLTest::renderDefaults3D() { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + DistanceFieldVector2D shader; + shader.bindVectorTexture(texture); + plane.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + /* Should be almost the same as Shaders::Vector output, but due to various + differences in the SDF output and too sharp default shininess it can't + be exact */ + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/defaults.tga"), + (DebugTools::CompareImageToFile{_manager, 189.0f, 6.1f})); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has off-by-one differences on edges, ARM Mali off-by-one in + all channels. */ + const Float maxThreshold = 3.0f, meanThreshold = 0.076f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 17.0f, meanThreshold = 0.480f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/defaults-distancefield.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void DistanceFieldVectorGLTest::render2D() { + auto&& data = RenderData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + DistanceFieldVector2D shader; + shader + /** @todo implement background color */ + .setColor(0xffff99_rgbf) + .setOutlineColor(0x9999ff_rgbf) + .setOutlineRange(data.outlineRangeStart, data.outlineRangeEnd) + .setSmoothness(data.smoothness) + .setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f})) + .bindVectorTexture(texture); + square.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has off-by-one differences when smoothing */ + const Float maxThreshold = 5.667f, meanThreshold = 0.268f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 17.0f, meanThreshold = 2.386f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join({SHADERS_TEST_DIR, "VectorTestFiles", data.file2D}), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void DistanceFieldVectorGLTest::render3D() { + auto&& data = RenderData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector-distancefield.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + DistanceFieldVector3D shader; + shader + /** @todo implement background color */ + .setColor(0xffff99_rgbf) + .setOutlineColor(0x9999ff_rgbf) + .setOutlineRange(data.outlineRangeStart, data.outlineRangeEnd) + .setSmoothness(data.smoothness) + .setTransformationProjectionMatrix( + Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::rotationY(-15.0_degf)* + Matrix4::rotationZ(15.0_degf)) + .bindVectorTexture(texture); + plane.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has off-by-one differences when smoothing plus a bunch of + different pixels on primitive edges */ + const Float maxThreshold = 17.0f, meanThreshold = 0.192f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 17.0f, meanThreshold = 1.613f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join({SHADERS_TEST_DIR, "VectorTestFiles", data.file3D}), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + }}}} CORRADE_TEST_MAIN(Magnum::Shaders::Test::DistanceFieldVectorGLTest) diff --git a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp index 41477c75c..dbea6588f 100644 --- a/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp +++ b/src/Magnum/Shaders/Test/MeshVisualizerGLTest.cpp @@ -23,10 +23,34 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include +#include +#include +#include + +#include "Magnum/DebugTools/CompareImage.h" #include "Magnum/GL/Context.h" #include "Magnum/GL/Extensions.h" #include "Magnum/GL/OpenGLTester.h" +#include "Magnum/GL/Framebuffer.h" +#include "Magnum/GL/Mesh.h" +#include "Magnum/GL/Renderbuffer.h" +#include "Magnum/GL/RenderbufferFormat.h" +#include "Magnum/Image.h" +#include "Magnum/ImageView.h" +#include "Magnum/PixelFormat.h" +#include "Magnum/MeshTools/Compile.h" +#include "Magnum/MeshTools/Duplicate.h" +#include "Magnum/Primitives/Circle.h" +#include "Magnum/Primitives/Icosphere.h" +#include "Magnum/Primitives/UVSphere.h" #include "Magnum/Shaders/MeshVisualizer.h" +#include "Magnum/Trade/AbstractImporter.h" +#include "Magnum/Trade/MeshData2D.h" +#include "Magnum/Trade/MeshData3D.h" + +#include "configure.h" namespace Magnum { namespace Shaders { namespace Test { namespace { @@ -40,6 +64,52 @@ struct MeshVisualizerGLTest: GL::OpenGLTester { void constructWireframeNoGeometryShader(); void constructMove(); + + void renderSetup(); + void renderTeardown(); + + void renderDefaults(); + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + void renderDefaultsWireframe(); + #endif + void render(); + void renderWireframe(); + + private: + PluginManager::Manager _manager{"nonexistent"}; + + GL::Renderbuffer _color{NoCreate}; + #ifndef MAGNUM_TARGET_GLES2 + GL::Renderbuffer _objectId{NoCreate}; + #endif + GL::Framebuffer _framebuffer{NoCreate}; +}; + +/* + Rendering tests done on: + + - Mesa Intel + - Mesa AMD + - SwiftShader ES2/ES3 + - ARM Mali (Huawei P10) ES2/ES3 + - WebGL 1 / 2 (on Mesa Intel) +*/ + +using namespace Math::Literals; + +constexpr struct { + const char* name; + MeshVisualizer::Flags flags; + Float width, smoothness; + const char* file; + const char* fileXfail; +} WireframeData[] { + #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}, + #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"} }; MeshVisualizerGLTest::MeshVisualizerGLTest() { @@ -50,6 +120,28 @@ MeshVisualizerGLTest::MeshVisualizerGLTest() { &MeshVisualizerGLTest::constructWireframeNoGeometryShader, &MeshVisualizerGLTest::constructMove}); + + addTests({&MeshVisualizerGLTest::renderDefaults, + #if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) + &MeshVisualizerGLTest::renderDefaultsWireframe, + #endif + &MeshVisualizerGLTest::render}, + &MeshVisualizerGLTest::renderSetup, + &MeshVisualizerGLTest::renderTeardown); + + addInstancedTests({&MeshVisualizerGLTest::renderWireframe}, + Containers::arraySize(WireframeData), + &MeshVisualizerGLTest::renderSetup, + &MeshVisualizerGLTest::renderTeardown); + + /* 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 + CORRADE_INTERNAL_ASSERT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif + #ifdef TGAIMPORTER_PLUGIN_FILENAME + CORRADE_INTERNAL_ASSERT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif } void MeshVisualizerGLTest::construct() { @@ -124,6 +216,239 @@ void MeshVisualizerGLTest::constructMove() { CORRADE_VERIFY(!b.id()); } +constexpr Vector2i RenderSize{80, 80}; + +void MeshVisualizerGLTest::renderSetup() { + /* Pick a color that's directly representable on RGBA4 as well to reduce + artifacts */ + GL::Renderer::setClearColor(0x111111_rgbf); + GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); + + _color = GL::Renderbuffer{}; + _color.setStorage( + #if !defined(MAGNUM_TARGET_GLES2) || !defined(MAGNUM_TARGET_WEBGL) + GL::RenderbufferFormat::RGBA8, + #else + GL::RenderbufferFormat::RGBA4, + #endif + RenderSize); + _framebuffer = GL::Framebuffer{{{}, RenderSize}}; + _framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color) + .clear(GL::FramebufferClear::Color) + .bind(); +} + +void MeshVisualizerGLTest::renderTeardown() { + _framebuffer = GL::Framebuffer{NoCreate}; + _color = GL::Renderbuffer{NoCreate}; +} + +void MeshVisualizerGLTest::renderDefaults() { + GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32)); + + MeshVisualizer shader; + sphere.draw(shader); + + 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(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "FlatTestFiles/defaults.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +#if !defined(MAGNUM_TARGET_GLES2) && !defined(MAGNUM_TARGET_WEBGL) +void MeshVisualizerGLTest::renderDefaultsWireframe() { + #ifndef MAGNUM_TARGET_GLES + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported")); + #else + if(!GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() + std::string(" is not supported")); + #endif + + #ifdef MAGNUM_TARGET_GLES + if(GL::Context::current().isExtensionSupported()) + Debug() << "Using" << GL::Extensions::NV::shader_noperspective_interpolation::string(); + #endif + + GL::Mesh sphere = MeshTools::compile(Primitives::icosphereSolid(1)); + + MeshVisualizer shader{MeshVisualizer::Flag::Wireframe}; + sphere.draw(shader); + + 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(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "MeshVisualizerTestFiles/defaults-wireframe.tga"), + (DebugTools::CompareImageToFile{_manager})); + } + + /** @todo make this unnecessary */ + shader.setViewportSize({80, 80}); + sphere.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "MeshVisualizerTestFiles/defaults-wireframe.tga"), + /* AMD has off-by-one errors on edges compared to Intel */ + (DebugTools::CompareImageToFile{_manager, 1.0f, 0.06f})); +} +#endif + +void MeshVisualizerGLTest::render() { + GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32)); + + MeshVisualizer shader; + shader.setColor(0x9999ff_rgbf) + .setTransformationProjectionMatrix( + Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::rotationY(-15.0_degf)* + Matrix4::rotationX(15.0_degf)); + sphere.draw(shader); + + 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(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "FlatTestFiles/colored3D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void MeshVisualizerGLTest::renderWireframe() { + auto&& data = WireframeData[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()) + CORRADE_SKIP(GL::Extensions::ARB::geometry_shader4::string() + std::string(" is not supported")); + #else + if(!(data.flags & MeshVisualizer::Flag::NoGeometryShader) && !GL::Context::current().isExtensionSupported()) + CORRADE_SKIP(GL::Extensions::EXT::geometry_shader::string() + std::string(" is not supported")); + #endif + + #ifdef MAGNUM_TARGET_GLES + if(GL::Context::current().isExtensionSupported()) + Debug() << "Using" << GL::Extensions::NV::shader_noperspective_interpolation::string(); + #endif + #endif + + const Trade::MeshData3D sphereData = Primitives::icosphereSolid(1); + + GL::Mesh sphere{NoCreate}; + if(data.flags & MeshVisualizer::Flag::NoGeometryShader) { + sphere = GL::Mesh{}; + sphere.setCount(sphereData.indices().size()); + + /* Duplicate the vertices */ + GL::Buffer positions; + positions.setData(MeshTools::duplicate(Containers::stridedArrayView(sphereData.indices()), Containers::stridedArrayView(sphereData.positions(0)))); + sphere.addVertexBuffer(std::move(positions), 0, MeshVisualizer::Position{}); + + /* Supply also the vertex ID, if needed */ + #ifndef MAGNUM_TARGET_GLES2 + if(!GL::Context::current().isExtensionSupported()) + #endif + { + Containers::Array vertexIndex{sphereData.indices().size()}; + std::iota(vertexIndex.begin(), vertexIndex.end(), 0.0f); + + GL::Buffer vertexId; + vertexId.setData(vertexIndex); + sphere.addVertexBuffer(std::move(vertexId), 0, MeshVisualizer::VertexIndex{}); + } + } else sphere = MeshTools::compile(sphereData); + + MeshVisualizer shader{data.flags|MeshVisualizer::Flag::Wireframe}; + shader.setColor(0xffff99_rgbf) + .setWireframeColor(0x9999ff_rgbf) + .setWireframeWidth(data.width) + .setSmoothness(data.smoothness) + .setViewportSize({80, 80}) + .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)); + sphere.draw(shader); + + 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 & MeshVisualizer::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(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join({SHADERS_TEST_DIR, "MeshVisualizerTestFiles", data.file}), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); + } + + /* Test it's not *too* off, at least */ + if(data.flags & MeshVisualizer::Flag::NoGeometryShader) { + #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(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join({SHADERS_TEST_DIR, "MeshVisualizerTestFiles", data.fileXfail}), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); + } +} + }}}} CORRADE_TEST_MAIN(Magnum::Shaders::Test::MeshVisualizerGLTest) diff --git a/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/defaults-wireframe.tga b/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/defaults-wireframe.tga new file mode 100644 index 0000000000000000000000000000000000000000..7a61e17e877dbf974d4207b0fdac09fd6149333c GIT binary patch literal 19218 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 literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-nogeo.tga b/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe-nogeo.tga new file mode 100644 index 0000000000000000000000000000000000000000..d04880f8422ca0d85883b76fdcd4600a90502262 GIT binary patch literal 19218 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 literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe.tga b/src/Magnum/Shaders/Test/MeshVisualizerTestFiles/wireframe.tga new file mode 100644 index 0000000000000000000000000000000000000000..9d972407210bd6d2177b77a62911f45ee5044b04 GIT binary patch literal 19218 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 literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/TestFiles/vector.tga b/src/Magnum/Shaders/Test/TestFiles/vector.tga new file mode 100644 index 0000000000000000000000000000000000000000..5b41170158e768b84ed21f77277763d88aa52344 GIT binary patch literal 16402 zcmeI2e`uCf6vwYCW6shx6Sh_)GnERmf^0Hd4vTcGtZbIlko8YQWHKmo3$@4=gn}5^ zVzIWRgV|U=Xh;&02E~Nz4{e2WNz#-w$D3MWue&|Z^FHT3_uO;$vX^s*|J>)FbM8H7 z-_N<{xzCUHVM1Ib;MgQKiF_D%>pS2(;5*>U^#`g&JOOYe_o?cuRz-CTd^&z~xSZ9M(HhQ5nq;mEub{-?76 z9^32ce;_3LgaiKhXAF8Yto+6fG-mny)FK-`n0xe?!Lkk6{Pe?P;DwmlnjxMUv5_-# zZ2lW#;)B4de?rPKQMTf(uZFEfaQOq*WaEnkC#BpMXB01M+)YjimtUI|FT|{)a-p6w ztzu2f0qyc+@(1&Daqw?_;_WB(G@|}JQkSxdWNbzmEdHNF zd}@4JfiYT0Qu-hkSr-2&5nqhNr5qv|BDf=K2a7*I)L+n~L$`-yl;8{&|7W7U1*^*@ zl2MH_So{&9-iy^`HOXkg87#h3FP(tdi`8Wb1eEQ;89e?HB^x{6V)c_|T!hHnoeP&z~j^Yd+f7pEc*@4wJ6Mhv=kUYM8(Eu3N-wGovM1x!YuyF^TiSK`9gx~3w zFS`xGc3ppjz5yN9N*DxcVoyPBiDmMmhi~+~C6SE1-3d4LN=XiT{WYPq_Qcl+jfDS*76q5N z{?ZWgI*1{=l<+s8cxJ%kpN<%H7G0UXp76~dXW^gm_R_#Z8=}ly|4Y2KL-(LSWSnvfsLunJ%lfhqy`uKK<&b3^*3lZ)2-F6jf5R~j`*R}v6fnMKW6GEZV$uu!y!Ka zT?=gY>wp=bP6`)^XRk znwmqB?|;^Qn?c|I9QM|DQghsYSNi`C&HdoVz5~7kz5~7kz5~7kz5~7kz5~7k4m$8Z DPrwLm literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorGLTest.cpp b/src/Magnum/Shaders/Test/VectorGLTest.cpp index 880f1edb9..df9cb3c0a 100644 --- a/src/Magnum/Shaders/Test/VectorGLTest.cpp +++ b/src/Magnum/Shaders/Test/VectorGLTest.cpp @@ -23,8 +23,32 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include +#include +#include + +#include "Magnum/DebugTools/CompareImage.h" +#include "Magnum/GL/Framebuffer.h" +#include "Magnum/GL/Mesh.h" #include "Magnum/GL/OpenGLTester.h" +#include "Magnum/GL/Renderbuffer.h" +#include "Magnum/GL/RenderbufferFormat.h" +#include "Magnum/GL/Texture.h" +#include "Magnum/GL/TextureFormat.h" +#include "Magnum/Image.h" +#include "Magnum/ImageView.h" +#include "Magnum/PixelFormat.h" +#include "Magnum/MeshTools/Compile.h" +#include "Magnum/Primitives/Plane.h" +#include "Magnum/Primitives/Square.h" #include "Magnum/Shaders/Vector.h" +#include "Magnum/Trade/AbstractImporter.h" +#include "Magnum/Trade/ImageData.h" +#include "Magnum/Trade/MeshData2D.h" +#include "Magnum/Trade/MeshData3D.h" + +#include "configure.h" namespace Magnum { namespace Shaders { namespace Test { namespace { @@ -33,14 +57,59 @@ struct VectorGLTest: GL::OpenGLTester { template void construct(); template void constructMove(); + + void renderSetup(); + void renderTeardown(); + + void renderDefaults2D(); + void renderDefaults3D(); + void render2D(); + void render3D(); + + private: + PluginManager::Manager _manager{"nonexistent"}; + + GL::Renderbuffer _color{NoCreate}; + #ifndef MAGNUM_TARGET_GLES2 + GL::Renderbuffer _objectId{NoCreate}; + #endif + GL::Framebuffer _framebuffer{NoCreate}; }; +/* + Rendering tests done on: + + - Mesa Intel + - Mesa AMD + - SwiftShader ES2/ES3 + - ARM Mali (Huawei P10) ES2/ES3 + - WebGL 1 / 2 (on Mesa Intel) +*/ + +using namespace Math::Literals; + VectorGLTest::VectorGLTest() { addTests({ &VectorGLTest::construct<2>, &VectorGLTest::construct<3>, &VectorGLTest::constructMove<2>, &VectorGLTest::constructMove<3>}); + + addTests({&VectorGLTest::renderDefaults2D, + &VectorGLTest::renderDefaults3D, + &VectorGLTest::render2D, + &VectorGLTest::render3D}, + &VectorGLTest::renderSetup, + &VectorGLTest::renderTeardown); + + /* 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 + CORRADE_INTERNAL_ASSERT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif + #ifdef TGAIMPORTER_PLUGIN_FILENAME + CORRADE_INTERNAL_ASSERT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif } template void VectorGLTest::construct() { @@ -77,6 +146,241 @@ template void VectorGLTest::constructMove() { CORRADE_VERIFY(!b.id()); } +constexpr Vector2i RenderSize{80, 80}; + +void VectorGLTest::renderSetup() { + /* Pick a color that's directly representable on RGBA4 as well to reduce + artifacts */ + GL::Renderer::setClearColor(0x111111_rgbf); + GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); + + _color = GL::Renderbuffer{}; + _color.setStorage( + #if !defined(MAGNUM_TARGET_GLES2) || !defined(MAGNUM_TARGET_WEBGL) + GL::RenderbufferFormat::RGBA8, + #else + GL::RenderbufferFormat::RGBA4, + #endif + RenderSize); + _framebuffer = GL::Framebuffer{{{}, RenderSize}}; + _framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color) + .clear(GL::FramebufferClear::Color) + .bind(); +} + +void VectorGLTest::renderTeardown() { + _framebuffer = GL::Framebuffer{NoCreate}; + _color = GL::Renderbuffer{NoCreate}; +} + +constexpr GL::TextureFormat TextureFormatR = + #ifndef MAGNUM_TARGET_GLES2 + GL::TextureFormat::R8 + #else + GL::TextureFormat::Luminance + #endif + ; + +void VectorGLTest::renderDefaults2D() { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + Vector2D shader; + shader.bindVectorTexture(texture); + square.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has off-by-one differences on edges, ARM Mali a bit more of + them */ + const Float maxThreshold = 1.0f, meanThreshold = 0.022f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 17.0f, meanThreshold = 0.359f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/defaults.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void VectorGLTest::renderDefaults3D() { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + Vector3D shader; + shader.bindVectorTexture(texture); + plane.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has off-by-one differences on edges, ARM Mali a bit more of + them */ + const Float maxThreshold = 1.0f, meanThreshold = 0.022f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 17.0f, meanThreshold = 0.359f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/defaults.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void VectorGLTest::render2D() { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh square = MeshTools::compile(Primitives::squareSolid(Primitives::SquareTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + Vector2D shader; + shader + .setBackgroundColor(0x9999ff_rgbf) + .setColor(0xffff99_rgbf) + .setTransformationProjectionMatrix( + Matrix3::projection({2.1f, 2.1f})* + Matrix3::rotation(5.0_degf)) + .bindVectorTexture(texture); + square.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has differently rasterized edges on four pixels */ + const Float maxThreshold = 170.0f, meanThreshold = 0.146f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 170.0f, meanThreshold = 0.962f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/vector2D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +void VectorGLTest::render3D() { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + GL::Mesh plane = MeshTools::compile(Primitives::planeSolid(Primitives::PlaneTextureCoords::Generate)); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + GL::Texture2D texture; + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(SHADERS_TEST_DIR, "TestFiles/vector.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge); + + #ifdef MAGNUM_TARGET_GLES2 + /* Don't want to bother with the fiasco of single-channel formats and + texture storage extensions on ES2 */ + texture.setImage(0, TextureFormatR, *image); + #else + texture.setStorage(1, TextureFormatR, image->size()) + .setSubImage(0, {}, *image); + #endif + + Vector3D shader; + shader + .setBackgroundColor(0x9999ff_rgbf) + .setColor(0xffff99_rgbf) + .setTransformationProjectionMatrix( + Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::rotationY(-15.0_degf)* + Matrix4::rotationZ(15.0_degf)) + .bindVectorTexture(texture); + plane.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has differently rasterized edges on four pixels */ + const Float maxThreshold = 170.0f, meanThreshold = 0.171f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 170.0f, meanThreshold = 0.660f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VectorTestFiles/vector3D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + }}}} CORRADE_TEST_MAIN(Magnum::Shaders::Test::VectorGLTest) diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/defaults-distancefield.tga b/src/Magnum/Shaders/Test/VectorTestFiles/defaults-distancefield.tga new file mode 100644 index 0000000000000000000000000000000000000000..f6b0079699b1576066a8bfe06f8ec6c395f68d8e GIT binary patch literal 19218 zcmeI2IY=cz5Qd-68w3%&5EHMBL=X`~BLfiw@dYBH7zlzUvYDB&Ch5kQc_rq(De{m`&fTl^!oamnwlD#BWy)vv7Nl{@9&N`Y!ub?Tzoa@{qXS6(9j?q z$Oi`pk%5}FU%h2EpRca2Iy*ayi;LBn63NWWY;A45zP|n{nzX(_Uce%z8d82MJ3D(| zVBqNJNJ7Yir3`jQ|iTyxQ8@T4Q4) z*LdWdoE&tP`ucj$GS3L_#l?lkJn3aD7CSjPL878SSY2IhZf=&=)F`W~t1(betc~y@ z=`L15nkT)Jm!f@bVdZ!1520aztUD*iDdr%S*Rg| z#PcFKfx~U{%jkWo0S7h*&SL2D7_>Pi$wqi#kDrliwzs#*Lcb8mJ2W)pZzVK#@?t_! z84P`CX(@M(UmhD9Q#H4cSD(x`H#dPB_PMz^t9bSO7wM|97Wyz_`_9ge>IsRDF9sq+ z(4T~)si>$>SsR8Ig9C;{)e{oW3rjE@5uIPasT!;6dU{|yPK?R^<>h6L=9h7t&g)Y{5=`YY8GydLwY8O%mE|{H zXn=qb43pH%%*^=sxT>1aqb5CBDj4S#R-K-nB6gLPm3o}OyZX5s@3MqfP-AMwMjit! zc6@bpb%D!lKmNkPf;6n8w2GIk62ig30k(Ag{r#AOGzm}C_;BFgGJBqBGcPw4Gf`h( zAE8MFZ0&)=TlwXGg%_3w@|KmAS<5>yF@an~#`;5`(lj+SNyAD?9Pp~zlHN#sY0J>n z)kT&B3K+o%O)9{Ffe$gli|xEHxS*gwv$p5PW7~^Q3{p%|TFcA#IAM$gI6j;amr58J z8R0IH%0}WF2XA+Gw+d6}u~v}+dXz?ZYier9czg-ih~^NOg?f&(F`W8PnGM{Jdt5OyKw`s$t}}63>gb@9pgYSsG=5fO!i4 zXi~X_FiB8-P2i+LHo}WnBX;7GUt3!nnH`@nJ3H&=QfW-_a(nQ}erai`y}cbPsK7-9 z_X#p&czBpUDp0n8mm7(76ozZewwQoae+)y9E-ET&X=%Y`nYRri+s4anM$ThHfg=lE z#3y^);x)s|HuHw32w&6j@&O@k85tPf=ZUQOzr`0FUo{NI9b7aFJO@r>O!>R+@9*O{ z_6&4|IOoS{A@awPg2)0Ee@_ZDKE4W=C6PH+mA?_$_?+WfIS)7wI1e}vI1e}vI1e}v MI1e}v{Ocb01rmL782|tP literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/defaults.tga b/src/Magnum/Shaders/Test/VectorTestFiles/defaults.tga new file mode 100644 index 0000000000000000000000000000000000000000..56317d3312bc6fbe45f4ed7f952a03d01843c8c1 GIT binary patch literal 19218 zcmeI2Z782#7{@)%!<1(cDHD>2#wbxrnbr_Ri6T+k3-)4~nmjZ{B&EgP?8Qo6c!e~I zXkK`xhUCRcEZNXBPh-RX|E;^7?#_MA`Q7_(yYJt>o!^_^b*|qz=XZUs^K_l-zHMym zY<_%lY;tV;e-z}m^nmn$^nmn$^nmn$^nmn$^nmn$^nmn$ZVx0TCO)ys4-C@{@e>uR ztE>O9$`1_t2@Ks;C9jo?wj5vGb5>OGKg{R7y}jAl+0oI_si~guZKZ``<% zpP#RWWy;v`fZy2IsGjzw@IHF$UqFE1w+YK6+mN>Y<4goK1_Zf>fFm2_e}@5hfHailWsB+8kY8DgPUNJ>f~HJQT0 zhYz)_6pit`%gf75BZ<=6+gmwtm^Nec!Kp+lGljvyL1tShjps#p%rufHu_^Jag??^s zj?`odm^{q2uk>j=@4~_Y(@vtq@)YoPb#;-NOd&Wp`0((M*MsrAySuyM_51AEGoH23 z7ZnvTF^TfdojYH@e&zLGJTIcYu&^*ma>>N(4B0157r#`9t?DlIM5ViFAkLf+_n z`SK++G?dh23J9lp&7n7*7k`TV1i>EDS}1*eebo_y+W1eOK3TkFjE#+{n^3YTys!b6 zK?FZMJv}|Vlhn@6uD-q=E1eo0_(9AY6%|D_ zp^7H*!jkdvalv{-TBE9}3O73ve#FPei+Qm#P=Hj?TwWN18+uz?8?FEj4h}pPPfyRx z%*^)oc1%}Z9Yz209`xIFgu_GV{i`}_L~_H%{Z$HxctsUE1JmGcs7 zG2!psyQdvfwFVh2L1d+LWfreGr$nH{0x~>mI<5Tp@ndlh_|+8NgM)*hpdbXglarGc zEmSIC;7GnsOR8wZk(JVqDZI!bD;8E%ROsYIhM9+{=yB&_CUB_!P2sJpt5b}`BLm7F zUJ*OCm^U&qlGj$PH=Y+WGb<}gF&~I zJQ*oIFE20g_}0|a@S3aj#`CK4vA7q!c=5vGA%ZYl5N#@cc>Vgdnu{kJ&%3p?rH&jB zK;l`_yLaz+)W~V1rKO1n7r$DJtP~Fz&)eVMuQeXKYePc=uJhDGE*#THCTr_c8l9UJ zkd5bUX=&kI3Xs`IPfy2IJUl#%$RDXlJb7_+bfoC0BBna>0K5rI>5b=w0UH||wY9Yg z2?-XHGZY%Lh&WS!v}Ovg;&Wt8v6fp~TM=t9LG&n*&_J|C4WgiEA}_HDYj$yQv7@5{ z_g~~RuxaZd#imzSSco@yNI!Z6Yv85qeEiPh#RmeO@8bc} z-Me>}mX@f7dWu%aOUy<*jJK6=RN-+UZWh?Vkjui0A9xPVJG@9+o?y+qJez+-FM0Ls z6&CBjjlVJqf3B?@UyEa>r^4ShzJJ^M{CehqtRp=jJs>?GJs>?GJs>?GJs>?GJs>^s H|MkGXWgkOP literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/outline2D.tga b/src/Magnum/Shaders/Test/VectorTestFiles/outline2D.tga new file mode 100644 index 0000000000000000000000000000000000000000..9ac9ac87535fefb4f312bc8968af05c7463cfdde GIT binary patch literal 19218 zcmeI22~ZVB8pja?1d>HqF$f~XAp)Wp4|G=rZ%TGmlrpHRiCUH*8riLwRil+`Jc7H1 z0ueRdqOP}i-^6&|_kG_d-imnR{-BG_)XW=#snU7%_Py$Q@0)(zGvB|z{>~m78(W*= zPpnO>ji-&9_49wQ0>v`7-`^)+CwqH$7Z)>W<(-`!%9bsqczy@o+EuDd`TXXqIdezTuPth;#e;k81ILMKcGy^Bz9jcI+6N?bXz&dYXP`@nQyS zIdNikUS4USnH*ydcoE#?HEUi@nNk@o-(IqW#&jMvOrX@w~KiIXSQ`I{EI|u%T*-y!_P1N62?^V&aa00~vg2?b=<34jCd} z%qFH49<~e^P~OQ&GN~kd+}vh#@6H%(+RAI!gn?zDuyPn-`tPKscC1rJIYrVAc6R@a zj((Pz$uQAy+yrUNH3TnSQt&*gLkFpSl3PJE@b|x4=kf$pHn59PH_- znk6nhU0rt%9?TffVV`M8mMD(c##p=?@m{I;$%2y9>IeYtz_;^4)%gS1P<%$w7mpE4bBC~eXsZ><+ z^n6+rf)aWu=NgU|k7?5HA~?hcD10=^uHdY5TEl+h8d_GqZsye4vlC=Vi75O0j=SGb1(up)MR#!)jV$98D%NTDaco*EiFU%~4v~QCp z+8Sx2z`!RN8L*w3osH{6QtXOlH*a!D=a~5TvUYZ=RT7s3lMJ9?oaI6Z)CS5I2GB&2 zADtdHY)DLuO3GfYu0O=a78G%gSGvDo0sJ4`zFin+40{=!6eGHNb-*%(kX0#MXk+nW zhz{-AC5-LE^z`vvx-NdAVkN$Uu z4tgmSz{!XikFnZ*^r-Uwf;JW}{sj{)s_Rr*$X_NE6u=nY)ELR#@VtnLumLkJ(_Wm^ zUu)J>%2Y|?+Q7?TJeRrQ1y0`V*+P7X5@^~J1l9zhFS&giV|(`JpBelpJzXzy{-cY_ zoFZdIB$=I?YgTxv6{D^2FRJShU?)G-GAVj6Ym^xohC1t|fs_b#4I0E4mQHJ|xQ~JR znR=Z#s-uX}zgaVwB=ysJObH)(iB$d6_uo^PRqkO)=3FUrwhVBys}=0 z#fUPLj)oLs)!aLAp$R@S2JhxGGTrJTeV`vWl2fk#S62~ zl^jZ%%)M|AWM;O}H&z2$wPFmnRh2~KO^m{e6(Sghx4euDj1T^FYSC)|s4&h5t|W(o zz&mrMR=6N3DdCkXtHdfUi9oV?^kB@rg$uE7sym2Fqwval&a^MSsOjxZ_SYvWN~8t^ z8)ST&Po5<06`4MZL-Hsx3&v|RDSHVu?}+bF!~qe%9Nb%BhO>r|=2hV-vcfxG}SOSODm zax$n9H(}(FZ@(o+&;u)kOGe51pbM&+h6D>?6kePoB@3aFFiFGkapx+nBaUNAu@8`H{URkZGU0?`Vxd|pnT=BV}V(7WKE=j zA5j8ls}m}7)I}nk+OZ>Npr8})IZ#e-9TqmTM-L40gS0dOmV|fF-MjM6CJ6)OtKvrh zCr%(p#?_JxDzSq|^%4su4mw3+p{NV}CRm8jGmm;=4~%P(7nhHBAid)^faoh#lBB7{VwJCUO)RO$Dql;IrWT7;zS=dhq#mVwt+b`C G!2bXMGX>cI literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/outline3D.tga b/src/Magnum/Shaders/Test/VectorTestFiles/outline3D.tga new file mode 100644 index 0000000000000000000000000000000000000000..0570265287f313b3dbfcdb12d3abd2212c0cc702 GIT binary patch literal 19218 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 TuAUR%&U^c_a9X4ODinVJK?2o1 literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.1-2D.tga b/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.1-2D.tga new file mode 100644 index 0000000000000000000000000000000000000000..ffea067545a617a2742179e388870c0c0952d82b GIT binary patch literal 19218 zcmeI22TT-c7={56DGCUv2nrS~D58iBL6qEisMx#Si3PD>SG@D!^i=E>MG%c8mc){1 zRATQ+)F{?y)YyCPz2QALx0A{23}G>523+!o{b!k3zV~~-{;!3Fm4)G_wMAv&lsd&*OU^~s3Gi3Yr z*!}zUum*42)^7TAXAh4bffqGGD`1mezfR4})O^kV^l8S!htX@+6f0l;$Ki!mkS_T8 zRS#?Kt5;^cYFwM@zk)sIkY9{#+TFWj&YUq`6RupD_wF4xe7}Y0fnR`3zkh$!ks~b= z5~{aqWxPWB^&7f#XIw@G3Q76+@q18fju)`w&Yy1Byt(Wg$$e)cTakTu6U>Dsj>qehjkQNzL2)v7=NHCH0FaRb@2L3DJ~ z%9WFE-b{Y~o;B(E_3;-jOuTw^=A%dR-o9mJZvfijo%8Y~*{Wj0hIWpQYDmTR(T0tk zor{-OwdTz`Cnb$NcW%Pv%UzR`e;G0ajdh+oH*)b}7G{qQr{2Cj`{`4#&;R^cnjJL6 zizUY$JJw?CShuoeEi5fXT(S*850e&GVK+BtPtWqf!CmIfi#>24plw^n5+ztvO&(RN zdiweOI(#^v*=F+OZi^NT+OlQv)~(|%To7GAL%g#dKZXu`HXAc8XlLgY7>MTv_v*!B zgE4?tuQUFR|WI)vHI09!-pzeB%a-&G0>YT2Go(zJ7ft4-b}gp+e&QvJEbeCJWfu06BW~ zYHjhNYQi#j?VO!ua*CHFDphJZems7fV#vHag=LbU`)}Al8SGNJw0N^@L!Tn>i{)1h z4<}0C$V7Fm_$9O=vv1?ZR@T-sQH9Hbwzg$z*Y3V#2@=Y(548s@2X*i6RI;SvvsiU; zAD>182H?NKnttz|@F7~^C2`=qL>NVZd6NJY)T0MQh%~wiGQ;w)UAu7PLJkg!k7MM1 zO`FDS+&K63YiJdi)dSwFXruB&%Z9~LP|3*UGUdaEftxq`G-#k^8{j2P<1Y)0`V?*X zRl`fDAyRc)xR4lbjF-gPbJ;RFYi?82mW_i$!~XrLLyVu*7O$E;Lmc#Bw2D0f&PaMC zB`JdCO==PJ6`Vty+}I#$tq;)U`|*W$Q^6ZQU z4@Mn6+;jPI8Y0>s+Q1^ki{r(N0w9`RiRzJt$kX57#oJrWc?s-1OU*2;Aq8fI-#Wo7 z2tyx)drrJ^g%L5uRm7MvFphT@uTX(-O-t+K?hf@*o0nNN!K!g=>^~~mB zL{K3!k77uL!*T+G4R@G1leta3Zrv!!AW;TWyu<(^7cC;bi614~=o7CfBs9@UQ7O^( z60gXrp?&*e=ORGahS3l$q&U41KS$hXi{coXik|aXLmg>&X*EnBtp=`q!aD0d3l-&G*1dn~zS!M~pWb;-v&?J#iu)$267U z3@O-HJn1_mtd6s1Q-R2QR=h0i>Z)hFQ*Pa&&;=~T0|y6LNz*Wwlfo4DOxGDnWfQE5 z`S_5#`B?E0i!7E(Awrhazy_Lg!g-D4*lKroZf1}uNl1-}N!l*;rA9GcMi4&AYX z)C_RS%YN(E*Xq#XUtbsg`2}dOEN(ydrR6tFkY#gbf@>^5Rbv zA=xKf@sov(-tbDr13U4DX%BUX>`O`<*)#a!PtyByvez@-oXBtLJ!ZVJXfM6Y_4n(t zZv;%`=zH!b3I4$EPjbu`62btARu@Ckd;yk%vr}RsrJ9sSwY{nQQV~%*acqrBb+Q0U zmClG;4WsmZQ}OaFGbJhqrl~qvFq=cL2%ihQQg!9Iy%}$wqs%0M&HS3At~__MncqA| hnMneh`87#hdG2O2zj=-_lLY>m`ITZf@AH!e{sR-cY)SwC literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.1-3D.tga b/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.1-3D.tga new file mode 100644 index 0000000000000000000000000000000000000000..76327db1ea1cbcac7de5022277f499df73375f55 GIT binary patch literal 19218 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 literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.2-2D.tga b/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.2-2D.tga new file mode 100644 index 0000000000000000000000000000000000000000..4605cc55942e1d79b57ea7581ceb32b228ff2e7f GIT binary patch literal 19218 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 literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.2-3D.tga b/src/Magnum/Shaders/Test/VectorTestFiles/smooth0.2-3D.tga new file mode 100644 index 0000000000000000000000000000000000000000..3ed7debb5397bdef2cbb28620c69e93d814e058a GIT binary patch literal 19218 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 V^{@H#dapyx6|OhKDi_32?_a+}ZzTW# literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VectorTestFiles/vector3D.tga b/src/Magnum/Shaders/Test/VectorTestFiles/vector3D.tga new file mode 100644 index 0000000000000000000000000000000000000000..f8f07efbebbf05faff9b99ff67e2df9315120605 GIT binary patch literal 19218 zcmeHNX;W1>5T)iH%(wYj{yk(-WY}>-YBBmY1K8kI!~>9p1U4N6t$dB`6G(aaSHaQV2#>b^H5| zR#y5aC;xu-Y`?Bf8K@AIpc8E>V*zTEl-=O>uU{XouJ(NRFxA($-PELvn@SZW$PM(! zts5IU9qjJvlauDHE&Qun`dZL`u(pPLIR5ge`u z?!NHk3GjzpqW!f82lqdJ?wXw)8yrk^_C+~z0}fcon=LINkjiGnLPf?7IokUNCME=) zP?OV%%Ap|We>FPl!^4x^Xl+%zoNBta7wOt}xA)9+cSlEY22qY=pa;b2^5MOI@j~|^ z?No2C?{4hD+CHtSqENa(bfSVDr}FGfz^nQ8O?MI6(O0ir1gr`XN^jy27on79lqMM{ zL9j!8NH|9nm(Ta_qtZsLMU}=`WhFAa+XBc2C`66K|9bmY8AzyzPE-(%yovNH_+mdQ z1v8Q=*@F}cY!?kV9JLljKE8FUZ)!?EyfDz0d-upCDnx0Lff5RJ5#e_Nj?0ie-W`N7 znmC(66*cze(9qEBqa)u7Jvhxn110to9bHKDrOsQ&#{vvWBhqpK554O2R2aKv@ANdc z6f#(U=;^t0cqn}T{P_(S>(nkI!{>@@I`n z;0C(P8R@bTXJTN$=ZkEU=n|?fut}Bu&Ox6^Pq0z}!yEqz(%$hE#N^?(`yAOZNv zfD8VDbT0oqeag**j5jYh;{6e+7@2`a3GEu;?wXvAE+@KEXNUsM6tZzb;>rhj9Wp|YxOuB0GIJN#1aLm#3NNdsdpP1Le(aoyN-=(IU`->UP8t? z#OasK%9N#GYvoHBf^BEgC~uF3v>B|ge9 z5s;b~T5%LAPDhu8qiAB$5`d6^4bEQ)K^eCe&Ny0Q-}~|<6c*=#0HZW@j$Eq*fhq(> z^kdrs9^cM8jg45SxU5j(^P@)u#4b3ftyO%5iZjw>;mDh~RuwSNL~h~r05`yW?CQgZ zJc1%)a`@51<3Psir{XJAIzgcozP!nA*9i}{)kS$Z${y+wLd)i+IAu#d-*a4;AEs1XO?)q z!|h+ZfA0sR9xMQEEMz1}vWyCxPE=N+;Z{(dLaJVQ?fC*KU zBR3Gfyy@Sr;{yR1An_7BU%)*oS^5HQJVFJP3x(?f-z(I^=|tsF5cK=E>!O;aL)Pc3 ze=oo*t?xoTxF~ZeLczvWQI2H5y?mJfaDm?gqpV82w8T94(WnROJh8^6QSPpJx~q9ra=flyCMiNSG`EP{xpat-JQv~VOF z-<|j9TZ}-$3>Q}1QIRd5kJ}d)l?XybTr7g{6;0e2Cl*)4lnX|X_$1X%`6OBTe9VeMx4 z%8%7($!sCYMf%7~Pub2Tl_lyfyz5yqn;=f#OfAC^iwuG#eg+#{!{Qy;lGz+_`$ygk z9DSDzj4Uqh+ioYLJ0ZzAjOO z#W2X1f<0O>xTK0{hnkCJDs06w&V`F5Nbx9Sh-?8|h)o7arEw{Ql;T?&@R>(ZkY`h6 zMp9zOZ0vlm62mTVI3Itio&ra|ME6uQ$@mfh=Q1=AF$%d1dKH3L_+AB^`C`ynryA>D DEoXwP literal 0 HcmV?d00001 diff --git a/src/Magnum/Shaders/Test/VertexColorGLTest.cpp b/src/Magnum/Shaders/Test/VertexColorGLTest.cpp index 55709e03d..9e0f3182c 100644 --- a/src/Magnum/Shaders/Test/VertexColorGLTest.cpp +++ b/src/Magnum/Shaders/Test/VertexColorGLTest.cpp @@ -23,8 +23,28 @@ DEALINGS IN THE SOFTWARE. */ +#include +#include +#include + +#include "Magnum/DebugTools/CompareImage.h" #include "Magnum/GL/OpenGLTester.h" +#include "Magnum/GL/Framebuffer.h" +#include "Magnum/GL/Mesh.h" +#include "Magnum/GL/Renderbuffer.h" +#include "Magnum/GL/RenderbufferFormat.h" +#include "Magnum/Image.h" +#include "Magnum/ImageView.h" +#include "Magnum/PixelFormat.h" +#include "Magnum/MeshTools/Compile.h" +#include "Magnum/Primitives/Circle.h" +#include "Magnum/Primitives/UVSphere.h" #include "Magnum/Shaders/VertexColor.h" +#include "Magnum/Trade/AbstractImporter.h" +#include "Magnum/Trade/MeshData2D.h" +#include "Magnum/Trade/MeshData3D.h" + +#include "configure.h" namespace Magnum { namespace Shaders { namespace Test { namespace { @@ -33,14 +53,65 @@ struct VertexColorGLTest: GL::OpenGLTester { template void construct(); template void constructMove(); + + void renderSetup(); + void renderTeardown(); + + template void renderDefaults2D(); + template void renderDefaults3D(); + + template void render2D(); + template void render3D(); + + private: + PluginManager::Manager _manager{"nonexistent"}; + + GL::Renderbuffer _color{NoCreate}; + #ifndef MAGNUM_TARGET_GLES2 + GL::Renderbuffer _objectId{NoCreate}; + #endif + GL::Framebuffer _framebuffer{NoCreate}; }; +/* + Rendering tests done on: + + - Mesa Intel + - Mesa AMD + - SwiftShader ES2/ES3 + - ARM Mali (Huawei P10) ES2/ES3 + - WebGL 1 / 2 (on Mesa Intel) +*/ + +using namespace Math::Literals; + VertexColorGLTest::VertexColorGLTest() { addTests({ &VertexColorGLTest::construct<2>, &VertexColorGLTest::construct<3>, &VertexColorGLTest::constructMove<2>, &VertexColorGLTest::constructMove<3>}); + + addTests({&VertexColorGLTest::renderDefaults2D, + &VertexColorGLTest::renderDefaults2D, + &VertexColorGLTest::renderDefaults3D, + &VertexColorGLTest::renderDefaults3D, + + &VertexColorGLTest::render2D, + &VertexColorGLTest::render2D, + &VertexColorGLTest::render3D, + &VertexColorGLTest::render3D}, + &VertexColorGLTest::renderSetup, + &VertexColorGLTest::renderTeardown); + + /* 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 + CORRADE_INTERNAL_ASSERT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif + #ifdef TGAIMPORTER_PLUGIN_FILENAME + CORRADE_INTERNAL_ASSERT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); + #endif } template void VertexColorGLTest::construct() { @@ -77,6 +148,193 @@ template void VertexColorGLTest::constructMove() { CORRADE_VERIFY(!b.id()); } +constexpr Vector2i RenderSize{80, 80}; + +void VertexColorGLTest::renderSetup() { + /* Pick a color that's directly representable on RGBA4 as well to reduce + artifacts */ + GL::Renderer::setClearColor(0x111111_rgbf); + GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); + + _color = GL::Renderbuffer{}; + _color.setStorage( + #if !defined(MAGNUM_TARGET_GLES2) || !defined(MAGNUM_TARGET_WEBGL) + GL::RenderbufferFormat::RGBA8, + #else + GL::RenderbufferFormat::RGBA4, + #endif + RenderSize); + _framebuffer = GL::Framebuffer{{{}, RenderSize}}; + _framebuffer.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color) + .clear(GL::FramebufferClear::Color) + .bind(); +} + +void VertexColorGLTest::renderTeardown() { + _framebuffer = GL::Framebuffer{NoCreate}; + _color = GL::Renderbuffer{NoCreate}; +} + +template void VertexColorGLTest::renderDefaults2D() { + setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4"); + + Trade::MeshData2D circleData = Primitives::circle2DSolid(32, + Primitives::CircleTextureCoords::Generate); + + /* All a single color */ + Containers::Array colorData{Containers::DirectInit, circleData.positions(0).size(), 0xffffff_rgbf}; + + GL::Buffer colors; + colors.setData(colorData); + GL::Mesh circle = MeshTools::compile(circleData); + circle.addVertexBuffer(colors, 0, GL::Attribute{}); + + VertexColor2D shader; + circle.draw(shader); + + 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 eight 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(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "FlatTestFiles/defaults.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +template void VertexColorGLTest::renderDefaults3D() { + setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4"); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + Trade::MeshData3D sphereData = Primitives::uvSphereSolid(16, 32, + Primitives::UVSphereTextureCoords::Generate); + + /* All a single color */ + Containers::Array colorData{Containers::DirectInit, sphereData.positions(0).size(), 0xffffff_rgbf}; + + GL::Buffer colors; + colors.setData(colorData); + GL::Mesh sphere = MeshTools::compile(sphereData); + sphere.addVertexBuffer(colors, 0, GL::Attribute{}); + + VertexColor3D shader; + sphere.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* SwiftShader has differently rasterized edges on eight 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(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "FlatTestFiles/defaults.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +template void VertexColorGLTest::render2D() { + setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4"); + + Trade::MeshData2D circleData = Primitives::circle2DSolid(32, + Primitives::CircleTextureCoords::Generate); + + /* Highlight a quarter */ + Containers::Array colorData{Containers::DirectInit, circleData.positions(0).size(), 0x9999ff_rgbf}; + for(std::size_t i = 8; i != 16; ++i) + colorData[i + 1] = 0xffff99_rgbf; + + GL::Buffer colors; + colors.setData(colorData); + GL::Mesh circle = MeshTools::compile(circleData); + circle.addVertexBuffer(colors, 0, GL::Attribute{}); + + VertexColor2D shader; + shader.setTransformationProjectionMatrix(Matrix3::projection({2.1f, 2.1f})); + circle.draw(shader); + + 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)) + /* AMD has minor rounding differences in the gradient compared to Intel, + SwiftShader as well */ + const Float maxThreshold = 1.0f, meanThreshold = 0.667f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 11.34f, meanThreshold = 1.479f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VertexColorTestFiles/vertexColor2D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + +template void VertexColorGLTest::render3D() { + setTestCaseTemplateName(T::Size == 3 ? "Color3" : "Color4"); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImageImporter plugins not found."); + + Trade::MeshData3D sphereData = Primitives::uvSphereSolid(16, 32, + Primitives::UVSphereTextureCoords::Generate); + + /* Highlight the middle rings */ + Containers::Array colorData{Containers::DirectInit, sphereData.positions(0).size(), 0x9999ff_rgbf}; + for(std::size_t i = 6*33; i != 9*33; ++i) + colorData[i + 1] = 0xffff99_rgbf; + + GL::Buffer colors; + colors.setData(colorData); + GL::Mesh sphere = MeshTools::compile(sphereData); + sphere.addVertexBuffer(colors, 0, GL::Attribute{}); + + VertexColor3D shader; + 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)); + sphere.draw(shader); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) + /* AMD has one different pixel compared to Intel, SwiftShader has + differently rasterized edges on five pixels */ + const Float maxThreshold = 204.0f, meanThreshold = 0.158f; + #else + /* WebGL 1 doesn't have 8bit renderbuffer storage, so it's way worse */ + const Float maxThreshold = 204.0f, meanThreshold = 1.284f; + #endif + CORRADE_COMPARE_WITH( + /* Dropping the alpha channel, as it's always 1.0 */ + Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Utility::Directory::join(SHADERS_TEST_DIR, "VertexColorTestFiles/vertexColor3D.tga"), + (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); +} + }}}} CORRADE_TEST_MAIN(Magnum::Shaders::Test::VertexColorGLTest) diff --git a/src/Magnum/Shaders/Test/VertexColorTestFiles/vertexColor2D.tga b/src/Magnum/Shaders/Test/VertexColorTestFiles/vertexColor2D.tga new file mode 100644 index 0000000000000000000000000000000000000000..c6beb73c68c3b21020030b3d004cd195b4b1d6a9 GIT binary patch literal 19218 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 AzW@LL literal 0 HcmV?d00001