You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

583 lines
24 KiB

/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022, 2023, 2024
Vladimír Vondruš <mosra@centrum.cz>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
#include <sstream>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/Utility/DebugStl.h>
#include "Magnum/Math/Color.h"
#include "Magnum/MeshTools/Combine.h"
#include "Magnum/Trade/MeshData.h"
namespace Magnum { namespace MeshTools { namespace Test { namespace {
struct CombineTest: TestSuite::Tester {
explicit CombineTest();
void indexedAttributes();
void indexedAttributesIndicesOnly();
void indexedAttributesSingleMesh();
void indexedAttributesNoMeshes();
void indexedAttributesNotIndexed();
void indexedAttributesDifferentPrimitive();
void indexedAttributesDifferentIndexCount();
void indexedAttributesImplementationSpecificIndexType();
void indexedAttributesImplementationSpecificVertexFormat();
void faceAttributes();
void faceAttributesMeshNotIndexed();
void faceAttributesUnexpectedPrimitive();
void faceAttributesUnexpectedFaceCount();
void faceAttributesFacesNotInterleaved();
void faceAttributesFaceAttributeOffsetOnly();
void faceAttributesImplementationSpecificIndexType();
void faceAttributesImplementationSpecificVertexFormat();
};
constexpr struct {
const char* name;
bool indexed;
} CombineFaceAttributesData[] {
{"", false},
{"indexed faces", true}
};
CombineTest::CombineTest() {
addTests({&CombineTest::indexedAttributes,
&CombineTest::indexedAttributesIndicesOnly,
&CombineTest::indexedAttributesSingleMesh,
&CombineTest::indexedAttributesNoMeshes,
&CombineTest::indexedAttributesNotIndexed,
&CombineTest::indexedAttributesDifferentPrimitive,
&CombineTest::indexedAttributesDifferentIndexCount,
&CombineTest::indexedAttributesImplementationSpecificIndexType,
&CombineTest::indexedAttributesImplementationSpecificVertexFormat});
addInstancedTests({&CombineTest::faceAttributes},
Containers::arraySize(CombineFaceAttributesData));
addTests({&CombineTest::faceAttributesMeshNotIndexed,
&CombineTest::faceAttributesUnexpectedPrimitive,
&CombineTest::faceAttributesUnexpectedFaceCount,
&CombineTest::faceAttributesFacesNotInterleaved,
&CombineTest::faceAttributesFaceAttributeOffsetOnly,
&CombineTest::faceAttributesImplementationSpecificIndexType,
&CombineTest::faceAttributesImplementationSpecificVertexFormat});
}
void CombineTest::indexedAttributes() {
const UnsignedInt indicesA[]{2, 1, 2, 0};
const Int dataA[]{2, 1, 0};
const UnsignedByte indicesB[]{3, 4, 3, 2};
const Byte dataB[][2]{{4, 1}, {3, 2}, {2, 3}, {1, 4}, {0, 5}};
const UnsignedShort indicesC[]{7, 6, 7, 5};
const Float dataC[]{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
Trade::MeshData a{MeshPrimitive::LineLoop,
{}, indicesA, Trade::MeshIndexData{indicesA},
{}, dataA, {Trade::MeshAttributeData{
Trade::meshAttributeCustom(2), Containers::arrayView(dataA)}}};
Trade::MeshData b{MeshPrimitive::LineLoop,
{}, indicesB, Trade::MeshIndexData{indicesB},
{}, dataB, {Trade::MeshAttributeData{
Trade::meshAttributeCustom(17), VertexFormat::Byte,
/* Array attribute to verify it's correctly propagated */
Containers::arrayView(dataB), 2}}};
Trade::MeshData c{MeshPrimitive::LineLoop,
{}, indicesC, Trade::MeshIndexData{indicesC},
{}, dataC, {Trade::MeshAttributeData{
/* Offset-only to verify these aren't causing any issues
internally */
Trade::meshAttributeCustom(22), VertexFormat::Float, 0, 8, sizeof(Float)}}};
Trade::MeshData result = combineIndexedAttributes({a, b, c});
CORRADE_COMPARE(result.primitive(), MeshPrimitive::LineLoop);
CORRADE_VERIFY(result.isIndexed());
CORRADE_COMPARE(result.indexType(), MeshIndexType::UnsignedInt);
CORRADE_COMPARE_AS(result.indices<UnsignedInt>(),
Containers::arrayView<UnsignedInt>({0, 1, 0, 2}),
TestSuite::Compare::Container);
CORRADE_COMPARE(result.attributeCount(), 3);
CORRADE_COMPARE(result.attributeName(0), Trade::meshAttributeCustom(2));
CORRADE_COMPARE(result.attributeFormat(0), VertexFormat::Int);
CORRADE_COMPARE_AS(result.attribute<Int>(0),
Containers::arrayView<Int>({0, 1, 2}),
TestSuite::Compare::Container);
CORRADE_COMPARE(result.attributeName(1), Trade::meshAttributeCustom(17));
CORRADE_COMPARE(result.attributeFormat(1), VertexFormat::Byte);
CORRADE_COMPARE(result.attributeArraySize(1), 2);
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Vector2b>(result.attribute<Byte[]>(1))),
Containers::arrayView<Vector2b>({{1, 4}, {0, 5}, {2, 3}}),
TestSuite::Compare::Container);
CORRADE_COMPARE(result.attributeName(2), Trade::meshAttributeCustom(22));
CORRADE_COMPARE(result.attributeFormat(2), VertexFormat::Float);
CORRADE_COMPARE_AS(result.attribute<Float>(2),
Containers::arrayView<Float>({7.0f, 6.0f, 5.0f}),
TestSuite::Compare::Container);
}
void CombineTest::indexedAttributesIndicesOnly() {
const UnsignedInt indicesA[]{2, 1, 2};
const UnsignedShort indicesB[]{3, 4, 3};
const UnsignedByte indicesC[]{7, 6, 7};
Trade::MeshData a{MeshPrimitive::LineLoop, {}, indicesA,
Trade::MeshIndexData{indicesA}, 3};
Trade::MeshData b{MeshPrimitive::LineLoop, {}, indicesB,
Trade::MeshIndexData{indicesB}, 5};
Trade::MeshData c{MeshPrimitive::LineLoop, {}, indicesC,
Trade::MeshIndexData{indicesC}, 8};
Trade::MeshData result = combineIndexedAttributes({a, b, c});
CORRADE_COMPARE(result.primitive(), MeshPrimitive::LineLoop);
CORRADE_VERIFY(result.isIndexed());
CORRADE_COMPARE(result.indexType(), MeshIndexType::UnsignedInt);
CORRADE_COMPARE_AS(result.indices<UnsignedInt>(),
Containers::arrayView<UnsignedInt>({0, 1, 0}),
TestSuite::Compare::Container);
CORRADE_COMPARE(result.attributeCount(), 0);
CORRADE_COMPARE(result.vertexCount(), 2);
}
void CombineTest::indexedAttributesSingleMesh() {
const UnsignedInt indices[]{2, 1, 2, 0, 5, 7};
const Float data[]{0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
Trade::MeshData a{MeshPrimitive::LineLoop,
{}, indices, Trade::MeshIndexData{indices},
{}, data, {Trade::MeshAttributeData{
Trade::meshAttributeCustom(22), Containers::arrayView(data)}}};
Trade::MeshData result = combineIndexedAttributes({a});
CORRADE_COMPARE(result.primitive(), MeshPrimitive::LineLoop);
CORRADE_VERIFY(result.isIndexed());
CORRADE_COMPARE(result.indexType(), MeshIndexType::UnsignedInt);
CORRADE_COMPARE_AS(result.indices<UnsignedInt>(),
Containers::arrayView<UnsignedInt>({0, 1, 0, 2, 3, 4}),
TestSuite::Compare::Container);
CORRADE_COMPARE(result.attributeCount(), 1);
CORRADE_COMPARE(result.attributeFormat(0), VertexFormat::Float);
CORRADE_COMPARE_AS(result.attribute<Float>(0),
Containers::arrayView<Float>({2.0f, 1.0f, 0.0f, 5.0f, 7.0f}),
TestSuite::Compare::Container);
}
void CombineTest::indexedAttributesNoMeshes() {
CORRADE_SKIP_IF_NO_ASSERT();
std::ostringstream out;
Error redirectError{&out};
combineIndexedAttributes({});
CORRADE_COMPARE(out.str(), "MeshTools::combineIndexedAttributes(): no meshes passed\n");
}
void CombineTest::indexedAttributesNotIndexed() {
CORRADE_SKIP_IF_NO_ASSERT();
const UnsignedShort indices[5]{};
Trade::MeshData a{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData b{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData c{MeshPrimitive::Lines, 1};
std::ostringstream out;
Error redirectError{&out};
combineIndexedAttributes({a, b, c});
CORRADE_COMPARE(out.str(), "MeshTools::combineIndexedAttributes(): data 2 is not indexed\n");
}
void CombineTest::indexedAttributesDifferentPrimitive() {
CORRADE_SKIP_IF_NO_ASSERT();
const UnsignedShort indices[5]{};
Trade::MeshData a{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData b{MeshPrimitive::Points,
{}, indices, Trade::MeshIndexData{indices}, 1};
std::ostringstream out;
Error redirectError{&out};
combineIndexedAttributes({a, b});
CORRADE_COMPARE(out.str(), "MeshTools::combineIndexedAttributes(): data 1 is MeshPrimitive::Points but expected MeshPrimitive::Lines\n");
}
void CombineTest::indexedAttributesDifferentIndexCount() {
CORRADE_SKIP_IF_NO_ASSERT();
const UnsignedShort indices[5]{};
Trade::MeshData a{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData b{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}, 1};
Trade::MeshData c{MeshPrimitive::Lines,
{}, indices,
Trade::MeshIndexData{Containers::arrayView(indices).prefix(4)}, 1};
std::ostringstream out;
Error redirectError{&out};
combineIndexedAttributes({a, b, c});
CORRADE_COMPARE(out.str(), "MeshTools::combineIndexedAttributes(): data 2 has 4 indices but expected 5\n");
}
void CombineTest::indexedAttributesImplementationSpecificIndexType() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData a{MeshPrimitive::Points,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
}};
Trade::MeshData b{MeshPrimitive::Points,
nullptr, Trade::MeshIndexData{meshIndexTypeWrap(0xcaca), Containers::StridedArrayView1D<const void>{}},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
}};
std::ostringstream out;
Error redirectError{&out};
combineIndexedAttributes({a, b});
CORRADE_COMPARE(out.str(), "MeshTools::combineIndexedAttributes(): data 1 has an implementation-specific index type 0xcaca\n");
}
void CombineTest::indexedAttributesImplementationSpecificVertexFormat() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData a{MeshPrimitive::Points,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
}};
Trade::MeshData b{MeshPrimitive::Points,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
Trade::MeshAttributeData{Trade::meshAttributeCustom(3), vertexFormatWrap(0xcaca), nullptr}
}};
std::ostringstream out;
Error redirectError{&out};
combineIndexedAttributes({a, b});
CORRADE_COMPARE(out.str(), "MeshTools::combineIndexedAttributes(): attribute 2 of mesh 1 has an implementation-specific format 0xcaca\n");
}
void CombineTest::faceAttributes() {
auto&& data = CombineFaceAttributesData[testCaseInstanceId()];
setTestCaseDescription(data.name);
using namespace Math::Literals;
/*
9 ------- 8
5 ------- 4 \ / 6
\ / \ \ C / / \
\ C / \ \ / / \
\ / B \ \ / / B \
\ / \ 7 / \
1 ------- 3 ==> 3 ------- 5
/ \ / 2 \ /
/ \ B / / \ \ B /
/ A \ / / \ \ /
/ \ / / A \ \ /
0 ------- 2 / \ 4
0 ------- 1
*/
const UnsignedShort indices[]{
0, 2, 1,
1, 2, 3,
1, 3, 4,
1, 4, 5
};
const Vector2 positions[] {
{0.0f, 0.0f},
{0.5f, 1.0f},
{1.0f, 0.0f},
{1.5f, 1.0f},
{1.0f, 2.0f},
{0.0f, 2.0f}
};
const struct FaceData {
Color3 color;
Byte id;
} faceData[] {
{0xaaaaaa_rgbf, 'A'},
{0xbbbbbb_rgbf, 'B'},
{0xbbbbbb_rgbf, 'B'},
{0xcccccc_rgbf, 'C'}
};
const UnsignedByte faceIndices[] { 0, 1, 1, 2 };
const FaceData faceDataIndexed[] {
{0xaaaaaa_rgbf, 'A'},
{0xbbbbbb_rgbf, 'B'},
{0xcccccc_rgbf, 'C'}
};
const Trade::MeshData mesh{MeshPrimitive::Triangles,
{}, indices, Trade::MeshIndexData{indices},
{}, positions, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
Containers::arrayView(positions)}
}};
const Trade::MeshData faceAttributesIndexed{MeshPrimitive::Faces,
{}, faceIndices, Trade::MeshIndexData{faceIndices},
{}, faceDataIndexed, {
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
Containers::StridedArrayView1D<const Color3>{faceDataIndexed,
&faceDataIndexed[0].color, 3, sizeof(FaceData)}},
Trade::MeshAttributeData{Trade::meshAttributeCustom(25),
Containers::StridedArrayView1D<const Byte>{faceDataIndexed,
&faceDataIndexed[0].id, 3, sizeof(FaceData)}},
}};
/* For a non-indexed variant test the overload that takes the attributes
directly, not wrapped in a MeshData */
Containers::Optional<Trade::MeshData> combined;
if(data.indexed)
combined = combineFaceAttributes(mesh, faceAttributesIndexed);
else
combined = combineFaceAttributes(mesh, {
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
Containers::StridedArrayView1D<const Color3>{faceData,
&faceData[0].color, 4, sizeof(FaceData)}},
Trade::MeshAttributeData{Trade::meshAttributeCustom(25),
Containers::StridedArrayView1D<const Byte>{faceData,
&faceData[0].id, 4, sizeof(FaceData)}}
});
CORRADE_COMPARE(combined->attributeCount(), 3);
CORRADE_COMPARE(combined->indexType(), MeshIndexType::UnsignedInt);
CORRADE_COMPARE_AS(combined->indices<UnsignedInt>(),
Containers::arrayView<UnsignedInt>({
0, 1, 2,
3, 4, 5,
3, 5, 6,
7, 8, 9
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(combined->attribute<Vector2>(Trade::MeshAttribute::Position),
Containers::arrayView<Vector2>({
{0.0f, 0.0f},
{1.0f, 0.0f},
{0.5f, 1.0f},
{0.5f, 1.0f},
{1.0f, 0.0f},
{1.5f, 1.0f},
{1.0f, 2.0f},
{0.5f, 1.0f},
{1.0f, 2.0f},
{0.0f, 2.0f}
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(combined->attribute<Color3>(Trade::MeshAttribute::Color),
Containers::arrayView<Color3>({
0xaaaaaa_rgbf, 0xaaaaaa_rgbf, 0xaaaaaa_rgbf,
0xbbbbbb_rgbf, 0xbbbbbb_rgbf, 0xbbbbbb_rgbf, 0xbbbbbb_rgbf,
0xcccccc_rgbf, 0xcccccc_rgbf, 0xcccccc_rgbf
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(combined->attribute<Byte>(Trade::meshAttributeCustom(25)),
Containers::arrayView<Byte>({
'A', 'A', 'A',
'B', 'B', 'B', 'B',
'C', 'C', 'C'
}), TestSuite::Compare::Container);
}
void CombineTest::faceAttributesMeshNotIndexed() {
CORRADE_SKIP_IF_NO_ASSERT();
const Trade::MeshData mesh{MeshPrimitive::Triangles, 3};
const Trade::MeshData faceAttributes{MeshPrimitive::Faces, 0};
std::ostringstream out;
Error redirectError{&out};
combineFaceAttributes(mesh, faceAttributes);
CORRADE_COMPARE(out.str(),
"MeshTools::combineFaceAttributes(): vertex mesh is not indexed\n");
}
void CombineTest::faceAttributesUnexpectedPrimitive() {
CORRADE_SKIP_IF_NO_ASSERT();
const UnsignedInt indices[] { 0, 0, 0 };
const Trade::MeshData a{MeshPrimitive::Triangles,
{}, indices, Trade::MeshIndexData{indices}, 1};
const Trade::MeshData b{MeshPrimitive::Lines,
{}, indices, Trade::MeshIndexData{indices}, 1};
const Trade::MeshData faceA{MeshPrimitive::Instances, 0};
const Trade::MeshData faceB{MeshPrimitive::Faces, 0};
std::ostringstream out;
Error redirectError{&out};
combineFaceAttributes(a, faceA);
combineFaceAttributes(b, faceB);
CORRADE_COMPARE(out.str(),
"MeshTools::combineFaceAttributes(): expected a MeshPrimitive::Triangles mesh and a MeshPrimitive::Faces mesh but got MeshPrimitive::Triangles and MeshPrimitive::Instances\n"
"MeshTools::combineFaceAttributes(): expected a MeshPrimitive::Triangles mesh and a MeshPrimitive::Faces mesh but got MeshPrimitive::Lines and MeshPrimitive::Faces\n");
}
void CombineTest::faceAttributesUnexpectedFaceCount() {
CORRADE_SKIP_IF_NO_ASSERT();
const UnsignedInt indices[] { 0, 0, 0 };
const Trade::MeshData mesh{MeshPrimitive::Triangles,
{}, indices, Trade::MeshIndexData{indices}, 1};
const Trade::MeshData faceAttributes{MeshPrimitive::Faces, 2};
std::ostringstream out;
Error redirectError{&out};
combineFaceAttributes(mesh, faceAttributes);
CORRADE_COMPARE(out.str(),
"MeshTools::combineFaceAttributes(): expected 1 face entries for 3 indices but got 2\n");
}
void CombineTest::faceAttributesImplementationSpecificIndexType() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData triangles{MeshPrimitive::Triangles,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
}};
Trade::MeshData trianglesImplementationSpecific{MeshPrimitive::Triangles,
nullptr, Trade::MeshIndexData{meshIndexTypeWrap(0xcaca), Containers::StridedArrayView1D<const void>{}},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
}};
Trade::MeshData faces{MeshPrimitive::Faces,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
}};
Trade::MeshData facesImplementationSpecific{MeshPrimitive::Faces,
nullptr, Trade::MeshIndexData{meshIndexTypeWrap(0xcaca), Containers::StridedArrayView1D<const void>{}},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
}};
std::ostringstream out;
Error redirectError{&out};
combineFaceAttributes(triangles, facesImplementationSpecific);
combineFaceAttributes(trianglesImplementationSpecific, faces);
CORRADE_COMPARE(out.str(),
"MeshTools::combineFaceAttributes(): face mesh has an implementation-specific index type 0xcaca\n"
"MeshTools::combineFaceAttributes(): vertex mesh has an implementation-specific index type 0xcaca\n");
}
void CombineTest::faceAttributesImplementationSpecificVertexFormat() {
CORRADE_SKIP_IF_NO_ASSERT();
Trade::MeshData triangles{MeshPrimitive::Triangles,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
}};
Trade::MeshData trianglesImplementationSpecific{MeshPrimitive::Triangles,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::Color, VertexFormat::Vector4, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, vertexFormatWrap(0xcaca), nullptr}
}};
Trade::MeshData faces{MeshPrimitive::Faces,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, nullptr},
}};
Trade::MeshData facesImplementationSpecific{MeshPrimitive::Faces,
nullptr, Trade::MeshIndexData{MeshIndexType::UnsignedShort, nullptr},
nullptr, {
Trade::MeshAttributeData{Trade::MeshAttribute::Normal, VertexFormat::Vector3, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::Color, VertexFormat::Vector4, nullptr},
Trade::MeshAttributeData{Trade::MeshAttribute::Tangent, vertexFormatWrap(0xcaca), nullptr}
}};
std::ostringstream out;
Error redirectError{&out};
combineFaceAttributes(triangles, facesImplementationSpecific);
combineFaceAttributes(trianglesImplementationSpecific, faces);
CORRADE_COMPARE(out.str(),
"MeshTools::combineFaceAttributes(): attribute 2 of mesh 1 has an implementation-specific format 0xcaca\n"
"MeshTools::combineFaceAttributes(): attribute 2 of mesh 0 has an implementation-specific format 0xcaca\n");
}
void CombineTest::faceAttributesFacesNotInterleaved() {
CORRADE_SKIP_IF_NO_ASSERT();
using namespace Math::Literals;
const UnsignedInt indices[] { 0, 0, 0, 0, 0, 0 };
const Trade::MeshData mesh{MeshPrimitive::Triangles,
{}, indices, Trade::MeshIndexData{indices}, 1};
const struct {
Color3 color[2];
Byte id[2];
} faceData[]{{
{0xaaaaaa_rgbf, 0xbbbbbb_rgbf},
{'A', 'B'}
}};
const Trade::MeshData faceAttributes{MeshPrimitive::Faces,
{}, faceData, {
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
Containers::arrayView(faceData[0].color)},
Trade::MeshAttributeData{Trade::meshAttributeCustom(25),
Containers::arrayView(faceData[0].id)}
}};
std::ostringstream out;
Error redirectError{&out};
combineFaceAttributes(mesh, faceAttributes);
CORRADE_COMPARE(out.str(),
"MeshTools::combineFaceAttributes(): face attributes are not interleaved\n");
}
void CombineTest::faceAttributesFaceAttributeOffsetOnly() {
CORRADE_SKIP_IF_NO_ASSERT();
std::ostringstream out;
Error redirectError{&out};
combineFaceAttributes(Trade::MeshData{MeshPrimitive::Triangles, 0}, {
Trade::MeshAttributeData{Trade::MeshAttribute::ObjectId,
Containers::ArrayView<UnsignedInt>{}},
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
VertexFormat::Vector4, 0, 5, 16}
});
CORRADE_COMPARE(out.str(),
"MeshTools::combineFaceAttributes(): face attribute 1 is offset-only\n");
}
}}}}
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CombineTest)