Browse Source

SceneTools: flattenTransformHierarchy*D() -> absoluteFieldTransform*D().

That's a second deprecation of this API in a short while, sorry. This
variant is hopefully the final one, with the previous one I still had
the problem that it contained a verb, which implied that it'd
*transform* the SceneData in some way which (unlike combineFields(),
filterFields() etc.) it didn't, it just extracts some data in a certain
way. This would all cause problems when there are APIs that actually do
perform hierarchy flattening.

It's also moved to a new, more general Hierarchy.h header which will
contain other hierarchy-related APIs. It doesn't make sense to have a
tiny header with just a single function, especially given it doesn't
depend on any heavy headers on its own.

Besides that it also makes the UnsignedInt overloads the main ones, and
the Trade::SceneField secondary, as is already done everywhere else (and
the opposite way was just bad inheritance from flattenMeshHierarchy()
it seems).
pull/620/head
Vladimír Vondruš 3 years ago
parent
commit
4a92ccfadd
  1. 14
      doc/snippets/MagnumSceneTools.cpp
  2. 2
      modules/FindMagnum.cmake
  3. 8
      src/Magnum/SceneTools/CMakeLists.txt
  4. 10
      src/Magnum/SceneTools/FlattenMeshHierarchy.cpp
  5. 26
      src/Magnum/SceneTools/FlattenMeshHierarchy.h
  6. 237
      src/Magnum/SceneTools/FlattenTransformationHierarchy.h
  7. 94
      src/Magnum/SceneTools/Hierarchy.cpp
  8. 237
      src/Magnum/SceneTools/Hierarchy.h
  9. 2
      src/Magnum/SceneTools/Test/CMakeLists.txt
  10. 14
      src/Magnum/SceneTools/Test/FlattenMeshHierarchyTest.cpp
  11. 146
      src/Magnum/SceneTools/Test/HierarchyTest.cpp
  12. 10
      src/Magnum/SceneTools/sceneconverter.cpp

14
doc/snippets/MagnumSceneTools.cpp

