Browse Source

Trade: internal tool for creating SceneData out of loose views.

To become the central piece of an upcoming SceneTools library, now I
need it just to implement duplication of objects that have more than one
mesh/light/camera/... assignment.
pull/525/head
Vladimír Vondruš 5 years ago
parent
commit
b192c4c3a3
  1. 3
      src/Magnum/Trade/CMakeLists.txt
  2. 193
      src/Magnum/Trade/Implementation/sceneTools.h
  3. 2
      src/Magnum/Trade/Test/CMakeLists.txt
  4. 324
      src/Magnum/Trade/Test/SceneToolsTest.cpp

3
src/Magnum/Trade/CMakeLists.txt

@ -76,7 +76,8 @@ set(MagnumTrade_HEADERS
set(MagnumTrade_PRIVATE_HEADERS
Implementation/arrayUtilities.h
Implementation/converterUtilities.h
Implementation/materialAttributeProperties.hpp)
Implementation/materialAttributeProperties.hpp
Implementation/sceneTools.h)
if(MAGNUM_BUILD_DEPRECATED)
list(APPEND MagnumTrade_SRCS

193
src/Magnum/Trade/Implementation/sceneTools.h

@ -0,0 +1,193 @@
#ifndef Magnum_Trade_Implementation_sceneTools_h
#define Magnum_Trade_Implementation_sceneTools_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 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 <unordered_map>
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Math/PackingBatch.h"
#include "Magnum/Trade/SceneData.h"
namespace Magnum { namespace Trade { namespace Implementation {
/* These two are needed because there (obviously) isn't any overload of
castInto with the same input and output type */
template<class T, class U> void copyOrCastInto(const Containers::StridedArrayView1D<const T>& src, const Containers::StridedArrayView1D<U>& dst) {
Math::castInto(Containers::arrayCast<2, const T>(src), Containers::arrayCast<2, U>(dst));
}
template<class T> void copyOrCastInto(const Containers::StridedArrayView1D<const T>& src, const Containers::StridedArrayView1D<T>& dst) {
Utility::copy(src, dst);
}
template<class T> void sceneCombineCopyObjects(const Containers::ArrayView<const SceneFieldData> fields, const Containers::ArrayView<const Containers::StridedArrayView2D<char>> itemViews, const Containers::ArrayView<const Containers::Pair<UnsignedInt, UnsignedInt>> itemViewMappings) {
std::size_t latestMapping = 0;
for(std::size_t i = 0; i != fields.size(); ++i) {
/* If there are no aliased object mappings, itemViewMappings should be
monotonically increasing. If it's not, it means the mapping is
shared with something earlier and it got already copied -- skip. */
const std::size_t mapping = itemViewMappings[i].first();
if(i && mapping <= latestMapping) continue;
latestMapping = mapping;
/* If the field has null object data, no need to copy anything. This
covers reserved fields but also fields of zero size. */
if(!fields[i].objectData()) continue;
const Containers::StridedArrayView1D<const void> src = fields[i].objectData();
const Containers::StridedArrayView1D<T> dst = Containers::arrayCast<1, T>(itemViews[mapping]);
if(fields[i].objectType() == SceneObjectType::UnsignedByte)
copyOrCastInto(Containers::arrayCast<const UnsignedByte>(src), dst);
else if(fields[i].objectType() == SceneObjectType::UnsignedShort)
copyOrCastInto(Containers::arrayCast<const UnsignedShort>(src), dst);
else if(fields[i].objectType() == SceneObjectType::UnsignedInt)
copyOrCastInto(Containers::arrayCast<const UnsignedInt>(src), dst);
else if(fields[i].objectType() == SceneObjectType::UnsignedLong)
copyOrCastInto(Containers::arrayCast<const UnsignedLong>(src), dst);
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
}
}
/* Combine fields of varying object type together into a SceneData of a single
given objectType. The fields are expected to point to existing object/field
memory, which will be then copied to the resulting scene. If you supply a
field with null object or field data, the object or field data will not get
copied, only a placeholder for copying the data later will be allocated. If
you however need to have placeholder object data shared among
Offset-only fields are not allowed.
The resulting fields are always tightly packed (not interleaved).
If multiple fields share the same object mapping views, those are preserved,
however they have to have the exact same length. Sharing object mappings
with different lengths will assert. */
/** @todo when published, add an initializer_list overload and turn all
internal asserts into (tested!) message asserts */
inline SceneData sceneCombine(const SceneObjectType objectType, const UnsignedLong objectCount, const Containers::ArrayView<const SceneFieldData> fields) {
const std::size_t objectTypeSize = sceneObjectTypeSize(objectType);
const std::size_t objectTypeAlignment = sceneObjectTypeAlignment(objectType);
/* Go through all fields and collect ArrayTuple allocations for these */
std::unordered_map<const void*, UnsignedInt> objectMappings;
Containers::Array<Containers::ArrayTuple::Item> items;
Containers::Array<Containers::Pair<UnsignedInt, UnsignedInt>> itemViewMappings{NoInit, fields.size()};
/* The item views are referenced from ArrayTuple::Item, not using a
growable array in order to avoid an accidental reallocation */
/** @todo once never-reallocating allocators are present, use them instead
of the manual offset */
Containers::Array<Containers::StridedArrayView2D<char>> itemViews{fields.size()*2};
std::size_t itemViewOffset = 0;
for(std::size_t i = 0; i != fields.size(); ++i) {
const SceneFieldData& field = fields[i];
CORRADE_INTERNAL_ASSERT(!field.isOffsetOnly());
/* Object data. Allocate if the view is a placeholder of if it wasn't
used by other fields yet. */
std::pair<std::unordered_map<const void*, UnsignedInt>::iterator, bool> inserted;
if(field.objectData().data())
inserted = objectMappings.emplace(field.objectData().data(), itemViewOffset);
if(field.objectData().data() && !inserted.second) {
itemViewMappings[i].first() = inserted.first->second;
/* Expect that fields sharing the same object mapping view have the
exact same length (the length gets stored in the output view
during the ArrayTuple::Item construction).
We could just ignore the sharing in that case, but that'd only
lead to misery down the line -- imagine a field that shares the
first two items with a mesh and a material object mapping. If it
would be the last, it gets duplicated and everything is great,
however if it's the first then both mesh and the material get
duplicated, and that then asserts inside the SceneData
constructor, as those are always expected to share.
One option that would solve this would be to store pointer+size
in the objectMappings map (and then only mappings that share
also the same size would be shared), another would be to use the
longest used view (and then the shorter prefixes would share
with it). The ultimate option would be to have some range map
where it'd be possible to locate also arbitrary subranges, not
just prefixes. A whole other topic altogether is checking for
the same stride, which is not done at all.
This might theoretically lead to assertions also when two
compile-time arrays share a common prefix and get deduplicated
by the compiler. But that's unlikely, at least for the internal
use case we have right now. */
CORRADE_INTERNAL_ASSERT(itemViews[inserted.first->second].size()[0] == field.size());
} else {
itemViewMappings[i].first() = itemViewOffset;
arrayAppend(items, InPlaceInit, NoInit, std::size_t(field.size()), objectTypeSize, objectTypeAlignment, itemViews[itemViewOffset]);
++itemViewOffset;
}
/* Field data. No aliasing here right now, no sharing between object
and field data either. */
/** @todo field aliasing might be useful at some point */
itemViewMappings[i].second() = itemViewOffset;
arrayAppend(items, InPlaceInit, NoInit, std::size_t(field.size()), sceneFieldTypeSize(field.fieldType())*(field.fieldArraySize() ? field.fieldArraySize() : 1), sceneFieldTypeAlignment(field.fieldType()), itemViews[itemViewOffset]);
++itemViewOffset;
}
/* Allocate the data */
Containers::Array<char> outData = Containers::ArrayTuple{items};
CORRADE_INTERNAL_ASSERT(!outData.deleter());
/* Copy the object data over and cast them as necessary */
if(objectType == SceneObjectType::UnsignedByte)
sceneCombineCopyObjects<UnsignedByte>(fields, itemViews, itemViewMappings);
else if(objectType == SceneObjectType::UnsignedShort)
sceneCombineCopyObjects<UnsignedShort>(fields, itemViews, itemViewMappings);
else if(objectType == SceneObjectType::UnsignedInt)
sceneCombineCopyObjects<UnsignedInt>(fields, itemViews, itemViewMappings);
else if(objectType == SceneObjectType::UnsignedLong)
sceneCombineCopyObjects<UnsignedLong>(fields, itemViews, itemViewMappings);
/* Copy the field data over. No special handling needed here. */
for(std::size_t i = 0; i != fields.size(); ++i) {
/* If the field has null field data, no need to copy anything. This
covers reserved fields but also fields of zero size. */
if(!fields[i].fieldData()) continue;
/** @todo isn't there some less awful way to create a 2D view, sigh */
Utility::copy(Containers::arrayCast<2, const char>(fields[i].fieldData(), sceneFieldTypeSize(fields[i].fieldType())*(fields[i].fieldArraySize() ? fields[i].fieldArraySize() : 1)), itemViews[itemViewMappings[i].second()]);
}
/* Map the fields to the new data */
Containers::Array<SceneFieldData> outFields{fields.size()};
for(std::size_t i = 0; i != fields.size(); ++i) {
outFields[i] = SceneFieldData{fields[i].name(), itemViews[itemViewMappings[i].first()], fields[i].fieldType(), itemViews[itemViewMappings[i].second()], fields[i].fieldArraySize()};
}
return SceneData{objectType, objectCount, std::move(outData), std::move(outFields)};
}
}}}
#endif

2
src/Magnum/Trade/Test/CMakeLists.txt

@ -59,6 +59,7 @@ corrade_add_test(TradePbrMetallicRoughnessMate___Test PbrMetallicRoughnessMateri
corrade_add_test(TradePbrSpecularGlossinessMat___Test PbrSpecularGlossinessMaterialDataTest.cpp LIBRARIES MagnumTradeTestLib)
corrade_add_test(TradePhongMaterialDataTest PhongMaterialDataTest.cpp LIBRARIES MagnumTradeTestLib)
corrade_add_test(TradeSceneDataTest SceneDataTest.cpp LIBRARIES MagnumTradeTestLib)
corrade_add_test(TradeSceneToolsTest SceneToolsTest.cpp LIBRARIES MagnumTrade)
corrade_add_test(TradeSkinDataTest SkinDataTest.cpp LIBRARIES MagnumTradeTestLib)
corrade_add_test(TradeTextureDataTest TextureDataTest.cpp LIBRARIES MagnumTrade)
@ -84,6 +85,7 @@ set_target_properties(
TradePbrSpecularGlossinessMat___Test
TradePhongMaterialDataTest
TradeSceneDataTest
TradeSceneToolsTest
TradeTextureDataTest
PROPERTIES FOLDER "Magnum/Trade/Test")

324
src/Magnum/Trade/Test/SceneToolsTest.cpp

@ -0,0 +1,324 @@
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021 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 <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
#include "Magnum/Math/Complex.h"
#include "Magnum/Math/Vector2.h"
#include "Magnum/Trade/Implementation/sceneTools.h"
namespace Magnum { namespace Trade { namespace Test { namespace {
struct SceneToolsTest: TestSuite::Tester {
explicit SceneToolsTest();
void combine();
void combineAlignment();
void combineObjectsShared();
void combineObjectsPlaceholderFieldPlaceholder();
void combineObjectSharedFieldPlaceholder();
};
struct {
const char* name;
SceneObjectType objectType;
} CombineData[]{
{"UnsignedByte output", SceneObjectType::UnsignedByte},
{"UnsignedShort output", SceneObjectType::UnsignedShort},
{"UnsignedInt output", SceneObjectType::UnsignedInt},
{"UnsignedLong output", SceneObjectType::UnsignedLong},
};
SceneToolsTest::SceneToolsTest() {
addInstancedTests({&SceneToolsTest::combine},
Containers::arraySize(CombineData));
addTests({&SceneToolsTest::combineAlignment,
&SceneToolsTest::combineObjectsShared,
&SceneToolsTest::combineObjectsPlaceholderFieldPlaceholder,
&SceneToolsTest::combineObjectSharedFieldPlaceholder});
}
using namespace Math::Literals;
void SceneToolsTest::combine() {
auto&& data = CombineData[testCaseInstanceId()];
setTestCaseDescription(data.name);
/* Testing the four possible object types, it should be possible to combine
them */
const UnsignedInt meshObjects[]{45, 78, 23};
const UnsignedByte meshes[]{3, 5, 17};
const UnsignedShort parentObjects[]{33, 25};
const Short parents[]{-1, 0};
const UnsignedByte translationObjects[]{16};
const Vector2d translations[]{{1.5, -0.5}};
const UnsignedLong fooObjects[]{15, 23};
const Int foos[]{0, 1, 2, 3};
SceneData scene = Implementation::sceneCombine(data.objectType, 167, Containers::arrayView({
SceneFieldData{SceneField::Mesh, Containers::arrayView(meshObjects), Containers::arrayView(meshes)},
SceneFieldData{SceneField::Parent, Containers::arrayView(parentObjects), Containers::arrayView(parents)},
SceneFieldData{SceneField::Translation, Containers::arrayView(translationObjects), Containers::arrayView(translations)},
/* Array field */
SceneFieldData{sceneFieldCustom(15), Containers::arrayView(fooObjects), Containers::StridedArrayView2D<const Int>{foos, {2, 2}}},
/* Empty field */
SceneFieldData{SceneField::Camera, Containers::ArrayView<const UnsignedByte>{}, Containers::ArrayView<const UnsignedShort>{}}
}));
CORRADE_COMPARE(scene.dataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(scene.objectType(), data.objectType);
CORRADE_COMPARE(scene.objectCount(), 167);
CORRADE_COMPARE(scene.fieldCount(), 5);
CORRADE_COMPARE(scene.fieldName(0), SceneField::Mesh);
CORRADE_COMPARE(scene.fieldType(0), SceneFieldType::UnsignedByte);
CORRADE_COMPARE(scene.fieldArraySize(0), 0);
CORRADE_COMPARE_AS(scene.objectsAsArray(0), Containers::arrayView<UnsignedInt>({
45, 78, 23
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<UnsignedByte>(0),
Containers::arrayView(meshes),
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.fieldName(1), SceneField::Parent);
CORRADE_COMPARE(scene.fieldType(1), SceneFieldType::Short);
CORRADE_COMPARE(scene.fieldArraySize(1), 0);
CORRADE_COMPARE_AS(scene.objectsAsArray(1), Containers::arrayView<UnsignedInt>({
33, 25
}), TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<Short>(1),
Containers::arrayView(parents),
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.fieldName(2), SceneField::Translation);
CORRADE_COMPARE(scene.fieldType(2), SceneFieldType::Vector2d);
CORRADE_COMPARE(scene.fieldArraySize(2), 0);
CORRADE_COMPARE_AS(scene.objectsAsArray(2),
Containers::arrayView<UnsignedInt>({16}),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<Vector2d>(2),
Containers::arrayView(translations),
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.fieldName(3), sceneFieldCustom(15));
CORRADE_COMPARE(scene.fieldType(3), SceneFieldType::Int);
CORRADE_COMPARE(scene.fieldArraySize(3), 2);
CORRADE_COMPARE_AS(scene.objectsAsArray(3),
Containers::arrayView<UnsignedInt>({15, 23}),
TestSuite::Compare::Container);
/** @todo clean up once it's possible to compare multidimensional
containers */
CORRADE_COMPARE_AS(scene.field<Int[]>(3)[0],
(Containers::StridedArrayView2D<const Int>{foos, {2, 2}})[0],
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<Int[]>(3)[1],
(Containers::StridedArrayView2D<const Int>{foos, {2, 2}})[1],
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.fieldName(4), SceneField::Camera);
CORRADE_COMPARE(scene.fieldType(4), SceneFieldType::UnsignedShort);
CORRADE_COMPARE(scene.fieldSize(4), 0);
CORRADE_COMPARE(scene.fieldArraySize(4), 0);
}
void SceneToolsTest::combineAlignment() {
const UnsignedShort meshObjects[]{15, 23, 47};
const UnsignedByte meshes[]{0, 1, 2};
const UnsignedShort translationObjects[]{5}; /* 1 byte padding before */
const Vector2d translations[]{{1.5, 3.0}}; /* 4 byte padding before */
SceneData scene = Implementation::sceneCombine(SceneObjectType::UnsignedShort, 167, Containers::arrayView({
SceneFieldData{SceneField::Mesh, Containers::arrayView(meshObjects), Containers::arrayView(meshes)},
SceneFieldData{SceneField::Translation, Containers::arrayView(translationObjects), Containers::arrayView(translations)}
}));
CORRADE_COMPARE(scene.dataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(scene.objectType(), SceneObjectType::UnsignedShort);
CORRADE_COMPARE(scene.objectCount(), 167);
CORRADE_COMPARE(scene.fieldCount(), 2);
CORRADE_COMPARE(scene.fieldName(0), SceneField::Mesh);
CORRADE_COMPARE(scene.fieldType(0), SceneFieldType::UnsignedByte);
CORRADE_COMPARE(scene.fieldArraySize(0), 0);
CORRADE_COMPARE_AS(scene.objects<UnsignedShort>(0),
Containers::arrayView(meshObjects),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<UnsignedByte>(0),
Containers::arrayView(meshes),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(reinterpret_cast<std::ptrdiff_t>(scene.objects(0).data()), 2, TestSuite::Compare::Divisible);
CORRADE_COMPARE(scene.objects(0).data(), scene.data());
CORRADE_COMPARE(scene.objects(0).stride()[0], 2);
CORRADE_COMPARE_AS(reinterpret_cast<std::ptrdiff_t>(scene.field(0).data()), 1, TestSuite::Compare::Divisible);
CORRADE_COMPARE(scene.field(0).data(), scene.data() + 3*2);
CORRADE_COMPARE(scene.field(0).stride()[0], 1);
CORRADE_COMPARE(scene.fieldName(1), SceneField::Translation);
CORRADE_COMPARE(scene.fieldType(1), SceneFieldType::Vector2d);
CORRADE_COMPARE(scene.fieldArraySize(1), 0);
CORRADE_COMPARE_AS(scene.objects<UnsignedShort>(1),
Containers::arrayView(translationObjects),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<Vector2d>(1),
Containers::arrayView(translations),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(reinterpret_cast<std::ptrdiff_t>(scene.objects(1).data()), 2, TestSuite::Compare::Divisible);
CORRADE_COMPARE(scene.objects(1).data(), scene.data() + 3*2 + 3 + 1);
CORRADE_COMPARE(scene.objects(1).stride()[0], 2);
CORRADE_COMPARE_AS(reinterpret_cast<std::ptrdiff_t>(scene.field(1).data()), 8, TestSuite::Compare::Divisible);
CORRADE_COMPARE(scene.field(1).data(), scene.data() + 3*2 + 3 + 1 + 2 + 4);
CORRADE_COMPARE(scene.field(1).stride()[0], 16);
}
void SceneToolsTest::combineObjectsShared() {
const UnsignedShort meshObjects[]{15, 23, 47};
const UnsignedByte meshes[]{0, 1, 2};
const Int meshMaterials[]{72, -1, 23};
const UnsignedShort translationRotationObjects[]{14, 22};
const Vector2 translations[]{{-1.0f, 25.3f}, {2.2f, 2.1f}};
const Complex rotations[]{Complex::rotation(35.0_degf), Complex::rotation(22.5_degf)};
SceneData scene = Implementation::sceneCombine(SceneObjectType::UnsignedInt, 173, Containers::arrayView({
/* Deliberately in an arbitrary order to avoid false assumptions like
fields sharing the same object mapping always being after each
other */
SceneFieldData{SceneField::Mesh, Containers::arrayView(meshObjects), Containers::arrayView(meshes)},
SceneFieldData{SceneField::Translation, Containers::arrayView(translationRotationObjects), Containers::arrayView(translations)},
SceneFieldData{SceneField::MeshMaterial, Containers::arrayView(meshObjects), Containers::arrayView(meshMaterials)},
SceneFieldData{SceneField::Rotation, Containers::arrayView(translationRotationObjects), Containers::arrayView(rotations)}
}));
CORRADE_COMPARE(scene.dataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(scene.objectType(), SceneObjectType::UnsignedInt);
CORRADE_COMPARE(scene.objectCount(), 173);
CORRADE_COMPARE(scene.fieldCount(), 4);
CORRADE_COMPARE(scene.fieldSize(SceneField::Mesh), 3);
CORRADE_COMPARE(scene.fieldSize(SceneField::MeshMaterial), 3);
CORRADE_COMPARE(scene.objects(SceneField::Mesh).data(), scene.objects(SceneField::MeshMaterial).data());
CORRADE_COMPARE(scene.fieldSize(SceneField::Translation), 2);
CORRADE_COMPARE(scene.fieldSize(SceneField::Rotation), 2);
CORRADE_COMPARE(scene.objects(SceneField::Translation).data(), scene.objects(SceneField::Rotation).data());
}
void SceneToolsTest::combineObjectsPlaceholderFieldPlaceholder() {
const UnsignedShort meshObjects[]{15, 23, 47};
const UnsignedByte meshes[]{0, 1, 2};
SceneData scene = Implementation::sceneCombine(SceneObjectType::UnsignedShort, 173, Containers::arrayView({
SceneFieldData{SceneField::Camera, Containers::ArrayView<UnsignedByte>{nullptr, 1}, Containers::ArrayView<UnsignedShort>{nullptr, 1}},
SceneFieldData{SceneField::Mesh, Containers::arrayView(meshObjects), Containers::arrayView(meshes)},
/* Looks like sharing object mapping with the Camera field, but
actually both are placeholders */
SceneFieldData{SceneField::Light, Containers::ArrayView<UnsignedShort>{nullptr, 2}, Containers::ArrayView<UnsignedInt>{nullptr, 2}},
/* Array field */
SceneFieldData{sceneFieldCustom(15), Containers::ArrayView<UnsignedShort>{nullptr, 2}, Containers::StridedArrayView2D<Short>{{nullptr, 16}, {2, 4}}},
}));
CORRADE_COMPARE(scene.dataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(scene.objectType(), SceneObjectType::UnsignedShort);
CORRADE_COMPARE(scene.objectCount(), 173);
CORRADE_COMPARE(scene.fieldCount(), 4);
CORRADE_COMPARE(scene.fieldType(SceneField::Camera), SceneFieldType::UnsignedShort);
CORRADE_COMPARE(scene.fieldSize(SceneField::Camera), 1);
CORRADE_COMPARE(scene.fieldArraySize(SceneField::Camera), 0);
CORRADE_COMPARE(scene.objects(SceneField::Camera).data(), scene.data());
CORRADE_COMPARE(scene.objects(SceneField::Camera).stride()[0], 2);
CORRADE_COMPARE(scene.field(SceneField::Camera).data(), scene.data() + 2);
CORRADE_COMPARE(scene.field(SceneField::Camera).stride()[0], 2);
CORRADE_COMPARE(scene.fieldType(SceneField::Mesh), SceneFieldType::UnsignedByte);
CORRADE_COMPARE(scene.fieldArraySize(SceneField::Mesh), 0);
CORRADE_COMPARE_AS(scene.objects<UnsignedShort>(SceneField::Mesh),
Containers::arrayView(meshObjects),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<UnsignedByte>(SceneField::Mesh),
Containers::arrayView(meshes),
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.fieldType(SceneField::Light), SceneFieldType::UnsignedInt);
CORRADE_COMPARE(scene.fieldSize(SceneField::Light), 2);
CORRADE_COMPARE(scene.fieldArraySize(SceneField::Light), 0);
CORRADE_COMPARE(scene.objects(SceneField::Light).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1);
CORRADE_COMPARE(scene.objects(SceneField::Light).stride()[0], 2);
CORRADE_COMPARE(scene.field(SceneField::Light).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2);
CORRADE_COMPARE(scene.field(SceneField::Light).stride()[0], 4);
CORRADE_COMPARE(scene.fieldType(sceneFieldCustom(15)), SceneFieldType::Short);
CORRADE_COMPARE(scene.fieldSize(sceneFieldCustom(15)), 2);
CORRADE_COMPARE(scene.fieldArraySize(sceneFieldCustom(15)), 4);
CORRADE_COMPARE(scene.objects(sceneFieldCustom(15)).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4);
CORRADE_COMPARE(scene.objects(sceneFieldCustom(15)).stride()[0], 2);
CORRADE_COMPARE(scene.field(sceneFieldCustom(15)).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4 + 2*2);
CORRADE_COMPARE(scene.field(sceneFieldCustom(15)).stride()[0], 4*2);
}
void SceneToolsTest::combineObjectSharedFieldPlaceholder() {
const UnsignedInt meshObjects[]{15, 23, 47};
const UnsignedByte meshes[]{0, 1, 2};
SceneData scene = Implementation::sceneCombine(SceneObjectType::UnsignedInt, 173, Containers::arrayView({
SceneFieldData{SceneField::Mesh, Containers::arrayView(meshObjects), Containers::arrayView(meshes)},
SceneFieldData{SceneField::MeshMaterial, Containers::arrayView(meshObjects), Containers::ArrayView<Int>{nullptr, 3}},
}));
CORRADE_COMPARE(scene.dataFlags(), DataFlag::Owned|DataFlag::Mutable);
CORRADE_COMPARE(scene.objectType(), SceneObjectType::UnsignedInt);
CORRADE_COMPARE(scene.objectCount(), 173);
CORRADE_COMPARE(scene.fieldCount(), 2);
CORRADE_COMPARE(scene.fieldType(SceneField::Mesh), SceneFieldType::UnsignedByte);
CORRADE_COMPARE(scene.fieldArraySize(SceneField::Mesh), 0);
CORRADE_COMPARE_AS(scene.objects<UnsignedInt>(0),
Containers::arrayView(meshObjects),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.field<UnsignedByte>(0),
Containers::arrayView(meshes),
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.fieldType(SceneField::MeshMaterial), SceneFieldType::Int);
CORRADE_COMPARE(scene.fieldSize(SceneField::MeshMaterial), 3);
CORRADE_COMPARE(scene.fieldArraySize(SceneField::MeshMaterial), 0);
CORRADE_COMPARE(scene.objects(SceneField::MeshMaterial).data(), scene.objects(SceneField::Mesh).data());
CORRADE_COMPARE_AS(scene.objects<UnsignedInt>(SceneField::MeshMaterial),
Containers::arrayView(meshObjects),
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.field(SceneField::MeshMaterial).data(), scene.data() + 3*4 + 3 + 1);
CORRADE_COMPARE(scene.field(SceneField::MeshMaterial).stride()[0], 4);
}
}}}}
CORRADE_TEST_MAIN(Magnum::Trade::Test::SceneToolsTest)
Loading…
Cancel
Save