mirror of https://github.com/mosra/magnum.git
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.
596 lines
24 KiB
596 lines
24 KiB
|
6 years ago
|
/*
|
||
|
|
This file is part of Magnum.
|
||
|
|
|
||
|
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019
|
||
|
|
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/TestSuite/Tester.h>
|
||
|
|
#include <Corrade/TestSuite/Compare/Container.h>
|
||
|
|
#include <Corrade/Utility/DebugStl.h>
|
||
|
|
|
||
|
|
#include "Magnum/Math/Color.h"
|
||
|
|
#include "Magnum/MeshTools/Concatenate.h"
|
||
|
|
|
||
|
|
namespace Magnum { namespace MeshTools { namespace Test { namespace {
|
||
|
|
|
||
|
|
struct ConcatenateTest: TestSuite::Tester {
|
||
|
|
explicit ConcatenateTest();
|
||
|
|
|
||
|
|
void concatenate();
|
||
|
|
void concatenateNotIndexed();
|
||
|
|
void concatenateNoAttributes();
|
||
|
|
void concatenateNoAttributesNotIndexed();
|
||
|
|
void concatenateOne();
|
||
|
|
void concatenateOneRvalue();
|
||
|
|
void concatenateInto();
|
||
|
|
void concatenateIntoNoIndexArray();
|
||
|
|
void concatenateIntoNonOwnedAttributeArray();
|
||
|
|
|
||
|
|
void concatenateUnsupportedPrimitive();
|
||
|
|
void concatenateInconsistentPrimitive();
|
||
|
|
void concatenateInconsistentAttributeType();
|
||
|
|
void concatenateIntoNoMeshes();
|
||
|
|
};
|
||
|
|
|
||
|
|
ConcatenateTest::ConcatenateTest() {
|
||
|
|
addTests({&ConcatenateTest::concatenate,
|
||
|
|
&ConcatenateTest::concatenateNotIndexed,
|
||
|
|
&ConcatenateTest::concatenateNoAttributes,
|
||
|
|
&ConcatenateTest::concatenateNoAttributesNotIndexed,
|
||
|
|
&ConcatenateTest::concatenateOne,
|
||
|
|
&ConcatenateTest::concatenateOneRvalue,
|
||
|
|
&ConcatenateTest::concatenateInto,
|
||
|
|
&ConcatenateTest::concatenateIntoNoIndexArray,
|
||
|
|
&ConcatenateTest::concatenateIntoNonOwnedAttributeArray,
|
||
|
|
|
||
|
|
&ConcatenateTest::concatenateUnsupportedPrimitive,
|
||
|
|
&ConcatenateTest::concatenateInconsistentPrimitive,
|
||
|
|
&ConcatenateTest::concatenateInconsistentAttributeType,
|
||
|
|
&ConcatenateTest::concatenateIntoNoMeshes});
|
||
|
|
}
|
||
|
|
|
||
|
|
/* MSVC 2015 doesn't like unnamed bitfields in local structs, so thhis has to
|
||
|
|
be outside */
|
||
|
|
struct VertexDataA {
|
||
|
|
Vector2 texcoords1;
|
||
|
|
Vector2 texcoords2;
|
||
|
|
Int:32;
|
||
|
|
Vector3 position;
|
||
|
|
};
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenate() {
|
||
|
|
using namespace Math::Literals;
|
||
|
|
|
||
|
|
/* First is non-indexed, this layout (including the gap) will be
|
||
|
|
preserved */
|
||
|
|
const VertexDataA vertexDataA[]{
|
||
|
|
{{0.1f, 0.2f}, {0.5f, 0.6f}, {1.0f, 2.0f, 3.0f}},
|
||
|
|
{{0.3f, 0.4f}, {0.7f, 0.8f}, {4.0f, 5.0f, 6.0f}}
|
||
|
|
};
|
||
|
|
Trade::MeshData a{MeshPrimitive::Points, {}, vertexDataA, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::stridedArrayView(vertexDataA,
|
||
|
|
&vertexDataA[0].texcoords1, 2, sizeof(VertexDataA))},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::stridedArrayView(vertexDataA,
|
||
|
|
&vertexDataA[0].texcoords2, 2, sizeof(VertexDataA))},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::stridedArrayView(vertexDataA,
|
||
|
|
&vertexDataA[0].position, 2, sizeof(VertexDataA))},
|
||
|
|
}};
|
||
|
|
|
||
|
|
/* Second is indexed, has only one texture coordinate of the two, an extra
|
||
|
|
color (which gets ignored) and misses the position (which will be
|
||
|
|
zero-filled) */
|
||
|
|
const struct VertexDataB {
|
||
|
|
Color4 color;
|
||
|
|
Vector2 texcoords1;
|
||
|
|
} vertexDataB[]{
|
||
|
|
{0x112233_rgbf, {0.15f, 0.25f}},
|
||
|
|
{0x445566_rgbf, {0.35f, 0.45f}},
|
||
|
|
{0x778899_rgbf, {0.55f, 0.65f}},
|
||
|
|
{0xaabbcc_rgbf, {0.75f, 0.85f}}
|
||
|
|
};
|
||
|
|
const UnsignedShort indicesB[]{0, 2, 1, 0, 3, 2};
|
||
|
|
Trade::MeshData b{MeshPrimitive::Points,
|
||
|
|
{}, indicesB, Trade::MeshIndexData{indicesB}, {}, vertexDataB, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
|
||
|
|
Containers::stridedArrayView(vertexDataB,
|
||
|
|
&vertexDataB[0].color, 4, sizeof(VertexDataB))},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::stridedArrayView(vertexDataB,
|
||
|
|
&vertexDataB[0].texcoords1, 4, sizeof(VertexDataB))},
|
||
|
|
}};
|
||
|
|
|
||
|
|
/* Third is again non-indexed, has one texcoord attribute more (which will
|
||
|
|
get ignored). Additionally, attribute memory order is inversed and mixed
|
||
|
|
together to verify the attributes are picked based on declaration order,
|
||
|
|
not memory order. */
|
||
|
|
const struct VertexDataC {
|
||
|
|
Vector2 texcoords2;
|
||
|
|
Vector3 position;
|
||
|
|
Vector2 texcoords3;
|
||
|
|
Vector2 texcoords1;
|
||
|
|
} vertexDataC[]{
|
||
|
|
{{0.425f, 0.475f}, {1.5f, 2.5f, 3.5f}, {0.725f, 0.775f}, {0.125f, 0.175f}},
|
||
|
|
{{0.525f, 0.575f}, {4.5f, 5.5f, 6.5f}, {0.825f, 0.875f}, {0.225f, 0.275f}},
|
||
|
|
{{0.625f, 0.675f}, {7.5f, 8.5f, 9.5f}, {0.925f, 0.975f}, {0.325f, 0.375f}},
|
||
|
|
};
|
||
|
|
Trade::MeshData c{MeshPrimitive::Points, {}, vertexDataC, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::stridedArrayView(vertexDataC,
|
||
|
|
&vertexDataC[0].texcoords1, 3, sizeof(VertexDataC))},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::stridedArrayView(vertexDataC,
|
||
|
|
&vertexDataC[0].position, 3, sizeof(VertexDataC))},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::stridedArrayView(vertexDataC,
|
||
|
|
&vertexDataC[0].texcoords2, 3, sizeof(VertexDataC))},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::stridedArrayView(vertexDataC,
|
||
|
|
&vertexDataC[0].texcoords3, 3, sizeof(VertexDataC))},
|
||
|
|
}};
|
||
|
|
|
||
|
|
Trade::MeshData dst = MeshTools::concatenate(a, {b, c});
|
||
|
|
CORRADE_COMPARE(dst.primitive(), MeshPrimitive::Points);
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 3);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector3>(Trade::MeshAttribute::Position),
|
||
|
|
Containers::arrayView<Vector3>({
|
||
|
|
{1.0f, 2.0f, 3.0f},
|
||
|
|
{4.0f, 5.0f, 6.0f},
|
||
|
|
{}, {}, {}, {}, /* Missing in the second mesh */
|
||
|
|
{1.5f, 2.5f, 3.5f},
|
||
|
|
{4.5f, 5.5f, 6.5f},
|
||
|
|
{7.5f, 8.5f, 9.5f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates),
|
||
|
|
Containers::arrayView<Vector2>({
|
||
|
|
{0.1f, 0.2f},
|
||
|
|
{0.3f, 0.4f},
|
||
|
|
{0.15f, 0.25f},
|
||
|
|
{0.35f, 0.45f},
|
||
|
|
{0.55f, 0.65f},
|
||
|
|
{0.75f, 0.85f},
|
||
|
|
{0.125f, 0.175f},
|
||
|
|
{0.225f, 0.275f},
|
||
|
|
{0.325f, 0.375f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates, 1),
|
||
|
|
Containers::arrayView<Vector2>({
|
||
|
|
{0.5f, 0.6f},
|
||
|
|
{0.7f, 0.8f},
|
||
|
|
{}, {}, {}, {}, /* Missing in the second mesh */
|
||
|
|
{0.425f, 0.475f},
|
||
|
|
{0.525f, 0.575f},
|
||
|
|
{0.625f, 0.675f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_VERIFY(dst.isIndexed());
|
||
|
|
CORRADE_COMPARE(dst.indexType(), MeshIndexType::UnsignedInt);
|
||
|
|
CORRADE_COMPARE_AS(dst.indices<UnsignedInt>(),
|
||
|
|
Containers::arrayView<UnsignedInt>({
|
||
|
|
0, 1, /* implicit for the first nonindexed mesh */
|
||
|
|
2, 4, 3, 2, 5, 4, /* offset for the second indexed mesh */
|
||
|
|
6, 7, 8 /* implicit + offset for the third mesh */
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
|
||
|
|
/* The original interleaved layout should be preserved */
|
||
|
|
CORRADE_VERIFY(isInterleaved(dst));
|
||
|
|
CORRADE_COMPARE(dst.attributeStride(0), sizeof(VertexDataA));
|
||
|
|
CORRADE_COMPARE(dst.attributeOffset(0), 0);
|
||
|
|
CORRADE_COMPARE(dst.attributeOffset(1), sizeof(Vector2));
|
||
|
|
CORRADE_COMPARE(dst.attributeOffset(2), 2*sizeof(Vector2) + 4);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateNotIndexed() {
|
||
|
|
const Vector3 positionA[]{
|
||
|
|
{1.0f, 2.0f, 3.0f},
|
||
|
|
{4.0f, 5.0f, 6.0f}
|
||
|
|
};
|
||
|
|
Trade::MeshData a{MeshPrimitive::Points, {}, positionA, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::arrayView(positionA)}
|
||
|
|
}};
|
||
|
|
|
||
|
|
const Vector3 positionB[]{
|
||
|
|
{1.5f, 2.5f, 3.5f},
|
||
|
|
{4.5f, 5.5f, 6.5f},
|
||
|
|
{7.5f, 8.5f, 9.5f},
|
||
|
|
};
|
||
|
|
Trade::MeshData b{MeshPrimitive::Points, {}, positionB, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::arrayView(positionB)}
|
||
|
|
}};
|
||
|
|
|
||
|
|
Trade::MeshData dst = MeshTools::concatenate(a, {b, b});
|
||
|
|
CORRADE_COMPARE(dst.primitive(), MeshPrimitive::Points);
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 1);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector3>(Trade::MeshAttribute::Position),
|
||
|
|
Containers::arrayView<Vector3>({
|
||
|
|
{1.0f, 2.0f, 3.0f},
|
||
|
|
{4.0f, 5.0f, 6.0f},
|
||
|
|
{1.5f, 2.5f, 3.5f},
|
||
|
|
{4.5f, 5.5f, 6.5f},
|
||
|
|
{7.5f, 8.5f, 9.5f},
|
||
|
|
{1.5f, 2.5f, 3.5f},
|
||
|
|
{4.5f, 5.5f, 6.5f},
|
||
|
|
{7.5f, 8.5f, 9.5f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_VERIFY(!dst.isIndexed());
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateNoAttributes() {
|
||
|
|
/* Compared to concatenate(), now the first and last is indexed */
|
||
|
|
const UnsignedShort indicesA[]{1, 0};
|
||
|
|
Trade::MeshData a{MeshPrimitive::Points, {}, indicesA, Trade::MeshIndexData{indicesA}, 2};
|
||
|
|
|
||
|
|
/* Second is not indexed, just a vertex count */
|
||
|
|
Trade::MeshData b{MeshPrimitive::Points, 6};
|
||
|
|
|
||
|
|
const UnsignedByte indicesC[]{1, 0, 1, 0};
|
||
|
|
Trade::MeshData c{MeshPrimitive::Points, {}, indicesC, Trade::MeshIndexData{indicesC}, 2};
|
||
|
|
|
||
|
|
Trade::MeshData dst = MeshTools::concatenate(a, {b, c});
|
||
|
|
CORRADE_COMPARE(dst.primitive(), MeshPrimitive::Points);
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 0);
|
||
|
|
CORRADE_COMPARE(dst.vertexCount(), 10);
|
||
|
|
CORRADE_VERIFY(!dst.vertexData());
|
||
|
|
CORRADE_VERIFY(dst.isIndexed());
|
||
|
|
CORRADE_COMPARE(dst.indexType(), MeshIndexType::UnsignedInt);
|
||
|
|
CORRADE_COMPARE_AS(dst.indices<UnsignedInt>(),
|
||
|
|
Containers::arrayView<UnsignedInt>({
|
||
|
|
1, 0,
|
||
|
|
2, 3, 4, 5, 6, 7,
|
||
|
|
9, 8, 9, 8
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateNoAttributesNotIndexed() {
|
||
|
|
Trade::MeshData a{MeshPrimitive::Points, 3};
|
||
|
|
Trade::MeshData b{MeshPrimitive::Points, 6};
|
||
|
|
Trade::MeshData c{MeshPrimitive::Points, 2};
|
||
|
|
|
||
|
|
Trade::MeshData dst = MeshTools::concatenate(a, {b, c});
|
||
|
|
CORRADE_COMPARE(dst.primitive(), MeshPrimitive::Points);
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 0);
|
||
|
|
CORRADE_COMPARE(dst.vertexCount(), 11);
|
||
|
|
CORRADE_VERIFY(!dst.vertexData());
|
||
|
|
CORRADE_VERIFY(!dst.isIndexed());
|
||
|
|
}
|
||
|
|
|
||
|
|
/* MSVC 2015 doesn't like unnamed bitfields in local structs, so thhis has to
|
||
|
|
be outside */
|
||
|
|
struct VertexDataNonInterleaved {
|
||
|
|
Vector2 texcoords1[2];
|
||
|
|
Vector2 texcoords2[2];
|
||
|
|
Int:32;
|
||
|
|
Int:32;
|
||
|
|
Vector3 position[2];
|
||
|
|
};
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateOne() {
|
||
|
|
const VertexDataNonInterleaved vertexData[]{{
|
||
|
|
{{0.1f, 0.2f},
|
||
|
|
{0.3f, 0.4f}},
|
||
|
|
{{0.5f, 0.6f},
|
||
|
|
{0.7f, 0.8f}},
|
||
|
|
{{1.0f, 2.0f, 3.0f},
|
||
|
|
{4.0f, 5.0f, 6.0f}}
|
||
|
|
}};
|
||
|
|
const UnsignedByte indices[]{1, 0, 1};
|
||
|
|
Trade::MeshData a{MeshPrimitive::Points,
|
||
|
|
{}, indices, Trade::MeshIndexData{indices}, {}, vertexData, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::arrayView(vertexData[0].texcoords1)},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::TextureCoordinates,
|
||
|
|
Containers::arrayView(vertexData[0].texcoords2)},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::arrayView(vertexData[0].position)},
|
||
|
|
}};
|
||
|
|
|
||
|
|
Trade::MeshData dst = MeshTools::concatenate(a);
|
||
|
|
CORRADE_COMPARE(dst.primitive(), MeshPrimitive::Points);
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 3);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector3>(Trade::MeshAttribute::Position),
|
||
|
|
Containers::arrayView<Vector3>({
|
||
|
|
{1.0f, 2.0f, 3.0f},
|
||
|
|
{4.0f, 5.0f, 6.0f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates),
|
||
|
|
Containers::arrayView<Vector2>({
|
||
|
|
{0.1f, 0.2f},
|
||
|
|
{0.3f, 0.4f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::TextureCoordinates, 1),
|
||
|
|
Containers::arrayView<Vector2>({
|
||
|
|
{0.5f, 0.6f},
|
||
|
|
{0.7f, 0.8f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_VERIFY(dst.isIndexed());
|
||
|
|
CORRADE_COMPARE(dst.indexType(), MeshIndexType::UnsignedInt);
|
||
|
|
CORRADE_COMPARE_AS(dst.indices<UnsignedInt>(),
|
||
|
|
Containers::arrayView<UnsignedInt>({
|
||
|
|
1, 0, 1
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
|
||
|
|
/* The mesh should get interleaved (w/o gaps) and owned */
|
||
|
|
CORRADE_VERIFY(isInterleaved(dst));
|
||
|
|
CORRADE_COMPARE(dst.attributeStride(0), 2*sizeof(Vector2) + sizeof(Vector3));
|
||
|
|
CORRADE_COMPARE(dst.indexDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable);
|
||
|
|
CORRADE_COMPARE(dst.vertexDataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateOneRvalue() {
|
||
|
|
Containers::Array<char> vertexData{sizeof(Vector2)*4};
|
||
|
|
auto positions = Containers::arrayCast<Vector2>(vertexData);
|
||
|
|
Containers::Array<char> indexData{sizeof(UnsignedInt)*6};
|
||
|
|
auto indices = Containers::arrayCast<UnsignedInt>(indexData);
|
||
|
|
Trade::MeshAttributeData attributeData[]{
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, positions}
|
||
|
|
};
|
||
|
|
|
||
|
|
/* The result should be just a pass-through, as both index and vertex data
|
||
|
|
are already owned */
|
||
|
|
Trade::MeshData dst = MeshTools::concatenate(Trade::MeshData{
|
||
|
|
MeshPrimitive::Triangles,
|
||
|
|
std::move(indexData), Trade::MeshIndexData{indices},
|
||
|
|
std::move(vertexData), Trade::meshAttributeDataNonOwningArray(attributeData)},
|
||
|
|
/* Explicitly pass an empty init list to ensure this overload is
|
||
|
|
covered as well */
|
||
|
|
std::initializer_list<Containers::Reference<const Trade::MeshData>>{});
|
||
|
|
CORRADE_COMPARE(dst.indexData().data(), static_cast<void*>(indices.data()));
|
||
|
|
CORRADE_COMPARE(dst.vertexData().data(), static_cast<void*>(positions.data()));
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateInto() {
|
||
|
|
Containers::Array<Trade::MeshAttributeData> attributeData{2};
|
||
|
|
Containers::Array<char> vertexData;
|
||
|
|
Containers::Array<char> indexData;
|
||
|
|
arrayResize(vertexData, Containers::DirectInit, (sizeof(Vector2) + sizeof(Vector3))*7, '\xff');
|
||
|
|
arrayResize(vertexData, 0);
|
||
|
|
arrayResize(indexData, Containers::DirectInit, sizeof(UnsignedInt)*9, '\xff');
|
||
|
|
arrayResize(indexData, 0);
|
||
|
|
const void* attributeDataPointer = attributeData;
|
||
|
|
const void* vertexDataPointer = vertexData;
|
||
|
|
const void* indexDataPointer = indexData;
|
||
|
|
|
||
|
|
attributeData[0] = Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
VertexFormat::Vector2, nullptr};
|
||
|
|
attributeData[1] = Trade::MeshAttributeData{Trade::MeshAttribute::Normal,
|
||
|
|
VertexFormat::Vector3, nullptr};
|
||
|
|
Trade::MeshIndexData indices{MeshIndexType::UnsignedInt, indexData};
|
||
|
|
Trade::MeshData dst{MeshPrimitive::Triangles,
|
||
|
|
std::move(indexData), indices,
|
||
|
|
std::move(vertexData), std::move(attributeData)};
|
||
|
|
|
||
|
|
const Vector2 positionsA[]{
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{-1.0f, 1.0f},
|
||
|
|
{ 1.0f, 1.0f}
|
||
|
|
};
|
||
|
|
const UnsignedShort indicesA[]{
|
||
|
|
0, 1, 2, 2, 1, 3
|
||
|
|
};
|
||
|
|
Trade::MeshData a{MeshPrimitive::Triangles,
|
||
|
|
{}, indicesA, Trade::MeshIndexData{indicesA},
|
||
|
|
{}, positionsA, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::arrayView(positionsA)}
|
||
|
|
}};
|
||
|
|
|
||
|
|
const Vector2 positionsB[]{
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{ 0.0f, 1.0f}
|
||
|
|
};
|
||
|
|
Trade::MeshData b{MeshPrimitive::Triangles,
|
||
|
|
{}, positionsB, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::arrayView(positionsB)}
|
||
|
|
}};
|
||
|
|
|
||
|
|
MeshTools::concatenateInto(dst, {a, b});
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 2);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::Position),
|
||
|
|
Containers::arrayView<Vector2>({
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{-1.0f, 1.0f},
|
||
|
|
{ 1.0f, 1.0f},
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{ 0.0f, 1.0f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
/* The normal isn't present in any attribute and thus should be zeroed out
|
||
|
|
(*not* the whatever garbage present there from before) */
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector3>(Trade::MeshAttribute::Normal),
|
||
|
|
Containers::arrayView<Vector3>({
|
||
|
|
{}, {}, {}, {}, {}, {}, {}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
CORRADE_VERIFY(dst.isIndexed());
|
||
|
|
CORRADE_COMPARE_AS(dst.indices<UnsignedInt>(),
|
||
|
|
Containers::arrayView<UnsignedInt>({
|
||
|
|
0, 1, 2, 2, 1, 3,
|
||
|
|
4, 5, 6
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
|
||
|
|
/* Verify that no reallocation happened */
|
||
|
|
CORRADE_COMPARE(dst.attributeData().size(), 2);
|
||
|
|
CORRADE_COMPARE(dst.attributeData().data(), attributeDataPointer);
|
||
|
|
CORRADE_COMPARE(dst.vertexData().size(), 7*(sizeof(Vector2) + sizeof(Vector3)));
|
||
|
|
CORRADE_COMPARE(dst.vertexData().data(), vertexDataPointer);
|
||
|
|
CORRADE_COMPARE(dst.indexData().size(), 9*sizeof(UnsignedInt));
|
||
|
|
CORRADE_COMPARE(dst.indexData().data(), indexDataPointer);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateIntoNoIndexArray() {
|
||
|
|
Containers::Array<Trade::MeshAttributeData> attributeData{1};
|
||
|
|
Containers::Array<char> vertexData;
|
||
|
|
Containers::Array<char> indexData;
|
||
|
|
arrayReserve(vertexData, sizeof(Vector2)*3);
|
||
|
|
arrayReserve(indexData, sizeof(UnsignedInt));
|
||
|
|
const void* attributeDataPointer = attributeData;
|
||
|
|
const void* vertexDataPointer = vertexData;
|
||
|
|
|
||
|
|
attributeData[0] = Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
VertexFormat::Vector2, nullptr};
|
||
|
|
Trade::MeshIndexData indices{MeshIndexType::UnsignedInt, indexData};
|
||
|
|
Trade::MeshData dst{MeshPrimitive::Triangles,
|
||
|
|
std::move(indexData), indices,
|
||
|
|
std::move(vertexData), std::move(attributeData)};
|
||
|
|
CORRADE_VERIFY(dst.isIndexed());
|
||
|
|
|
||
|
|
const Vector2 positions[]{
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{ 0.0f, 1.0f}
|
||
|
|
};
|
||
|
|
Trade::MeshData a{MeshPrimitive::Triangles,
|
||
|
|
{}, positions, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::arrayView(positions)}
|
||
|
|
}};
|
||
|
|
|
||
|
|
MeshTools::concatenateInto(dst, {a});
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 1);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::Position),
|
||
|
|
Containers::arrayView<Vector2>({
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{ 0.0f, 1.0f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
|
||
|
|
/* The index array gets removed, but no reallocation happens for the other
|
||
|
|
two */
|
||
|
|
CORRADE_VERIFY(!dst.isIndexed());
|
||
|
|
CORRADE_COMPARE(dst.attributeData().size(), 1);
|
||
|
|
CORRADE_COMPARE(dst.attributeData().data(), attributeDataPointer);
|
||
|
|
CORRADE_COMPARE(dst.vertexData().size(), 3*sizeof(Vector2));
|
||
|
|
CORRADE_COMPARE(dst.vertexData().data(), vertexDataPointer);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateIntoNonOwnedAttributeArray() {
|
||
|
|
Containers::Array<char> vertexData;
|
||
|
|
arrayReserve(vertexData, sizeof(Vector2)*3);
|
||
|
|
const void* vertexDataPointer = vertexData;
|
||
|
|
|
||
|
|
const Trade::MeshAttributeData attributeData[]{
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
VertexFormat::Vector2, nullptr}
|
||
|
|
};
|
||
|
|
Trade::MeshData dst{MeshPrimitive::Triangles,
|
||
|
|
std::move(vertexData), Trade::meshAttributeDataNonOwningArray(attributeData)};
|
||
|
|
|
||
|
|
const Vector2 positions[]{
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{ 0.0f, 1.0f}
|
||
|
|
};
|
||
|
|
Trade::MeshData a{MeshPrimitive::Triangles,
|
||
|
|
{}, positions, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
Containers::arrayView(positions)}
|
||
|
|
}};
|
||
|
|
|
||
|
|
MeshTools::concatenateInto(dst, {a});
|
||
|
|
CORRADE_COMPARE(dst.attributeCount(), 1);
|
||
|
|
CORRADE_COMPARE_AS(dst.attribute<Vector2>(Trade::MeshAttribute::Position),
|
||
|
|
Containers::arrayView<Vector2>({
|
||
|
|
{-1.0f, -1.0f},
|
||
|
|
{ 1.0f, -1.0f},
|
||
|
|
{ 0.0f, 1.0f}
|
||
|
|
}), TestSuite::Compare::Container);
|
||
|
|
|
||
|
|
/* Reallocation happens only for the attribute data as it's not owned */
|
||
|
|
CORRADE_VERIFY(!dst.isIndexed());
|
||
|
|
CORRADE_COMPARE(dst.attributeData().size(), 1);
|
||
|
|
CORRADE_VERIFY(dst.attributeData().data() != attributeData);
|
||
|
|
CORRADE_COMPARE(dst.vertexData().size(), 3*sizeof(Vector2));
|
||
|
|
CORRADE_COMPARE(dst.vertexData().data(), vertexDataPointer);
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateUnsupportedPrimitive() {
|
||
|
|
Trade::MeshData a{MeshPrimitive::TriangleStrip, 0};
|
||
|
|
|
||
|
|
std::ostringstream out;
|
||
|
|
Error redirectError{&out};
|
||
|
|
MeshTools::concatenate(a);
|
||
|
|
MeshTools::concatenateInto(a, {a});
|
||
|
|
CORRADE_COMPARE(out.str(),
|
||
|
|
"MeshTools::concatenate(): MeshPrimitive::TriangleStrip is not supported, turn it into a plain indexed mesh first\n"
|
||
|
|
"MeshTools::concatenateInto(): MeshPrimitive::TriangleStrip is not supported, turn it into a plain indexed mesh first\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateInconsistentPrimitive() {
|
||
|
|
/* Things are a bit duplicated to test correct numbering */
|
||
|
|
Trade::MeshData a{MeshPrimitive::Triangles, 0};
|
||
|
|
Trade::MeshData b{MeshPrimitive::Lines, 0};
|
||
|
|
|
||
|
|
std::ostringstream out;
|
||
|
|
Error redirectError{&out};
|
||
|
|
MeshTools::concatenate(a, {a, b});
|
||
|
|
MeshTools::concatenateInto(a, {a, b});
|
||
|
|
CORRADE_COMPARE(out.str(),
|
||
|
|
"MeshTools::concatenate(): expected MeshPrimitive::Triangles but got MeshPrimitive::Lines in mesh 1\n"
|
||
|
|
"MeshTools::concatenateInto(): expected MeshPrimitive::Triangles but got MeshPrimitive::Lines in mesh 1\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateInconsistentAttributeType() {
|
||
|
|
/* Things are a bit duplicated to test correct numbering */
|
||
|
|
Trade::MeshData a{MeshPrimitive::Lines, nullptr, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
VertexFormat::Vector3, nullptr},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
VertexFormat::Vector3, nullptr},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
|
||
|
|
VertexFormat::Vector3ubNormalized, nullptr}
|
||
|
|
}};
|
||
|
|
Trade::MeshData b{MeshPrimitive::Lines, nullptr, {
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position,
|
||
|
|
VertexFormat::Vector3, nullptr},
|
||
|
|
Trade::MeshAttributeData{Trade::MeshAttribute::Color,
|
||
|
|
VertexFormat::Vector3usNormalized, nullptr}
|
||
|
|
}};
|
||
|
|
|
||
|
|
std::ostringstream out;
|
||
|
|
Error redirectError{&out};
|
||
|
|
MeshTools::concatenate(a, {a, a, a, b});
|
||
|
|
MeshTools::concatenateInto(a, {a, a, a, b});
|
||
|
|
CORRADE_COMPARE(out.str(),
|
||
|
|
"MeshTools::concatenate(): expected VertexFormat::Vector3ubNormalized for attribute 2 (Trade::MeshAttribute::Color) but got VertexFormat::Vector3usNormalized in mesh 3 attribute 1\n"
|
||
|
|
"MeshTools::concatenateInto(): expected VertexFormat::Vector3ubNormalized for attribute 2 (Trade::MeshAttribute::Color) but got VertexFormat::Vector3usNormalized in mesh 3 attribute 1\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
void ConcatenateTest::concatenateIntoNoMeshes() {
|
||
|
|
Trade::MeshData destination{MeshPrimitive::Triangles, 0};
|
||
|
|
|
||
|
|
std::ostringstream out;
|
||
|
|
Error redirectError{&out};
|
||
|
|
MeshTools::concatenateInto(destination, {});
|
||
|
|
CORRADE_COMPARE(out.str(), "MeshTools::concatenateInto(): no meshes passed\n");
|
||
|
|
}
|
||
|
|
|
||
|
|
}}}}
|
||
|
|
|
||
|
|
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::ConcatenateTest)
|