@ -32,7 +32,7 @@
#include "Magnum/Math/Matrix4.h" #include "Magnum/Math/Matrix4.h"
#include "Magnum/MeshTools/Concatenate.h" #include "Magnum/MeshTools/Concatenate.h"
#include "Magnum/MeshTools/Transform.h" #include "Magnum/MeshTools/Transform.h"
#include "Magnum/SceneTools/FlattenTransformationHierarchy.h" #include "Magnum/SceneTools/Hierarchy.h"
#include "Magnum/SceneTools/OrderClusterParents.h" #include "Magnum/SceneTools/OrderClusterParents.h"
#include "Magnum/Trade/SceneData.h" #include "Magnum/Trade/SceneData.h"
#include "Magnum/Trade/MeshData.h" #include "Magnum/Trade/MeshData.h"
@ -43,14 +43,14 @@ using namespace Magnum;
int main() { int main() {
{ {
/* [flattenTransformationHierarchy2D-mesh-concatenate] */ /* [absoluteFieldTransformations2D-mesh-concatenate] */
Trade::SceneData scene = DOXYGEN_ELLIPSIS(Trade::SceneData{{}, 0, nullptr, {}}); Trade::SceneData scene = DOXYGEN_ELLIPSIS(Trade::SceneData{{}, 0, nullptr, {}});
Containers::Array<Trade::MeshData> meshes = DOXYGEN_ELLIPSIS({}); Containers::Array<Trade::MeshData> meshes = DOXYGEN_ELLIPSIS({});
Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>> Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>>
meshesMaterials = scene.meshesMaterialsAsArray(); meshesMaterials = scene.meshesMaterialsAsArray();
Containers::Array<Matrix3> transformations = Containers::Array<Matrix3> transformations =
SceneTools::flattenTransformationHierarchy2D(scene, Trade::SceneField::Mesh); SceneTools::absoluteFieldTransformations2D(scene, Trade::SceneField::Mesh);
/* Since a mesh can be referenced multiple times, we can't operate in-place */ /* Since a mesh can be referenced multiple times, we can't operate in-place */
Containers::Array<Trade::MeshData> flattenedMeshes; Containers::Array<Trade::MeshData> flattenedMeshes;
@ -60,16 +60,16 @@ for(std::size_t i = 0; i != meshesMaterials.size(); ++i) {
} }
Trade::MeshData concatenated = MeshTools::concatenate(flattenedMeshes); Trade::MeshData concatenated = MeshTools::concatenate(flattenedMeshes);
/* [flattenTransformationHierarchy2D-mesh-concatenate] */ /* [absoluteFieldTransformations2D-mesh-concatenate] */
} { } {
/* [flattenTransformationHierarchy3D-mesh-concatenate] */ /* [absoluteFieldTransformations3D-mesh-concatenate] */
Trade::SceneData scene = DOXYGEN_ELLIPSIS(Trade::SceneData{{}, 0, nullptr, {}}); Trade::SceneData scene = DOXYGEN_ELLIPSIS(Trade::SceneData{{}, 0, nullptr, {}});
Containers::Array<Trade::MeshData> meshes = DOXYGEN_ELLIPSIS({}); Containers::Array<Trade::MeshData> meshes = DOXYGEN_ELLIPSIS({});
Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>> Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>>
meshesMaterials = scene.meshesMaterialsAsArray(); meshesMaterials = scene.meshesMaterialsAsArray();
Containers::Array<Matrix4> transformations = Containers::Array<Matrix4> transformations =
SceneTools::flattenTransformationHierarchy3D(scene, Trade::SceneField::Mesh); SceneTools::absoluteFieldTransformations3D(scene, Trade::SceneField::Mesh);
/* Since a mesh can be referenced multiple times, we can't operate in-place */ /* Since a mesh can be referenced multiple times, we can't operate in-place */
Containers::Array<Trade::MeshData> flattenedMeshes; Containers::Array<Trade::MeshData> flattenedMeshes;
@ -79,7 +79,7 @@ for(std::size_t i = 0; i != meshesMaterials.size(); ++i) {
} }
Trade::MeshData concatenated = MeshTools::concatenate(flattenedMeshes); Trade::MeshData concatenated = MeshTools::concatenate(flattenedMeshes);
/* [flattenTransformationHierarchy3D-mesh-concatenate] */ /* [absoluteFieldTransformations3D-mesh-concatenate] */
} }
{ {

2
modules/FindMagnum.cmake

@ -910,7 +910,7 @@ foreach(_component ${Magnum_FIND_COMPONENTS})
# SceneTools library # SceneTools library
elseif(_component STREQUAL SceneTools) elseif(_component STREQUAL SceneTools)
set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES FlattenTransformationHierarchy.h) set(_MAGNUM_${_COMPONENT}_INCLUDE_PATH_NAMES Hierarchy.h)
# ShaderTools library # ShaderTools library
elseif(_component STREQUAL ShaderTools) elseif(_component STREQUAL ShaderTools)

8
src/Magnum/SceneTools/CMakeLists.txt

@ -45,13 +45,13 @@ set(MagnumSceneTools_SRCS )
set(MagnumSceneTools_GracefulAssert_SRCS set(MagnumSceneTools_GracefulAssert_SRCS
Combine.cpp Combine.cpp
Filter.cpp Filter.cpp
FlattenTransformationHierarchy.cpp Hierarchy.cpp
OrderClusterParents.cpp) OrderClusterParents.cpp)
set(MagnumSceneTools_HEADERS set(MagnumSceneTools_HEADERS
Combine.h Combine.h
Filter.h Filter.h
FlattenTransformationHierarchy.h Hierarchy.h
OrderClusterParents.h OrderClusterParents.h
visibility.h) visibility.h)
@ -63,7 +63,9 @@ set(MagnumSceneTools_PRIVATE_HEADERS
if(MAGNUM_BUILD_DEPRECATED) if(MAGNUM_BUILD_DEPRECATED)
list(APPEND MagnumSceneTools_GracefulAssert_SRCS FlattenMeshHierarchy.cpp) list(APPEND MagnumSceneTools_GracefulAssert_SRCS FlattenMeshHierarchy.cpp)
list(APPEND MagnumSceneTools_HEADERS FlattenMeshHierarchy.h) list(APPEND MagnumSceneTools_HEADERS
FlattenMeshHierarchy.h
FlattenTransformationHierarchy.h)
endif() endif()
## Objects shared between main and test library ## Objects shared between main and test library

10
src/Magnum/SceneTools/FlattenMeshHierarchy.cpp

@ -34,7 +34,7 @@
#include "Magnum/DimensionTraits.h" #include "Magnum/DimensionTraits.h"
#include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h" #include "Magnum/Math/Matrix4.h"
#include "Magnum/SceneTools/FlattenTransformationHierarchy.h" #include "Magnum/SceneTools/Hierarchy.h"
#include "Magnum/Trade/SceneData.h" #include "Magnum/Trade/SceneData.h"
namespace Magnum { namespace SceneTools { namespace Magnum { namespace SceneTools {
@ -44,18 +44,18 @@ namespace {
template<UnsignedInt> struct DimensionTraits; template<UnsignedInt> struct DimensionTraits;
template<> struct DimensionTraits<2> { template<> struct DimensionTraits<2> {
static Containers::Array<Matrix3> flatten(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix3& globalTransformation) { static Containers::Array<Matrix3> flatten(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix3& globalTransformation) {
return flattenTransformationHierarchy2D(scene, fieldId, globalTransformation); return absoluteFieldTransformations2D(scene, fieldId, globalTransformation);
} }
static void flattenInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation) { static void flattenInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation) {
return flattenTransformationHierarchy2DInto(scene, fieldId, transformations, globalTransformation); return absoluteFieldTransformations2DInto(scene, fieldId, transformations, globalTransformation);
} }
}; };
template<> struct DimensionTraits<3> { template<> struct DimensionTraits<3> {
static Containers::Array<Matrix4> flatten(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix4& globalTransformation) { static Containers::Array<Matrix4> flatten(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix4& globalTransformation) {
return flattenTransformationHierarchy3D(scene, fieldId, globalTransformation); return absoluteFieldTransformations3D(scene, fieldId, globalTransformation);
} }
static void flattenInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation) { static void flattenInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation) {
return flattenTransformationHierarchy3DInto(scene, fieldId, transformations, globalTransformation); return absoluteFieldTransformations3DInto(scene, fieldId, transformations, globalTransformation);
} }
}; };

26
src/Magnum/SceneTools/FlattenMeshHierarchy.h

@ -28,9 +28,9 @@
#ifdef MAGNUM_BUILD_DEPRECATED #ifdef MAGNUM_BUILD_DEPRECATED
/** @file /** @file
* @brief Function @ref Magnum::SceneTools::flattenMeshHierarchy2D(), @ref Magnum::SceneTools::flattenMeshHierarchy2DInto(), @ref Magnum::SceneTools::flattenMeshHierarchy3D(), @ref Magnum::SceneTools::flattenMeshHierarchy3DInto() * @brief Function @ref Magnum::SceneTools::flattenMeshHierarchy2D(), @ref Magnum::SceneTools::flattenMeshHierarchy2DInto(), @ref Magnum::SceneTools::flattenMeshHierarchy3D(), @ref Magnum::SceneTools::flattenMeshHierarchy3DInto()
* @m_deprecated_since_latest Use @ref Magnum/SceneTools/FlattenTransformationHierarchy.h * @m_deprecated_since_latest Use @ref Magnum/SceneTools/Hierarchy.h and the
* and the @relativeref{Magnum,SceneTools::flattenTransformationHierarchy2D()} / * @relativeref{Magnum,SceneTools::absoluteFieldTransformations2D()} /
* @relativeref{Magnum,SceneTools::flattenTransformationHierarchy3D()} * @relativeref{Magnum,SceneTools::absoluteFieldTransformations3D()}
* functions instead. * functions instead.
*/ */
#endif #endif
@ -47,7 +47,7 @@
#include "Magnum/Trade/Trade.h" #include "Magnum/Trade/Trade.h"
#ifndef _MAGNUM_NO_DEPRECATED_FLATTENMESHHIERARCHY #ifndef _MAGNUM_NO_DEPRECATED_FLATTENMESHHIERARCHY
CORRADE_DEPRECATED_FILE("use Magnum/SceneTools/FlattenTransformationHierarchy.h and the SceneTools::flattenTransformationHierarchy*D() functions instead") CORRADE_DEPRECATED_FILE("use Magnum/SceneTools/Hierarchy.h and the SceneTools::absoluteFieldTransformations*D() functions instead")
#endif #endif
namespace Magnum { namespace SceneTools { namespace Magnum { namespace SceneTools {
@ -55,11 +55,11 @@ namespace Magnum { namespace SceneTools {
/** /**
@brief Flatten a 2D mesh hierarchy @brief Flatten a 2D mesh hierarchy
@m_deprecated_since_latest Use @ref flattenTransformationHierarchy2D(const Trade::SceneData&, Trade::SceneField, const Matrix3& globalTransformation) @m_deprecated_since_latest Use @ref absoluteFieldTransformations2D(const Trade::SceneData&, Trade::SceneField, const Matrix3&)
with @ref Trade::SceneField::Mesh together with with @ref Trade::SceneField::Mesh together with
@ref Trade::SceneData::meshesMaterialsAsArray() instead. @ref Trade::SceneData::meshesMaterialsAsArray() instead.
*/ */
CORRADE_DEPRECATED("use flattenTransformationHierarchy2D() instead") MAGNUM_SCENETOOLS_EXPORT Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix3>> flattenMeshHierarchy2D(const Trade::SceneData& scene, const Matrix3& globalTransformation = {}); CORRADE_DEPRECATED("use absoluteFieldTransformations2D() instead") MAGNUM_SCENETOOLS_EXPORT Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix3>> flattenMeshHierarchy2D(const Trade::SceneData& scene, const Matrix3& globalTransformation = {});
/** /**
@brief Flatten a 2D mesh hierarchy into an existing array @brief Flatten a 2D mesh hierarchy into an existing array
@ -67,19 +67,19 @@ CORRADE_DEPRECATED("use flattenTransformationHierarchy2D() instead") MAGNUM_SCEN
@param[out] transformations Where to put the calculated transformations @param[out] transformations Where to put the calculated transformations
@param[in] globalTransformation Global transformation to prepend @param[in] globalTransformation Global transformation to prepend
@m_deprecated_since_latest Use @ref flattenTransformationHierarchy2DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix3>&, const Matrix3&) @m_deprecated_since_latest Use @ref absoluteFieldTransformations2DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix3>&, const Matrix3&)
with @ref Trade::SceneField::Mesh instead. with @ref Trade::SceneField::Mesh instead.
*/ */
CORRADE_DEPRECATED("use flattenTransformationHierarchy2DInto() instead") MAGNUM_SCENETOOLS_EXPORT void flattenMeshHierarchy2DInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {}); CORRADE_DEPRECATED("use absoluteFieldTransformations2DInto() instead") MAGNUM_SCENETOOLS_EXPORT void flattenMeshHierarchy2DInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {});
/** /**
@brief Flatten a 3D mesh hierarchy @brief Flatten a 3D mesh hierarchy
@m_deprecated_since_latest Use @ref flattenTransformationHierarchy3D(const Trade::SceneData&, Trade::SceneField, const Matrix4&) @m_deprecated_since_latest Use @ref absoluteFieldTransformations3D(const Trade::SceneData&, Trade::SceneField, const Matrix4&)
with @ref Trade::SceneField::Mesh together with with @ref Trade::SceneField::Mesh together with
@ref Trade::SceneData::meshesMaterialsAsArray() instead. @ref Trade::SceneData::meshesMaterialsAsArray() instead.
*/ */
CORRADE_DEPRECATED("use flattenTransformationHierarchy3D() instead") MAGNUM_SCENETOOLS_EXPORT Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix4>> flattenMeshHierarchy3D(const Trade::SceneData& scene, const Matrix4& globalTransformation = {}); CORRADE_DEPRECATED("use absoluteFieldTransformations3D() instead") MAGNUM_SCENETOOLS_EXPORT Containers::Array<Containers::Triple<UnsignedInt, Int, Matrix4>> flattenMeshHierarchy3D(const Trade::SceneData& scene, const Matrix4& globalTransformation = {});
/** /**
@brief Flatten a 3D mesh hierarchy into an existing array @brief Flatten a 3D mesh hierarchy into an existing array
@ -87,14 +87,14 @@ CORRADE_DEPRECATED("use flattenTransformationHierarchy3D() instead") MAGNUM_SCEN
@param[out] transformations Where to put the calculated transformations @param[out] transformations Where to put the calculated transformations
@param[in] globalTransformation Global transformation to prepend @param[in] globalTransformation Global transformation to prepend
@m_deprecated_since_latest Use @ref flattenTransformationHierarchy3DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix4>&, const Matrix4&) @m_deprecated_since_latest Use @ref absoluteFieldTransformations3DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix4>&, const Matrix4&)
with @ref Trade::SceneField::Mesh instead. with @ref Trade::SceneField::Mesh instead.
*/ */
CORRADE_DEPRECATED("use flattenTransformationHierarchy3DInto() instead") MAGNUM_SCENETOOLS_EXPORT void flattenMeshHierarchy3DInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {}); CORRADE_DEPRECATED("use absoluteFieldTransformations3DInto() instead") MAGNUM_SCENETOOLS_EXPORT void flattenMeshHierarchy3DInto(const Trade::SceneData& scene, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {});
}} }}
#else #else
#error use Magnum/SceneTools/FlattenTransformationHierarchy.h and the SceneTools::flattenTransformationHierarchy*D() functions instead #error use Magnum/SceneTools/FlattenTransformationHierarchy.h and the SceneTools::absoluteFieldTransformations*D() functions instead
#endif #endif
#endif #endif

237
src/Magnum/SceneTools/FlattenTransformationHierarchy.h

@ -25,219 +25,108 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#ifdef MAGNUM_BUILD_DEPRECATED
/** @file /** @file
* @brief Function @ref Magnum::SceneTools::flattenTransformationHierarchy2D(), @ref Magnum::SceneTools::flattenTransformationHierarchy2DInto(), @ref Magnum::SceneTools::flattenTransformationHierarchy3D(), @ref Magnum::SceneTools::flattenTransformationHierarchy3DInto() * @brief Function @ref Magnum::SceneTools::flattenTransformationHierarchy2D(), @ref Magnum::SceneTools::flattenTransformationHierarchy2DInto(), @ref Magnum::SceneTools::flattenTransformationHierarchy3D(), @ref Magnum::SceneTools::flattenTransformationHierarchy3DInto()
* @m_since_latest * @m_deprecated_since_latest Use @ref Magnum/SceneTools/Hierarchy.h and the
* @relativeref{Magnum,SceneTools::absoluteFieldTransformations2D()} /
* @relativeref{Magnum,SceneTools::absoluteFieldTransformations3D()}
* functions instead.
*/ */
#endif
#include "Magnum/Magnum.h" #include "Magnum/configure.h"
#include "Magnum/SceneTools/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace SceneTools {
/**
@brief Flatten a 2D transformation hierarchy for given field
@m_since_latest
For all entries of given @p field in @p scene returns an absolute
transformation of the object they're attached to in the scene with
@p globalTransformation prepended. The @ref Trade::SceneField::Parent field is
expected to be contained in the scene, having no cycles or duplicates, and the
scene is expected to be 2D. The @p field is expected to be present, if it's
empty, the function returns an empty array.
The operation is done in an @f$ \mathcal{O}(m + n) @f$ execution time and #ifdef MAGNUM_BUILD_DEPRECATED
memory complexity, with @f$ m @f$ being size of @p field and @f$ n @f$ being #include <Corrade/Containers/Array.h>
@ref Trade::SceneData::mappingBound(). The function calls #include <Corrade/Utility/Macros.h>
@ref orderClusterParents() internally.
The returned data are in the same order as object mapping entries in @p field. #include "Magnum/Math/Matrix3.h"
Fields attached to objects without a @ref Trade::SceneField::Parent or to #include "Magnum/Math/Matrix4.h"
objects in loose hierarchy subtrees will have their transformation set to an #include "Magnum/SceneTools/Hierarchy.h"
unspecified value. #include "Magnum/Trade/Trade.h"
This function can be used for example to flatten a mesh hierarchy, bake CORRADE_DEPRECATED_FILE("use Magnum/SceneTools/Hierarchy.h and the SceneTools::absoluteFieldTransformations*D() functions instead")
the transformations to actual meshes and then concatenate them together into a
single mesh:
@snippet MagnumSceneTools.cpp flattenTransformationHierarchy2D-mesh-concatenate namespace Magnum { namespace SceneTools {
@experimental /* Made header-only to not have to maintain a deprecated source file */
@see @ref flattenTransformationHierarchy2D(const Trade::SceneData&, UnsignedInt, const Matrix3&), /**
@ref flattenTransformationHierarchy2DInto(), @brief Flatten a 2D transformation hierarchy for given field
@ref flattenTransformationHierarchy3D(), @ref Trade::SceneData::hasField(), @m_deprecated_since_latest Use @ref absoluteFieldTransformations2D(const Trade::SceneData&, Trade::SceneField, const Matrix3&)
@ref Trade::SceneData::is2D() instead.
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations2D() instead") Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation = {}); return absoluteFieldTransformations2D(scene, field, globalTransformation);
#else }
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, Trade::SceneField field);
#endif
/** /**
@brief Flatten a 2D transformation hierarchy for given field ID @brief Flatten a 2D transformation hierarchy for given field ID
@m_since_latest @m_deprecated_since_latest Use @ref absoluteFieldTransformations2D(const Trade::SceneData&, UnsignedInt, const Matrix3&)
instead.
A variant of @ref flattenTransformationHierarchy2D(const Trade::SceneData&, Trade::SceneField, const Matrix3&)
that takes a field ID instead of name. Useful for example in combination with
@ref Trade::SceneData::findFieldId() to avoid a double lookup if it isn't clear
if a field exists at all. The @p fieldId is expected to be smaller than
@ref Trade::SceneData::fieldCount().
@experimental
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations2D() instead") Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation = {}); return absoluteFieldTransformations2D(scene, fieldId, globalTransformation);
#else }
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, UnsignedInt fieldId);
#endif
/** /**
@brief Flatten a 2D transformation hierarchy for given field into an existing array @brief Flatten a 2D transformation hierarchy for given field into an existing array
@param[in] scene Input scene @m_deprecated_since_latest Use @ref absoluteFieldTransformations2DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix3>&, const Matrix3&)
@param[in] field Field to calculate the transformations for instead.
@param[out] transformations Where to put the calculated transformations
@param[in] globalTransformation Global transformation to prepend
@m_since_latest
A variant of @ref flattenTransformationHierarchy2D(const Trade::SceneData&, Trade::SceneField, const Matrix3&)
that fills existing memory instead of allocating a new array. The
@p transformations array is expected to have the same size as the @p field.
@experimental
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations2DInto() instead") void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {}); return absoluteFieldTransformations2DInto(scene, field, transformations, globalTransformation);
#else }
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations);
#endif
/** /**
@brief Flatten a 2D transformation hierarchy for given field ID into an existing array @brief Flatten a 2D transformation hierarchy for given field ID into an existing array
@m_since_latest @m_deprecated_since_latest Use @ref absoluteFieldTransformations2DInto(const Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<Matrix3>&, const Matrix3&)
instead.
A variant of @ref flattenTransformationHierarchy2DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix3>&, const Matrix3&)
that takes a field ID instead of name. Useful for example in combination with
@ref Trade::SceneData::findFieldId() to avoid a double lookup if it isn't clear
if a field exists at all. The @p fieldId is expected to be smaller than
@ref Trade::SceneData::fieldCount().
@experimental
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations2DInto() instead") void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {}); return absoluteFieldTransformations2DInto(scene, fieldId, transformations, globalTransformation);
#else }
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations);
#endif
/** /**
@brief Flatten a 3D transformation hierarchy for given field @brief Flatten a 3D transformation hierarchy for given field
@m_since_latest @m_deprecated_since_latest Use @ref absoluteFieldTransformations3D(const Trade::SceneData&, Trade::SceneField, const Matrix4&)
instead.
For all entries of given @p field in @p scene returns an absolute
transformation of the object they're attached to in the scene with
@p globalTransformation prepended. The @ref Trade::SceneField::Parent field is
expected to be contained in the scene, having no cycles or duplicates, and the
scene is expected to be 3D. The @p field is expected to be present, if it's
empty, the function returns an empty array.
The operation is done in an @f$ \mathcal{O}(m + n) @f$ execution time and
memory complexity, with @f$ m @f$ being size of @p field and @f$ n @f$ being
@ref Trade::SceneData::mappingBound(). The function calls
@ref orderClusterParents() internally.
The returned data are in the same order as object mapping entries in @p field.
Fields attached to objects without a @ref Trade::SceneField::Parent or to
objects in loose hierarchy subtrees will have their transformation set to an
unspecified value.
This function can be used for example to flatten a mesh hierarchy, bake
the transformations to actual meshes and then concatenate them together into a
single mesh:
@snippet MagnumSceneTools.cpp flattenTransformationHierarchy3D-mesh-concatenate
@experimental
@see @ref flattenTransformationHierarchy3D(const Trade::SceneData&, UnsignedInt, const Matrix4&),
@ref flattenTransformationHierarchy3DInto(),
@ref flattenTransformationHierarchy2D(), @ref Trade::SceneData::hasField(),
@ref Trade::SceneData::is3D()
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations3D() instead") Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation = {}); return absoluteFieldTransformations3D(scene, field, globalTransformation);
#else }
/* To avoid including Matrix4 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, Trade::SceneField field);
#endif
/** /**
@brief Flatten a 3D transformation hierarchy for given field ID @brief Flatten a 3D transformation hierarchy for given field ID
@m_since_latest @m_deprecated_since_latest Use @ref absoluteFieldTransformations3D(const Trade::SceneData&, UnsignedInt, const Matrix4&)
instead.
A variant of @ref flattenTransformationHierarchy3D(const Trade::SceneData&, Trade::SceneField, const Matrix4&)
that takes a field ID instead of name. Useful for example in combination with
@ref Trade::SceneData::findFieldId() to avoid a double lookup if it isn't clear
if a field exists at all. The @p fieldId is expected to be smaller than
@ref Trade::SceneData::fieldCount().
@experimental
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations3D() instead") Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation = {}); return absoluteFieldTransformations3D(scene, fieldId, globalTransformation);
#else }
/* To avoid including Matrix34 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, UnsignedInt fieldId);
#endif
/** /**
@brief Flatten a 3D transformation hierarchy for given field into an existing array @brief Flatten a 3D transformation hierarchy for given field into an existing array
@param[in] scene Input scene @m_deprecated_since_latest Use @ref absoluteFieldTransformations3DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix4>&, const Matrix4&)
@param[in] field Field to calculate the transformations for instead.
@param[out] transformations Where to put the calculated transformations
@param[in] globalTransformation Global transformation to prepend
@m_since_latest
A variant of @ref flattenTransformationHierarchy3D(const Trade::SceneData&, Trade::SceneField, const Matrix4&)
that fills existing memory instead of allocating a new array. The
@p transformations array is expected to have the same size as the @p field.
@experimental
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations3DInto() instead") void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {}); return absoluteFieldTransformations3DInto(scene, field, transformations, globalTransformation);
#else }
/* To avoid including Matrix4 */
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations);
#endif
/** /**
@brief Flatten a 3D transformation hierarchy for given field into an existing array @brief Flatten a 3D transformation hierarchy for given field ID into an existing array
@m_since_latest @m_deprecated_since_latest Use @ref absoluteFieldTransformations3DInto(const Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<Matrix4>&, const Matrix4&)
instead.
A variant of @ref flattenTransformationHierarchy3DInto(const Trade::SceneData&, Trade::SceneField, const Containers::StridedArrayView1D<Matrix4>&, const Matrix4&)
that takes a field ID instead of name. Useful for example in combination with
@ref Trade::SceneData::findFieldId() to avoid a double lookup if it isn't clear
if a field exists at all. The @p fieldId is expected to be smaller than
@ref Trade::SceneData::fieldCount().
@experimental
*/ */
#ifdef DOXYGEN_GENERATING_OUTPUT inline CORRADE_DEPRECATED("use absoluteFieldTransformations3DInto() instead") void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {}) {
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {}); return absoluteFieldTransformations3DInto(scene, fieldId, transformations, globalTransformation);
#else }
/* To avoid including Matrix4 */
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations);
#endif
}} }}
#else
#error use Magnum/SceneTools/Hierarchy.h and the SceneTools::absoluteFieldTransformations*D() functions instead
#endif
#endif #endif

