Browse Source

MeshTools: explicit generateSmoothNormals() overloads for each index type.

The templated version had the unfortunate "feature" of not being able to
figure out the type when an array view or a C array got passed to it.
That led to worse-than-ideal UX and even though it's now a bit more
verbose on the implementation side, it's the preferred solution.
pull/371/head
Vladimír Vondruš 6 years ago
parent
commit
29f0fdb188
  1. 2
      doc/snippets/MagnumMeshTools-stl.cpp
  2. 2
      src/Magnum/MeshTools/Compile.cpp
  3. 46
      src/Magnum/MeshTools/GenerateNormals.cpp
  4. 36
      src/Magnum/MeshTools/GenerateNormals.h
  5. 33
      src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp

2
doc/snippets/MagnumMeshTools-stl.cpp

@ -58,7 +58,7 @@ std::vector<UnsignedInt> indices;
std::vector<Vector3> positions;
std::vector<Vector3> normals{positions.size()};
MeshTools::generateSmoothNormalsInto<UnsignedInt>(indices, positions, normals);
MeshTools::generateSmoothNormalsInto(indices, positions, normals);
/* [generateSmoothNormalsInto] */
}

2
src/Magnum/MeshTools/Compile.cpp

@ -199,7 +199,7 @@ GL::Mesh compile(const Trade::MeshData3D& meshData, CompileFlags flags) {
normalStorage = generateFlatNormals(positions);
useIndices = false;
} else {
normalStorage = generateSmoothNormals<UnsignedInt>(meshData.indices(), positions);
normalStorage = generateSmoothNormals(meshData.indices(), positions);
useIndices = true;
}

46
src/Magnum/MeshTools/GenerateNormals.cpp

@ -86,6 +86,8 @@ std::pair<std::vector<UnsignedInt>, std::vector<Vector3>> generateFlatNormals(co
}
#endif
namespace {
#if defined(CORRADE_MSVC2019_COMPATIBILITY) && !defined(CORRADE_MSVC2017_COMPATIBILITY)
/* When using /permissive- with MSVC2019, using namespace inside the function
below FOR SOME REASON gets lost when instantiating the template. That's
@ -94,7 +96,7 @@ std::pair<std::vector<UnsignedInt>, std::vector<Vector3>> generateFlatNormals(co
using namespace Math::Literals;
#endif
template<class T> void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const T>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals) {
template<class T> inline void generateSmoothNormalsIntoImplementation(const Containers::StridedArrayView1D<const T>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals) {
CORRADE_ASSERT(indices.size() % 3 == 0,
"MeshTools::generateSmoothNormalsInto(): index count not divisible by 3", );
CORRADE_ASSERT(normals.size() == positions.size(),
@ -217,22 +219,42 @@ template<class T> void generateSmoothNormalsInto(const Containers::StridedArrayV
}
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template void generateSmoothNormalsInto<UnsignedByte>(const Containers::StridedArrayView1D<const UnsignedByte>&, const Containers::StridedArrayView1D<const Vector3>&, const Containers::StridedArrayView1D<Vector3>&);
template void generateSmoothNormalsInto<UnsignedShort>(const Containers::StridedArrayView1D<const UnsignedShort>&, const Containers::StridedArrayView1D<const Vector3>&, const Containers::StridedArrayView1D<Vector3>&);
template void generateSmoothNormalsInto<UnsignedInt>(const Containers::StridedArrayView1D<const UnsignedInt>&, const Containers::StridedArrayView1D<const Vector3>&, const Containers::StridedArrayView1D<Vector3>&);
#endif
}
/* If not done this way but with templates instead, C++ wouldn't be able to
figure out on its own which overload to use when indices are not already a
strided arrray view */
void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const UnsignedByte>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals) {
generateSmoothNormalsIntoImplementation(indices, positions, normals);
}
void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const UnsignedShort>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals) {
generateSmoothNormalsIntoImplementation(indices, positions, normals);
}
void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const UnsignedInt>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals) {
generateSmoothNormalsIntoImplementation(indices, positions, normals);
}
template<class T> Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const T>& indices, const Containers::StridedArrayView1D<const Vector3>& positions) {
namespace {
template<class T> inline Containers::Array<Vector3> generateSmoothNormalsImplementation(const Containers::StridedArrayView1D<const T>& indices, const Containers::StridedArrayView1D<const Vector3>& positions) {
Containers::Array<Vector3> out{Containers::NoInit, positions.size()};
generateSmoothNormalsInto(indices, positions, out);
return out;
}
#ifndef DOXYGEN_GENERATING_OUTPUT
template Containers::Array<Vector3> generateSmoothNormals<UnsignedByte>(const Containers::StridedArrayView1D<const UnsignedByte>&, const Containers::StridedArrayView1D<const Vector3>&);
template Containers::Array<Vector3> generateSmoothNormals<UnsignedShort>(const Containers::StridedArrayView1D<const UnsignedShort>&, const Containers::StridedArrayView1D<const Vector3>&);
template Containers::Array<Vector3> generateSmoothNormals<UnsignedInt>(const Containers::StridedArrayView1D<const UnsignedInt>&, const Containers::StridedArrayView1D<const Vector3>&);
#endif
}
/* If not done this way but with templates instead, C++ wouldn't be able to
figure out on its own which overload to use when indices are not already a
strided arrray view */
Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const UnsignedByte>& indices, const Containers::StridedArrayView1D<const Vector3>& positions) {
return generateSmoothNormalsImplementation(indices, positions);
}
Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const UnsignedShort>& indices, const Containers::StridedArrayView1D<const Vector3>& positions) {
return generateSmoothNormalsImplementation(indices, positions);
}
Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const UnsignedInt>& indices, const Containers::StridedArrayView1D<const Vector3>& positions) {
return generateSmoothNormalsImplementation(indices, positions);
}
}}

