diff --git a/src/Magnum/Shaders/Test/CMakeLists.txt b/src/Magnum/Shaders/Test/CMakeLists.txt index da3ceb234..277a3da9f 100644 --- a/src/Magnum/Shaders/Test/CMakeLists.txt +++ b/src/Magnum/Shaders/Test/CMakeLists.txt @@ -152,6 +152,8 @@ if(BUILD_GL_TESTS) FlatTestFiles/defaults.tga FlatTestFiles/instanced2D.tga FlatTestFiles/instanced3D.tga + FlatTestFiles/instanced-textured2D.tga + FlatTestFiles/instanced-textured3D.tga FlatTestFiles/textured2D.tga FlatTestFiles/textured3D.tga FlatTestFiles/textured2D-alpha.tga diff --git a/src/Magnum/Shaders/Test/FlatGLTest.cpp b/src/Magnum/Shaders/Test/FlatGLTest.cpp index 5b68c7978..5a50d4e87 100644 --- a/src/Magnum/Shaders/Test/FlatGLTest.cpp +++ b/src/Magnum/Shaders/Test/FlatGLTest.cpp @@ -166,21 +166,21 @@ struct FlatGLTest: GL::OpenGLTester { Mesa Intel BADIOM ES2 xx - ES3 BADIOx - Mesa AMD BADI - Mesa llvmpipe BADI - SwiftShader ES2 BADIxx - ES3 BADI + ES3 BAD Ox + Mesa AMD BAD + Mesa llvmpipe BAD + SwiftShader ES2 BAD xx + ES3 BAD ANGLE ES2 xx - ES3 BADIOM + ES3 BAD OM ARM Mali (Huawei P10) ES2 BAD xx - ES3 BADIOx + ES3 BAD Ox WebGL (on Mesa Intel) 1.0 BAD xx - 2.0 BADIOM + 2.0 BAD OM NVidia BAD Intel Windows BAD AMD macOS BAD - Intel macOS BADIOx + Intel macOS BAD Ox iPhone 6 w/ iOS 12.4 ES3 BAD x */ @@ -274,6 +274,23 @@ const struct { FlatGL2D::Flag::Textured|FlatGL2D::Flag::AlphaMask, 1.0f} }; +constexpr struct { + const char* name; + const char* expected2D; + const char* expected3D; + FlatGL2D::Flags flags; + Float maxThreshold, meanThreshold; +} RenderInstancedData[] { + {"colored", "instanced2D.tga", "instanced3D.tga", + {}, + /* Minor differences on SwiftShader */ + 164.4f, 0.094f}, + {"textured", "instanced-textured2D.tga", "instanced-textured3D.tga", + FlatGL2D::Flag::InstancedTextureOffset|FlatGL2D::Flag::Textured, + /* Minor differences on SwiftShader */ + 192.67f, 0.140f}, +}; + #ifndef MAGNUM_TARGET_GLES2 constexpr struct { const char* name; @@ -462,7 +479,7 @@ FlatGLTest::FlatGLTest() { #endif /* MSVC needs explicit type due to default template args */ - addTests({ + addInstancedTests({ &FlatGLTest::renderInstanced2D, #ifndef MAGNUM_TARGET_GLES2 &FlatGLTest::renderInstanced2D, @@ -472,6 +489,7 @@ FlatGLTest::FlatGLTest() { &FlatGLTest::renderInstanced3D #endif }, + Containers::arraySize(RenderInstancedData), #ifndef MAGNUM_TARGET_GLES2 &FlatGLTest::renderObjectIdSetup, &FlatGLTest::renderObjectIdTeardown @@ -2090,6 +2108,9 @@ template void FlatGLTest::renderObjectId3D() { #endif template void FlatGLTest::renderInstanced2D() { + auto&& data = RenderInstancedData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + #ifndef MAGNUM_TARGET_GLES2 if(flag == FlatGL2D::Flag::UniformBuffers) { setTestCaseTemplateName("Flag::UniformBuffers"); @@ -2116,10 +2137,6 @@ template void FlatGLTest::renderInstanced2D() { #endif #endif - if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || - !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) - CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); - GL::Mesh circle = MeshTools::compile(Primitives::circle2DSolid(32, Primitives::Circle2DFlag::TextureCoordinates)); @@ -2130,11 +2147,14 @@ template void FlatGLTest::renderInstanced2D() { Vector2 textureOffset; UnsignedInt objectId; } instanceData[] { - {Matrix3::translation({-1.25f, -1.25f}), 0xff3333_rgbf, + {Matrix3::translation({-1.25f, -1.25f}), + data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf, {0.0f, 0.0f}, 211}, - {Matrix3::translation({ 1.25f, -1.25f}), 0x33ff33_rgbf, + {Matrix3::translation({ 1.25f, -1.25f}), + data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0x00ffff_rgbf, {1.0f, 0.0f}, 4627}, - {Matrix3::translation({ 0.00f, 1.25f}), 0x9999ff_rgbf, + {Matrix3::translation({ 0.00f, 1.25f}), + data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xff00ff_rgbf, {0.5f, 1.0f}, 35363}, }; @@ -2151,22 +2171,9 @@ template void FlatGLTest::renderInstanced2D() { ) .setInstanceCount(3); - Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); - CORRADE_VERIFY(importer); - - GL::Texture2D texture; - Containers::Optional image; - CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); - texture.setMinificationFilter(GL::SamplerFilter::Linear) - .setMagnificationFilter(GL::SamplerFilter::Linear) - .setWrapping(GL::SamplerWrapping::ClampToEdge) - .setStorage(1, TextureFormatRGB, image->size()) - .setSubImage(0, {}, *image); - /* Enable also Object ID, if supported */ - FlatGL2D::Flags flags = FlatGL2D::Flag::Textured| - FlatGL2D::Flag::VertexColor|FlatGL2D::Flag::InstancedTransformation| - FlatGL2D::Flag::InstancedTextureOffset|flag; + FlatGL2D::Flags flags = FlatGL2D::Flag::VertexColor| + FlatGL2D::Flag::InstancedTransformation|data.flags|flag; #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES if(GL::Context::current().isExtensionSupported()) @@ -2176,14 +2183,36 @@ template void FlatGLTest::renderInstanced2D() { } #endif FlatGL2D shader{flags}; - shader.bindTexture(texture); + + GL::Texture2D texture; + if(data.flags & FlatGL3D::Flag::Textured) { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + + shader.bindTexture(texture); + } if(flag == FlatGL2D::Flag{}) { - shader.setColor(0xffff99_rgbf) + shader + .setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) .setTransformationProjectionMatrix( Matrix3::projection({2.1f, 2.1f})* - Matrix3::scaling(Vector2{0.4f})) - .setTextureMatrix(Matrix3::scaling(Vector2{0.5f})); + Matrix3::scaling(Vector2{0.4f})); + + if(data.flags & FlatGL3D::Flag::Textured) + shader.setTextureMatrix(Matrix3::scaling(Vector2{0.5f})); #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES @@ -2215,11 +2244,12 @@ template void FlatGLTest::renderInstanced2D() { }}; GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { FlatMaterialUniform{} - .setColor(0xffff99_rgbf) + .setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) }}; + if(data.flags & FlatGL3D::Flag::Textured) + shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) - .bindTextureTransformationBuffer(textureTransformationUniform) .bindMaterialBuffer(materialUniform) .draw(circle); } @@ -2228,18 +2258,29 @@ template void FlatGLTest::renderInstanced2D() { MAGNUM_VERIFY_NO_GL_ERROR(); - #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) - /* Minor differences on AMD, SwiftShader a bit more */ - const Float maxThreshold = 3.0f, meanThreshold = 0.018f; - #else - /* WebGL 1 doesn't have 8bit renderbuffer storage */ - const Float maxThreshold = 3.0f, meanThreshold = 0.018f; - #endif + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); + + /* + Colored case: + + - First should be lower left, yellow with a yellow base color, so + yellow + - Second lower right, cyan with a yellow base color, so green + - Third up center, magenta with a yellow base color, so red + + Textured case: + + - Lower left has bottom left numbers, so light 7881 + - Lower light has bottom right, 1223 + - Up center has 6778 + */ 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(_testDir, "FlatTestFiles/instanced2D.tga"), - (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); + Utility::Directory::join({_testDir, "FlatTestFiles", data.expected2D}), + (DebugTools::CompareImageToFile{_manager, data.maxThreshold, data.meanThreshold})); #ifndef MAGNUM_TARGET_GLES2 /* Object ID -- no need to verify the whole image, just check that pixels @@ -2263,6 +2304,9 @@ template void FlatGLTest::renderInstanced2D() { } template void FlatGLTest::renderInstanced3D() { + auto&& data = RenderInstancedData[testCaseInstanceId()]; + setTestCaseDescription(data.name); + #ifndef MAGNUM_TARGET_GLES2 if(flag == FlatGL2D::Flag::UniformBuffers) { setTestCaseTemplateName("Flag::UniformBuffers"); @@ -2289,10 +2333,6 @@ template void FlatGLTest::renderInstanced3D() { #endif #endif - if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || - !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) - CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); - GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32, Primitives::UVSphereFlag::TextureCoordinates)); @@ -2303,11 +2343,17 @@ template void FlatGLTest::renderInstanced3D() { Vector2 textureOffset; UnsignedInt objectId; } instanceData[] { - {Matrix4::translation({-1.25f, -1.25f, 0.0f}), 0xff3333_rgbf, + {Matrix4::translation({-1.25f, -1.25f, 0.0f})* + /* To be consistent with Phong's output where it tests that the + normal matrix is applied properly */ + Matrix4::rotationX(90.0_degf), + data.flags & FlatGL3D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf, {0.0f, 0.0f}, 211}, - {Matrix4::translation({ 1.25f, -1.25f, 0.0f}), 0x33ff33_rgbf, + {Matrix4::translation({ 1.25f, -1.25f, 0.0f}), + data.flags & FlatGL3D::Flag::Textured ? 0xffffff_rgbf : 0x00ffff_rgbf, {1.0f, 0.0f}, 4627}, - {Matrix4::translation({ 0.0f, 1.0f, 1.0f}), 0x9999ff_rgbf, + {Matrix4::translation({ 0.0f, 1.0f, 1.0f}), + data.flags & FlatGL3D::Flag::Textured ? 0xffffff_rgbf : 0xff00ff_rgbf, {0.5f, 1.0f}, 35363} }; @@ -2324,22 +2370,9 @@ template void FlatGLTest::renderInstanced3D() { ) .setInstanceCount(3); - Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); - CORRADE_VERIFY(importer); - - GL::Texture2D texture; - Containers::Optional image; - CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); - texture.setMinificationFilter(GL::SamplerFilter::Linear) - .setMagnificationFilter(GL::SamplerFilter::Linear) - .setWrapping(GL::SamplerWrapping::ClampToEdge) - .setStorage(1, TextureFormatRGB, image->size()) - .setSubImage(0, {}, *image); - /* Enable also Object ID, if supported */ - FlatGL3D::Flags flags = FlatGL3D::Flag::Textured| - FlatGL3D::Flag::VertexColor|FlatGL3D::Flag::InstancedTransformation| - FlatGL3D::Flag::InstancedTextureOffset|flag; + FlatGL3D::Flags flags = FlatGL3D::Flag::VertexColor| + FlatGL3D::Flag::InstancedTransformation|data.flags|flag; #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES if(GL::Context::current().isExtensionSupported()) @@ -2349,15 +2382,37 @@ template void FlatGLTest::renderInstanced3D() { } #endif FlatGL3D shader{flags}; - shader.bindTexture(texture); + + GL::Texture2D texture; + if(data.flags & FlatGL2D::Flag::Textured) { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + texture.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + + shader.bindTexture(texture); + } if(flag == FlatGL3D::Flag{}) { - shader.setColor(0xffff99_rgbf) + shader + .setColor(data.flags & FlatGL2D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) .setTransformationProjectionMatrix( Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)* Matrix4::translation(Vector3::zAxis(-2.15f))* - Matrix4::scaling(Vector3{0.4f})) - .setTextureMatrix(Matrix3::scaling(Vector2{0.5f})); + Matrix4::scaling(Vector3{0.4f})); + + if(data.flags & FlatGL3D::Flag::Textured) + shader.setTextureMatrix(Matrix3::scaling(Vector2{0.5f})); #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES @@ -2390,11 +2445,12 @@ template void FlatGLTest::renderInstanced3D() { }}; GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { FlatMaterialUniform{} - .setColor(0xffff99_rgbf) + .setColor(data.flags & FlatGL3D::Flag::Textured ? 0xffffff_rgbf : 0xffff00_rgbf) }}; + if(data.flags & FlatGL3D::Flag::Textured) + shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindTransformationProjectionBuffer(transformationProjectionUniform) .bindDrawBuffer(drawUniform) - .bindTextureTransformationBuffer(textureTransformationUniform) .bindMaterialBuffer(materialUniform) .draw(sphere); } @@ -2403,18 +2459,30 @@ template void FlatGLTest::renderInstanced3D() { MAGNUM_VERIFY_NO_GL_ERROR(); - #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) - /* Minor differences on AMD, SwiftShader a bit more */ - const Float maxThreshold = 67.67f, meanThreshold = 0.062f; - #else - /* WebGL 1 doesn't have 8bit renderbuffer storage */ - const Float maxThreshold = 67.67f, meanThreshold = 0.062f; - #endif + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); + + /* + Colored case: + + - First should be lower left, yellow with a yellow base color, so + yellow + - Second lower right, cyan with a yellow base color, so green + - Third up center, magenta with a yellow base color, so red + + Textured case: + + - Lower left has bottom left numbers, so light 7881, rotated (78 + visible) + - Lower light has bottom right, 1223 + - Up center has 6778 + */ 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(_testDir, "FlatTestFiles/instanced3D.tga"), - (DebugTools::CompareImageToFile{_manager, maxThreshold, meanThreshold})); + Utility::Directory::join({_testDir, "FlatTestFiles", data.expected3D}), + (DebugTools::CompareImageToFile{_manager, data.maxThreshold, data.meanThreshold})); #ifndef MAGNUM_TARGET_GLES2 /* Object ID -- no need to verify the whole image, just check that pixels diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/instanced-textured2D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/instanced-textured2D.tga new file mode 100644 index 000000000..01359db39 Binary files /dev/null and b/src/Magnum/Shaders/Test/FlatTestFiles/instanced-textured2D.tga differ diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/instanced-textured3D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/instanced-textured3D.tga new file mode 100644 index 000000000..9ec1a93c8 Binary files /dev/null and b/src/Magnum/Shaders/Test/FlatTestFiles/instanced-textured3D.tga differ diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga index a130de40e..11dec3675 100644 Binary files a/src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga and b/src/Magnum/Shaders/Test/FlatTestFiles/instanced2D.tga differ diff --git a/src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga b/src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga index c1c4d9640..0aa0bb4d5 100644 Binary files a/src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga and b/src/Magnum/Shaders/Test/FlatTestFiles/instanced3D.tga differ diff --git a/src/Magnum/Shaders/Test/PhongGLTest.cpp b/src/Magnum/Shaders/Test/PhongGLTest.cpp index 100e2a576..b4389bbc4 100644 --- a/src/Magnum/Shaders/Test/PhongGLTest.cpp +++ b/src/Magnum/Shaders/Test/PhongGLTest.cpp @@ -49,6 +49,7 @@ #include "Magnum/GL/TextureFormat.h" #include "Magnum/Math/Color.h" #include "Magnum/Math/Matrix4.h" +#include "Magnum/Math/Swizzle.h" #include "Magnum/MeshTools/Compile.h" #include "Magnum/MeshTools/Transform.h" #include "Magnum/Primitives/Plane.h" @@ -173,21 +174,21 @@ struct PhongGLTest: GL::OpenGLTester { Mesa Intel BADLIOM ES2 xx - ES3 BADLIOx - Mesa AMD BAD I - Mesa llvmpipe BAD I - SwiftShader ES2 BADLIxx - ES3 BADLI + ES3 BADL Ox + Mesa AMD BAD + Mesa llvmpipe BAD + SwiftShader ES2 BADL xx + ES3 BADL ANGLE ES2 xx - ES3 BADLIOM + ES3 BADL OM ARM Mali (Huawei P10) ES2 BAD xx - ES3 BADLIOx + ES3 BADL Ox WebGL (on Mesa Intel) 1.0 BAD xx - 2.0 BADLIOM + 2.0 BADL OM NVidia BAD Intel Windows BAD AMD macOS BAD - Intel macOS BADLIOx + Intel macOS BADL Ox iPhone 6 w/ iOS 12.4 ES3 BAD x */ @@ -555,24 +556,14 @@ constexpr struct { PhongGL::Flags flags; Float maxThreshold, meanThreshold; } RenderInstancedData[] { - {"diffuse", "instanced.tga", {}, - #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) - /* AMD has one off pixel; SwiftShader a bit more */ - 96.34f, 0.113f, - #else - /* WebGL 1 doesn't have 8bit renderbuffer storage */ - 96.34f, 0.113f, - #endif - }, - {"diffuse + normal", "instanced-normal.tga", PhongGL::Flag::NormalTexture, - #if !(defined(MAGNUM_TARGET_GLES2) && defined(MAGNUM_TARGET_WEBGL)) - /* AMD has one off pixel, llvmpipe more */ - 96.0f, 0.333f, - #else - /* WebGL 1 doesn't have 8bit renderbuffer storage */ - 96.0f, 0.333f, - #endif - } + {"diffuse color", "instanced.tga", {}, + /* Minor differences on SwiftShader */ + 81.0f, 0.06f}, + {"diffuse texture", "instanced-textured.tga", + PhongGL::Flag::DiffuseTexture|PhongGL::Flag::InstancedTextureOffset, + /* Minor differences on SwiftShader */ + 112.0f, 0.09f}, + /** @todo test normal when there's usable texture */ }; #ifndef MAGNUM_TARGET_GLES2 @@ -614,6 +605,7 @@ constexpr struct { 4, 2, 3, 1, /* Minor differences on ARM Mali */ 4.67f, 0.02f}, + /** @todo test normal and per-draw scaling when there's usable texture */ }; #endif @@ -2833,16 +2825,13 @@ template void PhongGLTest::renderInstanced() { #endif #endif - if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || - !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) - CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); - GL::Mesh sphere = MeshTools::compile(Primitives::uvSphereSolid(16, 32, Primitives::UVSphereFlag::TextureCoordinates| Primitives::UVSphereFlag::Tangents)); - /* Three spheres, each in a different location, differently rotated to - ensure the normal matrix is properly used as well. */ + /* Three spheres, each in a different location. To test normal matrix + concatenation, everything is rotated 90° on Y, thus X is now -Z and Z is + now X. */ struct { Matrix4 transformation; Matrix3x3 normal; @@ -2850,18 +2839,22 @@ template void PhongGLTest::renderInstanced() { Vector2 textureOffset; UnsignedInt objectId; } instanceData[] { - {Matrix4::translation({-1.25f, -1.25f, 0.0f})* - Matrix4::rotationX(90.0_degf), - {}, 0xff3333_rgbf, {0.0f, 0.0f}, 211}, - {Matrix4::translation({ 1.25f, -1.25f, 0.0f})* - Matrix4::rotationY(90.0_degf), - {}, 0x33ff33_rgbf, {1.0f, 0.0f}, 4627}, - {Matrix4::translation({ 0.0f, 1.0f, 1.0f})* - Matrix4::rotationZ(90.0_degf), - {}, 0x9999ff_rgbf, {0.5f, 1.0f}, 35363} + {Matrix4::translation(Math::gather<'z', 'y', 'x'>(Vector3{-1.25f, -1.25f, 0.0f}))*Matrix4::rotationY(-90.0_degf)*Matrix4::rotationX(90.0_degf), + /* to test also per-instance normal matrix is applied properly -- + the texture should look the same as in the case of Flat 3D + instanced textured */ + (Matrix4::rotationY(-90.0_degf)*Matrix4::rotationX(90.0_degf)).normalMatrix(), + data.flags & PhongGL::Flag::DiffuseTexture ? 0xffffff_rgbf : 0xffff00_rgbf, + {0.0f, 0.0f}, 211}, + {Matrix4::translation(Math::gather<'z', 'y', 'x'>(Vector3{ 1.25f, -1.25f, 0.0f})), + {}, + data.flags & PhongGL::Flag::DiffuseTexture ? 0xffffff_rgbf : 0x00ffff_rgbf, + {1.0f, 0.0f}, 4627}, + {Matrix4::translation(Math::gather<'z', 'y', 'x'>(Vector3{ 0.0f, 1.0f, -1.0f})), + {}, + data.flags & PhongGL::Flag::DiffuseTexture ? 0xffffff_rgbf : 0xff00ff_rgbf, + {0.5f, 1.0f}, 35363} }; - for(auto& instance: instanceData) - instance.normal = instance.transformation.normalMatrix(); sphere .addVertexBufferInstanced(GL::Buffer{instanceData}, 1, 0, @@ -2877,31 +2870,9 @@ template void PhongGLTest::renderInstanced() { ) .setInstanceCount(3); - Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); - CORRADE_VERIFY(importer); - - Containers::Optional image; - CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); - GL::Texture2D diffuse; - diffuse.setMinificationFilter(GL::SamplerFilter::Linear) - .setMagnificationFilter(GL::SamplerFilter::Linear) - .setWrapping(GL::SamplerWrapping::ClampToEdge) - .setStorage(1, TextureFormatRGB, image->size()) - .setSubImage(0, {}, *image); - - CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/normal-texture.tga")) && (image = importer->image2D(0))); - GL::Texture2D normal; - normal.setMinificationFilter(GL::SamplerFilter::Linear) - .setMagnificationFilter(GL::SamplerFilter::Linear) - .setWrapping(GL::SamplerWrapping::ClampToEdge) - .setStorage(1, TextureFormatRGB, image->size()) - .setSubImage(0, {}, *image); - /* Enable also Object ID, if supported */ - PhongGL::Flags flags = PhongGL::Flag::DiffuseTexture| - PhongGL::Flag::VertexColor| - PhongGL::Flag::InstancedTransformation| - PhongGL::Flag::InstancedTextureOffset|data.flags|flag; + PhongGL::Flags flags = PhongGL::Flag::VertexColor| + PhongGL::Flag::InstancedTransformation|data.flags|flag; #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES if(GL::Context::current().isExtensionSupported()) @@ -2911,25 +2882,58 @@ template void PhongGLTest::renderInstanced() { } #endif PhongGL shader{flags, 2}; - shader.bindDiffuseTexture(diffuse); - if(data.flags & PhongGL::Flag::NormalTexture) - shader.bindNormalTexture(normal); + + GL::Texture2D diffuse; + GL::Texture2D normal; + if(data.flags & (PhongGL::Flag::DiffuseTexture|PhongGL::Flag::NormalTexture)) { + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); + + Containers::Pointer importer = _manager.loadAndInstantiate("AnyImageImporter"); + CORRADE_VERIFY(importer); + + if(data.flags & PhongGL::Flag::DiffuseTexture) { + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/diffuse-texture.tga")) && (image = importer->image2D(0))); + diffuse.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + shader.bindDiffuseTexture(diffuse); + } + + if(data.flags & PhongGL::Flag::NormalTexture) { + Containers::Optional image; + CORRADE_VERIFY(importer->openFile(Utility::Directory::join(_testDir, "TestFiles/normal-texture.tga")) && (image = importer->image2D(0))); + normal.setMinificationFilter(GL::SamplerFilter::Linear) + .setMagnificationFilter(GL::SamplerFilter::Linear) + .setWrapping(GL::SamplerWrapping::ClampToEdge) + .setStorage(1, TextureFormatRGB, image->size()) + .setSubImage(0, {}, *image); + shader.bindNormalTexture(normal); + } + } if(flag == PhongGL::Flag{}) { shader .setLightPositions({{-3.0f, -3.0f, 2.0f, 0.0f}, { 3.0f, -3.0f, 2.0f, 0.0f}}) + .setLightColors({0x999999_rgbf, 0x999999_rgbf}) + .setLightSpecularColors({0x0000ff_rgbf, 0x00ff00_rgbf}) .setTransformationMatrix( - Matrix4::translation(Vector3::zAxis(-1.75f))* - Matrix4::rotationY(-15.0_degf)* - Matrix4::rotationX(15.0_degf)* + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::rotationY(90.0_degf)* Matrix4::scaling(Vector3{0.4f})) - .setNormalMatrix((Matrix4::rotationY(-15.0_degf)* - Matrix4::rotationX(15.0_degf)).normalMatrix()) + .setNormalMatrix(Matrix4::rotationY(90.0_degf).normalMatrix()) .setProjectionMatrix( Matrix4::perspectiveProjection(60.0_degf, 1.0f, 0.1f, 10.0f)) - .setTextureMatrix(Matrix3::scaling(Vector2{0.5f})) - .setDiffuseColor(0xffff99_rgbf); + .setDiffuseColor(data.flags & PhongGL::Flag::DiffuseTexture ? + 0xffffff_rgbf : 0xffff00_rgbf); + + if(data.flags & PhongGL::Flag::TextureTransformation) + shader.setTextureMatrix(Matrix3::scaling(Vector2{0.5f})); #ifndef MAGNUM_TARGET_GLES2 #ifndef MAGNUM_TARGET_GLES @@ -2951,34 +2955,39 @@ template void PhongGLTest::renderInstanced() { }}; GL::Buffer transformationUniform{GL::Buffer::TargetHint::Uniform, { TransformationUniform3D{}.setTransformationMatrix( - Matrix4::translation(Vector3::zAxis(-1.75f))* - Matrix4::rotationY(-15.0_degf)* - Matrix4::rotationX(15.0_degf)* + Matrix4::translation(Vector3::zAxis(-2.15f))* + Matrix4::rotationY(90.0_degf)* Matrix4::scaling(Vector3{0.4f}) ) }}; GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, { PhongDrawUniform{} - .setNormalMatrix( - (Matrix4::rotationY(-15.0_degf)* - Matrix4::rotationX(15.0_degf)).normalMatrix()) + .setNormalMatrix(Matrix4::rotationY(90.0_degf).normalMatrix()) .setObjectId(1000) /* gets added to the per-instance ID */ }}; GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, { PhongMaterialUniform{} - .setDiffuseColor(0xffff99_rgbf) + .setDiffuseColor(data.flags & PhongGL::Flag::DiffuseTexture ? + 0xffffff_rgbf : 0xffff00_rgbf) }}; GL::Buffer textureTransformationUniform{GL::Buffer::TargetHint::Uniform, { TextureTransformationUniform{} .setTextureMatrix(Matrix3::scaling(Vector2{0.5f})) }}; GL::Buffer lightUniform{GL::Buffer::TargetHint::Uniform, { - PhongLightUniform{}.setPosition(Vector4{-3.0f, -3.0f, 2.0f, 0.0f}), - PhongLightUniform{}.setPosition(Vector4{3.0f, -3.0f, 2.0f, 0.0f}) + PhongLightUniform{} + .setPosition({-3.0f, -3.0f, 2.0f, 0.0f}) + .setColor(0x999999_rgbf) + .setSpecularColor(0x0000ff_rgbf), + PhongLightUniform{} + .setPosition({3.0f, -3.0f, 2.0f, 0.0f}) + .setColor(0x999999_rgbf) + .setSpecularColor(0x00ff00_rgbf) }}; + if(data.flags & PhongGL::Flag::TextureTransformation) + shader.bindTextureTransformationBuffer(textureTransformationUniform); shader.bindProjectionBuffer(projectionUniform) .bindTransformationBuffer(transformationUniform) - .bindTextureTransformationBuffer(textureTransformationUniform) .bindDrawBuffer(drawUniform) .bindMaterialBuffer(materialUniform) .bindLightBuffer(lightUniform) @@ -2987,6 +2996,25 @@ template void PhongGLTest::renderInstanced() { #endif else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + /* + Colored case: + + - First should be lower left, yellow with a blue and green highlight + on bottom left and right part + - Second lower right, cyan with a yellow light, so green, the same + highlight at the same position + - Third up center, magenta with a yellow light, so red, the same + highlight at the same position + + Textured case: + + - Lower left has bottom left numbers, so light 7881, rotated (78 + visible, should look the same as the multidraw case or as Flat) + - Lower light has bottom right, 1223, rotated (23 visible, looking at + the left side of the sphere in the equivalent Flat test) + - Up center has 6778, rotated (78 visible, looking at the left side + of the sphere in the equivalent Flat test) + */ MAGNUM_VERIFY_NO_GL_ERROR(); CORRADE_COMPARE_WITH( /* Dropping the alpha channel, as it's always 1.0 */ diff --git a/src/Magnum/Shaders/Test/PhongTestFiles/instanced-textured.tga b/src/Magnum/Shaders/Test/PhongTestFiles/instanced-textured.tga new file mode 100644 index 000000000..53b29b425 Binary files /dev/null and b/src/Magnum/Shaders/Test/PhongTestFiles/instanced-textured.tga differ diff --git a/src/Magnum/Shaders/Test/PhongTestFiles/instanced.tga b/src/Magnum/Shaders/Test/PhongTestFiles/instanced.tga index a761d9413..856356598 100644 Binary files a/src/Magnum/Shaders/Test/PhongTestFiles/instanced.tga and b/src/Magnum/Shaders/Test/PhongTestFiles/instanced.tga differ