94
src/Magnum/SceneTools/FlattenTransformationHierarchy.cpp → src/Magnum/SceneTools/Hierarchy.cpp

@ -23,7 +23,7 @@
DEALINGS IN THE SOFTWARE. DEALINGS IN THE SOFTWARE.
*/ */
#include "FlattenTransformationHierarchy.h" #include "Hierarchy.h"
#include <Corrade/Containers/Array.h> #include <Corrade/Containers/Array.h>
#include <Corrade/Containers/ArrayTuple.h> #include <Corrade/Containers/ArrayTuple.h>
@ -59,16 +59,16 @@ template<> struct SceneDataDimensionTraits<3> {
} }
}; };
template<UnsignedInt dimensions> void flattenTransformationHierarchyIntoImplementation(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<MatrixTypeFor<dimensions, Float>>& outputTransformations, const MatrixTypeFor<dimensions, Float>& globalTransformation) { template<UnsignedInt dimensions> void absoluteFieldTransformationsIntoImplementation(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<MatrixTypeFor<dimensions, Float>>& outputTransformations, const MatrixTypeFor<dimensions, Float>& globalTransformation) {
CORRADE_ASSERT(SceneDataDimensionTraits<dimensions>::isDimensions(scene), CORRADE_ASSERT(SceneDataDimensionTraits<dimensions>::isDimensions(scene),
"SceneTools::flattenTransformationHierarchy(): the scene is not" << dimensions << Debug::nospace << "D", ); "SceneTools::absoluteFieldTransformations(): the scene is not" << dimensions << Debug::nospace << "D", );
CORRADE_ASSERT(fieldId < scene.fieldCount(), CORRADE_ASSERT(fieldId < scene.fieldCount(),
"SceneTools::flattenTransformationHierarchy(): index" << fieldId << "out of range for" << scene.fieldCount() << "fields", ); "SceneTools::absoluteFieldTransformations(): index" << fieldId << "out of range for" << scene.fieldCount() << "fields", );
const Containers::Optional<UnsignedInt> parentFieldId = scene.findFieldId(Trade::SceneField::Parent); const Containers::Optional<UnsignedInt> parentFieldId = scene.findFieldId(Trade::SceneField::Parent);
CORRADE_ASSERT(parentFieldId, CORRADE_ASSERT(parentFieldId,
"SceneTools::flattenTransformationHierarchy(): the scene has no hierarchy", ); "SceneTools::absoluteFieldTransformations(): the scene has no hierarchy", );
CORRADE_ASSERT(outputTransformations.size() == scene.fieldSize(fieldId), CORRADE_ASSERT(outputTransformations.size() == scene.fieldSize(fieldId),
"SceneTools::flattenTransformationHierarchyInto(): bad output size, expected" << scene.fieldSize(fieldId) << "but got" << outputTransformations.size(), ); "SceneTools::absoluteFieldTransformationsInto(): bad output size, expected" << scene.fieldSize(fieldId) << "but got" << outputTransformations.size(), );
/* Allocate a single storage for all temporary data */ /* Allocate a single storage for all temporary data */
Containers::ArrayView<Containers::Pair<UnsignedInt, Int>> orderedClusteredParents; Containers::ArrayView<Containers::Pair<UnsignedInt, Int>> orderedClusteredParents;
@ -118,97 +118,97 @@ template<UnsignedInt dimensions> void flattenTransformationHierarchyIntoImplemen
} }
} }
template<UnsignedInt dimensions> void flattenTransformationHierarchyIntoImplementation(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<MatrixTypeFor<dimensions, Float>>& outputTransformations, const MatrixTypeFor<dimensions, Float>& globalTransformation) { template<UnsignedInt dimensions> void absoluteFieldTransformationsIntoImplementation(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<MatrixTypeFor<dimensions, Float>>& outputTransformations, const MatrixTypeFor<dimensions, Float>& globalTransformation) {
const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field); const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field);
CORRADE_ASSERT(fieldId, CORRADE_ASSERT(fieldId,
"SceneTools::flattenTransformationHierarchyInto(): field" << field << "not found", ); "SceneTools::absoluteFieldTransformationsInto(): field" << field << "not found", );
flattenTransformationHierarchyIntoImplementation<dimensions>(scene, *fieldId, outputTransformations, globalTransformation); absoluteFieldTransformationsIntoImplementation<dimensions>(scene, *fieldId, outputTransformations, globalTransformation);
} }
template<UnsignedInt dimensions> Containers::Array<MatrixTypeFor<dimensions, Float>> flattenTransformationHierarchyImplementation(const Trade::SceneData& scene, const UnsignedInt fieldId, const MatrixTypeFor<dimensions, Float>& globalTransformation) { template<UnsignedInt dimensions> Containers::Array<MatrixTypeFor<dimensions, Float>> absoluteFieldTransformationsImplementation(const Trade::SceneData& scene, const UnsignedInt fieldId, const MatrixTypeFor<dimensions, Float>& globalTransformation) {
CORRADE_ASSERT(fieldId < scene.fieldCount(), CORRADE_ASSERT(fieldId < scene.fieldCount(),
"SceneTools::flattenTransformationHierarchy(): index" << fieldId << "out of range for" << scene.fieldCount() << "fields", {}); "SceneTools::absoluteFieldTransformations(): index" << fieldId << "out of range for" << scene.fieldCount() << "fields", {});
Containers::Array<MatrixTypeFor<dimensions, Float>> out{NoInit, scene.fieldSize(fieldId)}; Containers::Array<MatrixTypeFor<dimensions, Float>> out{NoInit, scene.fieldSize(fieldId)};
flattenTransformationHierarchyIntoImplementation<dimensions>(scene, fieldId, out, globalTransformation); absoluteFieldTransformationsIntoImplementation<dimensions>(scene, fieldId, out, globalTransformation);
return out; return out;
} }
template<UnsignedInt dimensions> Containers::Array<MatrixTypeFor<dimensions, Float>> flattenTransformationHierarchyImplementation(const Trade::SceneData& scene, const Trade::SceneField field, const MatrixTypeFor<dimensions, Float>& globalTransformation) { template<UnsignedInt dimensions> Containers::Array<MatrixTypeFor<dimensions, Float>> absoluteFieldTransformationsImplementation(const Trade::SceneData& scene, const Trade::SceneField field, const MatrixTypeFor<dimensions, Float>& globalTransformation) {
const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field); const Containers::Optional<UnsignedInt> fieldId = scene.findFieldId(field);
CORRADE_ASSERT(fieldId, CORRADE_ASSERT(fieldId,
"SceneTools::flattenTransformationHierarchy(): field" << field << "not found", {}); "SceneTools::absoluteFieldTransformations(): field" << field << "not found", {});
Containers::Array<MatrixTypeFor<dimensions, Float>> out{NoInit, scene.fieldSize(*fieldId)}; Containers::Array<MatrixTypeFor<dimensions, Float>> out{NoInit, scene.fieldSize(*fieldId)};
flattenTransformationHierarchyIntoImplementation<dimensions>(scene, *fieldId, out, globalTransformation); absoluteFieldTransformationsIntoImplementation<dimensions>(scene, *fieldId, out, globalTransformation);
return out; return out;
} }
} }
Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, const Trade::SceneField field, const Matrix3& globalTransformation) { Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, const Trade::SceneField field, const Matrix3& globalTransformation) {
return flattenTransformationHierarchyImplementation<2>(scene, field, globalTransformation); return absoluteFieldTransformationsImplementation<2>(scene, field, globalTransformation);
} }
Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, const Trade::SceneField field) { Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, const Trade::SceneField field) {
return flattenTransformationHierarchyImplementation<2>(scene, field, {}); return absoluteFieldTransformationsImplementation<2>(scene, field, {});
} }
Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix3& globalTransformation) { Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix3& globalTransformation) {
return flattenTransformationHierarchyImplementation<2>(scene, fieldId, globalTransformation); return absoluteFieldTransformationsImplementation<2>(scene, fieldId, globalTransformation);
} }
Containers::Array<Matrix3> flattenTransformationHierarchy2D(const Trade::SceneData& scene, const UnsignedInt fieldId) { Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, const UnsignedInt fieldId) {
return flattenTransformationHierarchyImplementation<2>(scene, fieldId, {}); return absoluteFieldTransformationsImplementation<2>(scene, fieldId, {});
} }
void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation) { void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation) {
return flattenTransformationHierarchyIntoImplementation<2>(scene, field, transformations, globalTransformation); return absoluteFieldTransformationsIntoImplementation<2>(scene, field, transformations, globalTransformation);
} }
void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations) { void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations) {
return flattenTransformationHierarchyIntoImplementation<2>(scene, field, transformations, {}); return absoluteFieldTransformationsIntoImplementation<2>(scene, field, transformations, {});
} }
void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation) { void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation) {
return flattenTransformationHierarchyIntoImplementation<2>(scene, fieldId, transformations, globalTransformation); return absoluteFieldTransformationsIntoImplementation<2>(scene, fieldId, transformations, globalTransformation);
} }
void flattenTransformationHierarchy2DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations) { void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations) {
return flattenTransformationHierarchyIntoImplementation<2>(scene, fieldId, transformations, {}); return absoluteFieldTransformationsIntoImplementation<2>(scene, fieldId, transformations, {});
} }
Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, const Trade::SceneField field, const Matrix4& globalTransformation) { Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, const Trade::SceneField field, const Matrix4& globalTransformation) {
return flattenTransformationHierarchyImplementation<3>(scene, field, globalTransformation); return absoluteFieldTransformationsImplementation<3>(scene, field, globalTransformation);
} }
Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, const Trade::SceneField field) { Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, const Trade::SceneField field) {
return flattenTransformationHierarchyImplementation<3>(scene, field, {}); return absoluteFieldTransformationsImplementation<3>(scene, field, {});
} }
Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix4& globalTransformation) { Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, const UnsignedInt fieldId, const Matrix4& globalTransformation) {
return flattenTransformationHierarchyImplementation<3>(scene, fieldId, globalTransformation); return absoluteFieldTransformationsImplementation<3>(scene, fieldId, globalTransformation);
} }
Containers::Array<Matrix4> flattenTransformationHierarchy3D(const Trade::SceneData& scene, const UnsignedInt fieldId) { Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, const UnsignedInt fieldId) {
return flattenTransformationHierarchyImplementation<3>(scene, fieldId, {}); return absoluteFieldTransformationsImplementation<3>(scene, fieldId, {});
} }
void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation) { void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation) {
return flattenTransformationHierarchyIntoImplementation<3>(scene, field, transformations, globalTransformation); return absoluteFieldTransformationsIntoImplementation<3>(scene, field, transformations, globalTransformation);
} }
void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations) { void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, const Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations) {
return flattenTransformationHierarchyIntoImplementation<3>(scene, field, transformations, {}); return absoluteFieldTransformationsIntoImplementation<3>(scene, field, transformations, {});
} }
void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation) { void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation) {
return flattenTransformationHierarchyIntoImplementation<3>(scene, fieldId, transformations, globalTransformation); return absoluteFieldTransformationsIntoImplementation<3>(scene, fieldId, transformations, globalTransformation);
} }
void flattenTransformationHierarchy3DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations) { void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, const UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations) {
return flattenTransformationHierarchyIntoImplementation<3>(scene, fieldId, transformations, {}); return absoluteFieldTransformationsIntoImplementation<3>(scene, fieldId, transformations, {});
} }
}} }}

