diff --git a/doc/changelog.dox b/doc/changelog.dox index fdb6c7ce1..f576b62fb 100644 --- a/doc/changelog.dox +++ b/doc/changelog.dox @@ -415,6 +415,8 @@ See also: @subsubsection changelog-latest-new-primitives Primitives library +- New @ref Primitives::arrow2D() and @relativeref{Primitives,arrow3D()} + primitives - Added an option to generate texture coordinates in various layouts to @ref Primitives::cubeSolid() diff --git a/doc/generated/primitives.cpp b/doc/generated/primitives.cpp index d109b550a..d6cc79b6c 100644 --- a/doc/generated/primitives.cpp +++ b/doc/generated/primitives.cpp @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -94,12 +95,14 @@ struct PrimitiveVisualizer: Platform::WindowlessApplication { Containers::Pair axis2D(); Containers::Pair axis3D(); + Containers::Pair arrow2D(); Containers::Pair capsule2DWireframe(); Containers::Pair circle2DWireframe(); Containers::Pair crosshair2D(); Containers::Pair line2D(); Containers::Pair squareWireframe(); + Containers::Pair arrow3D(); Containers::Pair capsule3DWireframe(); Containers::Pair circle3DWireframe(); Containers::Pair crosshair3D(); @@ -221,7 +224,8 @@ int PrimitiveVisualizer::exec() { shader.setColor(OutlineColor) .setTransformationProjectionMatrix(Projection2D*Transformation2D); - for(auto fun: {&PrimitiveVisualizer::capsule2DWireframe, + for(auto fun: {&PrimitiveVisualizer::arrow2D, + &PrimitiveVisualizer::capsule2DWireframe, &PrimitiveVisualizer::circle2DWireframe, &PrimitiveVisualizer::crosshair2D, &PrimitiveVisualizer::line2D, @@ -244,7 +248,8 @@ int PrimitiveVisualizer::exec() { shader.setColor(OutlineColor) .setTransformationProjectionMatrix(Projection3D*Transformation3D); - for(auto fun: {&PrimitiveVisualizer::capsule3DWireframe, + for(auto fun: {&PrimitiveVisualizer::arrow3D, + &PrimitiveVisualizer::capsule3DWireframe, &PrimitiveVisualizer::circle3DWireframe, &PrimitiveVisualizer::crosshair3D, &PrimitiveVisualizer::coneWireframe, @@ -426,6 +431,11 @@ Containers::Pair PrimitiveVisualizer::g return {Primitives::gradient3DVertical(Gradient20Percent, Gradient80Percent), "gradient3dvertical.png"}; } +Containers::Pair PrimitiveVisualizer::arrow2D() { + Trade::MeshData mesh = Primitives::arrow2D({-1.0f, 0.0f}, {1.0f, 0.0f}); + return {Utility::move(mesh), "arrow2d.png"}; +} + Containers::Pair PrimitiveVisualizer::capsule2DWireframe() { Trade::MeshData capsule = Primitives::capsule2DWireframe(8, 1, 0.75f); MeshTools::transformPointsInPlace(Matrix3::scaling(Vector2{0.75f}), @@ -450,6 +460,11 @@ Containers::Pair PrimitiveVisualizer::s return {Primitives::squareWireframe(), "squarewireframe.png"}; } +Containers::Pair PrimitiveVisualizer::arrow3D() { + Trade::MeshData mesh = Primitives::arrow3D({-1.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}); + return {Utility::move(mesh), "arrow3d.png"}; +} + Containers::Pair PrimitiveVisualizer::capsule3DWireframe() { Trade::MeshData capsule = Primitives::capsule3DWireframe(8, 1, 16, 1.0f); MeshTools::transformPointsInPlace(Matrix4::scaling(Vector3{0.75f}), diff --git a/doc/namespaces.dox b/doc/namespaces.dox index 479987182..50e55a57f 100644 --- a/doc/namespaces.dox +++ b/doc/namespaces.dox @@ -486,6 +486,16 @@ See @ref building and @ref cmake for more information. @parblock +@m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} +@image html primitives-arrow2d.png width=128px +@ref arrow2D() +@m_enddiv + +@m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} +@image html primitives-arrow3d.png width=128px +@ref arrow3D() +@m_enddiv + @m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-axis2d.png width=128px @ref axis2D() @@ -556,19 +566,21 @@ See @ref building and @ref cmake for more information. @ref cubeSolid() \n @ref cubeSolidStrip() @m_enddiv +@m_div{m-clearfix-m m-show-m} @m_enddiv + @m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-cubewireframe.png width=128px @ref cubeWireframe() @m_enddiv -@m_div{m-clearfix-s m-show-s} @m_enddiv - @m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-cylindersolid.png width=128px @ref cylinderSolid() @m_enddiv -@m_div{m-clearfix-m m-show-m} @m_enddiv +@m_div{m-clearfix-s m-show-s} @m_enddiv + +@m_div{m-clearfix-l m-show-l} @m_enddiv @m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-cylinderwireframe.png width=128px @@ -580,8 +592,6 @@ See @ref building and @ref cmake for more information. @ref gradient2D() @m_enddiv -@m_div{m-clearfix-l m-show-l} @m_enddiv - @m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-gradient2dhorizontal.png width=128px @ref gradient2DHorizontal() @@ -642,27 +652,27 @@ See @ref building and @ref cmake for more information. @ref planeSolid() @m_enddiv -@m_div{m-col-l-2 m-push-l-1 m-col-m-3 m-push-m-0 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} +@m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-planewireframe.png width=128px @ref planeWireframe() @m_enddiv -@m_div{m-col-l-2 m-push-l-1 m-col-m-3 m-push-m-0 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} +@m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-squaresolid.png width=128px @ref squareSolid() @m_enddiv -@m_div{m-col-l-2 m-push-l-1 m-col-m-3 m-push-m-1 m-col-s-4 m-push-s-0 m-col-t-6 m-text-center m-nopadt m-nopadx} +@m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-squarewireframe.png width=128px @ref squareWireframe() @m_enddiv -@m_div{m-col-l-2 m-push-l-1 m-col-m-4 m-push-m-1 m-col-s-4 m-push-s-2 m-col-t-6 m-push-t-0 m-text-center m-nopadt m-nopadx} +@m_div{m-col-l-2 m-col-m-3 m-col-s-4 m-col-t-6 m-text-center m-nopadt m-nopadx} @image html primitives-uvspheresolid.png width=128px @ref uvSphereSolid() @m_enddiv -@m_div{m-col-l-2 m-push-l-1 m-col-m-3 m-push-m-1 m-col-s-4 m-push-s-2 m-col-t-6 m-push-t-3 m-text-center m-nopadt m-nopadx} +@m_div{m-col-l-2 m-push-l-5 m-col-s-4 m-push-s-4 m-col-t-6 m-push-t-3 m-text-center m-nopadt m-nopadx} @image html primitives-uvspherewireframe.png width=128px @ref uvSphereWireframe() @m_enddiv diff --git a/doc/primitives-arrow2d.png b/doc/primitives-arrow2d.png new file mode 100644 index 000000000..1b43eab2c Binary files /dev/null and b/doc/primitives-arrow2d.png differ diff --git a/doc/primitives-arrow3d.png b/doc/primitives-arrow3d.png new file mode 100644 index 000000000..0c8e60e4f Binary files /dev/null and b/doc/primitives-arrow3d.png differ diff --git a/doc/snippets/Primitives.cpp b/doc/snippets/Primitives.cpp index b8ecedc31..100259eeb 100644 --- a/doc/snippets/Primitives.cpp +++ b/doc/snippets/Primitives.cpp @@ -25,6 +25,7 @@ */ #include "Magnum/Math/Color.h" +#include "Magnum/Primitives/Arrow.h" #include "Magnum/Primitives/Gradient.h" #include "Magnum/Primitives/Line.h" #include "Magnum/Trade/MeshData.h" @@ -63,9 +64,21 @@ Primitives::line2D({0.0f, 0.0f}, {1.0f, 0.0f}); /* [line2D-identity] */ } +{ +/* [arrow2D-identity] */ +Primitives::arrow2D({0.0f, 0.0f}, {1.0f, 0.0f}); +/* [arrow2D-identity] */ +} + { /* [line3D-identity] */ Primitives::line3D({0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}); /* [line3D-identity] */ } + +{ +/* [arrow3D-identity] */ +Primitives::arrow3D({0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}); +/* [arrow3D-identity] */ +} } diff --git a/src/Magnum/Primitives/Arrow.cpp b/src/Magnum/Primitives/Arrow.cpp new file mode 100644 index 000000000..8c4facaa1 --- /dev/null +++ b/src/Magnum/Primitives/Arrow.cpp @@ -0,0 +1,107 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023, 2024, 2025, 2026 + 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 "Arrow.h" + +#include "Magnum/Mesh.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/Trade/MeshData.h" + +namespace Magnum { namespace Primitives { + +namespace { + +/* not 8-bit because GPUs (and Vulkan) don't like it nowadays */ +constexpr UnsignedShort Indices[]{ + 0, 1, + 1, 2, + 1, 3 +}; +constexpr Trade::MeshAttributeData Attributes2D[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, + VertexFormat::Vector2, 0, 4, sizeof(Vector2)}, +}; + +} + +Trade::MeshData arrow2D(const Vector2& a, const Vector2& b) { + Containers::Array vertexData{NoInit, sizeof(Vector2)*4}; + auto positions = Containers::arrayCast(vertexData); + + /* Line */ + positions[0] = a; + positions[1] = b; + + /* Arrowhead */ + const Vector2 direction = (b - a).resized(0.1f); + const Vector2 perpendicular = direction.perpendicular(); + positions[2] = b - direction - perpendicular; + positions[3] = b - direction + perpendicular; + + return Trade::MeshData{MeshPrimitive::Lines, + Trade::DataFlag::Global, Indices, Trade::MeshIndexData{Indices}, + Utility::move(vertexData), Trade::meshAttributeDataNonOwningArray(Attributes2D)}; +} + +namespace { + +constexpr Trade::MeshAttributeData Attributes3D[]{ + Trade::MeshAttributeData{Trade::MeshAttribute::Position, + VertexFormat::Vector3, 0, 4, sizeof(Vector3)}, +}; + +} + +Trade::MeshData arrow3D(const Vector3& a, const Vector3& b, const Vector3& tangent) { + Containers::Array vertexData{NoInit, sizeof(Vector3)*4}; + auto positions = Containers::arrayCast(vertexData); + + /* Line */ + positions[0] = a; + positions[1] = b; + + /* Arrowhead. The perpendicular sign is flipped compared to the 2D version + to have vertex positions match the 2D version in the default + orientation. */ + const Vector3 direction = (b - a).resized(0.1f); + const Vector3 perpendicular = Math::cross(direction, tangent).resized(0.1f); + positions[2] = b - direction + perpendicular; + positions[3] = b - direction - perpendicular; + + return Trade::MeshData{MeshPrimitive::Lines, + Trade::DataFlag::Global, Indices, Trade::MeshIndexData{Indices}, + Utility::move(vertexData), Trade::meshAttributeDataNonOwningArray(Attributes3D)}; +} + +Trade::MeshData arrow2D() { + return arrow2D({0.0f, 0.0f}, {1.0f, 0.0f}); +} + +Trade::MeshData arrow3D() { + return arrow3D({0.0f, 0.0f, 0.0f}, {1.0f, 0.0f, 0.0f}); +} + +}} diff --git a/src/Magnum/Primitives/Arrow.h b/src/Magnum/Primitives/Arrow.h new file mode 100644 index 000000000..0b605f2cc --- /dev/null +++ b/src/Magnum/Primitives/Arrow.h @@ -0,0 +1,103 @@ +#ifndef Magnum_Primitives_Arrow_h +#define Magnum_Primitives_Arrow_h +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023, 2024, 2025, 2026 + 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. +*/ + +/** @file + * @brief Function @ref Magnum::Primitives::arrow2D(), @ref Magnum::Primitives::arrow3D() + * @m_since_latest + */ + +#include "Magnum/Magnum.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/Primitives/visibility.h" +#include "Magnum/Trade/Trade.h" + +namespace Magnum { namespace Primitives { + +/** +@brief 2D arrow +@m_since_latest + +Indexed @ref MeshPrimitive::Lines with @ref VertexFormat::Vector2 positions +going from @p a to @p b and @ref MeshIndexType::UnsignedShort indices. The +arrowhead has a constant size independent of the length. The returned instance +references @ref Trade::DataFlag::Global index data --- pass the mesh through +@ref MeshTools::copy() to get a mutable copy, if needed. + +@image html primitives-arrow2d.png width=256px + +@see @ref arrow2D(), @ref arrow3D(const Vector3&, const Vector3&, const Vector3&), + @ref line2D(const Vector2&, const Vector2&), @ref axis2D(), + @ref crosshair2D() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData arrow2D(const Vector2& a, const Vector2& b); + +/** +@brief 2D arrow in an identity transformation +@m_since_latest + +Unit-size arrow in direction of positive X axis. Equivalent to calling +@ref arrow2D(const Vector2&, const Vector2&) as + +@snippet Primitives.cpp arrow2D-identity +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData arrow2D(); + +/** +@brief 3D arrow +@m_since_latest + +Indexed @ref MeshPrimitive::Lines with @ref VertexFormat::Vector3 positions +going from @p a to @p b and @ref MeshIndexType::UnsignedShort indices. The +arrowhead has a constant size independent of the length. The @p tangent +argument can be used to adjust orientation of the arrowhead, which is by +default aligned with the XY plane. The returned instance references +@ref Trade::DataFlag::Global index data --- pass the mesh through +@ref MeshTools::copy() to get a mutable copy, if needed. + +@image html primitives-arrow3d.png width=256px + +@see @ref arrow3D(), @ref arrow2D(const Vector2&, const Vector2&), + @ref line3D(const Vector3&, const Vector3&), @ref axis3D(), + @ref crosshair3D() +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData arrow3D(const Vector3& a, const Vector3& b, const Vector3& tangent = Vector3::zAxis()); + +/** +@brief 3D arrow in an identity transformation +@m_since_latest + +Unit-size arrow in direction of positive X axis. Equivalent to calling +@ref arrow3D(const Vector3&, const Vector3&, const Vector3&) as + +@snippet Primitives.cpp arrow3D-identity +*/ +MAGNUM_PRIMITIVES_EXPORT Trade::MeshData arrow3D(); + +}} + +#endif diff --git a/src/Magnum/Primitives/Axis.h b/src/Magnum/Primitives/Axis.h index cd13251c1..fbdeffca1 100644 --- a/src/Magnum/Primitives/Axis.h +++ b/src/Magnum/Primitives/Axis.h @@ -48,7 +48,8 @@ mesh through @ref MeshTools::copy() to get a mutable copy, if needed. @image html primitives-axis2d.png width=256px @see @ref axis3D(), @ref crosshair2D(), - @ref line2D(const Vector2&, const Vector2&) + @ref line2D(const Vector2&, const Vector2&), + @ref arrow2D(const Vector2&, const Vector2&) */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData axis2D(); @@ -65,7 +66,8 @@ pass the mesh through @ref MeshTools::copy() to get a mutable copy, if needed. @image html primitives-axis3d.png width=256px @see @ref axis2D(), @ref crosshair3D(), - @ref line3D(const Vector3&, const Vector3&) + @ref line3D(const Vector3&, const Vector3&), + @ref arrow3D(const Vector3&, const Vector3&, const Vector3&) */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData axis3D(); diff --git a/src/Magnum/Primitives/CMakeLists.txt b/src/Magnum/Primitives/CMakeLists.txt index 6fb355437..242c924ed 100644 --- a/src/Magnum/Primitives/CMakeLists.txt +++ b/src/Magnum/Primitives/CMakeLists.txt @@ -29,6 +29,7 @@ set(CMAKE_FOLDER "Magnum/Primitives") set(MagnumPrimitives_SRCS + Arrow.cpp Axis.cpp Crosshair.cpp Gradient.cpp @@ -50,6 +51,7 @@ set(MagnumPrimitives_GracefulAssert_SRCS UVSphere.cpp) set(MagnumPrimitives_HEADERS + Arrow.h Axis.h Capsule.h Circle.h diff --git a/src/Magnum/Primitives/Crosshair.h b/src/Magnum/Primitives/Crosshair.h index fb810088b..8b3d5bced 100644 --- a/src/Magnum/Primitives/Crosshair.h +++ b/src/Magnum/Primitives/Crosshair.h @@ -46,7 +46,8 @@ mesh through @ref MeshTools::copy() to get a mutable copy, if needed. @image html primitives-crosshair2d.png width=256px @see @ref crosshair3D(), @ref axis2D(), - @ref line2D(const Vector2&, const Vector2&) + @ref line2D(const Vector2&, const Vector2&), + @ref arrow2D(const Vector2&, const Vector2&) */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData crosshair2D(); @@ -61,7 +62,8 @@ mesh through @ref MeshTools::copy() to get a mutable copy, if needed. @image html primitives-crosshair3d.png width=256px @see @ref crosshair2D(), @ref axis2D(), - @ref line3D(const Vector3&, const Vector3&) + @ref line3D(const Vector3&, const Vector3&), + @ref arrow3D(const Vector3&, const Vector3&, const Vector3&) */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData crosshair3D(); diff --git a/src/Magnum/Primitives/Line.h b/src/Magnum/Primitives/Line.h index 3812819dd..9432342e0 100644 --- a/src/Magnum/Primitives/Line.h +++ b/src/Magnum/Primitives/Line.h @@ -44,7 +44,8 @@ going from @p a to @p b. @image html primitives-line2d.png width=256px -@see @ref line2D(), @ref line3D(const Vector3&, const Vector3&), @ref axis2D(), +@see @ref line2D(), @ref line3D(const Vector3&, const Vector3&), + @ref arrow2D(const Vector2&, const Vector2&), @ref axis2D(), @ref crosshair2D() */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData line2D(const Vector2& a, const Vector2& b); @@ -67,8 +68,9 @@ going from @p a to @p b. @image html primitives-line3d.png width=256px -@see @ref line3D(), @ref line2D(const Vector2&, const Vector2&), @ref axis3D(), - @ref crosshair3D() +@see @ref line3D(), @ref line2D(const Vector2&, const Vector2&), + @ref arrow3D(const Vector3&, const Vector3&, const Vector3&), + @ref axis3D(), @ref crosshair3D() */ MAGNUM_PRIMITIVES_EXPORT Trade::MeshData line3D(const Vector3& a, const Vector3& b); diff --git a/src/Magnum/Primitives/Test/ArrowTest.cpp b/src/Magnum/Primitives/Test/ArrowTest.cpp new file mode 100644 index 000000000..c7de37c49 --- /dev/null +++ b/src/Magnum/Primitives/Test/ArrowTest.cpp @@ -0,0 +1,134 @@ +/* + This file is part of Magnum. + + Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, + 2020, 2021, 2022, 2023, 2024, 2025, 2026 + 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 +#include + +#include "Magnum/Mesh.h" +#include "Magnum/Math/Vector3.h" +#include "Magnum/MeshTools/Transform.h" +#include "Magnum/Primitives/Arrow.h" +#include "Magnum/Trade/MeshData.h" + +namespace Magnum { namespace Primitives { namespace Test { namespace { + +struct ArrowTest: TestSuite::Tester { + explicit ArrowTest(); + + void twoDimensions(); + void twoDimensionsTransformed(); + void threeDimensions(); + void threeDimensionsTransformed(); + void threeDimensionsTangent(); +}; + +ArrowTest::ArrowTest() { + addTests({&ArrowTest::twoDimensions, + &ArrowTest::twoDimensionsTransformed, + &ArrowTest::threeDimensions, + &ArrowTest::threeDimensionsTransformed, + &ArrowTest::threeDimensionsTangent}); +} + +using namespace Math::Literals; + +void ArrowTest::twoDimensions() { + Trade::MeshData mesh = Primitives::arrow2D(); + CORRADE_COMPARE(mesh.primitive(), MeshPrimitive::Lines); + CORRADE_VERIFY(mesh.isIndexed()); + CORRADE_COMPARE_AS(mesh.indices(), Containers::arrayView({ + 0, 1, + 1, 2, + 1, 3 + }), TestSuite::Compare::Container); + CORRADE_COMPARE(mesh.attributeCount(), 1); + CORRADE_COMPARE_AS(mesh.attribute(Trade::MeshAttribute::Position), Containers::arrayView({ + {0.0f, 0.0f}, + {1.0f, 0.0f}, + {0.9f, -0.1f}, + {0.9f, 0.1f} + }), TestSuite::Compare::Container); +} + +void ArrowTest::twoDimensionsTransformed() { + /* The arrowhead should follow line direction, length shouldn't affect the + arrowhead size in any way */ + + Trade::MeshData mesh = Primitives::arrow2D({5.0f, 20.0f}, {5.0f, 10.0f}); + CORRADE_COMPARE_AS(mesh.attribute(Trade::MeshAttribute::Position), Containers::arrayView({ + {5.0f, 20.0f}, + {5.0f, 10.0f}, + {4.9f, 10.1f}, + {5.1f, 10.1f} + }), TestSuite::Compare::Container); +} + +void ArrowTest::threeDimensions() { + Trade::MeshData mesh = Primitives::arrow3D(); + CORRADE_COMPARE(mesh.primitive(), MeshPrimitive::Lines); + CORRADE_VERIFY(mesh.isIndexed()); + CORRADE_COMPARE_AS(mesh.indices(), Containers::arrayView({ + 0, 1, + 1, 2, + 1, 3 + }), TestSuite::Compare::Container); + CORRADE_COMPARE(mesh.attributeCount(), 1); + CORRADE_COMPARE_AS(mesh.attribute(Trade::MeshAttribute::Position), Containers::arrayView({ + {0.0f, 0.0f, 0.0f}, + {1.0f, 0.0f, 0.0f}, + {0.9f, -0.1f, 0.0f}, + {0.9f, 0.1f, 0.0f} + }), TestSuite::Compare::Container); +} + +void ArrowTest::threeDimensionsTransformed() { + /* The arrowhead should follow line direction, length shouldn't affect the + arrowhead size in any way */ + + Trade::MeshData mesh = Primitives::arrow3D({5.0f, 20.0f, 3.0f}, {5.0f, 10.0f, 3.0f}); + CORRADE_COMPARE_AS(mesh.attribute(Trade::MeshAttribute::Position), Containers::arrayView({ + {5.0f, 20.0f, 3.0f}, + {5.0f, 10.0f, 3.0f}, + {4.9f, 10.1f, 3.0f}, + {5.1f, 10.1f, 3.0f} + }), TestSuite::Compare::Container); +} + +void ArrowTest::threeDimensionsTangent() { + /* Arrow on a -Z plane with a X tangent should be the same as the default + one rotated by 90° around Y */ + + Trade::MeshData mesh = Primitives::arrow3D({}, {0.0f, 0.0f, -1.0f}, {1.0f, 0.0f, 0.0f}); + Trade::MeshData rotated = MeshTools::transform3D(Primitives::arrow3D(), Matrix4::rotationY(90.0_degf)); + CORRADE_COMPARE_AS( + mesh.attribute(Trade::MeshAttribute::Position), + rotated.attribute(Trade::MeshAttribute::Position), + TestSuite::Compare::Container); +} + +}}}} + +CORRADE_TEST_MAIN(Magnum::Primitives::Test::ArrowTest) diff --git a/src/Magnum/Primitives/Test/CMakeLists.txt b/src/Magnum/Primitives/Test/CMakeLists.txt index 8dfed211f..eee2825cb 100644 --- a/src/Magnum/Primitives/Test/CMakeLists.txt +++ b/src/Magnum/Primitives/Test/CMakeLists.txt @@ -28,6 +28,7 @@ # property that would have to be set on each target separately. set(CMAKE_FOLDER "Magnum/Primitives/Test") +corrade_add_test(PrimitivesArrowTest ArrowTest.cpp LIBRARIES MagnumPrimitives) corrade_add_test(PrimitivesAxisTest AxisTest.cpp LIBRARIES MagnumPrimitives) corrade_add_test(PrimitivesCapsuleTest CapsuleTest.cpp LIBRARIES MagnumPrimitivesTestLib) corrade_add_test(PrimitivesCircleTest CircleTest.cpp LIBRARIES MagnumPrimitivesTestLib)