Browse Source

SceneTools: support SceneFieldType::Bit in combineFields().

I'm (again) postponing implementation of a robust & optimized
Utility::copy() for bit array views. Attempted something, but it got out
of hand very quickly. Since the particular use case here isn't going to
be a perf bottleneck I think, it's fine to do it with just a dumb loop
for now.
pull/620/head
Vladimír Vondruš 3 years ago
parent
commit
f41b1f4fae
  1. 93
      src/Magnum/SceneTools/Implementation/combine.h
  2. 95
      src/Magnum/SceneTools/Test/CombineTest.cpp

93
src/Magnum/SceneTools/Implementation/combine.h

@ -30,6 +30,7 @@
#include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Containers/StridedBitArrayView.h>
#include <Corrade/Utility/Algorithms.h>
#include "Magnum/Math/Functions.h"
@ -46,7 +47,14 @@ namespace Magnum { namespace SceneTools { namespace Implementation {
/** @todo move everything to Combine.cpp and anonymous namespace once that
compatibility is dropped */
template<class T> void combineCopyMappings(const Containers::ArrayView<const Trade::SceneFieldData> fields, const Containers::ArrayView<const Containers::StridedArrayView2D<char>> itemViews, const Containers::ArrayView<const Containers::Pair<UnsignedInt, UnsignedInt>> itemViewMappings) {
union CombineItemView {
explicit CombineItemView() {}
Containers::StridedArrayView2D<char> types;
Containers::MutableStridedBitArrayView2D bits;
};
template<class T> void combineCopyMappings(const Containers::ArrayView<const Trade::SceneFieldData> fields, const Containers::ArrayView<const CombineItemView> 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 shared object mappings, itemViewMappings should be
@ -64,7 +72,7 @@ template<class T> void combineCopyMappings(const Containers::ArrayView<const Tra
second dimension is contiguous which Math::castInto() requires */
/** @todo this is an error-prone mess, fix better */
const Containers::StridedArrayView1D<const void> src = fields[i].mappingData();
const Containers::StridedArrayView2D<T> dst = Containers::arrayCast<2, T>(Containers::arrayCast<1, T>(itemViews[mapping]));
const Containers::StridedArrayView2D<T> dst = Containers::arrayCast<2, T>(Containers::arrayCast<1, T>(itemViews[mapping].types));
if(fields[i].mappingType() == Trade::SceneMappingType::UnsignedByte)
Math::castInto(Containers::arrayCast<2, const UnsignedByte>(Containers::arrayCast<const UnsignedByte>(src)), dst);
else if(fields[i].mappingType() == Trade::SceneMappingType::UnsignedShort)
@ -91,10 +99,12 @@ inline Trade::SceneData combineFields(const Trade::SceneMappingType mappingType,
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 */
growable array in order to avoid an accidental reallocation. It's either
of the two views in the union based on whether it's a mapping or data
view and what the data field type is */
/** @todo once never-reallocating allocators are present, use them instead
of the manual offset */
Containers::Array<Containers::StridedArrayView2D<char>> itemViews{fields.size()*2};
Containers::Array<CombineItemView> itemViews{fields.size()*2};
std::size_t itemViewOffset = 0;
/* Go through all fields and collect ArrayTuple allocations for these */
@ -126,7 +136,7 @@ inline Trade::SceneData combineFields(const Trade::SceneMappingType mappingType,
std::size_t(field.size()),
mappingTypeSize,
mappingTypeAlignment,
itemViews[itemViewOffset]);
itemViews[itemViewOffset].types);
++itemViewOffset;
}
@ -135,11 +145,19 @@ inline Trade::SceneData combineFields(const Trade::SceneMappingType mappingType,
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]);
const Trade::SceneFieldType fieldType = field.fieldType();
if(fieldType == Trade::SceneFieldType::Bit) {
arrayAppend(items, InPlaceInit,
NoInit,
Containers::Size2D{std::size_t(field.size()), field.fieldArraySize() ? field.fieldArraySize() : 1},
itemViews[itemViewOffset].bits);
} else {
arrayAppend(items, InPlaceInit,
NoInit,
std::size_t(field.size()), sceneFieldTypeSize(fieldType)*(field.fieldArraySize() ? field.fieldArraySize() : 1),
sceneFieldTypeAlignment(fieldType),
itemViews[itemViewOffset].types);
}
++itemViewOffset;
}
@ -163,24 +181,59 @@ inline Trade::SceneData combineFields(const Trade::SceneMappingType mappingType,
/* Copy the field data over. No special handling needed here. */
for(std::size_t i = 0; i != fields.size(); ++i) {
const Trade::SceneFieldData& field = fields[i];
const Containers::StridedArrayView1D<const void> src = field.fieldData();
const Trade::SceneFieldType fieldType = field.fieldType();
if(fieldType == Trade::SceneFieldType::Bit) {
const Containers::StridedBitArrayView2D src = field.fieldBitData();
/* If the field has null field data, no need to copy anything. This
covers reserved fields but also fields of zero size. */
if(!src.data()) continue;
/** @todo this needs Utility::copy() for bits, which is HARD */
const Containers::MutableStridedBitArrayView2D dst = itemViews[itemViewMappings[i].second()].bits;
const std::size_t arraySize = field.fieldArraySize() ? field.fieldArraySize() : 1;
for(std::size_t i = 0, iMax = field.size(); i != iMax; ++i) {
const Containers::StridedBitArrayView1D srcI = src[i];
const Containers::MutableStridedBitArrayView1D dstI = dst[i];
for(std::size_t j = 0; j != arraySize; ++j)
dstI.set(j, srcI[j]);
}
} else {
const Containers::StridedArrayView1D<const void> src = field.fieldData();
/* If the field has null field data, no need to copy anything. This
covers reserved fields but also fields of zero size. */
if(!src.data()) continue;
/* If the field has null field data, no need to copy anything. This
covers reserved fields but also fields of zero size. */
if(!src.data()) continue;
/** @todo isn't there some less awful way to create a 2D view, sigh */
Utility::copy(Containers::arrayCast<2, const char>(src, sceneFieldTypeSize(field.fieldType())*(field.fieldArraySize() ? field.fieldArraySize() : 1)), itemViews[itemViewMappings[i].second()]);
/** @todo isn't there some less awful way to create a 2D view, sigh */
Utility::copy(Containers::arrayCast<2, const char>(src, sceneFieldTypeSize(fieldType)*(field.fieldArraySize() ? field.fieldArraySize() : 1)), itemViews[itemViewMappings[i].second()].types);
}
}
/* Map the fields to the new data */
Containers::Array<Trade::SceneFieldData> outFields{fields.size()};
for(std::size_t i = 0; i != fields.size(); ++i) {
const Trade::SceneFieldData& field = fields[i];
outFields[i] = Trade::SceneFieldData{field.name(),
itemViews[itemViewMappings[i].first()],
field.fieldType(), itemViews[itemViewMappings[i].second()],
field.fieldArraySize(), field.flags()};
const Trade::SceneFieldType fieldType = field.fieldType();
if(fieldType == Trade::SceneFieldType::Bit) {
/* Pass arrays as 2D views, non-arrays as 1D views */
if(field.fieldArraySize())
outFields[i] = Trade::SceneFieldData{field.name(),
itemViews[itemViewMappings[i].first()].types,
itemViews[itemViewMappings[i].second()].bits,
field.flags()};
else
outFields[i] = Trade::SceneFieldData{field.name(),
itemViews[itemViewMappings[i].first()].types,
/** @todo creating a 1D view isn't really easy either, huh? */
itemViews[itemViewMappings[i].second()].bits.transposed<0, 1>()[0],
field.flags()};
} else {
outFields[i] = Trade::SceneFieldData{field.name(),
itemViews[itemViewMappings[i].first()].types,
fieldType, itemViews[itemViewMappings[i].second()].types,
field.fieldArraySize(), field.flags()};
}
}
return Trade::SceneData{mappingType, mappingBound, std::move(outData), std::move(outFields)};

95
src/Magnum/SceneTools/Test/CombineTest.cpp

@ -24,6 +24,7 @@
*/
#include <sstream>
#include <Corrade/Containers/StridedBitArrayView.h>
#include <Corrade/TestSuite/Tester.h>
#include <Corrade/TestSuite/Compare/Container.h>
#include <Corrade/TestSuite/Compare/Numeric.h>
@ -120,6 +121,27 @@ void CombineTest::fields() {
};
auto foos = Containers::stridedArrayView(fooData);
const struct Bool {
UnsignedShort mapping;
bool bit;
} boolData[]{
{23, false},
{24, true},
{25, false},
{26, true}
};
auto bools = Containers::stridedArrayView(boolData);
const struct Bits {
UnsignedByte mapping;
UnsignedByte bits;
} bitsData[]{
{13, 1 << 3 | 1 << 4},
{25, 1 << 4},
{77, 1 << 1 | 1 << 2 | 1 << 3},
};
auto bits = Containers::stridedArrayView(bitsData);
Trade::SceneData scene = combineFields(data.objectType, 167, {
Trade::SceneFieldData{Trade::SceneField::Mesh,
meshes.slice(&Mesh::mapping),
@ -137,13 +159,23 @@ void CombineTest::fields() {
Containers::arrayCast<2, const Int>(foos.slice(&Foo::foo)),
Trade::SceneFieldFlag::OrderedMapping},
/* Empty field */
Trade::SceneFieldData{Trade::SceneField::Camera, Containers::ArrayView<const UnsignedByte>{}, Containers::ArrayView<const UnsignedShort>{}}
Trade::SceneFieldData{Trade::SceneField::Camera, Containers::ArrayView<const UnsignedByte>{}, Containers::ArrayView<const UnsignedShort>{}},
/* Bit field */
Trade::SceneFieldData{Trade::sceneFieldCustom(16),
bools.slice(&Bool::mapping),
bools.slice(&Bool::bit).sliceBit(0),
Trade::SceneFieldFlag::ImplicitMapping},
/* Bit array field */
Trade::SceneFieldData{Trade::sceneFieldCustom(17),
bits.slice(&Bits::mapping),
Containers::StridedBitArrayView2D{Containers::BitArrayView{bitsData}, &bitsData[0].bits, 1, {3, 4}, {sizeof(Bits)*8, 1}},
Trade::SceneFieldFlag::OrderedMapping},
});
CORRADE_COMPARE(scene.dataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable);
CORRADE_COMPARE(scene.mappingType(), data.objectType);
CORRADE_COMPARE(scene.mappingBound(), 167);
CORRADE_COMPARE(scene.fieldCount(), 5);
CORRADE_COMPARE(scene.fieldCount(), 7);
CORRADE_COMPARE(scene.fieldName(0), Trade::SceneField::Mesh);
CORRADE_COMPARE(scene.fieldFlags(0), Trade::SceneFieldFlags{});
@ -199,6 +231,36 @@ void CombineTest::fields() {
CORRADE_COMPARE(scene.fieldType(4), Trade::SceneFieldType::UnsignedShort);
CORRADE_COMPARE(scene.fieldSize(4), 0);
CORRADE_COMPARE(scene.fieldArraySize(4), 0);
CORRADE_COMPARE(scene.fieldName(5), Trade::sceneFieldCustom(16));
CORRADE_COMPARE(scene.fieldFlags(5), Trade::SceneFieldFlag::ImplicitMapping);
CORRADE_COMPARE(scene.fieldType(5), Trade::SceneFieldType::Bit);
CORRADE_COMPARE(scene.fieldArraySize(5), 0);
CORRADE_COMPARE_AS(scene.mappingAsArray(5),
Containers::arrayView({23u, 24u, 25u, 26u}),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.fieldBits(5),
Containers::stridedArrayView({false, true, false, true}).sliceBit(0),
TestSuite::Compare::Container);
CORRADE_COMPARE(scene.fieldName(6), Trade::sceneFieldCustom(17));
CORRADE_COMPARE(scene.fieldFlags(6), Trade::SceneFieldFlag::OrderedMapping);
CORRADE_COMPARE(scene.fieldType(6), Trade::SceneFieldType::Bit);
CORRADE_COMPARE(scene.fieldArraySize(6), 4);
CORRADE_COMPARE_AS(scene.mappingAsArray(6),
Containers::arrayView({13u, 25u, 77u}),
TestSuite::Compare::Container);
/** @todo clean up once it's possible to compare multidimensional
containers */
CORRADE_COMPARE_AS(scene.fieldBitArrays(6)[0],
Containers::stridedArrayView({false, false, true, true}).sliceBit(0),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.fieldBitArrays(6)[1],
Containers::stridedArrayView({false, false, false, true}).sliceBit(0),
TestSuite::Compare::Container);
CORRADE_COMPARE_AS(scene.fieldBitArrays(6)[2],
Containers::stridedArrayView({true, true, true, false}).sliceBit(0),
TestSuite::Compare::Container);
}
void CombineTest::fieldsAlignment() {
@ -360,12 +422,16 @@ void CombineTest::fieldsMappingPlaceholderFieldPlaceholder() {
Trade::SceneFieldData{Trade::sceneFieldCustom(15),
Containers::ArrayView<UnsignedShort>{nullptr, 2},
Containers::StridedArrayView2D<Short>{{nullptr, 16}, {2, 4}}},
/* Bit array field */
Trade::SceneFieldData{Trade::sceneFieldCustom(16),
Containers::ArrayView<UnsignedLong>{nullptr, 3},
Containers::StridedBitArrayView2D{{nullptr, 1, 8}, {3, 2}}},
});
CORRADE_COMPARE(scene.dataFlags(), Trade::DataFlag::Owned|Trade::DataFlag::Mutable);
CORRADE_COMPARE(scene.mappingType(), Trade::SceneMappingType::UnsignedShort);
CORRADE_COMPARE(scene.mappingBound(), 173);
CORRADE_COMPARE(scene.fieldCount(), 4);
CORRADE_COMPARE(scene.fieldCount(), 5);
CORRADE_COMPARE(scene.fieldType(Trade::SceneField::Camera), Trade::SceneFieldType::UnsignedShort);
CORRADE_COMPARE(scene.fieldSize(Trade::SceneField::Camera), 1);
@ -387,18 +453,33 @@ void CombineTest::fieldsMappingPlaceholderFieldPlaceholder() {
CORRADE_COMPARE(scene.fieldType(Trade::SceneField::Light), Trade::SceneFieldType::UnsignedInt);
CORRADE_COMPARE(scene.fieldSize(Trade::SceneField::Light), 2);
CORRADE_COMPARE(scene.fieldArraySize(Trade::SceneField::Light), 0);
CORRADE_COMPARE(scene.mapping(Trade::SceneField::Light).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1);
CORRADE_COMPARE(scene.mapping(Trade::SceneField::Light).data(),
scene.data() + 2 + 2 + 3*2 + 3 + 1);
CORRADE_COMPARE(scene.mapping(Trade::SceneField::Light).stride()[0], 2);
CORRADE_COMPARE(scene.field(Trade::SceneField::Light).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2);
CORRADE_COMPARE(scene.field(Trade::SceneField::Light).data(),
scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2);
CORRADE_COMPARE(scene.field(Trade::SceneField::Light).stride()[0], 4);
CORRADE_COMPARE(scene.fieldType(Trade::sceneFieldCustom(15)), Trade::SceneFieldType::Short);
CORRADE_COMPARE(scene.fieldSize(Trade::sceneFieldCustom(15)), 2);
CORRADE_COMPARE(scene.fieldArraySize(Trade::sceneFieldCustom(15)), 4);
CORRADE_COMPARE(scene.mapping(Trade::sceneFieldCustom(15)).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4);
CORRADE_COMPARE(scene.mapping(Trade::sceneFieldCustom(15)).data(),
scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4);
CORRADE_COMPARE(scene.mapping(Trade::sceneFieldCustom(15)).stride()[0], 2);
CORRADE_COMPARE(scene.field(Trade::sceneFieldCustom(15)).data(), scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4 + 2*2);
CORRADE_COMPARE(scene.field(Trade::sceneFieldCustom(15)).data(),
scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4 + 2*2);
CORRADE_COMPARE(scene.field(Trade::sceneFieldCustom(15)).stride()[0], 4*2);
CORRADE_COMPARE(scene.fieldType(Trade::sceneFieldCustom(16)), Trade::SceneFieldType::Bit);
CORRADE_COMPARE(scene.fieldSize(Trade::sceneFieldCustom(16)), 3);
CORRADE_COMPARE(scene.fieldArraySize(Trade::sceneFieldCustom(16)), 2);
CORRADE_COMPARE(scene.mapping(Trade::sceneFieldCustom(16)).data(),
scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4 + 2*2 + 2*8);
CORRADE_COMPARE(scene.mapping(Trade::sceneFieldCustom(16)).stride()[0], 2);
CORRADE_COMPARE(scene.fieldBitArrays(Trade::sceneFieldCustom(16)).data(),
scene.data() + 2 + 2 + 3*2 + 3 + 1 + 2*2 + 2 + 2*4 + 2*2 + 2*8 + 3*2);
CORRADE_COMPARE(scene.fieldBitArrays(Trade::sceneFieldCustom(16)).offset(), 0);
CORRADE_COMPARE(scene.fieldBitArrays(Trade::sceneFieldCustom(16)).stride()[0], 2);
}
void CombineTest::fieldsMappingSharedFieldPlaceholder() {

Loading…
Cancel
Save