237
src/Magnum/SceneTools/Hierarchy.h

@ -0,0 +1,237 @@
#ifndef Magnum_SceneTools_Hierarchy_h
#define Magnum_SceneTools_Hierarchy_h
/*
This file is part of Magnum.
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
2020, 2021, 2022 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::absoluteFieldTransformations2D(), @ref Magnum::SceneTools::absoluteFieldTransformations2DInto(), @ref Magnum::SceneTools::absoluteFieldTransformations3D(), @ref Magnum::SceneTools::absoluteFieldTransformations3DInto()
* @m_since_latest
*/
#include "Magnum/Magnum.h"
#include "Magnum/SceneTools/visibility.h"
#include "Magnum/Trade/Trade.h"
namespace Magnum { namespace SceneTools {
/**
@brief Calculate absolute 2D transformations for given field
@m_since_latest
For all entries of given field in @p scene returns an absolute transformation
of the object they're attached to in the scene with @p globalTransformation
prepended. The @ref Trade::SceneField::Parent field is expected to be contained
in the scene, having no cycles or duplicates, the scene is expected to be 2D
and @p fieldId is expected to be less than @ref Trade::SceneData::fieldCount().
If the field is empty, the function returns an empty array.
The operation is done in an @f$ \mathcal{O}(m + n) @f$ execution time and
memory complexity, with @f$ m @f$ being size of @p fieldId and @f$ n @f$ being
@ref Trade::SceneData::mappingBound(). The function calls
@ref orderClusterParents() internally.
The returned data are in the same order as object mapping entries in
@p fieldId. Fields attached to objects without a @ref Trade::SceneField::Parent
or to objects in loose hierarchy subtrees will have their transformation set to
an unspecified value.
This function can be used for example to flatten a mesh hierarchy, bake
the transformations to actual meshes and then concatenate them together into a
single mesh:
@snippet MagnumSceneTools.cpp absoluteFieldTransformations2D-mesh-concatenate
@experimental
@see @ref absoluteFieldTransformations2D(const Trade::SceneData&, UnsignedInt, const Matrix3&),
@ref absoluteFieldTransformations2DInto(),
@ref absoluteFieldTransformations3D(), @ref Trade::SceneData::hasField(),
@ref Trade::SceneData::is2D()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation = {});
#else
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, UnsignedInt fieldId);
#endif
/**
@brief Calculate absolute 2D transformations for given named field
@m_since_latest
Translates @p field to a field ID using @ref Trade::SceneData::fieldId() and
delegates to @ref absoluteFieldTransformations2D(const Trade::SceneData&, UnsignedInt, const Matrix3&).
The @p field is expected to exist in @p scene.
@experimental
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation = {});
#else
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix3> absoluteFieldTransformations2D(const Trade::SceneData& scene, Trade::SceneField field);
#endif
/**
@brief Calculate absolute 2D transformations for given field into an existing array
@param[in] scene Input scene
@param[in] fieldId Field to calculate the transformations for
@param[out] transformations Where to put the calculated transformations
@param[in] globalTransformation Global transformation to prepend
@m_since_latest
A variant of @ref absoluteFieldTransformations2D(const Trade::SceneData&, UnsignedInt, const Matrix3&)
that fills existing memory instead of allocating a new array. The
@p transformations array is expected to have the same size as the @p fieldId.
@see @ref Trade::SceneData::fieldSize()
@experimental
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {});
#else
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix3>& transformations);
#endif
/**
@brief Calculate absolute 2D transformations for given named field into an existing array
@m_since_latest
Translates @p field to a field ID using @ref Trade::SceneData::fieldId() and
delegates to @ref absoluteFieldTransformations2DInto(const Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<Matrix3>&, const Matrix3&)
The @p field is expected to exist in @p scene.
@experimental
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation = {});
#else
/* To avoid including Matrix3 */
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations, const Matrix3& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations2DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix3>& transformations);
#endif
/**
@brief Calculate absolute 2D transformations for given field
@m_since_latest
For all entries of given field in @p scene returns an absolute transformation
of the object they're attached to in the scene with @p globalTransformation
prepended. The @ref Trade::SceneField::Parent field is expected to be contained
in the scene, having no cycles or duplicates, the scene is expected to be 3D
and @p fieldId is expected to be less than @ref Trade::SceneData::fieldCount().
If the field is empty, the function returns an empty array.
The operation is done in an @f$ \mathcal{O}(m + n) @f$ execution time and
memory complexity, with @f$ m @f$ being size of @p fieldId and @f$ n @f$ being
@ref Trade::SceneData::mappingBound(). The function calls
@ref orderClusterParents() internally.
The returned data are in the same order as object mapping entries in
@p fieldId. Fields attached to objects without a @ref Trade::SceneField::Parent
or to objects in loose hierarchy subtrees will have their transformation set to
an unspecified value.
This function can be used for example to flatten a mesh hierarchy, bake
the transformations to actual meshes and then concatenate them together into a
single mesh:
@snippet MagnumSceneTools.cpp absoluteFieldTransformations3D-mesh-concatenate
@experimental
@see @ref absoluteFieldTransformations3D(const Trade::SceneData&, UnsignedInt, const Matrix4&),
@ref absoluteFieldTransformations3DInto(),
@ref absoluteFieldTransformations2D(), @ref Trade::SceneData::hasField(),
@ref Trade::SceneData::is3D()
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation = {});
#else
/* To avoid including Matrix4 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, UnsignedInt fieldId, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, UnsignedInt fieldId);
#endif
/**
@brief Calculate absolute 3D transformations for given named field
@m_since_latest
Translates @p field to a field ID using @ref Trade::SceneData::fieldId() and
delegates to @ref absoluteFieldTransformations3D(const Trade::SceneData&, UnsignedInt, const Matrix4&).
The @p field is expected to exist in @p scene.
@experimental
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation = {});
#else
/* To avoid including Matrix4 */
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, Trade::SceneField field, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT Containers::Array<Matrix4> absoluteFieldTransformations3D(const Trade::SceneData& scene, Trade::SceneField field);
#endif
/**
@brief Calculate absolute 3D transformations for given field into an existing array
@param[in] scene Input scene
@param[in] fieldId Field to calculate the transformations for
@param[out] transformations Where to put the calculated transformations
@param[in] globalTransformation Global transformation to prepend
@m_since_latest
A variant of @ref absoluteFieldTransformations3D(const Trade::SceneData&, UnsignedInt, const Matrix4&)
that fills existing memory instead of allocating a new array. The
@p transformations array is expected to have the same size as the @p fieldId.
@see @ref Trade::SceneData::fieldSize()
@experimental
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {});
#else
/* To avoid including Matrix4 */
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, UnsignedInt fieldId, const Containers::StridedArrayView1D<Matrix4>& transformations);
#endif
/**
@brief Calculate absolute 3D transformations for given named field into an existing array
@m_since_latest
Translates @p field to a field ID using @ref Trade::SceneData::fieldId() and
delegates to @ref absoluteFieldTransformations3DInto(const Trade::SceneData&, UnsignedInt, const Containers::StridedArrayView1D<Matrix4>&, const Matrix4&)
The @p field is expected to exist in @p scene.
@experimental
*/
#ifdef DOXYGEN_GENERATING_OUTPUT
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation = {});
#else
/* To avoid including Matrix4 */
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations, const Matrix4& globalTransformation);
MAGNUM_SCENETOOLS_EXPORT void absoluteFieldTransformations3DInto(const Trade::SceneData& scene, Trade::SceneField field, const Containers::StridedArrayView1D<Matrix4>& transformations);
#endif
}}
#endif

