diff --git a/src/Magnum/MeshTools/CMakeLists.txt b/src/Magnum/MeshTools/CMakeLists.txt index 338d27603..4328d958a 100644 --- a/src/Magnum/MeshTools/CMakeLists.txt +++ b/src/Magnum/MeshTools/CMakeLists.txt @@ -41,6 +41,7 @@ set(MagnumMeshTools_GracefulAssert_SRCS FilterAttributes.cpp FlipNormals.cpp GenerateIndices.cpp + GenerateLines.cpp GenerateNormals.cpp Interleave.cpp Reference.cpp @@ -56,6 +57,7 @@ set(MagnumMeshTools_HEADERS FilterAttributes.h FlipNormals.h GenerateIndices.h + GenerateLines.h GenerateNormals.h Interleave.h InterleaveFlags.h diff --git a/src/Magnum/MeshTools/GenerateLines.cpp b/src/Magnum/MeshTools/GenerateLines.cpp new file mode 100644 index 000000000..6eb2ddc86 --- /dev/null +++ b/src/Magnum/MeshTools/GenerateLines.cpp @@ -0,0 +1,162 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + 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. +*/ + +#include "GenerateLines.h" + +#include + +#include "Magnum/DimensionTraits.h" +#include "Magnum/Math/Vector3.h" + +namespace Magnum { namespace MeshTools { + +namespace { + +// TODO take line segment count? easier to document, harder to use with a strip/loop +template inline void generateLineIndicesIntoImplementation(const std::size_t lineStripPointCount, const Containers::StridedArrayView1D& indices) { + // TODO assert lineStripPointCount > 2 and indices.size() == (lineStripPointCount - 1)*6 + + for(std::size_t i = 0, max = lineStripPointCount/2; i != max; ++i) { + /* For consistency same as the Text library does + 0---2 0---2 5 + | | | / /| + | | | / / | + | | |/ / | + 1---3 1 3---4 */ + indices[i*6 + 0] = i*4 + 0; + indices[i*6 + 1] = i*4 + 1; + indices[i*6 + 2] = i*4 + 2; + indices[i*6 + 3] = i*4 + 1; + indices[i*6 + 4] = i*4 + 3; + indices[i*6 + 5] = i*4 + 2; + } +} + +} + +void generateLineIndicesInto(const std::size_t lineStripPointCount, const Containers::StridedArrayView1D& indices) { + return generateLineIndicesIntoImplementation(lineStripPointCount, indices); +} + +void generateLineIndicesInto(const std::size_t lineStripPointCount, const Containers::StridedArrayView1D& indices) { + return generateLineIndicesIntoImplementation(lineStripPointCount, indices); +} + +/* TODO useful for anything?? need to cap like SVG + + 0-------+-----+-+ + | / |/ + A---------B / + | / / /| + 2---/---/-----+ + / / / + / / / + +---C---+ */ + +namespace { + +// TODO take indices? +template void generateLinesIntoImplementation(const Containers::StridedArrayView1D>& lineStripPositions, const Containers::StridedArrayView1D>& positions, const Containers::StridedArrayView1D>& directions, const Containers::StridedArrayView1D>& neighborDirections, const bool loop) { + // TODO assert lineStripPositions.size() > 2 and positions,tangents,normals.size() == (lineStripPositions.size() - 1)*4 + + for(std::size_t i = 0, max = lineStripPositions.size() - 1; i != max; ++i) { + /* + Illustrative example of a line segment from A to B, with quad + corners 0, 1, 2 and 3. Each gets either a `+d` or `-d` for the + segment direction, and `pd` or `nd` for prev/next directions. The + next segment is from B to C, forming the `nd`, and A is the first + point of a line strip, so `pd` will be a zero vector. + + TODO this is outdated, all directions should be the same + <-d-0-----------2-+d-> direction: +----> + | / \ + A---------B nd prevDirection: + + | / \ v + <-d-1-------3-+d-> \ nextDirection: + + \ \ . \ + nd . . \ + v C . v + */ + const VectorTypeFor a = lineStripPositions[i + 0]; + const VectorTypeFor b = lineStripPositions[i + 1]; + const VectorTypeFor direction = b - a; + + /* Direction to the previous point. If we're at the line start, it's + a zero vector to indicate that a line cap should be drawn, otherwise + it's a normalized vector. */ + // TODO normalization clashes with zero-length line segments, thse + // would be zero as well, causing caps to appear + VectorTypeFor prevDirection{NoInit}; + if(i == 0) { + if(!loop) prevDirection = {}; + else prevDirection = (lineStripPositions[max] - a).normalized(); + } else prevDirection = (lineStripPositions[i - 1] - a).normalized(); + + /* Direction to the next point. If we're at the line end, it's a zero + vector to indicate that a line cap should be drawn, otherwise it's a + normalized vector. */ + // TODO normalization clashes with zero-length line segments, thse + // would be zero as well, causing caps to appear + VectorTypeFor nextDirection{NoInit}; + if(i + 1 == max) { + if(!loop) nextDirection = {}; + else nextDirection = (lineStripPositions[0] - a).normalized(); + } else nextDirection = (lineStripPositions[i + 2] - b).normalized(); + + /* Save all output for this segment. Since the line width is a shader + input, the quad actually has no width at all, it's expanded later + with the help of normal and tangent properties */ + positions[i*4 + 0] = positions[i*4 + 2] = a; + positions[i*4 + 1] = positions[i*4 + 3] = a; + neighborDirections[i*4 + 0] = neighborDirections[i*4 + 2] = prevDirection; + neighborDirections[i*4 + 1] = neighborDirections[i*4 + 3] = nextDirection; + directions[i*4 + 0] = direction; + directions[i*4 + 1] = direction; + directions[i*4 + 2] = direction; + directions[i*4 + 3] = direction; + } +} + +} + +void generateLineStripInto(const Containers::StridedArrayView1D& lineStripPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections) { + return generateLinesIntoImplementation<2>(lineStripPositions, positions, directions, neighborDirections, false); +} + +void generateLineStripInto(const Containers::StridedArrayView1D& lineStripPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections) { + return generateLinesIntoImplementation<3>(lineStripPositions, positions, directions, neighborDirections, false); +} + +void generateLineLoopInto(const Containers::StridedArrayView1D& lineLoopPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections) { + return generateLinesIntoImplementation<2>(lineLoopPositions, positions, directions, neighborDirections, true); +} + +void generateLineLoopInto(const Containers::StridedArrayView1D& lineLoopPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections) { + return generateLinesIntoImplementation<3>(lineLoopPositions, positions, directions, neighborDirections, true); +} + +// Trade::MeshData generateLineStrip( + +}} diff --git a/src/Magnum/MeshTools/GenerateLines.h b/src/Magnum/MeshTools/GenerateLines.h new file mode 100644 index 000000000..c911e7b88 --- /dev/null +++ b/src/Magnum/MeshTools/GenerateLines.h @@ -0,0 +1,54 @@ +#ifndef Magnum_MeshTools_GenerateLines_h +#define Magnum_MeshTools_GenerateLines_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022 Vladimír Vondruš + + 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. +*/ + +#include "Magnum/MeshTools/visibility.h" +#include "Magnum/Trade/Trade.h" + +namespace Magnum { namespace MeshTools { + +void generateLineIndicesInto(std::size_t lineStripPointCount, const Containers::StridedArrayView1D& indices); + +void generateLineIndicesInto(std::size_t lineStripPointCount, const Containers::StridedArrayView1D& indices); + +void generateLineStripInto(const Containers::StridedArrayView1D& lineStripPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections); + +void generateLineStripInto(const Containers::StridedArrayView1D& lineStripPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections); + +void generateLineLoopInto(const Containers::StridedArrayView1D& lineStripPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections); + +void generateLineLoopInto(const Containers::StridedArrayView1D& lineStripPositions, const Containers::StridedArrayView1D& positions, const Containers::StridedArrayView1D& directions, const Containers::StridedArrayView1D& neighborDirections); + +// Trade::MeshData generateLineStrip(const Containers::StridedArrayView1D& lineStripPositions); +// +// Trade::MeshData generateLineLoop(const Containers::StridedArrayView1D& lineStripPositions); + +// TODO take indexed line segments, probably? can't work with strips +// TODO *fuck* can't work with that either, need to generate triangles from scratch + +}} + +#endif