mirror of https://github.com/mosra/magnum.git
Browse Source
To be used with the recently added MaterialTools::removeDuplicates() for example, or internally by other upcoming scene tools such as importer filtering.pull/168/head
8 changed files with 1195 additions and 2 deletions
@ -0,0 +1,66 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022, 2023 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/Containers/GrowableArray.h> |
||||||
|
#include <Corrade/Containers/Iterable.h> |
||||||
|
#include <Corrade/PluginManager/Manager.h> |
||||||
|
|
||||||
|
#include "Magnum/MaterialTools/RemoveDuplicates.h" |
||||||
|
#include "Magnum/SceneTools/Map.h" |
||||||
|
#include "Magnum/Trade/AbstractImporter.h" |
||||||
|
#include "Magnum/Trade/MaterialData.h" |
||||||
|
#include "Magnum/Trade/SceneData.h" |
||||||
|
|
||||||
|
#define DOXYGEN_ELLIPSIS(...) __VA_ARGS__ |
||||||
|
|
||||||
|
using namespace Magnum; |
||||||
|
|
||||||
|
int main() { |
||||||
|
{ |
||||||
|
/* -Wnonnull in GCC 11+ "helpfully" says "this is null" if I don't initialize
|
||||||
|
the font pointer. I don't care, I just want you to check compilation errors, |
||||||
|
not more! */ |
||||||
|
PluginManager::Manager<Trade::AbstractImporter> manager; |
||||||
|
/* [removeDuplicatesInPlace] */ |
||||||
|
Containers::Pointer<Trade::AbstractImporter> importer = DOXYGEN_ELLIPSIS(manager.loadAndInstantiate("SomethingWhatever")); |
||||||
|
|
||||||
|
/* Import all materials */ |
||||||
|
Containers::Array<Trade::MaterialData> materials; |
||||||
|
for(UnsignedInt i = 0; i != importer->materialCount(); ++i) |
||||||
|
arrayAppend(materials, *importer->material(i)); |
||||||
|
|
||||||
|
/* Remove duplicates, putting the unique materials to the prefix and removing
|
||||||
|
the rest */ |
||||||
|
Containers::Pair<Containers::Array<UnsignedInt>, std::size_t> mapping = |
||||||
|
MaterialTools::removeDuplicatesInPlace(materials); |
||||||
|
arrayRemoveSuffix(materials, materials.size() - mapping.second()); |
||||||
|
|
||||||
|
/* Apply the mapping to unique materials to the scene */ |
||||||
|
Trade::SceneData scene = DOXYGEN_ELLIPSIS(Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}}); |
||||||
|
SceneTools::mapIndexFieldInPlace(scene, |
||||||
|
Trade::SceneField::MeshMaterial, mapping.first()); |
||||||
|
/* [removeDuplicatesInPlace] */ |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,201 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022, 2023 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 "Map.h" |
||||||
|
|
||||||
|
#include <Corrade/Containers/Optional.h> |
||||||
|
|
||||||
|
#include "Magnum/Math/PackingBatch.h" |
||||||
|
#include "Magnum/SceneTools/Combine.h" |
||||||
|
#include "Magnum/Trade/SceneData.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace SceneTools { |
||||||
|
|
||||||
|
Trade::SceneData mapIndexField(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
CORRADE_ASSERT(fieldId < scene.fieldCount(), |
||||||
|
"SceneTools::mapIndexField(): index" << fieldId << "out of range for" << scene.fieldCount() << "fields", |
||||||
|
(Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}})); |
||||||
|
|
||||||
|
const Trade::SceneFieldType fieldType = scene.fieldType(fieldId); |
||||||
|
Containers::Array<Trade::SceneFieldData> fields{NoInit, scene.fieldCount()}; |
||||||
|
for(std::size_t i = 0; i != scene.fieldCount(); ++i) { |
||||||
|
if(i == fieldId) { |
||||||
|
CORRADE_ASSERT(scene.fieldArraySize(i) == 0, |
||||||
|
"SceneTools::mapIndexField(): array field mapping isn't supported", |
||||||
|
(Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}})); |
||||||
|
|
||||||
|
Trade::SceneFieldType outputFieldType; |
||||||
|
if(fieldType == Trade::SceneFieldType::UnsignedInt || |
||||||
|
fieldType == Trade::SceneFieldType::UnsignedShort || |
||||||
|
fieldType == Trade::SceneFieldType::UnsignedByte) |
||||||
|
outputFieldType = Trade::SceneFieldType::UnsignedInt; |
||||||
|
else if(fieldType == Trade::SceneFieldType::Int || |
||||||
|
fieldType == Trade::SceneFieldType::Short || |
||||||
|
fieldType == Trade::SceneFieldType::Byte) |
||||||
|
outputFieldType = Trade::SceneFieldType::Int; |
||||||
|
else CORRADE_ASSERT_UNREACHABLE("SceneTools::mapIndexField(): unsupported field type" << fieldType, |
||||||
|
(Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}})); |
||||||
|
|
||||||
|
fields[i] = Trade::SceneFieldData{scene.fieldName(i), |
||||||
|
scene.mapping(i), outputFieldType, |
||||||
|
Containers::StridedArrayView2D<const char>{{nullptr, ~std::size_t{}}, {scene.fieldSize(i), 4}}, |
||||||
|
/* We aren't removing any field entries from the scene nor
|
||||||
|
modifying the mapping in any way, so the flags can be passed |
||||||
|
through in full */ |
||||||
|
scene.fieldFlags(i)}; // TODO test flags
|
||||||
|
|
||||||
|
/* Otherwise grab the field in full. This will also convert offset-only
|
||||||
|
fields to absolute. */ |
||||||
|
} else fields[i] = scene.fieldData(i); |
||||||
|
} |
||||||
|
|
||||||
|
/* Create a new SceneData out of the unpacked index field and all others,
|
||||||
|
unpack its data into the placeholder location */ |
||||||
|
Trade::SceneData unpacked = combineFields(scene.mappingType(), scene.mappingBound(), fields); |
||||||
|
if(fieldType == Trade::SceneFieldType::UnsignedInt) |
||||||
|
Math::castInto(scene.field<UnsignedInt>(fieldId), |
||||||
|
unpacked.mutableField<UnsignedInt>(fieldId)); |
||||||
|
else if(fieldType == Trade::SceneFieldType::UnsignedShort) |
||||||
|
Math::castInto(scene.field<UnsignedShort>(fieldId), |
||||||
|
unpacked.mutableField<UnsignedInt>(fieldId)); |
||||||
|
else if(fieldType == Trade::SceneFieldType::UnsignedByte) |
||||||
|
Math::castInto(scene.field<UnsignedByte>(fieldId), |
||||||
|
unpacked.mutableField<UnsignedInt>(fieldId)); |
||||||
|
else if(fieldType == Trade::SceneFieldType::Int) |
||||||
|
Math::castInto(scene.field<Int>(fieldId), |
||||||
|
unpacked.mutableField<Int>(fieldId)); |
||||||
|
else if(fieldType == Trade::SceneFieldType::Short) |
||||||
|
Math::castInto(scene.field<Short>(fieldId), |
||||||
|
unpacked.mutableField<Int>(fieldId)); |
||||||
|
else if(fieldType == Trade::SceneFieldType::Byte) |
||||||
|
Math::castInto(scene.field<Byte>(fieldId), |
||||||
|
unpacked.mutableField<Int>(fieldId)); |
||||||
|
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ |
||||||
|
|
||||||
|
mapIndexFieldInPlace(unpacked, fieldId, mapping); |
||||||
|
return unpacked; |
||||||
|
} |
||||||
|
|
||||||
|
Trade::SceneData mapIndexField(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field); |
||||||
|
CORRADE_ASSERT(fieldId, |
||||||
|
"SceneTools::mapIndexField(): field" << field << "not found", |
||||||
|
(Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}})); |
||||||
|
|
||||||
|
return mapIndexField(scene, *fieldId, mapping); |
||||||
|
} |
||||||
|
|
||||||
|
Trade::SceneData mapIndexField(Trade::SceneData&& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
CORRADE_ASSERT(fieldId < scene.fieldCount(), |
||||||
|
"SceneTools::mapIndexField(): index" << fieldId << "out of range for" << scene.fieldCount() << "fields", |
||||||
|
(Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}})); |
||||||
|
|
||||||
|
/* Perform the operation in-place, if we can transfewr the ownership and
|
||||||
|
have the field in the target format already. There's currently no way to |
||||||
|
create a SceneData that's Owned but not Mutable so check for Owned is |
||||||
|
enough. */ |
||||||
|
if(scene.dataFlags() & Trade::DataFlag::Owned && |
||||||
|
(scene.fieldType(fieldId) == Trade::SceneFieldType::UnsignedInt || |
||||||
|
scene.fieldType(fieldId) == Trade::SceneFieldType::Int)) |
||||||
|
{ |
||||||
|
mapIndexFieldInPlace(scene, fieldId, mapping); |
||||||
|
return Utility::move(scene); |
||||||
|
} |
||||||
|
|
||||||
|
/* Otherwise delegate to the function that does all the copying and format
|
||||||
|
expansion */ |
||||||
|
return mapIndexField(scene, fieldId, mapping); |
||||||
|
} |
||||||
|
|
||||||
|
Trade::SceneData mapIndexField(Trade::SceneData&& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field); |
||||||
|
CORRADE_ASSERT(fieldId, |
||||||
|
"SceneTools::mapIndexField(): field" << field << "not found", |
||||||
|
(Trade::SceneData{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}})); |
||||||
|
|
||||||
|
// TODO test that it gets actually moved
|
||||||
|
return mapIndexField(Utility::move(scene), *fieldId, mapping); |
||||||
|
} |
||||||
|
|
||||||
|
namespace { |
||||||
|
|
||||||
|
template<class T> void mapImplementation(const Containers::StridedArrayView1D<T>& field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
for(T& i: field) { |
||||||
|
CORRADE_ASSERT(i < mapping.size(), |
||||||
|
"SceneTools::mapIndexFieldInPlace(): index" << i << "out of range for" << mapping.size() << "mapping values", ); |
||||||
|
CORRADE_ASSERT(mapping[i] < (1ull << sizeof(T)*8), |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value" << mapping[i] << "not representable in" << Trade::Implementation::SceneFieldTypeFor<T>::type(), ); |
||||||
|
i = mapping[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> void mapSignedImplementation(const Containers::StridedArrayView1D<T>& field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
for(T& i: field) { |
||||||
|
if(i == T(-1)) |
||||||
|
continue; |
||||||
|
|
||||||
|
CORRADE_ASSERT(UnsignedInt(i) < mapping.size(), |
||||||
|
"SceneTools::mapIndexFieldInPlace(): index" << i << "out of range for" << mapping.size() << "mapping values", ); |
||||||
|
CORRADE_ASSERT(mapping[i] >= 0 && mapping[i] < (1u << (sizeof(T)*8 - 1)), |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value" << mapping[i] << "not representable in" << Trade::Implementation::SceneFieldTypeFor<T>::type(), ); |
||||||
|
i = T(mapping[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void mapIndexFieldInPlace(Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
CORRADE_ASSERT(fieldId < scene.fieldCount(), |
||||||
|
"SceneTools::mapIndexFieldInPlace(): index" << fieldId << "out of range for" << scene.fieldCount() << "fields", ); |
||||||
|
CORRADE_ASSERT(scene.dataFlags() & Trade::DataFlag::Mutable, |
||||||
|
"SceneTools::mapIndexFieldInPlace(): data not mutable", ); |
||||||
|
CORRADE_ASSERT(scene.fieldArraySize(fieldId) == 0, |
||||||
|
"SceneTools::mapIndexFieldInPlace(): array field mapping isn't supported", ); |
||||||
|
|
||||||
|
const Trade::SceneFieldType fieldType = scene.fieldType(fieldId); |
||||||
|
if(fieldType == Trade::SceneFieldType::UnsignedInt) |
||||||
|
mapImplementation(scene.mutableField<UnsignedInt>(fieldId), mapping); |
||||||
|
else if(fieldType == Trade::SceneFieldType::UnsignedShort) |
||||||
|
mapImplementation(scene.mutableField<UnsignedShort>(fieldId), mapping); |
||||||
|
else if(fieldType == Trade::SceneFieldType::UnsignedByte) |
||||||
|
mapImplementation(scene.mutableField<UnsignedByte>(fieldId), mapping); |
||||||
|
else if(fieldType == Trade::SceneFieldType::Int) |
||||||
|
mapSignedImplementation(scene.mutableField<Int>(fieldId), mapping); |
||||||
|
else if(fieldType == Trade::SceneFieldType::Short) |
||||||
|
mapSignedImplementation(scene.mutableField<Short>(fieldId), mapping); |
||||||
|
else if(fieldType == Trade::SceneFieldType::Byte) |
||||||
|
mapSignedImplementation(scene.mutableField<Byte>(fieldId), mapping); |
||||||
|
else CORRADE_ASSERT_UNREACHABLE("SceneTools::mapIndexFieldInPlace(): unsupported field type" << fieldType, ); |
||||||
|
} |
||||||
|
|
||||||
|
void mapIndexFieldInPlace(Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping) { |
||||||
|
const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field); |
||||||
|
CORRADE_ASSERT(fieldId, |
||||||
|
"SceneTools::mapIndexFieldInPlace(): field" << field << "not found", ); |
||||||
|
|
||||||
|
return mapIndexFieldInPlace(scene, *fieldId, mapping); |
||||||
|
} |
||||||
|
|
||||||
|
}} |
||||||
@ -0,0 +1,145 @@ |
|||||||
|
#ifndef Magnum_SceneTools_Map_h |
||||||
|
#define Magnum_SceneTools_Map_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022, 2023 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. |
||||||
|
*/ |
||||||
|
|
||||||
|
/** @file
|
||||||
|
* @brief Function @ref Magnum::SceneTools::mapIndexField(), @ref Magnum::SceneTools::mapIndexFieldInPlace() |
||||||
|
* @m_since_latest |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "Magnum/SceneTools/visibility.h" |
||||||
|
#include "Magnum/Trade/Trade.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace SceneTools { |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Map an index field in a scene |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Maps a field containing data indices, such as @ref Trade::SceneField::Mesh or |
||||||
|
@ref Trade::SceneField::Camera, to different indices by iterating through the |
||||||
|
field at index @p fieldId and replacing a particular @cpp value @ce with |
||||||
|
@cpp mapping[value] @ce. If the field has a signed type (such as is the case |
||||||
|
with @ref Trade::SceneField::MeshMaterial), @cpp -1 @ce is treated as an |
||||||
|
"unset" value and preserved verbatim. |
||||||
|
|
||||||
|
Expects that @p fieldId is less than @ref Trade::SceneData::fieldCount(), the |
||||||
|
field is @ref Trade::SceneFieldType::UnsignedInt, |
||||||
|
@relativeref{Trade::SceneFieldType,Int}, @relativeref{Trade::SceneFieldType,UnsignedShort}, |
||||||
|
@relativeref{Trade::SceneFieldType,Short}, |
||||||
|
@relativeref{Trade::SceneFieldType,UnsignedByte} or |
||||||
|
@relativeref{Trade::SceneFieldType,Byte} and is not an array, and that the |
||||||
|
@p mapping array is large enough to cover all field values. |
||||||
|
|
||||||
|
The output field is always a @ref Trade::SceneFieldType::UnsignedInt if the |
||||||
|
input type is unsigned and @ref Trade::SceneFieldType::Int if it's signed. See |
||||||
|
also @ref mapIndexField(Trade::SceneData&&, UnsignedInt, const Containers::StridedArrayView1D<const UnsignedInt>&) |
||||||
|
for a potentially more efficient operation instead of always performing a full |
||||||
|
copy, you can also do an in-place mapping using |
||||||
|
@ref mapIndexFieldInPlace(Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<const UnsignedInt>&) |
||||||
|
which doesn't change the field type but additionally expects that the |
||||||
|
@p mapping values don't overflow given type. |
||||||
|
*/ |
||||||
|
MAGNUM_SCENETOOLS_EXPORT Trade::SceneData mapIndexField(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<const UnsignedInt>& mapping); |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Map a named index field in a scene |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Translates @p field to a field ID using @ref Trade::SceneData::fieldId() and |
||||||
|
delegates to @ref mapIndexField(const Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<const UnsignedInt>&). |
||||||
|
The @p field is expected to exist in @p scene. |
||||||
|
*/ |
||||||
|
MAGNUM_SCENETOOLS_EXPORT Trade::SceneData mapIndexField(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping); |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Map an index field in a scene |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Compared to @ref mapIndexField(const Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<const UnsignedInt>&) |
||||||
|
this function can perform the mapping in-place, transferring the data ownership |
||||||
|
to the returned instance if the data is owned and mutable and the field at |
||||||
|
index @p fieldId is @ref Trade::SceneFieldType::UnsignedInt or |
||||||
|
@ref Trade::SceneFieldType::Int. |
||||||
|
*/ |
||||||
|
MAGNUM_SCENETOOLS_EXPORT Trade::SceneData mapIndexField(Trade::SceneData&& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<const UnsignedInt>& mapping); |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Map a named index field in a scene |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Translates @p field to a field ID using @ref Trade::SceneData::fieldId() and |
||||||
|
delegates to @ref mapIndexField(Trade::SceneData&&, UnsignedInt, const Containers::StridedArrayView1D<const UnsignedInt>&). |
||||||
|
The @p field is expected to exist in @p scene. |
||||||
|
*/ |
||||||
|
MAGNUM_SCENETOOLS_EXPORT Trade::SceneData mapIndexField(Trade::SceneData&& scene, Trade::SceneField field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping); |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Map an index field in a scene in-place |
||||||
|
@param[in,out] scene Scene |
||||||
|
@param[in] fieldId Field to map |
||||||
|
@param[in] mapping Index value mapping |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Maps a field containing data indices, such as @ref Trade::SceneField::Mesh or |
||||||
|
@ref Trade::SceneField::Camera, to different indices by iterating through the |
||||||
|
field at index @p fieldId and replacing a particular @cpp value @ce with |
||||||
|
@cpp mapping[value] @ce. If the field has a signed type (such as is the case |
||||||
|
with @ref Trade::SceneField::MeshMaterial), @cpp -1 @ce is treated as an |
||||||
|
"unset" value and preserved verbatim. |
||||||
|
|
||||||
|
Expects that the @p scene has mutable data, @p fieldId is less than |
||||||
|
@ref Trade::SceneData::fieldCount(), the field is |
||||||
|
@ref Trade::SceneFieldType::UnsignedInt, |
||||||
|
@relativeref{Trade::SceneFieldType,Int}, @relativeref{Trade::SceneFieldType,UnsignedShort}, |
||||||
|
@relativeref{Trade::SceneFieldType,Short}, |
||||||
|
@relativeref{Trade::SceneFieldType,UnsignedByte} or |
||||||
|
@relativeref{Trade::SceneFieldType,Byte} and is not an array, the @p mapping |
||||||
|
array is large enough to cover all field values and the @p mapping values don't |
||||||
|
overflow given type. |
||||||
|
|
||||||
|
If you need to map to a larger index range that doesn't fit into the original |
||||||
|
field type, use @ref mapIndexField(const Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<const UnsignedInt>&) instead. |
||||||
|
@see @ref Trade::SceneData::dataFlags() |
||||||
|
*/ |
||||||
|
MAGNUM_SCENETOOLS_EXPORT void mapIndexFieldInPlace(Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<const UnsignedInt>& mapping); |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Map a named index field in a scene in-place |
||||||
|
@param[in,out] scene Scene |
||||||
|
@param[in] field Field to map |
||||||
|
@param[in] mapping Index value mapping |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Translates @p field to a field ID using @ref Trade::SceneData::fieldId() and |
||||||
|
delegates to @ref mapIndexFieldInPlace(Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<const UnsignedInt>&). |
||||||
|
The @p field is expected to exist in @p scene. |
||||||
|
*/ |
||||||
|
MAGNUM_SCENETOOLS_EXPORT void mapIndexFieldInPlace(Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<const UnsignedInt>& mapping); |
||||||
|
|
||||||
|
}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,761 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022, 2023 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> /** @todo remove once Debug is stream-free */ |
||||||
|
#include <Corrade/Containers/StridedBitArrayView.h> |
||||||
|
#include <Corrade/Containers/StringIterable.h> |
||||||
|
#include <Corrade/Containers/StringView.h> |
||||||
|
#include <Corrade/Containers/StringStl.h> /** @todo remove once Debug is stream-free */ |
||||||
|
#include <Corrade/TestSuite/Tester.h> |
||||||
|
#include <Corrade/TestSuite/Compare/Container.h> |
||||||
|
#include <Corrade/TestSuite/Compare/String.h> |
||||||
|
#include <Corrade/Utility/Algorithms.h> |
||||||
|
#include <Corrade/Utility/DebugStl.h> /** @todo remove once Debug is stream-free */ |
||||||
|
|
||||||
|
#include "Magnum/Math/TypeTraits.h" |
||||||
|
#include "Magnum/SceneTools/Map.h" |
||||||
|
#include "Magnum/Trade/SceneData.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace SceneTools { namespace Test { namespace { |
||||||
|
|
||||||
|
struct MapTest: TestSuite::Tester { |
||||||
|
explicit MapTest(); |
||||||
|
|
||||||
|
template<class T> void indexField(); |
||||||
|
template<class T> void indexFieldSigned(); |
||||||
|
void indexFieldOffsetOnly(); |
||||||
|
void indexFieldFieldNotFound(); |
||||||
|
void indexFieldInvalidType(); |
||||||
|
void indexFieldArrayField(); |
||||||
|
void indexFieldIndexOutOfBounds(); |
||||||
|
void indexFieldMappingNotRepresentable(); |
||||||
|
|
||||||
|
void indexFieldRvalue(); |
||||||
|
void indexFieldRvalueSigned(); |
||||||
|
void indexFieldRvalueNamed(); |
||||||
|
void indexFieldRvalueNotOwned(); |
||||||
|
void indexFieldRvalueNotFullType(); |
||||||
|
}; |
||||||
|
|
||||||
|
const struct { |
||||||
|
const char* name; |
||||||
|
bool inPlace; |
||||||
|
bool byName; |
||||||
|
} IndexFieldData[]{ |
||||||
|
{"in place, by ID", true, false}, |
||||||
|
{"in place, by name", true, true}, |
||||||
|
{"by ID", false, false}, |
||||||
|
{"by name", false, true} |
||||||
|
}; |
||||||
|
|
||||||
|
const struct { |
||||||
|
const char* name; |
||||||
|
bool byName; |
||||||
|
} IndexFieldRvalueData[]{ |
||||||
|
{"by ID", false}, |
||||||
|
{"by name", true} |
||||||
|
}; |
||||||
|
|
||||||
|
MapTest::MapTest() { |
||||||
|
addInstancedTests<MapTest>({ |
||||||
|
&MapTest::indexField<UnsignedInt>, |
||||||
|
&MapTest::indexField<UnsignedShort>, |
||||||
|
&MapTest::indexField<UnsignedByte>, |
||||||
|
&MapTest::indexFieldSigned<Int>, |
||||||
|
&MapTest::indexFieldSigned<Short>, |
||||||
|
&MapTest::indexFieldSigned<Byte>}, |
||||||
|
Containers::arraySize(IndexFieldData)); |
||||||
|
|
||||||
|
addTests({&MapTest::indexFieldOffsetOnly, |
||||||
|
&MapTest::indexFieldFieldNotFound, |
||||||
|
&MapTest::indexFieldInvalidType, |
||||||
|
&MapTest::indexFieldArrayField, |
||||||
|
&MapTest::indexFieldIndexOutOfBounds, |
||||||
|
&MapTest::indexFieldMappingNotRepresentable}); |
||||||
|
|
||||||
|
addInstancedTests({&MapTest::indexFieldRvalue, |
||||||
|
&MapTest::indexFieldRvalueSigned}, |
||||||
|
Containers::arraySize(IndexFieldRvalueData)); |
||||||
|
|
||||||
|
addTests({&MapTest::indexFieldRvalueNotOwned, |
||||||
|
&MapTest::indexFieldRvalueNotFullType}); |
||||||
|
} |
||||||
|
|
||||||
|
template<class> struct IndexFieldTraits; |
||||||
|
|
||||||
|
template<> struct IndexFieldTraits<UnsignedInt> { |
||||||
|
enum: UnsignedInt { Max = 0xffffffffu }; |
||||||
|
}; |
||||||
|
template<> struct IndexFieldTraits<Int> { |
||||||
|
enum: Int { Max = 0x7fffffffu }; |
||||||
|
}; |
||||||
|
template<> struct IndexFieldTraits<UnsignedShort> { |
||||||
|
enum: UnsignedShort { Max = 0xffff }; |
||||||
|
}; |
||||||
|
template<> struct IndexFieldTraits<Short> { |
||||||
|
enum: Short { Max = 0x7fff }; |
||||||
|
}; |
||||||
|
template<> struct IndexFieldTraits<UnsignedByte> { |
||||||
|
enum: UnsignedByte { Max = 0xff }; |
||||||
|
}; |
||||||
|
template<> struct IndexFieldTraits<Byte> { |
||||||
|
enum: Byte { Max = 0x7f }; |
||||||
|
}; |
||||||
|
|
||||||
|
template<class T> void MapTest::indexField() { |
||||||
|
auto&& data = IndexFieldData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.name); |
||||||
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
||||||
|
|
||||||
|
struct { |
||||||
|
UnsignedLong parentMapping[5]; |
||||||
|
Int parent[5]; |
||||||
|
UnsignedLong meshMaterialMapping[4]; |
||||||
|
T mesh[4]; |
||||||
|
Short custom[4][2]; |
||||||
|
} sceneData[]{{ |
||||||
|
{0, 11, 22, 33, 44}, |
||||||
|
{-1, -1, 1, 4, 0}, |
||||||
|
{0, 33, 2, 2}, |
||||||
|
{5, 9, 1, 0}, /* this one gets mapped */ |
||||||
|
{{9, 2}, {-1, 3}, {5, 6}, {0, 1}}, |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedLong, 5, Trade::DataFlag::Mutable, sceneData, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Parent, |
||||||
|
Containers::arrayView(sceneData->parentMapping), |
||||||
|
Containers::arrayView(sceneData->parent)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(sceneData->meshMaterialMapping), |
||||||
|
Containers::arrayView(sceneData->mesh), |
||||||
|
/* Verify that the flags get preserved */ |
||||||
|
Trade::SceneFieldFlag::MultiEntry}, |
||||||
|
/* Verify that array fields are supported in non-mapped fields */ |
||||||
|
Trade::SceneFieldData{Trade::sceneFieldCustom(1), |
||||||
|
Trade::SceneMappingType::UnsignedLong, |
||||||
|
Containers::arrayView(sceneData->meshMaterialMapping), |
||||||
|
Trade::SceneFieldType::Short, |
||||||
|
Containers::arrayView(sceneData->custom), 2}, |
||||||
|
}}; |
||||||
|
|
||||||
|
/* The 0xffffffffu values shouldn't be used for anything */ |
||||||
|
const UnsignedInt mapping[]{ |
||||||
|
12, 0, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
||||||
|
/* If not doing an in-place mapping, the output doesn't have to fit
|
||||||
|
into the original type */ |
||||||
|
data.inPlace ? UnsignedInt(IndexFieldTraits<T>::Max) : 1000000u, |
||||||
|
0xffffffffu, 0xffffffffu, 0xffffffffu, 3 |
||||||
|
}; |
||||||
|
|
||||||
|
Trade::SceneData output{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}}; |
||||||
|
if(data.inPlace) { |
||||||
|
if(data.byName) |
||||||
|
mapIndexFieldInPlace(scene, Trade::SceneField::Mesh, mapping); |
||||||
|
else |
||||||
|
mapIndexFieldInPlace(scene, 1, mapping); |
||||||
|
} else { |
||||||
|
if(data.byName) |
||||||
|
output = mapIndexField(scene, Trade::SceneField::Mesh, mapping); |
||||||
|
else |
||||||
|
output = mapIndexField(scene, 1, mapping); |
||||||
|
} |
||||||
|
const Trade::SceneData& result = data.inPlace ? scene : output; |
||||||
|
|
||||||
|
/* Mapping should stay untouched */ |
||||||
|
CORRADE_COMPARE(result.mappingBound(), 5); |
||||||
|
CORRADE_COMPARE(result.mappingType(), Trade::SceneMappingType::UnsignedLong); |
||||||
|
CORRADE_COMPARE_AS(result.mapping<UnsignedLong>(0), Containers::arrayView<UnsignedLong>({ |
||||||
|
0, 11, 22, 33, 44 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(result.mapping<UnsignedLong>(1), Containers::arrayView<UnsignedLong>({ |
||||||
|
0, 33, 2, 2 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(result.mapping<UnsignedLong>(2), Containers::arrayView<UnsignedLong>({ |
||||||
|
0, 33, 2, 2 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* All fields except the mesh should stay the same as before. With the
|
||||||
|
in-place variant the type should stay the same, otherwise expanded to |
||||||
|
32-bit. */ |
||||||
|
CORRADE_COMPARE_AS(result.field<Int>(0), Containers::arrayView<Int>({ |
||||||
|
-1, -1, 1, 4, 0 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
if(data.inPlace) { |
||||||
|
CORRADE_COMPARE(result.fieldType(1), Trade::Implementation::SceneFieldTypeFor<T>::type()); |
||||||
|
CORRADE_COMPARE_AS(result.field<T>(1), Containers::arrayView<T>({ |
||||||
|
IndexFieldTraits<T>::Max, 3, 0, 12 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} else { |
||||||
|
CORRADE_COMPARE(result.fieldType(1), Trade::SceneFieldType::UnsignedInt); |
||||||
|
CORRADE_COMPARE_AS(result.field<UnsignedInt>(1), Containers::arrayView<UnsignedInt>({ |
||||||
|
1000000, 3, 0, 12 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
/* The flags should be preserved */ |
||||||
|
CORRADE_COMPARE(result.fieldFlags(1), Trade::SceneFieldFlag::MultiEntry); |
||||||
|
/* Non-mapped array field should be copied as-is without any assert */ |
||||||
|
CORRADE_COMPARE_AS((result.field<Short[]>(2).transposed<0, 1>()[0]), Containers::arrayView<Short>({ |
||||||
|
9, -1, 5, 0 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS((result.field<Short[]>(2).transposed<0, 1>()[1]), Containers::arrayView<Short>({ |
||||||
|
2, 3, 6, 1 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> void MapTest::indexFieldSigned() { |
||||||
|
auto&& data = IndexFieldData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.name); |
||||||
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
||||||
|
|
||||||
|
/* Similar to indexField(), except that here the meshMaterial gets mapped
|
||||||
|
instead */ |
||||||
|
|
||||||
|
struct { |
||||||
|
UnsignedByte parentMapping[5]; |
||||||
|
Int parent[5]; |
||||||
|
UnsignedByte meshMaterialMapping[4]; |
||||||
|
T meshMaterial[4]; |
||||||
|
UnsignedShort mesh[4]; |
||||||
|
} sceneData[]{{ |
||||||
|
{0, 11, 22, 33, 44}, |
||||||
|
{-1, -1, 1, 4, 0}, |
||||||
|
{0, 33, 2, 2}, |
||||||
|
{9, -1, 5, 1}, /* this one gets mapped */ |
||||||
|
{5, 9, 1, 0}, |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedByte, 55, Trade::DataFlag::Mutable, sceneData, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Parent, |
||||||
|
Containers::arrayView(sceneData->parentMapping), |
||||||
|
Containers::arrayView(sceneData->parent)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(sceneData->meshMaterialMapping), |
||||||
|
Containers::arrayView(sceneData->meshMaterial)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(sceneData->meshMaterialMapping), |
||||||
|
Containers::arrayView(sceneData->mesh)}, |
||||||
|
}}; |
||||||
|
|
||||||
|
/* The 0xffffffffu values shouldn't be used for anything */ |
||||||
|
const UnsignedInt mapping[]{ |
||||||
|
0xffffffffu, 12, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
||||||
|
IndexFieldTraits<T>::Max, 0xffffffffu, 0xffffffffu, 0xffffffffu, 3 |
||||||
|
}; |
||||||
|
|
||||||
|
Trade::SceneData output{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {}}; |
||||||
|
if(data.inPlace) { |
||||||
|
if(data.byName) |
||||||
|
mapIndexFieldInPlace(scene, Trade::SceneField::MeshMaterial, mapping); |
||||||
|
else |
||||||
|
mapIndexFieldInPlace(scene, 1, mapping); |
||||||
|
} else { |
||||||
|
if(data.byName) |
||||||
|
output = mapIndexField(scene, Trade::SceneField::MeshMaterial, mapping); |
||||||
|
else |
||||||
|
output = mapIndexField(scene, 1, mapping); |
||||||
|
} |
||||||
|
const Trade::SceneData& result = data.inPlace ? scene : output; |
||||||
|
|
||||||
|
/* Mapping should stay untouched */ |
||||||
|
CORRADE_COMPARE(result.mappingBound(), 55); |
||||||
|
CORRADE_COMPARE(result.mappingType(), Trade::SceneMappingType::UnsignedByte); |
||||||
|
CORRADE_COMPARE_AS(result.mapping<UnsignedByte>(0), Containers::arrayView<UnsignedByte>({ |
||||||
|
0, 11, 22, 33, 44 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(result.mapping<UnsignedByte>(1), Containers::arrayView<UnsignedByte>({ |
||||||
|
0, 33, 2, 2 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(result.mapping<UnsignedByte>(2), Containers::arrayView<UnsignedByte>({ |
||||||
|
0, 33, 2, 2 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* All fields except the mesh material should stay the same as before. With
|
||||||
|
the in-place variant the type should stay the same, otherwise expanded |
||||||
|
to 32-bit. */ |
||||||
|
CORRADE_COMPARE_AS(result.field<Int>(0), Containers::arrayView<Int>({ |
||||||
|
-1, -1, 1, 4, 0 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
if(data.inPlace) { |
||||||
|
CORRADE_COMPARE(result.fieldType(1), Trade::Implementation::SceneFieldTypeFor<T>::type()); |
||||||
|
CORRADE_COMPARE_AS(result.field<T>(1), Containers::arrayView<T>({ |
||||||
|
3, -1, IndexFieldTraits<T>::Max, 12 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} else { |
||||||
|
CORRADE_COMPARE(result.fieldType(1), Trade::SceneFieldType::Int); |
||||||
|
CORRADE_COMPARE_AS(result.field<Int>(1), Containers::arrayView<Int>({ |
||||||
|
3, -1, IndexFieldTraits<T>::Max, 12 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
CORRADE_COMPARE_AS(result.field<UnsignedShort>(2), Containers::arrayView<UnsignedShort>({ |
||||||
|
5, 9, 1, 0 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldOffsetOnly() { |
||||||
|
/* Subset of indexField() with the mapped field being specified as
|
||||||
|
offset-only. Should "just work" without any special treatment needed in |
||||||
|
the implementation. */ |
||||||
|
|
||||||
|
struct SceneData { |
||||||
|
UnsignedShort meshMaterialMapping[4]; |
||||||
|
Byte meshMaterial[4]; |
||||||
|
UnsignedShort mesh[4]; |
||||||
|
} sceneData[]{{ |
||||||
|
{0, 33, 2, 2}, |
||||||
|
{9, -1, 5, 1}, |
||||||
|
{5, 9, 1, 0}, /* this one gets mapped */ |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedShort, 5, Trade::DataFlag::Mutable, sceneData, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(sceneData->meshMaterialMapping), |
||||||
|
Containers::arrayView(sceneData->meshMaterial)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, 4, |
||||||
|
Trade::SceneMappingType::UnsignedShort, offsetof(SceneData, meshMaterialMapping), sizeof(UnsignedShort), |
||||||
|
Trade::SceneFieldType::UnsignedShort, offsetof(SceneData, mesh), sizeof(UnsignedShort)}, |
||||||
|
}}; |
||||||
|
|
||||||
|
/* The 0xffffffffu values shouldn't be used for anything */ |
||||||
|
const UnsignedInt mapping[]{ |
||||||
|
12, 0, 0xffffffffu, 0xffffffffu, 0xffffffffu, |
||||||
|
0xffff, 0xffffffffu, 0xffffffffu, 0xffffffffu, 3 |
||||||
|
}; |
||||||
|
mapIndexFieldInPlace(scene, Trade::SceneField::Mesh, mapping); |
||||||
|
CORRADE_COMPARE_AS(scene.field<UnsignedShort>(1), Containers::arrayView<UnsignedShort>({ |
||||||
|
0xffff, 3, 0, 12 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldFieldNotFound() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Parent, |
||||||
|
Trade::SceneMappingType::UnsignedInt, nullptr, |
||||||
|
Trade::SceneFieldType::Int, nullptr}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Trade::SceneMappingType::UnsignedInt, nullptr, |
||||||
|
Trade::SceneFieldType::UnsignedInt, nullptr}, |
||||||
|
}}; |
||||||
|
|
||||||
|
UnsignedInt mapping[5]{}; |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
mapIndexField(scene, 2, mapping); |
||||||
|
mapIndexFieldInPlace(scene, 2, mapping); |
||||||
|
mapIndexField(scene, Trade::SceneField::MeshMaterial, mapping); |
||||||
|
mapIndexFieldInPlace(scene, Trade::SceneField::MeshMaterial, mapping); |
||||||
|
CORRADE_COMPARE_AS(out.str(), |
||||||
|
"SceneTools::mapIndexField(): index 2 out of range for 2 fields\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): index 2 out of range for 2 fields\n" |
||||||
|
"SceneTools::mapIndexField(): field Trade::SceneField::MeshMaterial not found\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): field Trade::SceneField::MeshMaterial not found\n", |
||||||
|
TestSuite::Compare::String); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldInvalidType() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Trade::SceneMappingType::UnsignedInt, nullptr, |
||||||
|
Trade::SceneFieldType::UnsignedInt, nullptr}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Parent, |
||||||
|
Trade::SceneMappingType::UnsignedInt, nullptr, |
||||||
|
Trade::SceneFieldType::Long, nullptr}, |
||||||
|
}}; |
||||||
|
|
||||||
|
UnsignedInt mapping[5]{}; |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
mapIndexField(scene, 1, mapping); |
||||||
|
mapIndexFieldInPlace(scene, 1, mapping); |
||||||
|
CORRADE_COMPARE_AS(out.str(), |
||||||
|
"SceneTools::mapIndexField(): unsupported field type Trade::SceneFieldType::Long\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): unsupported field type Trade::SceneFieldType::Long\n", |
||||||
|
TestSuite::Compare::String); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldArrayField() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Trade::SceneMappingType::UnsignedInt, nullptr, |
||||||
|
Trade::SceneFieldType::UnsignedInt, nullptr}, |
||||||
|
Trade::SceneFieldData{Trade::sceneFieldCustom(0x1337), |
||||||
|
Trade::SceneMappingType::UnsignedInt, nullptr, |
||||||
|
Trade::SceneFieldType::Byte, nullptr, 3}, |
||||||
|
}}; |
||||||
|
|
||||||
|
UnsignedInt mapping[5]{}; |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
mapIndexField(scene, 1, mapping); |
||||||
|
mapIndexFieldInPlace(scene, 1, mapping); |
||||||
|
CORRADE_COMPARE_AS(out.str(), |
||||||
|
"SceneTools::mapIndexField(): array field mapping isn't supported\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): array field mapping isn't supported\n", |
||||||
|
TestSuite::Compare::String); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldIndexOutOfBounds() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
const struct { |
||||||
|
UnsignedShort meshMaterialMapping[4]; |
||||||
|
Byte meshMaterial[4]; |
||||||
|
UnsignedShort mesh[4]; |
||||||
|
} sceneData[]{{ |
||||||
|
{}, |
||||||
|
{5, -1, 9, -2}, |
||||||
|
{5, 10, 1, 0}, |
||||||
|
}}; |
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedShort, 5, {}, sceneData, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(sceneData->meshMaterialMapping), |
||||||
|
Containers::arrayView(sceneData->mesh)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(sceneData->meshMaterialMapping), |
||||||
|
Containers::arrayView(sceneData->meshMaterial)}, |
||||||
|
}}; |
||||||
|
|
||||||
|
const UnsignedInt mapping9[9]{}; |
||||||
|
const UnsignedInt mapping10[10]{}; |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
mapIndexField(scene, Trade::SceneField::MeshMaterial, mapping10); |
||||||
|
mapIndexField(scene, Trade::SceneField::MeshMaterial, mapping9); |
||||||
|
mapIndexField(scene, Trade::SceneField::Mesh, mapping10); |
||||||
|
CORRADE_COMPARE_AS(out.str(), |
||||||
|
"SceneTools::mapIndexFieldInPlace(): index -2 out of range for 10 mapping values\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): index 9 out of range for 9 mapping values\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): index 10 out of range for 10 mapping values\n", |
||||||
|
TestSuite::Compare::String); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldMappingNotRepresentable() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
struct { |
||||||
|
UnsignedShort mapping[4]; |
||||||
|
UnsignedShort mesh[4]; |
||||||
|
UnsignedByte light[4]; |
||||||
|
Int custom1[4]; |
||||||
|
Short custom2[4]; |
||||||
|
Byte meshMaterial[4]; |
||||||
|
} sceneData[]{{ |
||||||
|
{}, |
||||||
|
{0, 4, 3, 1}, |
||||||
|
{0, 4, 3, 1}, |
||||||
|
{0, -1, 3, 1}, |
||||||
|
{0, -1, 2, 1}, |
||||||
|
{0, -1, 0, 1}, |
||||||
|
}}; |
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedShort, 1, Trade::DataFlag::Mutable, sceneData, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(sceneData->mapping), |
||||||
|
Containers::arrayView(sceneData->mesh)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Light, |
||||||
|
Containers::arrayView(sceneData->mapping), |
||||||
|
Containers::arrayView(sceneData->light)}, |
||||||
|
Trade::SceneFieldData{Trade::sceneFieldCustom(1), |
||||||
|
Containers::arrayView(sceneData->mapping), |
||||||
|
Containers::arrayView(sceneData->custom1)}, |
||||||
|
Trade::SceneFieldData{Trade::sceneFieldCustom(2), |
||||||
|
Containers::arrayView(sceneData->mapping), |
||||||
|
Containers::arrayView(sceneData->custom2)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(sceneData->mapping), |
||||||
|
Containers::arrayView(sceneData->meshMaterial)}, |
||||||
|
}}; |
||||||
|
|
||||||
|
UnsignedInt mappingUnsigned[]{ |
||||||
|
/* Index 1 is too large for UnsignedByte, 2 isn't used, 3 is
|
||||||
|
too large for UnsignedShort */ |
||||||
|
1, 0x100, 0xffffffffu, 0x10000, 3 |
||||||
|
}; |
||||||
|
UnsignedInt mappingSigned[]{ |
||||||
|
/* Index 1 is too large for a Byte, 3 too large for Int, 2 too large
|
||||||
|
for Short */ |
||||||
|
1, 0x80, 0x8000, 0x80000000u |
||||||
|
}; |
||||||
|
|
||||||
|
/* These should all be okay as they expand to 32 bits */ |
||||||
|
mapIndexField(scene, Trade::SceneField::Mesh, mappingUnsigned); |
||||||
|
mapIndexField(scene, Trade::SceneField::Light, mappingUnsigned); |
||||||
|
mapIndexField(scene, Trade::sceneFieldCustom(2), mappingSigned); |
||||||
|
mapIndexField(scene, Trade::SceneField::MeshMaterial, mappingSigned); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
mapIndexFieldInPlace(scene, Trade::SceneField::Mesh, mappingUnsigned); |
||||||
|
mapIndexFieldInPlace(scene, Trade::SceneField::Light, mappingUnsigned); |
||||||
|
/* This one expands to 32 bits but is still signed which isn't enough */ |
||||||
|
mapIndexField(scene, Trade::sceneFieldCustom(1), mappingSigned); |
||||||
|
mapIndexFieldInPlace(scene, Trade::sceneFieldCustom(1), mappingSigned); |
||||||
|
mapIndexFieldInPlace(scene, Trade::sceneFieldCustom(2), mappingSigned); |
||||||
|
mapIndexFieldInPlace(scene, Trade::SceneField::MeshMaterial, mappingSigned); |
||||||
|
CORRADE_COMPARE_AS(out.str(), |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value 65536 not representable in Trade::SceneFieldType::UnsignedShort\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value 65536 not representable in Trade::SceneFieldType::UnsignedByte\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value 2147483648 not representable in Trade::SceneFieldType::Int\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value 2147483648 not representable in Trade::SceneFieldType::Int\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value 32768 not representable in Trade::SceneFieldType::Short\n" |
||||||
|
"SceneTools::mapIndexFieldInPlace(): mapping value 128 not representable in Trade::SceneFieldType::Byte\n", |
||||||
|
TestSuite::Compare::String); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldRvalue() { |
||||||
|
auto&& data = IndexFieldRvalueData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.name); |
||||||
|
|
||||||
|
struct Data { |
||||||
|
UnsignedByte mapping[4]; |
||||||
|
Short meshMaterial[4]; |
||||||
|
UnsignedInt mesh[4]; |
||||||
|
}; |
||||||
|
Containers::Array<char> sceneData{NoInit, sizeof(Data)}; |
||||||
|
Containers::StridedArrayView1D<Data> view = Containers::arrayCast<Data>(sceneData); |
||||||
|
Utility::copy({{ |
||||||
|
{77, 33, 44, 66}, |
||||||
|
{2, -1, 0, 1}, |
||||||
|
{3, 4, 1, 0}, |
||||||
|
}}, view); |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedByte, 88, Utility::move(sceneData), { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(view[0].mapping), |
||||||
|
Containers::arrayView(view[0].meshMaterial)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(view[0].mapping), |
||||||
|
Containers::arrayView(view[0].mesh)}, |
||||||
|
}}; |
||||||
|
const Trade::SceneFieldData* originalFields = scene.fieldData(); |
||||||
|
|
||||||
|
const UnsignedInt mapping[]{ |
||||||
|
15, 16, 0xffffffffu, 7, 9 |
||||||
|
}; |
||||||
|
Trade::SceneData mapped = data.byName ? |
||||||
|
mapIndexField(Utility::move(scene), Trade::SceneField::Mesh, mapping) : |
||||||
|
mapIndexField(Utility::move(scene), 1, mapping); |
||||||
|
|
||||||
|
/* Mapping should stay untouched */ |
||||||
|
CORRADE_COMPARE(mapped.mappingBound(), 88); |
||||||
|
CORRADE_COMPARE(mapped.mappingType(), Trade::SceneMappingType::UnsignedByte); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(0), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(1), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Mesh should be mapped, materials should stay the same as before */ |
||||||
|
CORRADE_COMPARE_AS(mapped.field<Short>(0), Containers::arrayView<Short>({ |
||||||
|
2, -1, 0, 1 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mapped.field<UnsignedInt>(1), Containers::arrayView<UnsignedInt>({ |
||||||
|
7, 9, 16, 15 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Both data should be transferred without any copy */ |
||||||
|
CORRADE_COMPARE(mapped.data().data(), view.data()); |
||||||
|
CORRADE_COMPARE(mapped.fieldData().data(), originalFields); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldRvalueSigned() { |
||||||
|
auto&& data = IndexFieldRvalueData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.name); |
||||||
|
|
||||||
|
struct Data { |
||||||
|
UnsignedByte mapping[4]; |
||||||
|
UnsignedShort mesh[4]; |
||||||
|
Int meshMaterial[4]; |
||||||
|
}; |
||||||
|
Containers::Array<char> sceneData{NoInit, sizeof(Data)}; |
||||||
|
Containers::StridedArrayView1D<Data> view = Containers::arrayCast<Data>(sceneData); |
||||||
|
Utility::copy({{ |
||||||
|
{77, 33, 44, 66}, |
||||||
|
{3, 4, 1, 0}, |
||||||
|
{2, -1, 0, 3}, |
||||||
|
}}, view); |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedByte, 88, Utility::move(sceneData), { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(view[0].mapping), |
||||||
|
Containers::arrayView(view[0].mesh)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(view[0].mapping), |
||||||
|
Containers::arrayView(view[0].meshMaterial)}, |
||||||
|
}}; |
||||||
|
const Trade::SceneFieldData* originalFields = scene.fieldData(); |
||||||
|
|
||||||
|
const UnsignedInt mapping[]{ |
||||||
|
15, 0xffffffffu, 16, 7 |
||||||
|
}; |
||||||
|
Trade::SceneData mapped = data.byName ? |
||||||
|
mapIndexField(Utility::move(scene), Trade::SceneField::MeshMaterial, mapping) : |
||||||
|
mapIndexField(Utility::move(scene), 1, mapping); |
||||||
|
|
||||||
|
/* Mapping should stay untouched */ |
||||||
|
CORRADE_COMPARE(mapped.mappingBound(), 88); |
||||||
|
CORRADE_COMPARE(mapped.mappingType(), Trade::SceneMappingType::UnsignedByte); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(0), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(1), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Mesh should stay the same as before, materials should be mapped */ |
||||||
|
CORRADE_COMPARE_AS(mapped.field<UnsignedShort>(0), Containers::arrayView<UnsignedShort>({ |
||||||
|
3, 4, 1, 0 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mapped.field<Int>(1), Containers::arrayView<Int>({ |
||||||
|
16, -1, 15, 7 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Both data should be transferred without any copy */ |
||||||
|
CORRADE_COMPARE(mapped.data().data(), view.data()); |
||||||
|
CORRADE_COMPARE(mapped.fieldData().data(), originalFields); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldRvalueNotOwned() { |
||||||
|
/* Like indexFieldRvalue(), but the data is not owned so it should perform
|
||||||
|
a copy */ |
||||||
|
|
||||||
|
struct { |
||||||
|
UnsignedByte mapping[4]; |
||||||
|
Short meshMaterial[4]; |
||||||
|
UnsignedInt mesh[4]; |
||||||
|
} sceneData[]{{ |
||||||
|
{77, 33, 44, 66}, |
||||||
|
{2, -1, 0, 1}, |
||||||
|
{3, 4, 1, 0}, |
||||||
|
}}; |
||||||
|
|
||||||
|
/* Mark the data as Mutable to test it isn't accidentally treated the same
|
||||||
|
as Owned */ |
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedByte, 88, Trade::DataFlag::Mutable, sceneData, { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(sceneData->mapping), |
||||||
|
Containers::arrayView(sceneData->meshMaterial)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(sceneData->mapping), |
||||||
|
Containers::arrayView(sceneData->mesh)}, |
||||||
|
}}; |
||||||
|
const Trade::SceneFieldData* originalFields = scene.fieldData(); |
||||||
|
|
||||||
|
const UnsignedInt mapping[]{ |
||||||
|
15, 16, 0xffffffffu, 7, 9 |
||||||
|
}; |
||||||
|
Trade::SceneData mapped = mapIndexField(Utility::move(scene), 1, mapping); |
||||||
|
|
||||||
|
/* Mapping should stay untouched */ |
||||||
|
CORRADE_COMPARE(mapped.mappingBound(), 88); |
||||||
|
CORRADE_COMPARE(mapped.mappingType(), Trade::SceneMappingType::UnsignedByte); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(0), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(1), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Mesh should be mapped, materials should stay the same as before */ |
||||||
|
CORRADE_COMPARE_AS(mapped.field<Short>(0), Containers::arrayView<Short>({ |
||||||
|
2, -1, 0, 1 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mapped.field<UnsignedInt>(1), Containers::arrayView<UnsignedInt>({ |
||||||
|
7, 9, 16, 15 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Data should be copied */ |
||||||
|
CORRADE_VERIFY(mapped.data().data() != static_cast<void*>(sceneData)); |
||||||
|
CORRADE_VERIFY(mapped.fieldData().data() != originalFields); |
||||||
|
} |
||||||
|
|
||||||
|
void MapTest::indexFieldRvalueNotFullType() { |
||||||
|
/* Like indexFieldRvalue(), but the field is not a 32-bit type */ |
||||||
|
|
||||||
|
struct Data { |
||||||
|
UnsignedByte mapping[4]; |
||||||
|
Int meshMaterial[4]; |
||||||
|
UnsignedShort mesh[4]; |
||||||
|
}; |
||||||
|
Containers::Array<char> sceneData{NoInit, sizeof(Data)}; |
||||||
|
Containers::StridedArrayView1D<Data> view = Containers::arrayCast<Data>(sceneData); |
||||||
|
Utility::copy({{ |
||||||
|
{77, 33, 44, 66}, |
||||||
|
{2, -1, 0, 1}, |
||||||
|
{3, 4, 1, 0}, |
||||||
|
}}, view); |
||||||
|
|
||||||
|
Trade::SceneData scene{Trade::SceneMappingType::UnsignedByte, 88, Utility::move(sceneData), { |
||||||
|
Trade::SceneFieldData{Trade::SceneField::MeshMaterial, |
||||||
|
Containers::arrayView(view[0].mapping), |
||||||
|
Containers::arrayView(view[0].meshMaterial)}, |
||||||
|
Trade::SceneFieldData{Trade::SceneField::Mesh, |
||||||
|
Containers::arrayView(view[0].mapping), |
||||||
|
Containers::arrayView(view[0].mesh)}, |
||||||
|
}}; |
||||||
|
const Trade::SceneFieldData* originalFields = scene.fieldData(); |
||||||
|
|
||||||
|
const UnsignedInt mapping[]{ |
||||||
|
15, 16, 0xffffffffu, 7, 9 |
||||||
|
}; |
||||||
|
Trade::SceneData mapped = mapIndexField(Utility::move(scene), 1, mapping); |
||||||
|
|
||||||
|
/* Mapping should stay untouched */ |
||||||
|
CORRADE_COMPARE(mapped.mappingBound(), 88); |
||||||
|
CORRADE_COMPARE(mapped.mappingType(), Trade::SceneMappingType::UnsignedByte); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(0), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mapped.mapping<UnsignedByte>(1), Containers::arrayView<UnsignedByte>({ |
||||||
|
77, 33, 44, 66 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Mesh should be mapped, materials should stay the same as before. As a
|
||||||
|
copy is performed, the type is expanded to 32 bits. */ |
||||||
|
CORRADE_COMPARE_AS(mapped.field<Int>(0), Containers::arrayView<Int>({ |
||||||
|
2, -1, 0, 1 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE(mapped.fieldType(1), Trade::SceneFieldType::UnsignedInt); |
||||||
|
CORRADE_COMPARE_AS(mapped.field<UnsignedInt>(1), Containers::arrayView<UnsignedInt>({ |
||||||
|
7, 9, 16, 15 |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
/* Data should be copied */ |
||||||
|
CORRADE_VERIFY(mapped.data().data() != static_cast<void*>(sceneData)); |
||||||
|
CORRADE_VERIFY(mapped.fieldData().data() != originalFields); |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
CORRADE_TEST_MAIN(Magnum::SceneTools::Test::MapTest) |
||||||
Loading…
Reference in new issue