2
src/Magnum/SceneTools/Test/CMakeLists.txt

@ -53,7 +53,7 @@ file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>/configure.h
corrade_add_test(SceneToolsCombineTest CombineTest.cpp LIBRARIES MagnumSceneToolsTestLib) corrade_add_test(SceneToolsCombineTest CombineTest.cpp LIBRARIES MagnumSceneToolsTestLib)
corrade_add_test(SceneToolsConvertToSingleFunc___Test ConvertToSingleFunctionObjectsTest.cpp LIBRARIES MagnumSceneToolsTestLib) corrade_add_test(SceneToolsConvertToSingleFunc___Test ConvertToSingleFunctionObjectsTest.cpp LIBRARIES MagnumSceneToolsTestLib)
corrade_add_test(SceneToolsFilterTest FilterTest.cpp LIBRARIES MagnumSceneToolsTestLib) corrade_add_test(SceneToolsFilterTest FilterTest.cpp LIBRARIES MagnumSceneToolsTestLib)
corrade_add_test(SceneToolsFlattenTra___HierarchyTest FlattenTransformationHierarchyTest.cpp LIBRARIES MagnumSceneToolsTestLib) corrade_add_test(SceneToolsHierarchyTest HierarchyTest.cpp LIBRARIES MagnumSceneToolsTestLib)
corrade_add_test(SceneToolsOrderClusterParentsTest OrderClusterParentsTest.cpp LIBRARIES MagnumSceneToolsTestLib) corrade_add_test(SceneToolsOrderClusterParentsTest OrderClusterParentsTest.cpp LIBRARIES MagnumSceneToolsTestLib)
corrade_add_test(SceneToolsSceneConverterImple___Test SceneConverterImplementationTest.cpp corrade_add_test(SceneToolsSceneConverterImple___Test SceneConverterImplementationTest.cpp

14
src/Magnum/SceneTools/Test/FlattenMeshHierarchyTest.cpp

@ -311,7 +311,7 @@ void FlattenMeshHierarchyTest::not2DNot3D() {
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
/* Used to assert even on an empty scene, now it does an early-out if the /* Used to assert even on an empty scene, now it does an early-out if the
mesh field doesn't exist because flattenTransformationHierarchy() would mesh field doesn't exist because absoluteFieldTransformations() would
assert instead. That behavioral change is fine for a deprecated API. */ assert instead. That behavioral change is fine for a deprecated API. */
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { 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::Mesh, Trade::SceneMappingType::UnsignedInt, nullptr, Trade::SceneFieldType::UnsignedInt, nullptr},
@ -324,15 +324,15 @@ void FlattenMeshHierarchyTest::not2DNot3D() {
flattenMeshHierarchy3D(scene); flattenMeshHierarchy3D(scene);
CORRADE_IGNORE_DEPRECATED_POP CORRADE_IGNORE_DEPRECATED_POP
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"SceneTools::flattenTransformationHierarchy(): the scene is not 2D\n" "SceneTools::absoluteFieldTransformations(): the scene is not 2D\n"
"SceneTools::flattenTransformationHierarchy(): the scene is not 3D\n"); "SceneTools::absoluteFieldTransformations(): the scene is not 3D\n");
} }
void FlattenMeshHierarchyTest::noParentField() { void FlattenMeshHierarchyTest::noParentField() {
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
/* Used to assert even on an empty scene, now it does an early-out if the /* Used to assert even on an empty scene, now it does an early-out if the
mesh field doesn't exist because flattenTransformationHierarchy() would mesh field doesn't exist because absoluteFieldTransformations() would
assert instead. That behavioral change is fine for a deprecated API. */ assert instead. That behavioral change is fine for a deprecated API. */
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { 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::Mesh, Trade::SceneMappingType::UnsignedInt, nullptr, Trade::SceneFieldType::UnsignedInt, nullptr},
@ -345,7 +345,7 @@ void FlattenMeshHierarchyTest::noParentField() {
flattenMeshHierarchy2D(scene); flattenMeshHierarchy2D(scene);
CORRADE_IGNORE_DEPRECATED_POP CORRADE_IGNORE_DEPRECATED_POP
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"SceneTools::flattenTransformationHierarchy(): the scene has no hierarchy\n"); "SceneTools::absoluteFieldTransformations(): the scene has no hierarchy\n");
} }
void FlattenMeshHierarchyTest::noMeshField() { void FlattenMeshHierarchyTest::noMeshField() {
@ -499,8 +499,8 @@ void FlattenMeshHierarchyTest::intoInvalidSize() {
flattenMeshHierarchy3DInto(scene3D, transformations3D); flattenMeshHierarchy3DInto(scene3D, transformations3D);
CORRADE_IGNORE_DEPRECATED_POP CORRADE_IGNORE_DEPRECATED_POP
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"SceneTools::flattenTransformationHierarchyInto(): bad output size, expected 5 but got 6\n" "SceneTools::absoluteFieldTransformationsInto(): bad output size, expected 5 but got 6\n"
"SceneTools::flattenTransformationHierarchyInto(): bad output size, expected 5 but got 4\n"); "SceneTools::absoluteFieldTransformationsInto(): bad output size, expected 5 but got 4\n");
} }
}}}} }}}}