36
src/Magnum/MeshTools/GenerateNormals.h

@ -118,13 +118,19 @@ Martijn Buijs.
@see @ref generateSmoothNormalsInto(), @ref generateFlatNormals(),
@ref MeshTools::CompileFlag::GenerateSmoothNormals
*/
template<class T> MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const T>& indices, const Containers::StridedArrayView1D<const Vector3>& positions);
MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const UnsignedInt>& indices, const Containers::StridedArrayView1D<const Vector3>& positions);
#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__)
extern template MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals<UnsignedByte>(const Containers::StridedArrayView1D<const UnsignedByte>&, const Containers::StridedArrayView1D<const Vector3>&);
extern template MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals<UnsignedShort>(const Containers::StridedArrayView1D<const UnsignedShort>&, const Containers::StridedArrayView1D<const Vector3>&);
extern template MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals<UnsignedInt>(const Containers::StridedArrayView1D<const UnsignedInt>&, const Containers::StridedArrayView1D<const Vector3>&);
#endif
/**
* @overload
* @m_since{2019,10}
*/
MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const UnsignedShort>& indices, const Containers::StridedArrayView1D<const Vector3>& positions);
/**
* @overload
* @m_since{2019,10}
*/
MAGNUM_MESHTOOLS_EXPORT Containers::Array<Vector3> generateSmoothNormals(const Containers::StridedArrayView1D<const UnsignedByte>& indices, const Containers::StridedArrayView1D<const Vector3>& positions);
/**
@brief Generate smooth normals into an existing array
@ -147,13 +153,19 @@ conversions:
@see @ref generateFlatNormalsInto()
*/
template<class T> MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const T>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals);
MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const UnsignedInt>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals);
#if defined(CORRADE_TARGET_WINDOWS) && !defined(__MINGW32__)
extern template MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto<UnsignedByte>(const Containers::StridedArrayView1D<const UnsignedByte>&, const Containers::StridedArrayView1D<const Vector3>&, const Containers::StridedArrayView1D<Vector3>&);
extern template MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto<UnsignedShort>(const Containers::StridedArrayView1D<const UnsignedShort>&, const Containers::StridedArrayView1D<const Vector3>&, const Containers::StridedArrayView1D<Vector3>&);
extern template MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto<UnsignedInt>(const Containers::StridedArrayView1D<const UnsignedInt>&, const Containers::StridedArrayView1D<const Vector3>&, const Containers::StridedArrayView1D<Vector3>&);
#endif
/**
* @overload
* @m_since{2019,10}
*/
MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const UnsignedShort>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals);
/**
* @overload
* @m_since{2019,10}
*/
MAGNUM_MESHTOOLS_EXPORT void generateSmoothNormalsInto(const Containers::StridedArrayView1D<const UnsignedByte>& indices, const Containers::StridedArrayView1D<const Vector3>& positions, const Containers::StridedArrayView1D<Vector3>& normals);
}}

33
src/Magnum/MeshTools/Test/GenerateNormalsTest.cpp

