Browse Source

MeshTools: port away from std::pair in various internals.

Probably no significant impact here except for compilation times due to
not needing to use <utility> anymore.
pull/617/head
Vladimír Vondruš 3 years ago
parent
commit
06832574a2
  1. 24
      src/Magnum/MeshTools/Concatenate.cpp
  2. 15
      src/Magnum/MeshTools/Concatenate.h
  3. 30
      src/Magnum/MeshTools/GenerateNormals.cpp

24
src/Magnum/MeshTools/Concatenate.cpp

@ -33,7 +33,7 @@ namespace Magnum { namespace MeshTools {
namespace Implementation {
std::pair<UnsignedInt, UnsignedInt> concatenateIndexVertexCount(const Containers::Iterable<const Trade::MeshData>& meshes) {
Containers::Pair<UnsignedInt, UnsignedInt> concatenateIndexVertexCount(const Containers::Iterable<const Trade::MeshData>& meshes) {
UnsignedInt indexCount = 0;
UnsignedInt vertexCount = 0;
for(const Trade::MeshData& mesh: meshes) {
@ -101,10 +101,10 @@ Trade::MeshData concatenate(Containers::Array<char>&& 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<Trade::MeshAttribute, std::pair<UnsignedInt, bool>, MeshAttributeHash> attributeMap;
std::unordered_multimap<Trade::MeshAttribute, Containers::Pair<UnsignedInt, bool>, 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<char>&& 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<char>&& 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<char>&& 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<const Trade::MeshData>& 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<UnsignedInt, UnsignedInt> indexVertexCount = Implementation::concatenateIndexVertexCount(meshes);
const Containers::Pair<UnsignedInt, UnsignedInt> indexVertexCount = Implementation::concatenateIndexVertexCount(meshes);
Containers::Array<char> indexData{NoInit,
indexVertexCount.first*sizeof(UnsignedInt)};
indexVertexCount.first()*sizeof(UnsignedInt)};
Containers::Array<char> 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():");
}
}}

15
src/Magnum/MeshTools/Concatenate.h

@ -32,6 +32,7 @@
#include <Corrade/Containers/GrowableArray.h>
#include <Corrade/Containers/Iterable.h>
#include <Corrade/Containers/Pair.h>
#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<UnsignedInt, UnsignedInt> concatenateIndexVertexCount(const Containers::Iterable<const Trade::MeshData>& meshes);
MAGNUM_MESHTOOLS_EXPORT Containers::Pair<UnsignedInt, UnsignedInt> concatenateIndexVertexCount(const Containers::Iterable<const Trade::MeshData>& meshes);
MAGNUM_MESHTOOLS_EXPORT Trade::MeshData concatenate(Containers::Array<char>&& indexData, UnsignedInt vertexCount, Containers::Array<char>&& vertexData, Containers::Array<Trade::MeshAttributeData>&& attributeData, const Containers::Iterable<const Trade::MeshData>& meshes, const char* assertPrefix);
}
@ -114,19 +115,19 @@ template<template<class> class Allocator = Containers::ArrayAllocator> void conc
}
#endif
std::pair<UnsignedInt, UnsignedInt> indexVertexCount = Implementation::concatenateIndexVertexCount(meshes);
const Containers::Pair<UnsignedInt, UnsignedInt> indexVertexCount = Implementation::concatenateIndexVertexCount(meshes);
Containers::Array<char> 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<Allocator>(indexData, NoInit, indexVertexCount.first*sizeof(UnsignedInt));
Containers::arrayResize<Allocator>(indexData, NoInit, indexVertexCount.first()*sizeof(UnsignedInt));
}
Containers::Array<Trade::MeshAttributeData> attributeData = Implementation::interleavedLayout(std::move(destination), {}, flags);
Containers::Array<char> 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<template<class> class Allocator = Containers::ArrayAllocator> void conc
Containers::arrayResize<Allocator>(vertexData, 0);
/* A cast to std::size_t is needed in order to allow sizes over 4 GB on
64-bit */
Containers::arrayResize<Allocator>(vertexData, ValueInit, attributeStride*std::size_t(indexVertexCount.second));
Containers::arrayResize<Allocator>(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():");
}
}}

30
src/Magnum/MeshTools/GenerateNormals.cpp

@ -26,6 +26,7 @@
#include "GenerateNormals.h"
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Pair.h>
#include <Corrade/Containers/StridedArrayView.h>
#include "Magnum/Math/Functions.h"
@ -147,25 +148,28 @@ template<class T> 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<std::pair<Vector3, Math::Vector3<Rad>>> crossAngles{NoInit, indices.size()/3};
Containers::Array<Containers::Pair<Vector3, Math::Vector3<Rad>>> 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<Rad>{Math::ZeroInit};
crossAngles[i].second() = Math::Vector3<Rad>{Math::ZeroInit};
continue;
}
@ -174,10 +178,10 @@ template<class T> 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<class T> 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<Vector3, Math::Vector3<Rad>>& crossAngle = crossAngles[triangleIds[t]];
const Containers::Pair<Vector3, Math::Vector3<Rad>>& 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<class T> 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 */

Loading…
Cancel
Save