146
src/Magnum/SceneTools/Test/FlattenTransformationHierarchyTest.cpp → src/Magnum/SceneTools/Test/HierarchyTest.cpp

@ -31,24 +31,24 @@
#include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix3.h"
#include "Magnum/Math/Matrix4.h" #include "Magnum/Math/Matrix4.h"
#include "Magnum/SceneTools/FlattenTransformationHierarchy.h" #include "Magnum/SceneTools/Hierarchy.h"
#include "Magnum/Trade/SceneData.h" #include "Magnum/Trade/SceneData.h"
namespace Magnum { namespace SceneTools { namespace Test { namespace { namespace Magnum { namespace SceneTools { namespace Test { namespace {
struct FlattenTransformationHierarchyTest: TestSuite::Tester { struct HierarchyTest: TestSuite::Tester {
explicit FlattenTransformationHierarchyTest(); explicit HierarchyTest();
void test2D(); void absoluteFieldTransformations2D();
void test3D(); void absoluteFieldTransformations3D();
void fieldNotFound(); void absoluteFieldTransformationsFieldNotFound();
void not2DNot3D(); void absoluteFieldTransformationsNot2DNot3D();
void noParentField(); void absoluteFieldTransformationsNoParentField();
void into2D(); void absoluteFieldTransformationsInto2D();
void into3D(); void absoluteFieldTransformationsInto3D();
void intoInvalidSize(); void absoluteFieldTransformationsIntoInvalidSize();
}; };
using namespace Math::Literals; using namespace Math::Literals;
@ -102,20 +102,20 @@ const struct {
5}, 5},
}; };
FlattenTransformationHierarchyTest::FlattenTransformationHierarchyTest() { HierarchyTest::HierarchyTest() {
addInstancedTests({&FlattenTransformationHierarchyTest::test2D, addInstancedTests({&HierarchyTest::absoluteFieldTransformations2D,
&FlattenTransformationHierarchyTest::test3D}, &HierarchyTest::absoluteFieldTransformations3D},
Containers::arraySize(TestData)); Containers::arraySize(TestData));
addTests({&FlattenTransformationHierarchyTest::fieldNotFound, addTests({&HierarchyTest::absoluteFieldTransformationsFieldNotFound,
&FlattenTransformationHierarchyTest::not2DNot3D, &HierarchyTest::absoluteFieldTransformationsNot2DNot3D,
&FlattenTransformationHierarchyTest::noParentField}); &HierarchyTest::absoluteFieldTransformationsNoParentField});
addInstancedTests({&FlattenTransformationHierarchyTest::into2D, addInstancedTests({&HierarchyTest::absoluteFieldTransformationsInto2D,
&FlattenTransformationHierarchyTest::into3D}, &HierarchyTest::absoluteFieldTransformationsInto3D},
Containers::arraySize(IntoData)); Containers::arraySize(IntoData));
addTests({&FlattenTransformationHierarchyTest::intoInvalidSize}); addTests({&HierarchyTest::absoluteFieldTransformationsIntoInvalidSize});
} }
const struct Scene { const struct Scene {
@ -198,7 +198,7 @@ const struct Scene {
{16, 113}} {16, 113}}
}}; }};
void FlattenTransformationHierarchyTest::test2D() { void HierarchyTest::absoluteFieldTransformations2D() {
auto&& data = TestData[testCaseInstanceId()]; auto&& data = TestData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -230,14 +230,14 @@ void FlattenTransformationHierarchyTest::test2D() {
/* To test all overloads */ /* To test all overloads */
if(data.globalTransformation2D != Matrix3{}) { if(data.globalTransformation2D != Matrix3{}) {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
out = flattenTransformationHierarchy2D(scene, 2, data.globalTransformation2D); out = SceneTools::absoluteFieldTransformations2D(scene, 2, data.globalTransformation2D);
else else
out = flattenTransformationHierarchy2D(scene, Trade::SceneField::Mesh, data.globalTransformation2D); out = SceneTools::absoluteFieldTransformations2D(scene, Trade::SceneField::Mesh, data.globalTransformation2D);
} else { } else {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
out = flattenTransformationHierarchy2D(scene, 2); out = SceneTools::absoluteFieldTransformations2D(scene, 2);
else else
out = flattenTransformationHierarchy2D(scene, Trade::SceneField::Mesh); out = SceneTools::absoluteFieldTransformations2D(scene, Trade::SceneField::Mesh);
} }
CORRADE_COMPARE_AS(out, Containers::arrayView({ CORRADE_COMPARE_AS(out, Containers::arrayView({
@ -257,7 +257,7 @@ void FlattenTransformationHierarchyTest::test2D() {
}).prefix(data.expectedOutputSize), TestSuite::Compare::Container); }).prefix(data.expectedOutputSize), TestSuite::Compare::Container);
} }
void FlattenTransformationHierarchyTest::test3D() { void HierarchyTest::absoluteFieldTransformations3D() {
auto&& data = TestData[testCaseInstanceId()]; auto&& data = TestData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -289,14 +289,14 @@ void FlattenTransformationHierarchyTest::test3D() {
/* To test all overloads */ /* To test all overloads */
if(data.globalTransformation3D != Matrix4{}) { if(data.globalTransformation3D != Matrix4{}) {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
out = flattenTransformationHierarchy3D(scene, 2, data.globalTransformation3D); out = SceneTools::absoluteFieldTransformations3D(scene, 2, data.globalTransformation3D);
else else
out = flattenTransformationHierarchy3D(scene, Trade::SceneField::Mesh, data.globalTransformation3D); out = SceneTools::absoluteFieldTransformations3D(scene, Trade::SceneField::Mesh, data.globalTransformation3D);
} else { } else {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
out = flattenTransformationHierarchy3D(scene, 2); out = SceneTools::absoluteFieldTransformations3D(scene, 2);
else else
out = flattenTransformationHierarchy3D(scene, Trade::SceneField::Mesh); out = SceneTools::absoluteFieldTransformations3D(scene, Trade::SceneField::Mesh);
} }
CORRADE_COMPARE_AS(out, Containers::arrayView({ CORRADE_COMPARE_AS(out, Containers::arrayView({
@ -316,7 +316,7 @@ void FlattenTransformationHierarchyTest::test3D() {
}).prefix(data.expectedOutputSize), TestSuite::Compare::Container); }).prefix(data.expectedOutputSize), TestSuite::Compare::Container);
} }
void FlattenTransformationHierarchyTest::fieldNotFound() { void HierarchyTest::absoluteFieldTransformationsFieldNotFound() {
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {
@ -326,18 +326,18 @@ void FlattenTransformationHierarchyTest::fieldNotFound() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
flattenTransformationHierarchy2D(scene, Trade::SceneField::Mesh); SceneTools::absoluteFieldTransformations2D(scene, Trade::SceneField::Mesh);
flattenTransformationHierarchy3D(scene, Trade::SceneField::Mesh); SceneTools::absoluteFieldTransformations3D(scene, Trade::SceneField::Mesh);
flattenTransformationHierarchy2D(scene, 2); SceneTools::absoluteFieldTransformations2D(scene, 2);
flattenTransformationHierarchy3D(scene, 2); SceneTools::absoluteFieldTransformations3D(scene, 2);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"SceneTools::flattenTransformationHierarchy(): field Trade::SceneField::Mesh not found\n" "SceneTools::absoluteFieldTransformations(): field Trade::SceneField::Mesh not found\n"
"SceneTools::flattenTransformationHierarchy(): field Trade::SceneField::Mesh not found\n" "SceneTools::absoluteFieldTransformations(): field Trade::SceneField::Mesh not found\n"
"SceneTools::flattenTransformationHierarchy(): index 2 out of range for 2 fields\n" "SceneTools::absoluteFieldTransformations(): index 2 out of range for 2 fields\n"
"SceneTools::flattenTransformationHierarchy(): index 2 out of range for 2 fields\n"); "SceneTools::absoluteFieldTransformations(): index 2 out of range for 2 fields\n");
} }
void FlattenTransformationHierarchyTest::not2DNot3D() { void HierarchyTest::absoluteFieldTransformationsNot2DNot3D() {
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {
@ -346,18 +346,18 @@ void FlattenTransformationHierarchyTest::not2DNot3D() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
flattenTransformationHierarchy2D(scene, Trade::SceneField::Parent); SceneTools::absoluteFieldTransformations2D(scene, Trade::SceneField::Parent);
flattenTransformationHierarchy2D(scene, 0); SceneTools::absoluteFieldTransformations2D(scene, 0);
flattenTransformationHierarchy3D(scene, Trade::SceneField::Parent); SceneTools::absoluteFieldTransformations3D(scene, Trade::SceneField::Parent);
flattenTransformationHierarchy3D(scene, 0); SceneTools::absoluteFieldTransformations3D(scene, 0);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"SceneTools::flattenTransformationHierarchy(): the scene is not 2D\n" "SceneTools::absoluteFieldTransformations(): the scene is not 2D\n"
"SceneTools::flattenTransformationHierarchy(): the scene is not 2D\n" "SceneTools::absoluteFieldTransformations(): the scene is not 2D\n"
"SceneTools::flattenTransformationHierarchy(): the scene is not 3D\n" "SceneTools::absoluteFieldTransformations(): the scene is not 3D\n"
"SceneTools::flattenTransformationHierarchy(): the scene is not 3D\n"); "SceneTools::absoluteFieldTransformations(): the scene is not 3D\n");
} }
void FlattenTransformationHierarchyTest::noParentField() { void HierarchyTest::absoluteFieldTransformationsNoParentField() {
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, { Trade::SceneData scene{Trade::SceneMappingType::UnsignedInt, 0, nullptr, {
@ -366,14 +366,14 @@ void FlattenTransformationHierarchyTest::noParentField() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
flattenTransformationHierarchy2D(scene, Trade::SceneField::Transformation); SceneTools::absoluteFieldTransformations2D(scene, Trade::SceneField::Transformation);
flattenTransformationHierarchy2D(scene, 0); SceneTools::absoluteFieldTransformations2D(scene, 0);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"SceneTools::flattenTransformationHierarchy(): the scene has no hierarchy\n" "SceneTools::absoluteFieldTransformations(): the scene has no hierarchy\n"
"SceneTools::flattenTransformationHierarchy(): the scene has no hierarchy\n"); "SceneTools::absoluteFieldTransformations(): the scene has no hierarchy\n");
} }
void FlattenTransformationHierarchyTest::into2D() { void HierarchyTest::absoluteFieldTransformationsInto2D() {
auto&& data = IntoData[testCaseInstanceId()]; auto&& data = IntoData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -403,14 +403,14 @@ void FlattenTransformationHierarchyTest::into2D() {
/* To test all overloads */ /* To test all overloads */
if(data.globalTransformation2D != Matrix3{}) { if(data.globalTransformation2D != Matrix3{}) {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
flattenTransformationHierarchy2DInto(scene, 2, out, data.globalTransformation2D); absoluteFieldTransformations2DInto(scene, 2, out, data.globalTransformation2D);
else else
flattenTransformationHierarchy2DInto(scene, Trade::SceneField::Mesh, out, data.globalTransformation2D); absoluteFieldTransformations2DInto(scene, Trade::SceneField::Mesh, out, data.globalTransformation2D);
} else { } else {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
flattenTransformationHierarchy2DInto(scene, 2, out); absoluteFieldTransformations2DInto(scene, 2, out);
else else
flattenTransformationHierarchy2DInto(scene, Trade::SceneField::Mesh, out); absoluteFieldTransformations2DInto(scene, Trade::SceneField::Mesh, out);
} }
CORRADE_COMPARE_AS(out, Containers::arrayView<Matrix3>({ CORRADE_COMPARE_AS(out, Containers::arrayView<Matrix3>({
@ -430,7 +430,7 @@ void FlattenTransformationHierarchyTest::into2D() {
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
} }
void FlattenTransformationHierarchyTest::into3D() { void HierarchyTest::absoluteFieldTransformationsInto3D() {
auto&& data = IntoData[testCaseInstanceId()]; auto&& data = IntoData[testCaseInstanceId()];
setTestCaseDescription(data.name); setTestCaseDescription(data.name);
@ -460,14 +460,14 @@ void FlattenTransformationHierarchyTest::into3D() {
/* To test all overloads */ /* To test all overloads */
if(data.globalTransformation3D != Matrix4{}) { if(data.globalTransformation3D != Matrix4{}) {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
flattenTransformationHierarchy3DInto(scene, 2, out, data.globalTransformation3D); absoluteFieldTransformations3DInto(scene, 2, out, data.globalTransformation3D);
else else
flattenTransformationHierarchy3DInto(scene, Trade::SceneField::Mesh, out, data.globalTransformation3D); absoluteFieldTransformations3DInto(scene, Trade::SceneField::Mesh, out, data.globalTransformation3D);
} else { } else {
if(data.fieldIdInsteadOfName) if(data.fieldIdInsteadOfName)
flattenTransformationHierarchy3DInto(scene, 2, out); absoluteFieldTransformations3DInto(scene, 2, out);
else else
flattenTransformationHierarchy3DInto(scene, Trade::SceneField::Mesh, out); absoluteFieldTransformations3DInto(scene, Trade::SceneField::Mesh, out);
} }
CORRADE_COMPARE_AS(out, Containers::arrayView<Matrix4>({ CORRADE_COMPARE_AS(out, Containers::arrayView<Matrix4>({
@ -487,7 +487,7 @@ void FlattenTransformationHierarchyTest::into3D() {
}), TestSuite::Compare::Container); }), TestSuite::Compare::Container);
} }
void FlattenTransformationHierarchyTest::intoInvalidSize() { void HierarchyTest::absoluteFieldTransformationsIntoInvalidSize() {
CORRADE_SKIP_IF_NO_ASSERT(); CORRADE_SKIP_IF_NO_ASSERT();
struct Data { struct Data {
@ -515,17 +515,17 @@ void FlattenTransformationHierarchyTest::intoInvalidSize() {
std::ostringstream out; std::ostringstream out;
Error redirectError{&out}; Error redirectError{&out};
flattenTransformationHierarchy2DInto(scene2D, Trade::SceneField::Mesh, transformations2D); absoluteFieldTransformations2DInto(scene2D, Trade::SceneField::Mesh, transformations2D);
flattenTransformationHierarchy2DInto(scene2D, 1, transformations2D); absoluteFieldTransformations2DInto(scene2D, 1, transformations2D);
flattenTransformationHierarchy3DInto(scene3D, Trade::SceneField::Mesh, transformations3D); absoluteFieldTransformations3DInto(scene3D, Trade::SceneField::Mesh, transformations3D);
flattenTransformationHierarchy3DInto(scene3D, 1, transformations3D); absoluteFieldTransformations3DInto(scene3D, 1, transformations3D);
CORRADE_COMPARE(out.str(), CORRADE_COMPARE(out.str(),
"SceneTools::flattenTransformationHierarchyInto(): bad output size, expected 5 but got 6\n" "SceneTools::absoluteFieldTransformationsInto(): bad output size, expected 5 but got 6\n"
"SceneTools::flattenTransformationHierarchyInto(): bad output size, expected 5 but got 6\n" "SceneTools::absoluteFieldTransformationsInto(): bad output size, expected 5 but got 6\n"
"SceneTools::flattenTransformationHierarchyInto(): bad output size, expected 5 but got 4\n" "SceneTools::absoluteFieldTransformationsInto(): bad output size, expected 5 but got 4\n"
"SceneTools::flattenTransformationHierarchyInto(): bad output size, expected 5 but got 4\n"); "SceneTools::absoluteFieldTransformationsInto(): bad output size, expected 5 but got 4\n");
} }
}}}} }}}}
CORRADE_TEST_MAIN(Magnum::SceneTools::Test::FlattenTransformationHierarchyTest) CORRADE_TEST_MAIN(Magnum::SceneTools::Test::HierarchyTest)

10
src/Magnum/SceneTools/sceneconverter.cpp

@ -38,7 +38,7 @@
#include "Magnum/MeshTools/Reference.h" #include "Magnum/MeshTools/Reference.h"
#include "Magnum/MeshTools/RemoveDuplicates.h" #include "Magnum/MeshTools/RemoveDuplicates.h"
#include "Magnum/MeshTools/Transform.h" #include "Magnum/MeshTools/Transform.h"
#include "Magnum/SceneTools/FlattenTransformationHierarchy.h" #include "Magnum/SceneTools/Hierarchy.h"
#include "Magnum/Trade/AbstractImporter.h" #include "Magnum/Trade/AbstractImporter.h"
#include "Magnum/Trade/MeshData.h" #include "Magnum/Trade/MeshData.h"
#include "Magnum/Trade/AbstractImageConverter.h" #include "Magnum/Trade/AbstractImageConverter.h"
@ -311,9 +311,9 @@ on meshes and materials before passing them to any converter.
If `--concatenate-meshes` is given, all meshes of the input file are If `--concatenate-meshes` is given, all meshes of the input file are
first concatenated into a single mesh using @ref MeshTools::concatenate(), with first concatenated into a single mesh using @ref MeshTools::concatenate(), with
the scene hierarchy transformation baked in using the scene hierarchy transformation baked in using
@ref SceneTools::flattenTransformationHierarchy3D(), and then passed through @ref SceneTools::absoluteFieldTransformations3D(), and then passed through the
the remaining operations. Only attributes that are present in the first mesh remaining operations. Only attributes that are present in the first mesh are
are taken, if `--only-mesh-attributes` is specified as well, the IDs reference taken, if `--only-mesh-attributes` is specified as well, the IDs reference
attributes of the first mesh. attributes of the first mesh.
*/ */
@ -820,7 +820,7 @@ well, the IDs reference attributes of the first mesh.)")
Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>> Containers::Array<Containers::Pair<UnsignedInt, Containers::Pair<UnsignedInt, Int>>>
meshesMaterials = scene->meshesMaterialsAsArray(); meshesMaterials = scene->meshesMaterialsAsArray();
Containers::Array<Matrix4> transformations = Containers::Array<Matrix4> transformations =
SceneTools::flattenTransformationHierarchy3D(*scene, Trade::SceneField::Mesh); SceneTools::absoluteFieldTransformations3D(*scene, Trade::SceneField::Mesh);
Containers::Array<Trade::MeshData> flattenedMeshes; Containers::Array<Trade::MeshData> flattenedMeshes;
{ {
Trade::Implementation::Duration d{conversionTime}; Trade::Implementation::Duration d{conversionTime};

Loading…
Cancel
Save