@ -51,7 +51,7 @@ struct GenerateNormalsTest: TestSuite::Tester {
void flatWrongCount();
void flatIntoWrongSize();
void smoothTwoTriangles();
template<class T> void smoothTwoTriangles();
void smoothCube();
void smoothBeveledCube();
void smoothCylinder();
@ -72,7 +72,9 @@ GenerateNormalsTest::GenerateNormalsTest() {
&GenerateNormalsTest::flatWrongCount,
&GenerateNormalsTest::flatIntoWrongSize,
&GenerateNormalsTest::smoothTwoTriangles,
&GenerateNormalsTest::smoothTwoTriangles<UnsignedByte>,
&GenerateNormalsTest::smoothTwoTriangles<UnsignedShort>,
&GenerateNormalsTest::smoothTwoTriangles<UnsignedInt>,
&GenerateNormalsTest::smoothCube,
&GenerateNormalsTest::smoothBeveledCube,
&GenerateNormalsTest::smoothCylinder,
@ -155,12 +157,14 @@ void GenerateNormalsTest::flatIntoWrongSize() {
CORRADE_COMPARE(out.str(), "MeshTools::generateFlatNormalsInto(): bad output size, expected 6 but got 7\n");
}
void GenerateNormalsTest::smoothTwoTriangles() {
const UnsignedInt indices[]{0, 1, 2, 3, 4, 5};
template<class T> void GenerateNormalsTest::smoothTwoTriangles() {
setTestCaseTemplateName(Math::TypeTraits<T>::name());
const T indices[]{0, 1, 2, 3, 4, 5};
/* Should generate the same output as flat normals */
CORRADE_COMPARE_AS(
generateSmoothNormals(Containers::stridedArrayView(indices), TwoTriangles),
generateSmoothNormals(indices, TwoTriangles),
(Containers::Array<Vector3>{Containers::InPlaceInit, {
Vector3::zAxis(),
Vector3::zAxis(),
@ -194,7 +198,7 @@ void GenerateNormalsTest::smoothCube() {
/* Normals should be the same as positions, only normalized */
CORRADE_COMPARE_AS(
generateSmoothNormals(Containers::stridedArrayView(indices), positions),
generateSmoothNormals(indices, positions),
(Containers::Array<Vector3>{Containers::InPlaceInit, {
positions[0]/Constants::sqrt3(),
positions[1]/Constants::sqrt3(),
@ -207,7 +211,6 @@ void GenerateNormalsTest::smoothCube() {
}}), TestSuite::Compare::Container);
}
constexpr Vector3 BeveledCubePositions[] {
{-1.0f, -0.6f, 1.1f},
{ 1.0f, -0.6f, 1.1f},
@ -284,7 +287,7 @@ void GenerateNormalsTest::smoothBeveledCube() {
Vector3 x{0.996072f, 0.0754969f, 0.0462723f};
Vector3 y{0.0467958f, 0.997808f, 0.0467958f};
CORRADE_COMPARE_AS(generateSmoothNormals(
Containers::stridedArrayView(BeveledCubeIndices), BeveledCubePositions),
BeveledCubeIndices, BeveledCubePositions),
(Containers::Array<Vector3>{Containers::InPlaceInit, {
z*Math::sign(BeveledCubePositions[ 0]),
z*Math::sign(BeveledCubePositions[ 1]),
@ -341,8 +344,7 @@ void GenerateNormalsTest::smoothZeroAreaTriangle() {
0, 1, 2, 1, 2, 1
};
CORRADE_COMPARE_AS(generateSmoothNormals(
Containers::stridedArrayView(indices), positions),
CORRADE_COMPARE_AS(generateSmoothNormals(indices, positions),
(Containers::Array<Vector3>{Containers::InPlaceInit, {
Vector3::zAxis(),
Vector3::zAxis(),
@ -364,8 +366,7 @@ void GenerateNormalsTest::smoothNanPosition() {
0, 1, 2, 1, 2, 1
};
Containers::Array<Vector3> generated = generateSmoothNormals(
Containers::stridedArrayView(indices), positions);
Containers::Array<Vector3> generated = generateSmoothNormals(indices, positions);
CORRADE_COMPARE_AS(generated.prefix(3),
(Containers::Array<Vector3>{Containers::InPlaceInit, {
Vector3::zAxis(),
@ -381,7 +382,7 @@ void GenerateNormalsTest::smoothWrongCount() {
const UnsignedByte indices[7]{};
const Vector3 positions[1];
generateSmoothNormals(Containers::stridedArrayView(indices), positions);
generateSmoothNormals(indices, positions);
CORRADE_COMPARE(out.str(), "MeshTools::generateSmoothNormalsInto(): index count not divisible by 3\n");
}
@ -392,7 +393,7 @@ void GenerateNormalsTest::smoothIntoWrongSize() {
const UnsignedByte indices[6]{};
const Vector3 positions[3];
Vector3 normals[4];
generateSmoothNormalsInto(Containers::stridedArrayView(indices), positions, normals);
generateSmoothNormalsInto(indices, positions, normals);
CORRADE_COMPARE(out.str(), "MeshTools::generateSmoothNormalsInto(): bad output size, expected 3 but got 4\n");
}
@ -412,9 +413,7 @@ void GenerateNormalsTest::benchmarkFlat() {
void GenerateNormalsTest::benchmarkSmooth() {
Containers::Array<Vector3> normals{Containers::NoInit, Containers::arraySize(BeveledCubePositions)};
CORRADE_BENCHMARK(10) {
generateSmoothNormalsInto(
Containers::stridedArrayView(BeveledCubeIndices),
BeveledCubePositions, normals);
generateSmoothNormalsInto(BeveledCubeIndices, BeveledCubePositions, normals);
}
CORRADE_COMPARE(Math::min(normals), (Vector3{-0.996072f, -0.997808f, -0.996072f}));

Loading…
Cancel
Save