Browse Source

SceneTools: make orderClusterParents() use one allocation instead of 4.

Mmm. I wonder how much will future mosra hate me for making this code so
obfuscated.
pull/542/merge
Vladimír Vondruš 4 years ago
parent
commit
eb2e4ff25d
  1. 31
      src/Magnum/SceneTools/OrderClusterParents.cpp

31
src/Magnum/SceneTools/OrderClusterParents.cpp

@ -26,6 +26,7 @@
#include "OrderClusterParents.h"
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayTuple.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/Pair.h>
@ -45,7 +46,6 @@ Containers::Array<Containers::Pair<UnsignedInt, Int>> orderClusterParents(const
}
void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D<UnsignedInt>& mappingDestination, const Containers::StridedArrayView1D<Int>& parentDestination) {
#ifndef CORRADE_NO_ASSERT
const Containers::Optional<UnsignedInt> parentFieldId = scene.findFieldId(Trade::SceneField::Parent);
CORRADE_ASSERT(parentFieldId,
"SceneTools::orderClusterParentsInto(): the scene has no hierarchy", );
@ -54,15 +54,34 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St
"SceneTools::orderClusterParentsInto(): expected mapping destination view with" << parentFieldSize << "elements but got" << mappingDestination.size(), );
CORRADE_ASSERT(parentDestination.size() == scene.fieldSize(*parentFieldId),
"SceneTools::orderClusterParentsInto(): expected parent destination view with" << parentFieldSize << "elements but got" << parentDestination.size(), );
#endif
/* Convert the parent list to a child list to sort them toplogically */
const Containers::Array<Containers::Pair<UnsignedInt, Int>> parents = scene.parentsAsArray();
/* Allocate a single storage for all temporary data */
Containers::ArrayView<Containers::Pair<UnsignedInt, Int>> parents;
Containers::ArrayView<UnsignedInt> childrenOffsets;
Containers::ArrayView<UnsignedInt> children;
Containers::ArrayView<Int> parentsToProcess;
Containers::ArrayTuple storage{
/* Output of scene.parentsInto() */
{NoInit, parentFieldSize, parents},
/* Running children offset (+1) for each node including root (+1), plus
one more element when we shift the array by one below */
{ValueInit, std::size_t(scene.mappingBound() + 3), childrenOffsets},
{NoInit, parentFieldSize, children},
/* List of parents to process. Can't reuse mappingDestination because
this includes one more element for root objects. */
{NoInit, parentFieldSize + 1, parentsToProcess}
};
/* Convert the parent list to a child list to sort them toplogically.
Explicit slice() template parameters needed by GCC 4.8 and MSVC 2015 */
scene.parentsInto(
stridedArrayView(parents).slice<UnsignedInt>(&Containers::Pair<UnsignedInt, Int>::first),
stridedArrayView(parents).slice<Int>(&Containers::Pair<UnsignedInt, Int>::second)
);
/* Children offset for each node including root. First calculate the count
of children for each, skipping the first element (parent.second() can be
-1, accounting for that as well)... */
Containers::Array<UnsignedInt> childrenOffsets{DirectInit, scene.mappingBound() + 3, 0u};
for(const Containers::Pair<UnsignedInt, Int>& parent: parents) {
CORRADE_INTERNAL_ASSERT(parent.first() < scene.mappingBound() && (parent.second() == -1 || UnsignedInt(parent.second()) < scene.mappingBound()));
++childrenOffsets[parent.second() + 2];
@ -84,7 +103,6 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St
now `[childrenOffsets[i + 1], childrenOffsets[i + 2])` contains a range
in which the `children` array below contains a list of children for
`i`. */
Containers::Array<UnsignedInt> children{NoInit, parents.size()};
for(const Containers::Pair<UnsignedInt, Int>& parent: parents)
children[childrenOffsets[parent.second() + 2]++] = parent.first();
@ -92,7 +110,6 @@ void orderClusterParentsInto(const Trade::SceneData& scene, const Containers::St
other) and build a list of (id, parent id) where a parent is always
before its children */
std::size_t outputOffset = 0;
Containers::Array<Int> parentsToProcess{NoInit, parents.size() + 1};
parentsToProcess[0] = -1;
for(std::size_t i = 0; i != outputOffset + 1; ++i) {
const Int objectId = parentsToProcess[i];

Loading…
Cancel
Save