diff --git a/src/Magnum/MeshTools/Concatenate.cpp b/src/Magnum/MeshTools/Concatenate.cpp index b965dc5a6..6b8fee426 100644 --- a/src/Magnum/MeshTools/Concatenate.cpp +++ b/src/Magnum/MeshTools/Concatenate.cpp @@ -33,7 +33,7 @@ namespace Magnum { namespace MeshTools { namespace Implementation { -std::pair concatenateIndexVertexCount(const Containers::Iterable& meshes) { +Containers::Pair concatenateIndexVertexCount(const Containers::Iterable& meshes) { UnsignedInt indexCount = 0; UnsignedInt vertexCount = 0; for(const Trade::MeshData& mesh: meshes) { @@ -101,10 +101,10 @@ Trade::MeshData concatenate(Containers::Array&& indexData, const UnsignedI /* Create an attribute map. Yes, this is an inevitable fugly thing that allocates like mad, while everything else is zero-alloc. Containers::HashMap can't be here soon enough. */ - std::unordered_multimap, MeshAttributeHash> attributeMap; + std::unordered_multimap, MeshAttributeHash> attributeMap; attributeMap.reserve(out.attributeCount()); for(UnsignedInt i = 0; i != out.attributeCount(); ++i) - attributeMap.emplace(out.attributeName(i), std::make_pair(i, false)); + attributeMap.emplace(out.attributeName(i), Containers::pair(i, false)); /* Go through all meshes and put all attributes and index arrays together. */ std::size_t indexOffset = 0; @@ -140,7 +140,7 @@ Trade::MeshData concatenate(Containers::Array&& indexData, const UnsignedI /* Reset markers saying which attribute has already been copied */ for(auto it = attributeMap.begin(); it != attributeMap.end(); ++it) - it->second.second = false; + it->second.second() = false; /* Copy attributes to their destination, skipping ones that don't have any equivalent in the destination mesh */ @@ -151,12 +151,12 @@ Trade::MeshData concatenate(Containers::Array&& indexData, const UnsignedI UnsignedInt dst = ~UnsignedInt{}; auto found = attributeMap.end(); for(auto it = range.first; it != range.second; ++it) { - if(it->second.second) continue; + if(it->second.second()) continue; /* The range is unordered so we need to go through everything and pick one with smallest ID */ - if(it->second.first < dst) { - dst = it->second.first; + if(it->second.first() < dst) { + dst = it->second.first(); found = it; } } @@ -188,7 +188,7 @@ Trade::MeshData concatenate(Containers::Array&& indexData, const UnsignedI Utility::copy(srcAttribute, dstAttribute.sliceSize( {vertexOffset, 0}, {mesh.vertexCount(), srcAttribute.size()[1]})); - found->second.second = true; + found->second.second() = true; } /* Update vertex offset for the next mesh */ @@ -230,12 +230,12 @@ Trade::MeshData concatenate(const Containers::Iterable& m /* Calculate total index/vertex count and allocate the target memory. Index data are allocated with NoInit as the whole array will be written, however vertex data might have holes and thus it's zero-initialized. */ - const std::pair indexVertexCount = Implementation::concatenateIndexVertexCount(meshes); + const Containers::Pair indexVertexCount = Implementation::concatenateIndexVertexCount(meshes); Containers::Array indexData{NoInit, - indexVertexCount.first*sizeof(UnsignedInt)}; + indexVertexCount.first()*sizeof(UnsignedInt)}; Containers::Array vertexData{ValueInit, - attributeData.isEmpty() ? 0 : (attributeData[0].stride()*indexVertexCount.second)}; - return Implementation::concatenate(std::move(indexData), indexVertexCount.second, std::move(vertexData), std::move(attributeData), meshes, "MeshTools::concatenate():"); + attributeData.isEmpty() ? 0 : (attributeData[0].stride()*indexVertexCount.second())}; + return Implementation::concatenate(std::move(indexData), indexVertexCount.second(), std::move(vertexData), std::move(attributeData), meshes, "MeshTools::concatenate():"); } }} diff --git a/src/Magnum/MeshTools/Concatenate.h b/src/Magnum/MeshTools/Concatenate.h index 54e055b1d..d020bfea6 100644 --- a/src/Magnum/MeshTools/Concatenate.h +++ b/src/Magnum/MeshTools/Concatenate.h @@ -32,6 +32,7 @@ #include #include +#include #include "Magnum/MeshTools/Interleave.h" #include "Magnum/Trade/MeshData.h" @@ -39,7 +40,7 @@ namespace Magnum { namespace MeshTools { namespace Implementation { - MAGNUM_MESHTOOLS_EXPORT std::pair concatenateIndexVertexCount(const Containers::Iterable& meshes); + MAGNUM_MESHTOOLS_EXPORT Containers::Pair concatenateIndexVertexCount(const Containers::Iterable& meshes); MAGNUM_MESHTOOLS_EXPORT Trade::MeshData concatenate(Containers::Array&& indexData, UnsignedInt vertexCount, Containers::Array&& vertexData, Containers::Array&& attributeData, const Containers::Iterable& meshes, const char* assertPrefix); } @@ -114,19 +115,19 @@ template class Allocator = Containers::ArrayAllocator> void conc } #endif - std::pair indexVertexCount = Implementation::concatenateIndexVertexCount(meshes); + const Containers::Pair indexVertexCount = Implementation::concatenateIndexVertexCount(meshes); Containers::Array indexData; - if(indexVertexCount.first) { + if(indexVertexCount.first()) { indexData = destination.releaseIndexData(); /* Everything is overwritten here so we don't need to zero-out the memory */ - Containers::arrayResize(indexData, NoInit, indexVertexCount.first*sizeof(UnsignedInt)); + Containers::arrayResize(indexData, NoInit, indexVertexCount.first()*sizeof(UnsignedInt)); } Containers::Array attributeData = Implementation::interleavedLayout(std::move(destination), {}, flags); Containers::Array vertexData; - if(!attributeData.isEmpty() && indexVertexCount.second) { + if(!attributeData.isEmpty() && indexVertexCount.second()) { const UnsignedInt attributeStride = attributeData[0].stride(); vertexData = destination.releaseVertexData(); /* Resize to 0 and then to the desired size to zero-out whatever was @@ -135,10 +136,10 @@ template class Allocator = Containers::ArrayAllocator> void conc Containers::arrayResize(vertexData, 0); /* A cast to std::size_t is needed in order to allow sizes over 4 GB on 64-bit */ - Containers::arrayResize(vertexData, ValueInit, attributeStride*std::size_t(indexVertexCount.second)); + Containers::arrayResize(vertexData, ValueInit, attributeStride*std::size_t(indexVertexCount.second())); } - destination = Implementation::concatenate(std::move(indexData), indexVertexCount.second, std::move(vertexData), std::move(attributeData), meshes, "MeshTools::concatenateInto():"); + destination = Implementation::concatenate(std::move(indexData), indexVertexCount.second(), std::move(vertexData), std::move(attributeData), meshes, "MeshTools::concatenateInto():"); } }} diff --git a/src/Magnum/MeshTools/GenerateNormals.cpp b/src/Magnum/MeshTools/GenerateNormals.cpp index 1ac005333..16d74321f 100644 --- a/src/Magnum/MeshTools/GenerateNormals.cpp +++ b/src/Magnum/MeshTools/GenerateNormals.cpp @@ -26,6 +26,7 @@ #include "GenerateNormals.h" #include +#include #include #include "Magnum/Math/Functions.h" @@ -147,25 +148,28 @@ template inline void generateSmoothNormalsIntoImplementation(const Cont /* Precalculate cross product and interior angles of each face --- the loop below would otherwise calculate it for every vertex, which is at least 3x as much work */ - Containers::Array>> crossAngles{NoInit, indices.size()/3}; + Containers::Array>> crossAngles{NoInit, indices.size()/3}; for(std::size_t i = 0; i != crossAngles.size(); ++i) { const Vector3 v0 = positions[indices[i*3 + 0]]; const Vector3 v1 = positions[indices[i*3 + 1]]; const Vector3 v2 = positions[indices[i*3 + 2]]; /* Cross product */ - crossAngles[i].first = Math::cross(v2 - v1, v0 - v1); + crossAngles[i].first() = Math::cross(v2 - v1, v0 - v1); /* If any of the vectors is zero, the normalization would result in a NaN and the angle calculation will assert. This happens also when any of the original positions is NaN. If that's the case, skip the rest. Given triangle will then contribute with a zero total angle, - effectively getting ignored for normal calculation. */ + effectively getting ignored for normal calculation. + + If, however, an angle + */ const Vector3 v10n = (v1 - v0).normalized(); const Vector3 v20n = (v2 - v0).normalized(); const Vector3 v21n = (v2 - v1).normalized(); if(Math::isNan(v10n) || Math::isNan(v20n) || Math::isNan(v21n)) { - crossAngles[i].second = Math::Vector3{Math::ZeroInit}; + crossAngles[i].second() = Math::Vector3{Math::ZeroInit}; continue; } @@ -174,10 +178,10 @@ template inline void generateSmoothNormalsIntoImplementation(const Cont /* This using namespace doesn't work with MSVC2019 with /permissive- (it gets lost when instantiating?!), so it's duplicated above */ using namespace Math::Literals; - crossAngles[i].second[0] = Math::angle(v10n, v20n); - crossAngles[i].second[1] = Math::angle(-v10n, v21n); - crossAngles[i].second[2] = Rad(180.0_degf) - - crossAngles[i].second[0] - crossAngles[i].second[1]; + crossAngles[i].second()[0] = Math::angle(v10n, v20n); + crossAngles[i].second()[1] = Math::angle(-v10n, v21n); + crossAngles[i].second()[2] = Rad(180.0_degf) + - crossAngles[i].second()[0] - crossAngles[i].second()[1]; } /* For every vertex v, calculate normals from all faces it belongs to and @@ -195,14 +199,14 @@ template inline void generateSmoothNormalsIntoImplementation(const Cont /* Cross product is a vector in direction of the normal with length equal to size of the parallelogram */ - const std::pair>& crossAngle = crossAngles[triangleIds[t]]; + const Containers::Pair>& crossAngle = crossAngles[triangleIds[t]]; /* Angle between two sides of the triangle that share vertex `v`. The shared vertex can be one of the three. */ Rad angle; - if(v == v0i) angle = crossAngle.second[0]; - else if(v == v1i) angle = crossAngle.second[1]; - else if(v == v2i) angle = crossAngle.second[2]; + if(v == v0i) angle = crossAngle.second()[0]; + else if(v == v1i) angle = crossAngle.second()[1]; + else if(v == v2i) angle = crossAngle.second()[2]; else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ /* The normal is cross.normalized(), we need to multiply it it by @@ -213,7 +217,7 @@ template inline void generateSmoothNormalsIntoImplementation(const Cont that as well. Finally we need to weight by the angle, and in that case only the ratio is important as well, so it doesn't matter if degrees or radians. */ - normals[v] += crossAngle.first*Float(angle); + normals[v] += crossAngle.first()*Float(angle); } /* Normalize the accumulated direction */