mirror of https://github.com/mosra/magnum.git
Browse Source
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
4 changed files with 521 additions and 1 deletions
@ -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 |
||||
@ -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…
Reference in new issue