From ee06eb2093c1dd7ef2c854577725d10ca38effaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Thu, 20 Feb 2020 16:22:58 +0100 Subject: [PATCH] MeshTools: support the 40 new attribute formats by deleting some code. Hur hur. --- src/Magnum/MeshTools/Compile.cpp | 29 ++-- src/Magnum/MeshTools/Test/CompileGLTest.cpp | 154 +++++++++++++++++++- 2 files changed, 163 insertions(+), 20 deletions(-) diff --git a/src/Magnum/MeshTools/Compile.cpp b/src/Magnum/MeshTools/Compile.cpp index 104819b96..74b434449 100644 --- a/src/Magnum/MeshTools/Compile.cpp +++ b/src/Magnum/MeshTools/Compile.cpp @@ -58,8 +58,7 @@ GL::Mesh compile(const Trade::MeshData& meshData, CompileFlags flags) { if(meshData.primitive() == MeshPrimitive::Triangles && (flags & (CompileFlag::GenerateFlatNormals|CompileFlag::GenerateSmoothNormals))) { CORRADE_ASSERT(meshData.attributeCount(Trade::MeshAttribute::Position), "MeshTools::compile(): the mesh has no positions, can't generate normals", GL::Mesh{}); - /* Right now this could fire only if we have 2D positions, which is - unlikely; in the future it might fire once packed formats are added */ + /* This could fire if we have 2D positions or for packed formats */ CORRADE_ASSERT(meshData.attributeFormat(Trade::MeshAttribute::Position) == VertexFormat::Vector3, "MeshTools::compile(): can't generate normals for" << meshData.attributeFormat(Trade::MeshAttribute::Position) << "positions", GL::Mesh{}); @@ -72,8 +71,7 @@ GL::Mesh compile(const Trade::MeshData& meshData, CompileFlags flags) { Trade::MeshAttribute::Normal, VertexFormat::Vector3, nullptr}; extra = {&normalAttribute, 1}; - /* If we reuse a normal location, expect correct type. Again this won't - fire now, but might in the future once packed formats are added */ + /* If we reuse a normal location, expect correct type */ } else CORRADE_ASSERT(meshData.attributeFormat(Trade::MeshAttribute::Normal) == VertexFormat::Vector3, "MeshTools::compile(): can't generate normals into" << meshData.attributeFormat(Trade::MeshAttribute::Normal), GL::Mesh{}); @@ -142,32 +140,27 @@ GL::Mesh compile(const Trade::MeshData& meshData, GL::Buffer&& indices, GL::Buff GL::Buffer verticesRef = GL::Buffer::wrap(vertices.id(), GL::Buffer::TargetHint::Array); for(UnsignedInt i = 0; i != meshData.attributeCount(); ++i) { Containers::Optional attribute; + const VertexFormat format = meshData.attributeFormat(i); switch(meshData.attributeName(i)) { case Trade::MeshAttribute::Position: - if(meshData.attributeFormat(i) == VertexFormat::Vector2) - attribute.emplace(Shaders::Generic2D::Position{}); - else if(meshData.attributeFormat(i) == VertexFormat::Vector3) - attribute.emplace(Shaders::Generic3D::Position{}); - else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + /* Pick 3D position always, the type will properly reduce it to + a 2-component version if needed */ + attribute.emplace(Shaders::Generic3D::Position{}, format); break; case Trade::MeshAttribute::Normal: - CORRADE_INTERNAL_ASSERT(meshData.attributeFormat(i) == VertexFormat::Vector3); - attribute.emplace(Shaders::Generic3D::Normal{}); + attribute.emplace(Shaders::Generic3D::Normal{}, format); break; case Trade::MeshAttribute::TextureCoordinates: - CORRADE_INTERNAL_ASSERT(meshData.attributeFormat(i) == VertexFormat::Vector2); /** @todo have Generic2D derived from Generic that has all attribute definitions common for 2D and 3D */ - attribute.emplace(Shaders::Generic2D::TextureCoordinates{}); + attribute.emplace(Shaders::Generic2D::TextureCoordinates{}, format); break; case Trade::MeshAttribute::Color: /** @todo have Generic2D derived from Generic that has all attribute definitions common for 2D and 3D */ - if(meshData.attributeFormat(i) == VertexFormat::Vector3) - attribute.emplace(Shaders::Generic2D::Color3{}); - else if(meshData.attributeFormat(i) == VertexFormat::Vector4) - attribute.emplace(Shaders::Generic2D::Color4{}); - else CORRADE_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ + /* Pick Color4 always, the type will properly reduce it to a + 3-component version if needed */ + attribute.emplace(Shaders::Generic2D::Color4{}, format); break; /* So it doesn't yell that we didn't handle a known attribute */ diff --git a/src/Magnum/MeshTools/Test/CompileGLTest.cpp b/src/Magnum/MeshTools/Test/CompileGLTest.cpp index 4257c215e..fa80cb067 100644 --- a/src/Magnum/MeshTools/Test/CompileGLTest.cpp +++ b/src/Magnum/MeshTools/Test/CompileGLTest.cpp @@ -90,9 +90,13 @@ struct CompileGLTest: GL::OpenGLTester { /** @todo remove the template once MeshDataXD is gone */ template void twoDimensions(); template void threeDimensions(); + + void packedAttributes(); + void unknownAttribute(); void generateNormalsNoPosition(); void generateNormals2DPosition(); + void generateNormalsNoFloats(); void externalBuffers(); void externalBuffersInvalid(); @@ -198,9 +202,12 @@ CompileGLTest::CompileGLTest() { CORRADE_IGNORE_DEPRECATED_POP #endif - addTests({&CompileGLTest::unknownAttribute, + addTests({&CompileGLTest::packedAttributes, + + &CompileGLTest::unknownAttribute, &CompileGLTest::generateNormalsNoPosition, - &CompileGLTest::generateNormals2DPosition}); + &CompileGLTest::generateNormals2DPosition, + &CompileGLTest::generateNormalsNoFloats}); addInstancedTests({&CompileGLTest::externalBuffers}, Containers::arraySize(DataExternal)); @@ -578,6 +585,133 @@ template void CompileGLTest::threeDimensions() { } } +void CompileGLTest::packedAttributes() { + /* Same as above, just packed */ + const struct Vertex { + Vector3s position; + Vector3s normal; + Vector2us textureCoordinates; + Color4ub color; + } vertexData[]{ + {Math::pack(Vector3{-0.75f, -0.75f, -0.35f}), + Math::pack(Vector3{-0.5f, -0.5f, 1.0f}.normalized()), + Math::pack(Vector2{0.0f, 0.0f}), 0x00ff00_rgb}, + {Math::pack(Vector3{ 0.00f, -0.75f, -0.25f}), + Math::pack(Vector3{ 0.0f, -0.5f, 1.0f}.normalized()), + Math::pack(Vector2{0.5f, 0.0f}), 0x808000_rgb}, + {Math::pack(Vector3{ 0.75f, -0.75f, -0.35f}), + Math::pack(Vector3{ 0.5f, -0.5f, 1.0f}.normalized()), + Math::pack(Vector2{1.0f, 0.0f}), 0xff0000_rgb}, + + {Math::pack(Vector3{-0.75f, 0.00f, -0.25f}), + Math::pack(Vector3{-0.5f, 0.0f, 1.0f}.normalized()), + Math::pack(Vector2{0.0f, 0.5f}), 0x00ff80_rgb}, + {Math::pack(Vector3{ 0.00f, 0.00f, 0.00f}), + Math::pack(Vector3{ 0.0f, 0.0f, 1.0f}.normalized()), + Math::pack(Vector2{0.5f, 0.5f}), 0x808080_rgb}, + {Math::pack(Vector3{ 0.75f, 0.00f, -0.25f}), + Math::pack(Vector3{ 0.5f, 0.0f, 1.0f}.normalized()), + Math::pack(Vector2{1.0f, 0.5f}), 0xff0080_rgb}, + + {Math::pack(Vector3{-0.75f, 0.75f, -0.35f}), + Math::pack(Vector3{-0.5f, 0.5f, 1.0f}.normalized()), + Math::pack(Vector2{0.0f, 1.0f}), 0x00ffff_rgb}, + {Math::pack(Vector3{ 0.0f, 0.75f, -0.25f}), + Math::pack(Vector3{ 0.0f, 0.5f, 1.0f}.normalized()), + Math::pack(Vector2{0.5f, 1.0f}), 0x8080ff_rgb}, + {Math::pack(Vector3{ 0.75f, 0.75f, -0.35f}), + Math::pack(Vector3{ 0.5f, 0.5f, 1.0f}.normalized()), + Math::pack(Vector2{1.0f, 1.0f}), 0xff00ff_rgb} + }; + static_assert(sizeof(Vertex) % 4 == 0, + "the vertex is not 4-byte aligned and that's bad"); + + const UnsignedByte indexData[]{ + 0, 1, 4, 0, 4, 3, + 1, 2, 5, 1, 5, 4, + 3, 4, 7, 3, 7, 6, + 4, 5, 8, 4, 8, 7 + }; + + Trade::MeshData meshData{MeshPrimitive::Triangles, {}, indexData, + Trade::MeshIndexData{indexData}, {}, vertexData, { + Trade::MeshAttributeData{ + Trade::MeshAttribute::Position, + VertexFormat::Vector3sNormalized, + Containers::stridedArrayView(vertexData, &vertexData[0].position, + Containers::arraySize(vertexData), sizeof(Vertex))}, + Trade::MeshAttributeData{ + Trade::MeshAttribute::Normal, + VertexFormat::Vector3sNormalized, + Containers::stridedArrayView(vertexData, &vertexData[0].normal, + Containers::arraySize(vertexData), sizeof(Vertex))}, + Trade::MeshAttributeData{ + Trade::MeshAttribute::TextureCoordinates, + VertexFormat::Vector2usNormalized, + Containers::stridedArrayView(vertexData, &vertexData[0].textureCoordinates, + Containers::arraySize(vertexData), sizeof(Vertex))}, + Trade::MeshAttributeData{ + Trade::MeshAttribute::Color, + /* It should figure out the type itself here */ + Containers::stridedArrayView(vertexData, &vertexData[0].color, + Containers::arraySize(vertexData), sizeof(Vertex))} + }}; + + GL::Mesh mesh = compile(meshData); + + MAGNUM_VERIFY_NO_GL_ERROR(); + + if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || + !(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded)) + CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found."); + + Matrix4 projection = Matrix4::perspectiveProjection(45.0_degf, 1.0f, 0.1f, 10.0f); + Matrix4 transformation = Matrix4::translation(Vector3::zAxis(-2.0f)); + + /* In all checks below, the rendering should be practically 1:1 as above + with full-blown attribute types */ + + /* Check positions and normals */ + _framebuffer.clear(GL::FramebufferClear::Color); + _phong + .setDiffuseColor(0x33ff66_rgbf) + .setTransformationMatrix(transformation) + .setNormalMatrix(transformation.normalMatrix()) + .setProjectionMatrix(projection); + mesh.draw(_phong); + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE_WITH( + _framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), + Utility::Directory::join(COMPILEGLTEST_TEST_DIR, "phong.tga"), + /* SwiftShader has some minor off-by-one precision differences */ + (DebugTools::CompareImageToFile{_manager, 0.5f, 0.0113f})); + + /* Check colors */ + _framebuffer.clear(GL::FramebufferClear::Color); + _color3D + .setTransformationProjectionMatrix(projection*transformation); + mesh.draw(_color3D); + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE_WITH( + _framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), + Utility::Directory::join(COMPILEGLTEST_TEST_DIR, "color3D.tga"), + /* SwiftShader has some minor off-by-one precision differences */ + (DebugTools::CompareImageToFile{_manager, 0.5f, 0.0162f})); + + /* Check texture coordinates */ + _framebuffer.clear(GL::FramebufferClear::Color); + _flatTextured3D + .setTransformationProjectionMatrix(projection*transformation) + .bindTexture(_texture); + mesh.draw(_flatTextured3D); + MAGNUM_VERIFY_NO_GL_ERROR(); + CORRADE_COMPARE_WITH( + _framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), + Utility::Directory::join(COMPILEGLTEST_TEST_DIR, "textured3D.tga"), + /* SwiftShader has some minor off-by-one precision differences */ + (DebugTools::CompareImageToFile{_manager, 1.0f, 0.0948f})); +} + void CompileGLTest::unknownAttribute() { Trade::MeshData data{MeshPrimitive::Triangles, nullptr, {Trade::MeshAttributeData{Trade::meshAttributeCustom(115), @@ -612,6 +746,22 @@ void CompileGLTest::generateNormals2DPosition() { "MeshTools::compile(): can't generate normals for VertexFormat::Vector2 positions\n"); } +void CompileGLTest::generateNormalsNoFloats() { + Trade::MeshData data{MeshPrimitive::Triangles, + nullptr, { + Trade::MeshAttributeData{Trade::MeshAttribute::Position, + VertexFormat::Vector3, nullptr}, + Trade::MeshAttributeData{Trade::MeshAttribute::Normal, + VertexFormat::Vector3h, nullptr}, + }}; + + std::ostringstream out; + Error redirectError{&out}; + MeshTools::compile(data, CompileFlag::GenerateFlatNormals); + CORRADE_COMPARE(out.str(), + "MeshTools::compile(): can't generate normals into VertexFormat::Vector3h\n"); +} + void CompileGLTest::externalBuffers() { auto&& data = DataExternal[testCaseInstanceId()]; setTestCaseDescription(data.name);