From f237bb3c9cf81b368a02102392e7231b9ebe4dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Mon, 11 Nov 2024 19:55:22 +0100 Subject: [PATCH] MeshTools: doc++ Not too great yet, but at least the most common operations have an example snippet that shows real use, instead of jumping off a cliff right into the most detailed description. --- doc/snippets/MeshTools.cpp | 46 ++++++++++++++++++++ src/Magnum/MeshTools/Combine.h | 16 +++++-- src/Magnum/MeshTools/Compile.h | 3 +- src/Magnum/MeshTools/CompressIndices.h | 11 +++-- src/Magnum/MeshTools/Concatenate.h | 31 ++++++++----- src/Magnum/MeshTools/Filter.h | 12 ++--- src/Magnum/MeshTools/GenerateIndices.h | 4 +- src/Magnum/MeshTools/RemoveDuplicates.h | 58 ++++++++++++++----------- src/Magnum/MeshTools/Tipsify.h | 1 + src/Magnum/MeshTools/Transform.h | 17 +++++--- 10 files changed, 142 insertions(+), 57 deletions(-) diff --git a/doc/snippets/MeshTools.cpp b/doc/snippets/MeshTools.cpp index f5970aef6..794e3a72d 100644 --- a/doc/snippets/MeshTools.cpp +++ b/doc/snippets/MeshTools.cpp @@ -29,6 +29,7 @@ #include "Magnum/Math/Color.h" #include "Magnum/Math/FunctionsBatch.h" +#include "Magnum/MeshTools/Combine.h" #include "Magnum/MeshTools/CompressIndices.h" #include "Magnum/MeshTools/Concatenate.h" #include "Magnum/MeshTools/Duplicate.h" @@ -45,6 +46,8 @@ #include "Magnum/MeshTools/CombineIndexedArrays.h" #endif +#define DOXYGEN_ELLIPSIS(...) __VA_ARGS__ + using namespace Magnum; using namespace Magnum::Math::Literals; @@ -53,6 +56,17 @@ using namespace Magnum::Math::Literals; avoid -Wmisssing-prototypes */ void mainMeshTools(); void mainMeshTools() { +{ +Trade::MeshData mesh{{}, 0}; +/* [combineFaceAttributes] */ +Containers::ArrayView faceColors = DOXYGEN_ELLIPSIS({}); + +Trade::MeshData meshWithFaceColors = MeshTools::combineFaceAttributes(mesh, { + Trade::MeshAttributeData{Trade::MeshAttribute::Color, faceColors} +}); +/* [combineFaceAttributes] */ +} + #ifdef MAGNUM_BUILD_DEPRECATED { CORRADE_IGNORE_DEPRECATED_PUSH @@ -96,6 +110,27 @@ CORRADE_IGNORE_DEPRECATED_POP } #endif +{ +/* [concatenate] */ +Trade::MeshData sphere = DOXYGEN_ELLIPSIS(Trade::MeshData{{}, 0}); +Trade::MeshData cube = DOXYGEN_ELLIPSIS(Trade::MeshData{{}, 0}); +Trade::MeshData cylinder = DOXYGEN_ELLIPSIS(Trade::MeshData{{}, 0}); + +Trade::MeshData primitives = MeshTools::concatenate({sphere, cube, cylinder}); +/* [concatenate] */ + +/* [concatenate-offsets] */ +UnsignedInt sphereIndexOffset = 0; +UnsignedInt sphereVertexOffset = 0; +UnsignedInt cubeIndexOffset = sphereIndexOffset + sphere.indexCount(), + cubeVertexOffset = sphereVertexOffset + sphere.vertexCount(); +UnsignedInt cylinderIndexOffset = cubeIndexOffset + cube.indexCount(), + cylinderVertexOffset = cubeVertexOffset + cube.vertexCount(); +/* [concatenate-offsets] */ +static_cast(cylinderIndexOffset); +static_cast(cylinderVertexOffset); +} + { /* [generateFlatNormals] */ Containers::ArrayView indices; @@ -163,6 +198,17 @@ data = data.prefix(unique.second()); /* [removeDuplicates] */ } +{ +/* [removeDuplicatesFuzzy] */ +Containers::ArrayView positions; + +Containers::Pair, std::size_t> unique = + MeshTools::removeDuplicatesFuzzyInPlace( + Containers::arrayCast<2, Float>(positions)); +positions = positions.prefix(unique.second()); +/* [removeDuplicatesFuzzy] */ +} + #ifdef MAGNUM_BUILD_DEPRECATED { CORRADE_IGNORE_DEPRECATED_PUSH diff --git a/src/Magnum/MeshTools/Combine.h b/src/Magnum/MeshTools/Combine.h index b69e559a8..31e158dbb 100644 --- a/src/Magnum/MeshTools/Combine.h +++ b/src/Magnum/MeshTools/Combine.h @@ -114,17 +114,27 @@ indexed, it's assumed to have the data unique; if it's not indexed, it's first made unique using @ref removeDuplicates() and in that case it's expected to be interleaved. Index buffers and attributes in both meshes are expected to not have an implementation-specific format. + +The @ref combineFaceAttributes(const Trade::MeshData&, Containers::ArrayView) +overload allows for more convenient addition of per-face attributes into a mesh +without having to wrap them in a @ref Trade::MeshData first. See its +documentation for a usage example. @see @ref isInterleaved(), @ref isMeshIndexTypeImplementationSpecific(), @ref isVertexFormatImplementationSpecific() */ MAGNUM_MESHTOOLS_EXPORT Trade::MeshData combineFaceAttributes(const Trade::MeshData& mesh, const Trade::MeshData& faceAttributes); /** -@overload +@brief Combine per-face attributes into an existing mesh @m_since{2020,06} -Same as above with @p faceAttributes wrapped in a @ref Trade::MeshData with -@ref MeshPrimitive::Faces and no index buffer. Same as in the above case, +Wraps @p faceAttributes in a @ref Trade::MeshData with @ref MeshPrimitive::Faces +and no index buffer and calls @ref combineFaceAttributes(const Trade::MeshData&, const Trade::MeshData&). +Example usage --- adding a per-face color to an existing mesh: + +@snippet MeshTools.cpp combineFaceAttributes + +Same as with @ref combineFaceAttributes(const Trade::MeshData&, const Trade::MeshData&), @p faceAttributes is expected to be interleaved. Note that offset-only @ref Trade::MeshAttributeData instances are not supported in the @p faceAttributes array. diff --git a/src/Magnum/MeshTools/Compile.h b/src/Magnum/MeshTools/Compile.h index 1c829b18b..cd177f058 100644 --- a/src/Magnum/MeshTools/Compile.h +++ b/src/Magnum/MeshTools/Compile.h @@ -321,7 +321,8 @@ Useful to get subsequently fed to @ref Shaders::FlatGL::Configuration::setJointCount() or to @ref Shaders::FlatGL::setPerVertexJointCount() if @ref Shaders::FlatGL::Flag::DynamicPerVertexJointCount is enabled, and -similarly with other builtin shaders. +similarly with other builtin shaders. See @ref shaders-usage-skinning for a +high-level introduction. @note This function is available only if Magnum is compiled with @ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features diff --git a/src/Magnum/MeshTools/CompressIndices.h b/src/Magnum/MeshTools/CompressIndices.h index f18465267..67c9732a0 100644 --- a/src/Magnum/MeshTools/CompressIndices.h +++ b/src/Magnum/MeshTools/CompressIndices.h @@ -80,7 +80,7 @@ A negative @p offset value will do an operation inverse to the above. See also operation directly on a @ref Trade::MeshData instance. The @p atLeast parameter is expected to not be an implementation-specific type. -@see @ref isMeshIndexTypeImplementationSpecific() +@see @ref isMeshIndexTypeImplementationSpecific(), @ref Math::castInto() */ MAGNUM_MESHTOOLS_EXPORT Containers::Pair, MeshIndexType> compressIndices(const Containers::StridedArrayView1D& indices, MeshIndexType atLeast = MeshIndexType::UnsignedShort, Long offset = 0); @@ -152,9 +152,12 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Pair, MeshIndexType> Does the same as @ref compressIndices(const Containers::StridedArrayView2D&, MeshIndexType, Long), but together with adjusting vertex attribute offsets in the passed -@ref Trade::MeshData instance. This function will unconditionally make a copy -of all vertex data, use @ref compressIndices(Trade::MeshData&&, MeshIndexType) -to avoid that copy. +@ref Trade::MeshData instance. By default the function will make a copy of all +vertex data, pass a r-value in order to pick the +@ref compressIndices(Trade::MeshData&&, MeshIndexType) overload and avoid the +copy. The function is by default using at least a 16-bit index type because +while @ref MeshIndexType::UnsignedByte can make the in-memory representation +smaller, it's not supported by all GPU APIs and its usage is discouraged. The mesh is expected to be indexed and the index type and the @p atLeast parameter is expected to not be implementation-specific type. diff --git a/src/Magnum/MeshTools/Concatenate.h b/src/Magnum/MeshTools/Concatenate.h index d9bd4e4bb..df4e7812d 100644 --- a/src/Magnum/MeshTools/Concatenate.h +++ b/src/Magnum/MeshTools/Concatenate.h @@ -51,16 +51,27 @@ namespace Implementation { @param flags Flags to pass to @ref interleavedLayout() @m_since{2020,06} -The returned mesh contains vertices from all meshes concatenated together. If -any mesh is indexed (expected to not have an implementation-specific index -type), the resulting mesh is indexed as well, with indices adjusted for vertex -offsets of particular meshes. The behavior is undefined if any mesh has indices -out of range for its particular vertex count. Meshes with -@ref MeshPrimitive::LineStrip, @ref MeshPrimitive::LineLoop, -@ref MeshPrimitive::TriangleStrip and @ref MeshPrimitive::TriangleFan can't be -concatenated --- use @ref generateIndices() to turn them into -@ref MeshPrimitive::Lines or @ref MeshPrimitive::Triangles first. The @p meshes -array is expected to have at least one item. +Returns a mesh that contains index and vertex data from all input meshes +concatenated together. Usage example: + +@snippet MeshTools.cpp concatenate + +Relative order of passed meshes is preserved in the resulting index and vertex +data, meaning you can directly calculate their offsets for example if it's +desirable to render or modify them separately. If any mesh is indexed, the +resulting mesh is indexed as well, with indices adjusted for vertex offsets of +particular meshes. + +@snippet MeshTools.cpp concatenate-offsets + +The indices, if present, are expected to not have an implementation-specific +index type. The behavior is undefined if any mesh has indices out of range for +its particular vertex count. Meshes with @ref MeshPrimitive::LineStrip, +@ref MeshPrimitive::LineLoop, @ref MeshPrimitive::TriangleStrip and +@ref MeshPrimitive::TriangleFan can't be concatenated --- use +@ref generateIndices() to turn them into @ref MeshPrimitive::Lines or +@ref MeshPrimitive::Triangles first. The @p meshes array is expected to have at +least one item. All attributes from the first mesh are taken, expected to not have an implementation-specific format. For each following mesh attributes present in diff --git a/src/Magnum/MeshTools/Filter.h b/src/Magnum/MeshTools/Filter.h index e7633eaf7..a34c893cb 100644 --- a/src/Magnum/MeshTools/Filter.h +++ b/src/Magnum/MeshTools/Filter.h @@ -66,9 +66,9 @@ present, is left untouched. Attributes from the list that are not present in @p mesh are skipped, duplicates in the list are treated the same as if given attribute was listed just once. If given attribute is present multiple times in the mesh (such as secondary colors or texture coordinates), all its occurences -are kept --- if you want a different behavior, use the -@ref filterOnlyAttributes(const Trade::MeshData&, Containers::ArrayView) -overload and pick attributes by their IDs instead. +are kept --- if you want a different behavior, use +@ref filterAttributes(const Trade::MeshData&, Containers::BitArrayView) and +pick attributes by their IDs instead. This function only operates on the attribute metadata --- if you'd like to have the vertex data repacked to contain just the remaining attributes as well, pass @@ -94,9 +94,9 @@ present, is left untouched. Attributes from the list that are not present in @p mesh are skipped, duplicates in the list are treated the same as if given attribute was listed just once. If given attribute is present multiple times in the mesh (such as secondary colors or texture coordinates), all its occurences -are removed --- if you want a different behavior, use the -@ref filterOnlyAttributes(const Trade::MeshData&, Containers::ArrayView) -overload and pick attributes by their IDs instead. +are removed --- if you want a different behavior, use +@ref filterAttributes(const Trade::MeshData&, Containers::BitArrayView) and +pick attributes by their IDs instead. This function only operates on the attribute metadata --- if you'd like to have the vertex mesh repacked to contain just the remaining attributes as well, pass diff --git a/src/Magnum/MeshTools/GenerateIndices.h b/src/Magnum/MeshTools/GenerateIndices.h index 7ee290f1e..542d0245c 100644 --- a/src/Magnum/MeshTools/GenerateIndices.h +++ b/src/Magnum/MeshTools/GenerateIndices.h @@ -506,7 +506,7 @@ MAGNUM_MESHTOOLS_EXPORT void generateQuadIndicesInto(const Containers::StridedAr MAGNUM_MESHTOOLS_EXPORT void generateQuadIndicesInto(const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& quads, const Containers::StridedArrayView1D& output); /** -@brief Convert a mesh to plain indexed lines or triangles +@brief Convert a mesh to a plain indexed one @m_since{2020,06} If @p mesh is one of @ref MeshPrimitive::LineStrip, @@ -535,7 +535,7 @@ avoid that copy. MAGNUM_MESHTOOLS_EXPORT Trade::MeshData generateIndices(const Trade::MeshData& mesh); /** -@brief Convert a mesh to plain indexed lines or triangles +@brief Convert a mesh to a plain indexed one @m_since{2020,06} Compared to @ref generateIndices(const Trade::MeshData&) this function can diff --git a/src/Magnum/MeshTools/RemoveDuplicates.h b/src/Magnum/MeshTools/RemoveDuplicates.h index b9d125274..c170bbc17 100644 --- a/src/Magnum/MeshTools/RemoveDuplicates.h +++ b/src/Magnum/MeshTools/RemoveDuplicates.h @@ -55,20 +55,21 @@ namespace Magnum { namespace MeshTools { @m_since{2020,06} Removes duplicate data from given array by comparing the second dimension of -each item, the second dimension is expected to be contiguous. A plain bit-exact +each item. Usage example: + +@snippet MeshTools.cpp removeDuplicates + +The second dimension is expected to be contiguous. A plain bit-exact matching is used, if you need fuzzy comparison for floating-point data, use @ref removeDuplicatesFuzzyInPlace() instead. If you want to remove duplicate data from an already indexed array, use @ref removeDuplicatesIndexedInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView2D&) -instead. Usage example: - -@snippet MeshTools.cpp removeDuplicates - -See @ref removeDuplicates(const Containers::StridedArrayView2D&) +instead. See @ref removeDuplicates(const Containers::StridedArrayView2D&) for a variant that doesn't modify the input data in any way but instead returns -an index array pointing to original data locations. -@see @ref Corrade::Containers::StridedArrayView::isContiguous(), - @ref removeDuplicatesInPlaceInto() +an index array pointing to original data locations. Use +@ref removeDuplicatesInPlaceInto() to place the indices into existing memory +instead of allocating a new array. +@see @relativeref{Corrade,Containers::StridedArrayView::isContiguous()} */ MAGNUM_MESHTOOLS_EXPORT Containers::Pair, std::size_t> removeDuplicatesInPlace(const Containers::StridedArrayView2D& data); @@ -80,8 +81,9 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Pair, std::si @return Size of unique prefix in the cleaned up @p data array @m_since{2020,06} -Same as above, except that the index array is not allocated but put into -@p indices instead. Expects that @p indices has the same size as @p data. +Like @ref removeDuplicatesInPlace(), except that the index array is not +allocated but put into @p indices instead. Expects that @p indices has the same +size as @p data. @see @ref removeDuplicatesInto() */ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesInPlaceInto(const Containers::StridedArrayView2D& data, const Containers::StridedArrayView1D& indices); @@ -95,7 +97,9 @@ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesInPlaceInto(const Containers Compared to @ref removeDuplicatesInPlace(const Containers::StridedArrayView2D&) this function doesn't modify the input data array in any way but instead -returns an index array pointing to original data locations. +returns an index array pointing to original data locations. Use +@ref removeDuplicatesInto() to place the indices into existing memory instead +of allocating a new array. */ MAGNUM_MESHTOOLS_EXPORT Containers::Pair, std::size_t> removeDuplicates(const Containers::StridedArrayView2D& data); @@ -162,14 +166,17 @@ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesIndexedInPlace(const Contain Removes duplicate data from the array by collapsing them into buckets of size @p epsilon. First vector in given bucket is used, other ones are thrown away, -no interpolation is done. Note that this function is meant to be used for -floating-point data (or generally with non-zero @p epsilon), for data where -bit-exact matching is sufficient use @ref removeDuplicatesInPlace(const Containers::StridedArrayView2D&) -instead. +no interpolation is done. Usage example: -If you want to remove duplicate data from an already indexed array, use -@ref removeDuplicatesFuzzyIndexedInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView2D&, Float) -and friends instead. +@snippet MeshTools.cpp removeDuplicatesFuzzy + +Note that this function is meant to be used for floating-point data (or +generally with non-zero @p epsilon), for data where bit-exact matching is +sufficient use @ref removeDuplicatesInPlace(const Containers::StridedArrayView2D&) +instead. If you want to remove duplicate data from an already indexed array, +use @ref removeDuplicatesFuzzyIndexedInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView2D&, Float) +and friends instead. Use @ref removeDuplicatesFuzzyInPlaceInto() to place the +indices into existing memory instead of allocating a new array. If you want to remove duplicates in multiple incidental arrays, first remove duplicates in each array separately and then combine the resulting index arrays @@ -193,8 +200,9 @@ MAGNUM_MESHTOOLS_EXPORT Containers::Pair, std::si @return Size of unique prefix in the cleaned up @p data array @m_since{2020,06} -Same as above, except that the index array is not allocated but put into -@p indices instead. Expects that @p indices has the same size as @p data. +Like @ref removeDuplicatesFuzzyInPlace(), except that the index array is not +allocated but put into @p indices instead. Expects that @p indices has the same +size as @p data. */ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesFuzzyInPlaceInto(const Containers::StridedArrayView2D& data, const Containers::StridedArrayView1D& indices, Float epsilon = Math::TypeTraits::epsilon()); @@ -277,10 +285,10 @@ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesFuzzyIndexedInPlace(const Co @brief Remove duplicates from indexed data using fuzzy comparison in-place on a type-erased index array @m_since{2020,06} -Expects that the second dimension of @p indices is contiguous and represents -the actual 1/2/4-byte index type. Based on its size then calls -@ref removeDuplicatesFuzzyIndexedInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView2D&, Float) -or the other overloads. +Calls @ref removeDuplicatesFuzzyIndexedInPlace(const Containers::StridedArrayView1D&, const Containers::StridedArrayView2D&, Float) +or the other overloads based on size of the second dimension of @p indices. +Expects that the second dimension is contiguous and represents the actual +1/2/4-byte index type. */ MAGNUM_MESHTOOLS_EXPORT std::size_t removeDuplicatesFuzzyIndexedInPlace(const Containers::StridedArrayView2D& indices, const Containers::StridedArrayView2D& data, Float epsilon = Math::TypeTraits::epsilon()); diff --git a/src/Magnum/MeshTools/Tipsify.h b/src/Magnum/MeshTools/Tipsify.h index 8b38046cd..c2b7a613d 100644 --- a/src/Magnum/MeshTools/Tipsify.h +++ b/src/Magnum/MeshTools/Tipsify.h @@ -56,6 +56,7 @@ array for beter usage of post-transform vertex cache. Algorithm used: for Vertex Locality and Reduced Overdraw, SIGGRAPH 2007, https://gfx.cs.princeton.edu/pubs/Sander_2007_%3eTR/tipsy.pdf*. @todo Ability to compute vertex count automatically +@see @relativeref{Trade,MeshOptimizerSceneConverter} */ MAGNUM_MESHTOOLS_EXPORT void tipsifyInPlace(const Containers::StridedArrayView1D& indices, UnsignedInt vertexCount, std::size_t cacheSize); diff --git a/src/Magnum/MeshTools/Transform.h b/src/Magnum/MeshTools/Transform.h index ff9c9a963..4618b30be 100644 --- a/src/Magnum/MeshTools/Transform.h +++ b/src/Magnum/MeshTools/Transform.h @@ -152,12 +152,12 @@ template U transformPoints(const T& transformation, U vectors) Expects that the mesh contains a two-dimensional @ref Trade::MeshAttribute::Position with index @p id (and in morph target @p morphTargetId if not @cpp -1 @ce) and that the attribute does not have an -implementation-specific format. To avoid data loss with packed types, the positions are converted to @ref VertexFormat::Vector2 if not -already. In that case the data layouting is done by @ref interleavedLayout() -with the @p flags parameter propagated to it, see its documentation for -detailed behavior description. Other attributes, position attributes other than -@p id or with different @p morphTargetId, and indices (if any) are passed -through untouched. +implementation-specific format. To avoid data loss with packed types, the +positions are converted to @ref VertexFormat::Vector2 if not already. In that +case the data layouting is done by @ref interleavedLayout() with the @p flags +parameter propagated to it, see its documentation for detailed behavior +description. Other attributes, position attributes other than @p id or with +different @p morphTargetId, and indices (if any) are passed through untouched. See also @ref transform2D(Trade::MeshData&&, const Matrix3&, UnsignedInt, Int, InterleaveFlags) for a potentially more efficient operation instead of always performing a full @@ -237,6 +237,11 @@ behavior description. Other attributes, additional position/TBN attributes other than @p id or with different @p morphTargetId, and indices (if any) are passed through untouched. +If you're applying negative scaling, you may want to also flip face winding +afterwards using @ref flipFaceWindingInPlace(). + +@todoc reference the MeshData flipFaceWindingInPlace variant once it exists + See also @ref transform3D(Trade::MeshData&&, const Matrix4&, UnsignedInt, Int, InterleaveFlags) for a potentially more efficient operation instead of always performing a full copy, you can also do an in-place transformation using @ref transform3DInPlace().