diff --git a/src/Magnum/SceneTools/FlattenMeshHierarchy.cpp b/src/Magnum/SceneTools/FlattenMeshHierarchy.cpp index 9253aaa80..ec12a0bd9 100644 --- a/src/Magnum/SceneTools/FlattenMeshHierarchy.cpp +++ b/src/Magnum/SceneTools/FlattenMeshHierarchy.cpp @@ -26,7 +26,9 @@ #include "FlattenMeshHierarchy.h" #include +#include #include +#include #include #include @@ -45,16 +47,16 @@ template<> struct SceneDataDimensionTraits<2> { static bool isDimensions(const Trade::SceneData& scene) { return scene.is2D(); } - static Containers::Array> transformationsAsArray(const Trade::SceneData& scene) { - return scene.transformations2DAsArray(); + static void transformationsInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D& mappingDestination, const Containers::StridedArrayView1D& transformationDestination) { + return scene.transformations2DInto(mappingDestination, transformationDestination); } }; template<> struct SceneDataDimensionTraits<3> { static bool isDimensions(const Trade::SceneData& scene) { return scene.is3D(); } - static Containers::Array> transformationsAsArray(const Trade::SceneData& scene) { - return scene.transformations3DAsArray(); + static void transformationsInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D& mappingDestination, const Containers::StridedArrayView1D& transformationDestination) { + return scene.transformations3DInto(mappingDestination, transformationDestination); } }; @@ -62,7 +64,8 @@ template Containers::Array>> flattenMeshHierarchyImplementation(const Trade::SceneData& scene, const MatrixTypeFor& globalTransformation) { CORRADE_ASSERT(SceneDataDimensionTraits::isDimensions(scene), "SceneTools::flattenMeshHierarchy(): the scene is not" << dimensions << Debug::nospace << "D", {}); - CORRADE_ASSERT(scene.hasField(Trade::SceneField::Parent), + const Containers::Optional parentFieldId = scene.findFieldId(Trade::SceneField::Parent); + CORRADE_ASSERT(parentFieldId, "SceneTools::flattenMeshHierarchy(): the scene has no hierarchy", {}); /* If there's no mesh field in the file, nothing to do. Another case is @@ -70,16 +73,32 @@ Containers::Array> orderedClusteredParents = orderClusterParents(scene); + /* Allocate a single storage for all temporary data */ + Containers::ArrayView> orderedClusteredParents; + Containers::ArrayView>> transformations; + Containers::ArrayView> absoluteTransformations; + Containers::ArrayTuple storage{ + /* Output of orderClusterParentsInto() */ + {NoInit, scene.fieldSize(*parentFieldId), orderedClusteredParents}, + /* Output of scene.transformationsXDInto() */ + {NoInit, scene.transformationFieldSize(), transformations}, + /* Above transformations but indexed by object ID */ + {ValueInit, std::size_t(scene.mappingBound() + 1), absoluteTransformations} + }; + /* Explicit slice() template parameters needed by GCC 4.8 and MSVC 2015 */ + orderClusterParentsInto(scene, + stridedArrayView(orderedClusteredParents).slice(&Containers::Pair::first), + stridedArrayView(orderedClusteredParents).slice(&Containers::Pair::second)); + SceneDataDimensionTraits::transformationsInto(scene, + stridedArrayView(transformations).template slice(&Containers::Pair>::first), + stridedArrayView(transformations).template slice>(&Containers::Pair>::second)); /* Retrieve transformations of all objects, indexed by object ID. Since not - all nodes in the hierarchy may have a transformation assigned, - initialize the whole array to identity first. */ + all nodes in the hierarchy may have a transformation assigned, the whole + array got initialized to identity first. */ /** @todo switch to a hashmap eventually? */ - Containers::Array> absoluteTransformations{DefaultInit, scene.mappingBound() + 1}; absoluteTransformations[0] = globalTransformation; - /** @todo switch to *Into() in a loop to avoid temp allocations */ - for(const Containers::Pair>& transformation: SceneDataDimensionTraits::transformationsAsArray(scene)) { + for(const Containers::Pair>& transformation: transformations) { CORRADE_INTERNAL_ASSERT(transformation.first() < scene.mappingBound()); absoluteTransformations[transformation.first() + 1] = transformation.second(); }