mirror of https://github.com/mosra/magnum.git
Browse Source
Currently just the bare minimum, more features such as handling multiple contiguous strips and loops inside a single mesh or an overlapping layout will come later.pull/601/head
14 changed files with 1518 additions and 2 deletions
@ -0,0 +1,84 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 "CompileLines.h" |
||||||
|
|
||||||
|
#include "Magnum/GL/Buffer.h" |
||||||
|
#include "Magnum/GL/Mesh.h" |
||||||
|
#include "Magnum/MeshTools/Compile.h" |
||||||
|
#include "Magnum/MeshTools/Implementation/GenerateLines.h" |
||||||
|
|
||||||
|
/* This header is included only privately and doesn't introduce any linker
|
||||||
|
dependency (taking just the PreviousPosition, NextPosition and Annotation |
||||||
|
attribute typedefs), thus it's completely safe to not link to the Shaders |
||||||
|
library */ |
||||||
|
#include "Magnum/Shaders/LineGL.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { |
||||||
|
|
||||||
|
GL::Mesh compileLines(const Trade::MeshData& lineMesh) { |
||||||
|
Trade::MeshData mesh = Implementation::generateLines(lineMesh); |
||||||
|
|
||||||
|
#ifdef CORRADE_GRACEFUL_ASSERT |
||||||
|
/* If it asserted inside, bail */ |
||||||
|
if(!mesh.attributeCount()) return GL::Mesh{}; |
||||||
|
#endif |
||||||
|
|
||||||
|
/* Upload the buffers, bind the line-specific attributes manually */ |
||||||
|
GL::Buffer indices{GL::Buffer::TargetHint::ElementArray, mesh.indexData()}; |
||||||
|
GL::Buffer vertices{GL::Buffer::TargetHint::Array, mesh.vertexData()}; |
||||||
|
GL::Mesh out = compile(mesh, std::move(indices), vertices); |
||||||
|
|
||||||
|
/* Warn about attributes that are conflicting with line-specific attributes
|
||||||
|
and thus will get overwritten */ |
||||||
|
static_assert(Shaders::GenericGL3D::TextureCoordinates::Location == UnsignedInt(Shaders::LineGL3D::Annotation::Location), ""); |
||||||
|
static_assert(Shaders::GenericGL3D::Tangent::Location == UnsignedInt(Shaders::LineGL3D::PreviousPosition::Location), ""); |
||||||
|
static_assert(Shaders::GenericGL3D::Normal::Location == UnsignedInt(Shaders::LineGL3D::NextPosition::Location), ""); |
||||||
|
if(const Containers::Optional<UnsignedInt> id = lineMesh.findAttributeId(Trade::MeshAttribute::TextureCoordinates)) |
||||||
|
Warning{} << "MeshTools::compileLines():" << lineMesh.attributeName(*id) << "conflicts with line annotation attribute, ignoring"; |
||||||
|
if(const Containers::Optional<UnsignedInt> id = lineMesh.findAttributeId(Trade::MeshAttribute::Tangent)) |
||||||
|
Warning{} << "MeshTools::compileLines():" << lineMesh.attributeName(*id) << "conflicts with line previous position attribute, ignoring"; |
||||||
|
if(const Containers::Optional<UnsignedInt> id = lineMesh.findAttributeId(Trade::MeshAttribute::Normal)) |
||||||
|
Warning{} << "MeshTools::compileLines():" << lineMesh.attributeName(*id) << "conflicts with line next position attribute, ignoring"; |
||||||
|
|
||||||
|
/* PreviousPosition / NextPosition are bound to the same location in both
|
||||||
|
2D and 3D, using the 3D variant so it can be trimmed to just two |
||||||
|
components in 2D (which wouldn't be possible the other way around) */ |
||||||
|
out.addVertexBuffer(vertices, |
||||||
|
mesh.attributeOffset(Implementation::MeshAttributePreviousPosition), |
||||||
|
mesh.attributeStride(Implementation::MeshAttributePreviousPosition), |
||||||
|
GL::DynamicAttribute{Shaders::LineGL3D::PreviousPosition{}, mesh.attributeFormat(Implementation::MeshAttributePreviousPosition)}); |
||||||
|
out.addVertexBuffer(vertices, |
||||||
|
mesh.attributeOffset(Implementation::MeshAttributeNextPosition), |
||||||
|
mesh.attributeStride(Implementation::MeshAttributeNextPosition), |
||||||
|
GL::DynamicAttribute{Shaders::LineGL3D::NextPosition{}, mesh.attributeFormat(Implementation::MeshAttributeNextPosition)}); |
||||||
|
out.addVertexBuffer(std::move(vertices), |
||||||
|
mesh.attributeOffset(Implementation::MeshAttributeAnnotation), |
||||||
|
mesh.attributeStride(Implementation::MeshAttributeAnnotation), |
||||||
|
GL::DynamicAttribute{Shaders::LineGL3D::Annotation{}, mesh.attributeFormat(Implementation::MeshAttributeAnnotation)}); |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
}} |
||||||
@ -0,0 +1,92 @@ |
|||||||
|
#ifndef Magnum_MeshTools_CompileLines_h |
||||||
|
#define Magnum_MeshTools_CompileLines_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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. |
||||||
|
*/ |
||||||
|
|
||||||
|
#if defined(MAGNUM_TARGET_GL) && !defined(MAGNUM_TARGET_GLES2) |
||||||
|
/** @file
|
||||||
|
* @brief Function @ref Magnum::MeshTools::compileLines() |
||||||
|
* @m_since_latest |
||||||
|
*/ |
||||||
|
#endif |
||||||
|
|
||||||
|
#include "Magnum/configure.h" |
||||||
|
|
||||||
|
#if defined(MAGNUM_TARGET_GL) && !defined(MAGNUM_TARGET_GLES2) |
||||||
|
#include "Magnum/GL/GL.h" |
||||||
|
#include "Magnum/MeshTools/visibility.h" |
||||||
|
#include "Magnum/Trade/Trade.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { |
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Compile a line mesh for use with @ref Shaders::LineGL |
||||||
|
@m_since_latest |
||||||
|
|
||||||
|
Returns a @ref MeshPrimitive::Triangles mesh with |
||||||
|
@ref MeshIndexType::UnsignedInt indices, all input attributes preserved in |
||||||
|
their original format, and additionally with |
||||||
|
@ref Shaders::LineGL::PreviousPosition and @ref Shaders::LineGL::NextPosition |
||||||
|
attributes added in the same format as the input |
||||||
|
@ref Trade::MeshAttribute::Position, and the @ref Shaders::LineGL::Annotation |
||||||
|
attribute as @ref VertexFormat::UnsignedInt, according to the |
||||||
|
@ref Shaders-LineGL-mesh-representation documentation of the shader. |
||||||
|
|
||||||
|
Each line segment in the input vertices is converted to a quad, with first two |
||||||
|
vertices inheriting vertex data from the first point of the segment and second |
||||||
|
two vertices inheriting data from the second point of the segment. If the input |
||||||
|
mesh is indexed, it's deindexed first. Neighbor information from a |
||||||
|
@ref MeshPrimitive::LineStrip or @ref MeshPrimitive::LineLoop mesh is used to |
||||||
|
form a single contiguous strip or a loop, @ref MeshPrimitive::Lines is treated |
||||||
|
as loose segments. |
||||||
|
|
||||||
|
For compatibility with shaders other than @ref Shaders::LineGL, the output mesh |
||||||
|
can be also interpreted as indexed @ref MeshPrimitive::Lines --- out of every |
||||||
|
six indices forming a quad, two will form a line segment between the two |
||||||
|
original points, and the remaining four collapse into two degenerate line |
||||||
|
segments. |
||||||
|
|
||||||
|
Expects that the mesh contains at least a @ref Trade::MeshAttribute::Position |
||||||
|
and is a line @relativeref{Magnum,MeshPrimitive}. |
||||||
|
|
||||||
|
@note This function is available only if Magnum is compiled with |
||||||
|
@ref MAGNUM_TARGET_GL enabled (done by default). See @ref building-features |
||||||
|
for more information. |
||||||
|
|
||||||
|
@requires_gles30 @ref Shaders::LineGL requires integer support in shaders which |
||||||
|
is not available in OpenGL ES 2.0, thus neither this function is defined |
||||||
|
in OpenGL ES 2.0 builds. |
||||||
|
@requires_webgl20 @ref Shaders::LineGL requires integer support in shaders which |
||||||
|
is not available in WebGL 1.0, thus neither this function is defined in |
||||||
|
WebGL 1.0 builds. |
||||||
|
*/ |
||||||
|
MAGNUM_MESHTOOLS_EXPORT GL::Mesh compileLines(const Trade::MeshData& lineMesh); |
||||||
|
|
||||||
|
}} |
||||||
|
#else |
||||||
|
#error this header is available only in the desktop OpenGL, OpenGL ES 3.0+ and WebGL 2.0 builds |
||||||
|
#endif |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,287 @@ |
|||||||
|
#ifndef Magnum_MeshTools_Implementation_GenerateLines_h |
||||||
|
#define Magnum_MeshTools_Implementation_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š <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 <Corrade/Containers/GrowableArray.h> |
||||||
|
#include <Corrade/Containers/Optional.h> |
||||||
|
#include <Corrade/Containers/StridedArrayView.h> |
||||||
|
#include <Corrade/Utility/Algorithms.h> |
||||||
|
|
||||||
|
#include "Magnum/MeshTools/Duplicate.h" |
||||||
|
#include "Magnum/MeshTools/GenerateIndices.h" |
||||||
|
#include "Magnum/Trade/MeshData.h" |
||||||
|
|
||||||
|
/* This header is included only privately and doesn't introduce any linker
|
||||||
|
dependency (taking just the LineVertexAnnotations enum), thus it's |
||||||
|
completely safe to not link to the Shaders library */ |
||||||
|
#include "Magnum/Shaders/Line.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { namespace Implementation { namespace { |
||||||
|
|
||||||
|
/* This code is used internally by compileLines() and returns a MeshData
|
||||||
|
instance in order to be testable. The intention is to eventually make this |
||||||
|
API public and the custom attributes builtin in order to make it possible to |
||||||
|
(for example) produce glTF files that are already directly renderable as |
||||||
|
wide line meshes. */ |
||||||
|
|
||||||
|
constexpr Trade::MeshAttribute MeshAttributePreviousPosition = Trade::meshAttributeCustom(32765); |
||||||
|
constexpr Trade::MeshAttribute MeshAttributeNextPosition = Trade::meshAttributeCustom(32766); |
||||||
|
constexpr Trade::MeshAttribute MeshAttributeAnnotation = Trade::meshAttributeCustom(32767); |
||||||
|
|
||||||
|
Trade::MeshData generateLines(const Trade::MeshData& lineMesh) { |
||||||
|
CORRADE_ASSERT(lineMesh.primitive() == MeshPrimitive::Lines || |
||||||
|
lineMesh.primitive() == MeshPrimitive::LineStrip || |
||||||
|
lineMesh.primitive() == MeshPrimitive::LineLoop, |
||||||
|
"Trade::MeshTools::compileLines(): expected a line primitive, got" << lineMesh.primitive(), (Trade::MeshData{MeshPrimitive::Triangles, 0})); |
||||||
|
|
||||||
|
/** @todo this will assert if the count in MeshData is wrong, check here
|
||||||
|
already */ |
||||||
|
const UnsignedInt quadCount = primitiveCount(lineMesh.primitive(), lineMesh.isIndexed() ? lineMesh.indexCount() : lineMesh.vertexCount()); |
||||||
|
|
||||||
|
/** @todo combine this allocation with pointDuplicationIndices below, and
|
||||||
|
then reuse for the final index buffer */ |
||||||
|
Containers::Array<UnsignedInt> originalIndices; |
||||||
|
if(lineMesh.primitive() == MeshPrimitive::Lines) { |
||||||
|
if(lineMesh.isIndexed()) |
||||||
|
originalIndices = lineMesh.indicesAsArray(); |
||||||
|
} else { |
||||||
|
if(lineMesh.primitive() == MeshPrimitive::LineStrip) { |
||||||
|
if(lineMesh.isIndexed()) |
||||||
|
originalIndices = generateLineStripIndices(lineMesh.indices()); |
||||||
|
else |
||||||
|
originalIndices = generateLineStripIndices(lineMesh.vertexCount()); |
||||||
|
} else if(lineMesh.primitive() == MeshPrimitive::LineLoop) { |
||||||
|
if(lineMesh.isIndexed()) |
||||||
|
originalIndices = generateLineLoopIndices(lineMesh.indices()); |
||||||
|
else |
||||||
|
originalIndices = generateLineLoopIndices(lineMesh.vertexCount()); |
||||||
|
} else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */ |
||||||
|
} |
||||||
|
|
||||||
|
/* Create a source index array for duplicate() by combining indices of a
|
||||||
|
form 00112233 (i.e., duplicating every point twice) with the original |
||||||
|
mesh indices (if there are any) */ |
||||||
|
Containers::Array<UnsignedInt> pointDuplicationIndices{NoInit, quadCount*4}; |
||||||
|
for(UnsignedInt i = 0; i != quadCount; ++i) { |
||||||
|
pointDuplicationIndices[i*4 + 0] = |
||||||
|
pointDuplicationIndices[i*4 + 1] = i*2 + 0; |
||||||
|
pointDuplicationIndices[i*4 + 2] = |
||||||
|
pointDuplicationIndices[i*4 + 3] = i*2 + 1; |
||||||
|
} |
||||||
|
if(originalIndices) |
||||||
|
duplicateInto(pointDuplicationIndices, Containers::arrayCast<2, char>(stridedArrayView(originalIndices)), Containers::arrayCast<2, char>(stridedArrayView(pointDuplicationIndices))); |
||||||
|
|
||||||
|
/* Position is required, everything else is optional */ |
||||||
|
const Containers::Optional<UnsignedInt> positionAttributeId = lineMesh.findAttributeId(Trade::MeshAttribute::Position); |
||||||
|
CORRADE_ASSERT(positionAttributeId, |
||||||
|
"Trade::MeshTools::compileLines(): the mesh has no positions", (Trade::MeshData{MeshPrimitive::Triangles, 0})); |
||||||
|
|
||||||
|
/* Duplicate the input mesh to have each input line segment turned into
|
||||||
|
four vertices for a quad. Allocate space for the additional attributes |
||||||
|
as well. */ |
||||||
|
Trade::MeshData mesh = duplicate(Trade::MeshData{MeshPrimitive::Triangles, {}, pointDuplicationIndices, Trade::MeshIndexData{pointDuplicationIndices}, {}, lineMesh.vertexData(), Trade::meshAttributeDataNonOwningArray(lineMesh.attributeData()), lineMesh.vertexCount()}, { |
||||||
|
Trade::MeshAttributeData{MeshAttributePreviousPosition, |
||||||
|
lineMesh.attributeFormat(*positionAttributeId), nullptr}, |
||||||
|
Trade::MeshAttributeData{MeshAttributeNextPosition, |
||||||
|
lineMesh.attributeFormat(*positionAttributeId), nullptr}, |
||||||
|
/** @todo use a 8-bit type and make the attribute non-interleaved to
|
||||||
|
save space? */ |
||||||
|
Trade::MeshAttributeData{MeshAttributeAnnotation, |
||||||
|
VertexFormat::UnsignedInt, nullptr}, |
||||||
|
}); |
||||||
|
|
||||||
|
CORRADE_INTERNAL_ASSERT(mesh.attributeName(*positionAttributeId) == Trade::MeshAttribute::Position); |
||||||
|
|
||||||
|
/* Fill in previous/next positions, if we have any vertices at all */ |
||||||
|
if(quadCount) { |
||||||
|
/* Form 3D arrays where the second dimension is 2 elements */ |
||||||
|
const Containers::StridedArrayView2D<const char> positions = mesh.attribute(Trade::MeshAttribute::Position); |
||||||
|
const Containers::StridedArrayView3D<const char> positions3{mesh.vertexData(), static_cast<const char*>(positions.data()), |
||||||
|
{positions.size()[0]/2, 2, positions.size()[1]}, |
||||||
|
{positions.stride()[0]*2, positions.stride()[0], positions.stride()[1]}}; |
||||||
|
|
||||||
|
const Containers::StridedArrayView2D<char> previousPositions = mesh.mutableAttribute(MeshAttributePreviousPosition); |
||||||
|
const Containers::StridedArrayView3D<char> previousPositions3{mesh.mutableVertexData(), static_cast<char*>(previousPositions.data()), |
||||||
|
{previousPositions.size()[0]/2, 2, previousPositions.size()[1]}, |
||||||
|
{previousPositions.stride()[0]*2, previousPositions.stride()[0], previousPositions.stride()[1]}}; |
||||||
|
|
||||||
|
const Containers::StridedArrayView2D<char> nextPositions = mesh.mutableAttribute(MeshAttributeNextPosition); |
||||||
|
const Containers::StridedArrayView3D<char> nextPositions3{mesh.mutableVertexData(), static_cast<char*>(nextPositions.data()), |
||||||
|
{nextPositions.size()[0]/2, 2, nextPositions.size()[1]}, |
||||||
|
{nextPositions.stride()[0]*2, nextPositions.stride()[0], nextPositions.stride()[1]}}; |
||||||
|
|
||||||
|
/* Zero-init all previous/next positions for predictable output */ |
||||||
|
/** @todo have NoInit / ValueInit overload of duplicate(), interleave()
|
||||||
|
and interleavedLayout() instea, significantly faster than doing it |
||||||
|
manually on sparse views after */ |
||||||
|
{ |
||||||
|
constexpr const char Zero[sizeof(Float)*3]{}; |
||||||
|
Containers::StridedArrayView2D<const char> zeros{Zero, positions.size(), {0, 1}}; |
||||||
|
Utility::copy(zeros, previousPositions); |
||||||
|
Utility::copy(zeros, nextPositions); |
||||||
|
} |
||||||
|
|
||||||
|
/* Given AABBCCDDEEFF, we want to copy Position from AA__CC__EE__ to
|
||||||
|
__BB__DD__FF's PreviousPosition, and Position from __BB__DD__FF to |
||||||
|
AA__CC__EE__'s NextPosition. Strip one group of 2 from either prefix |
||||||
|
or suffix, pick every 2nd in the first dimension, and copy. */ |
||||||
|
Utility::copy( |
||||||
|
positions3.exceptSuffix(1).every(2), |
||||||
|
previousPositions3.exceptPrefix(1).every(2)); |
||||||
|
Utility::copy( |
||||||
|
positions3.exceptPrefix(1).every(2), |
||||||
|
nextPositions3.exceptSuffix(1).every(2)); |
||||||
|
|
||||||
|
/* Fill in previous/next neighbor positions if this is a line loop /
|
||||||
|
line strip and there's more than one quad. Given AABBCCDDEEFF, want |
||||||
|
to copy Position from AA__CC______ to ____CC__EE__'s |
||||||
|
PreviousPosition, and Position from ______DD__FF to __BB__DD____'s |
||||||
|
NextPosition, and in case of loops also Position from ________EE__ |
||||||
|
to AA__________'s PreviousPosition and Position from __BB________ to |
||||||
|
__________FF's NextPosition. */ |
||||||
|
/** @todo put together with the annotations once it's generalized to
|
||||||
|
the index buffer */ |
||||||
|
if((lineMesh.primitive() == MeshPrimitive::LineStrip || |
||||||
|
lineMesh.primitive() == MeshPrimitive::LineLoop) && quadCount > 1) { |
||||||
|
Utility::copy( |
||||||
|
positions3.exceptSuffix(2).every(2), |
||||||
|
previousPositions3.exceptPrefix(2).every(2)); |
||||||
|
Utility::copy( |
||||||
|
positions3.exceptPrefix(3).every(2), |
||||||
|
nextPositions3.exceptPrefix(1).exceptSuffix(2).every(2)); |
||||||
|
} |
||||||
|
if(lineMesh.primitive() == MeshPrimitive::LineLoop) { |
||||||
|
Utility::copy(positions3[positions3.size()[0] - 2], previousPositions3.front()); |
||||||
|
Utility::copy(positions3[1], nextPositions3.back()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* Fill in point annotation */ |
||||||
|
const Containers::StridedArrayView1D<Shaders::LineVertexAnnotations> annotations = Containers::arrayCast<Shaders::LineVertexAnnotations>(mesh.mutableAttribute<UnsignedInt>(MeshAttributeAnnotation)); |
||||||
|
for(UnsignedInt i = 0; i != quadCount; ++i) { |
||||||
|
annotations[i*4 + 0] = Shaders::LineVertexAnnotation::Up|Shaders::LineVertexAnnotation::Begin; |
||||||
|
annotations[i*4 + 1] = Shaders::LineVertexAnnotation::Begin; |
||||||
|
annotations[i*4 + 2] = Shaders::LineVertexAnnotation::Up; |
||||||
|
annotations[i*4 + 3] = {}; |
||||||
|
} |
||||||
|
|
||||||
|
/* A line strip has joins everywhere except the first and last two
|
||||||
|
vertices; line loop joins also the first and last two vertices if it's |
||||||
|
non-empty */ |
||||||
|
/** @todo add a flag to use the original index buffer somehow to figure out
|
||||||
|
abitrary joins and loops */ |
||||||
|
if(lineMesh.primitive() == MeshPrimitive::LineStrip || |
||||||
|
lineMesh.primitive() == MeshPrimitive::LineLoop) { |
||||||
|
for(UnsignedInt i = 0; i != quadCount; ++i) { |
||||||
|
annotations[i*4 + 0] |= Shaders::LineVertexAnnotation::Join; |
||||||
|
annotations[i*4 + 1] |= Shaders::LineVertexAnnotation::Join; |
||||||
|
annotations[i*4 + 2] |= Shaders::LineVertexAnnotation::Join; |
||||||
|
annotations[i*4 + 3] |= Shaders::LineVertexAnnotation::Join; |
||||||
|
} |
||||||
|
} |
||||||
|
if(quadCount && lineMesh.primitive() == MeshPrimitive::LineStrip) { |
||||||
|
annotations[0] &= ~Shaders::LineVertexAnnotation::Join; |
||||||
|
annotations[1] &= ~Shaders::LineVertexAnnotation::Join; |
||||||
|
annotations[quadCount*4 - 2] &= ~Shaders::LineVertexAnnotation::Join; |
||||||
|
annotations[quadCount*4 - 1] &= ~Shaders::LineVertexAnnotation::Join; |
||||||
|
} |
||||||
|
|
||||||
|
/* Create an index buffer */ |
||||||
|
Containers::Array<UnsignedInt> indexData; |
||||||
|
arrayReserve(indexData, quadCount*6); |
||||||
|
for(UnsignedInt i = 0; i != quadCount; ++i) { |
||||||
|
/* The order is chosen in a way that makes it possible to interpret
|
||||||
|
the 6 indices as 3 lines instead of 2 triangles, and additionally |
||||||
|
those forming only one line, with the other two degenerating to an |
||||||
|
invisible point to avoid overlaps that would break blending. |
||||||
|
|
||||||
|
0---2 2 |
||||||
|
| / /| 0---2 |
||||||
|
| / / | |
||||||
|
|/ / | 11 32 |
||||||
|
1 1---3 */ |
||||||
|
arrayAppend(indexData, { |
||||||
|
i*4 + 2, |
||||||
|
i*4 + 0, |
||||||
|
i*4 + 1, |
||||||
|
|
||||||
|
i*4 + 1, |
||||||
|
i*4 + 3, |
||||||
|
i*4 + 2 |
||||||
|
}); |
||||||
|
|
||||||
|
/* Add also indices for the bevel in both orientations (one will always
|
||||||
|
degenerate). For the line fallback these will all degenerate. |
||||||
|
|
||||||
|
2 2 2---4 4 4-- |
||||||
|
/| | / /| | 23 44 |
||||||
|
/ | | / / | | / |
||||||
|
| |/ / | |/ 35 |
||||||
|
--3 3 3---5 5 5 */ |
||||||
|
if(i + 1 != quadCount && annotations[i*4 + 3] & Shaders::LineVertexAnnotation::Join) { |
||||||
|
arrayAppend(indexData, { |
||||||
|
i*4 + 2, |
||||||
|
i*4 + 3, |
||||||
|
i*4 + 4, |
||||||
|
|
||||||
|
i*4 + 4, |
||||||
|
i*4 + 3, |
||||||
|
i*4 + 5, |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* And finally also bevel indices between the last and first segment in
|
||||||
|
case of loops, if the loop isn't empty |
||||||
|
|
||||||
|
-2 -2---0 0 0- |
||||||
|
/| | / /| | |
||||||
|
| | / / | | |
||||||
|
| |/ / | |/ |
||||||
|
-1 -1 -1--1 1 */ |
||||||
|
if(quadCount && annotations[0] & Shaders::LineVertexAnnotation::Join) { |
||||||
|
CORRADE_INTERNAL_ASSERT(annotations[quadCount*4 - 1] & Shaders::LineVertexAnnotation::Join); |
||||||
|
|
||||||
|
arrayAppend(indexData, { |
||||||
|
quadCount*4 - 2, |
||||||
|
quadCount*4 - 1, |
||||||
|
0u, |
||||||
|
|
||||||
|
0u, |
||||||
|
quadCount*4 - 1, |
||||||
|
1u |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
Trade::MeshIndexData indices{indexData}; |
||||||
|
return Trade::MeshData{mesh.primitive(), |
||||||
|
indexData ? Containers::arrayAllocatorCast<char>(std::move(indexData)) : Containers::Array<char>{}, indices, |
||||||
|
mesh.releaseVertexData(), mesh.releaseAttributeData()}; |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,368 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 <sstream> |
||||||
|
#include <Corrade/Containers/GrowableArray.h> |
||||||
|
#include <Corrade/Containers/String.h> |
||||||
|
#include <Corrade/Containers/StringIterable.h> |
||||||
|
#include <Corrade/PluginManager/Manager.h> |
||||||
|
#include <Corrade/Utility/DebugStl.h> |
||||||
|
#include <Corrade/Utility/Path.h> |
||||||
|
|
||||||
|
#include "Magnum/Image.h" |
||||||
|
#include "Magnum/ImageView.h" |
||||||
|
#include "Magnum/PixelFormat.h" |
||||||
|
#include "Magnum/DebugTools/CompareImage.h" |
||||||
|
#include "Magnum/GL/Framebuffer.h" |
||||||
|
#include "Magnum/GL/Mesh.h" |
||||||
|
#include "Magnum/GL/OpenGLTester.h" |
||||||
|
#include "Magnum/GL/Renderbuffer.h" |
||||||
|
#include "Magnum/GL/RenderbufferFormat.h" |
||||||
|
#include "Magnum/Math/Color.h" |
||||||
|
#include "Magnum/Math/Matrix3.h" |
||||||
|
#include "Magnum/Math/Matrix4.h" |
||||||
|
#include "Magnum/MeshTools/Compile.h" |
||||||
|
#include "Magnum/MeshTools/CompileLines.h" |
||||||
|
#include "Magnum/Shaders/FlatGL.h" |
||||||
|
#include "Magnum/Shaders/Line.h" |
||||||
|
#include "Magnum/Shaders/LineGL.h" |
||||||
|
#include "Magnum/Trade/MeshData.h" |
||||||
|
#include "Magnum/Trade/AbstractImporter.h" |
||||||
|
|
||||||
|
#include "configure.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { namespace Test { namespace { |
||||||
|
|
||||||
|
struct CompileLinesGLTest: GL::OpenGLTester { |
||||||
|
explicit CompileLinesGLTest(); |
||||||
|
|
||||||
|
void renderSetup(); |
||||||
|
void renderTeardown(); |
||||||
|
|
||||||
|
void twoDimensions(); |
||||||
|
void threeDimensions(); |
||||||
|
void linePrimitiveCompatibility(); |
||||||
|
void conflictingAttributes(); |
||||||
|
|
||||||
|
void emptyMesh(); |
||||||
|
|
||||||
|
void notLines(); |
||||||
|
void noAttributes(); |
||||||
|
void noPositionAttribute(); |
||||||
|
|
||||||
|
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"}; |
||||||
|
|
||||||
|
GL::Renderbuffer _color; |
||||||
|
GL::Framebuffer _framebuffer{{{}, {32, 32}}}; |
||||||
|
}; |
||||||
|
|
||||||
|
using namespace Math::Literals; |
||||||
|
|
||||||
|
const struct { |
||||||
|
const char* name; |
||||||
|
bool colors; |
||||||
|
bool flip; |
||||||
|
Shaders::LineJoinStyle joinStyle; |
||||||
|
const char* expected; |
||||||
|
} TwoDimensionsData[]{ |
||||||
|
{"", false, false, Shaders::LineJoinStyle::Miter, "miter.tga"}, |
||||||
|
{"bevel", false, false, Shaders::LineJoinStyle::Bevel, "bevel.tga"}, |
||||||
|
{"bevel, flipped", false, true, Shaders::LineJoinStyle::Bevel, "bevel.tga"}, |
||||||
|
{"vertex color", true, false, Shaders::LineJoinStyle::Miter, "vertex-color.tga"}, |
||||||
|
}; |
||||||
|
|
||||||
|
const struct { |
||||||
|
const char* name; |
||||||
|
Trade::MeshAttribute attribute; |
||||||
|
VertexFormat format; |
||||||
|
const char* expected; |
||||||
|
} ConflictingAttributesData[]{ |
||||||
|
{"texture coordinates", |
||||||
|
Trade::MeshAttribute::TextureCoordinates, VertexFormat::Vector2, |
||||||
|
"MeshTools::compileLines(): Trade::MeshAttribute::TextureCoordinates conflicts with line annotation attribute, ignoring\n"}, |
||||||
|
{"tangent", |
||||||
|
Trade::MeshAttribute::Tangent, VertexFormat::Vector3, |
||||||
|
"MeshTools::compileLines(): Trade::MeshAttribute::Tangent conflicts with line previous position attribute, ignoring\n"}, |
||||||
|
{"normal", |
||||||
|
Trade::MeshAttribute::Normal, VertexFormat::Vector3, |
||||||
|
"MeshTools::compileLines(): Trade::MeshAttribute::Normal conflicts with line next position attribute, ignoring\n"}, |
||||||
|
}; |
||||||
|
|
||||||
|
CompileLinesGLTest::CompileLinesGLTest() { |
||||||
|
addInstancedTests({&CompileLinesGLTest::twoDimensions}, |
||||||
|
Containers::arraySize(TwoDimensionsData), |
||||||
|
&CompileLinesGLTest::renderSetup, |
||||||
|
&CompileLinesGLTest::renderTeardown); |
||||||
|
|
||||||
|
addTests({&CompileLinesGLTest::threeDimensions, |
||||||
|
&CompileLinesGLTest::linePrimitiveCompatibility}, |
||||||
|
&CompileLinesGLTest::renderSetup, |
||||||
|
&CompileLinesGLTest::renderTeardown); |
||||||
|
|
||||||
|
addInstancedTests({&CompileLinesGLTest::conflictingAttributes}, |
||||||
|
Containers::arraySize(ConflictingAttributesData), |
||||||
|
&CompileLinesGLTest::renderSetup, |
||||||
|
&CompileLinesGLTest::renderTeardown); |
||||||
|
|
||||||
|
addTests({&CompileLinesGLTest::emptyMesh, |
||||||
|
|
||||||
|
&CompileLinesGLTest::notLines, |
||||||
|
&CompileLinesGLTest::noAttributes, |
||||||
|
&CompileLinesGLTest::noPositionAttribute}); |
||||||
|
|
||||||
|
/* Load the plugins directly from the build tree. Otherwise they're either
|
||||||
|
static and already loaded or not present in the build tree */ |
||||||
|
#ifdef ANYIMAGEIMPORTER_PLUGIN_FILENAME |
||||||
|
CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(ANYIMAGEIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||||
|
#endif |
||||||
|
#ifdef TGAIMPORTER_PLUGIN_FILENAME |
||||||
|
CORRADE_INTERNAL_ASSERT_OUTPUT(_manager.load(TGAIMPORTER_PLUGIN_FILENAME) & PluginManager::LoadState::Loaded); |
||||||
|
#endif |
||||||
|
|
||||||
|
_color.setStorage(GL::RenderbufferFormat::RGBA8, {32, 32}); |
||||||
|
_framebuffer |
||||||
|
.attachRenderbuffer(GL::Framebuffer::ColorAttachment{0}, _color) |
||||||
|
.bind(); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::renderSetup() { |
||||||
|
GL::Renderer::enable(GL::Renderer::Feature::FaceCulling); |
||||||
|
_framebuffer.clear(GL::FramebufferClear::Color); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::renderTeardown() {} |
||||||
|
|
||||||
|
void CompileLinesGLTest::twoDimensions() { |
||||||
|
auto&& data = TwoDimensionsData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.name); |
||||||
|
|
||||||
|
struct Vertex { |
||||||
|
Vector2 position; |
||||||
|
Color3 color; |
||||||
|
} vertexData[]{ |
||||||
|
{{-1.0f, -1.0f}, 0xdcdcdc_rgbf}, |
||||||
|
{{+1.0f, -1.0f}, 0xdcdcdc_rgbf}, |
||||||
|
{{+1.0f, +1.0f}, 0x2f83cc_rgbf}, |
||||||
|
{{-1.0f, +1.0f}, 0x2f83cc_rgbf}, |
||||||
|
}; |
||||||
|
auto vertices = Containers::stridedArrayView(vertexData); |
||||||
|
|
||||||
|
Containers::Array<Trade::MeshAttributeData> attributes; |
||||||
|
arrayAppend(attributes, InPlaceInit, Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)); |
||||||
|
if(data.colors) |
||||||
|
arrayAppend(attributes, InPlaceInit, Trade::MeshAttribute::Color, vertices.slice(&Vertex::color)); |
||||||
|
|
||||||
|
GL::Mesh mesh = compileLines(Trade::MeshData{MeshPrimitive::LineLoop, {}, vertexData, std::move(attributes)}); |
||||||
|
|
||||||
|
Shaders::LineGL2D shader{Shaders::LineGL2D::Configuration{} |
||||||
|
.setFlags(data.colors ? Shaders::LineGL2D::Flag::VertexColor : Shaders::LineGL2D::Flags{}) |
||||||
|
.setJoinStyle(data.joinStyle)}; |
||||||
|
shader |
||||||
|
.setViewportSize({32, 32}) |
||||||
|
.setWidth(9) |
||||||
|
.setTransformationProjectionMatrix(Matrix3::scaling(Vector2{21.0f/32.0f}*Vector2::yScale(data.flip ? -1.0f : 1.0f))) |
||||||
|
.draw(mesh); |
||||||
|
|
||||||
|
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||||
|
CORRADE_COMPARE_WITH( |
||||||
|
_framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), |
||||||
|
Utility::Path::join({MESHTOOLS_TEST_DIR, "CompileLinesTestFiles", data.expected}), |
||||||
|
(DebugTools::CompareImageToFile{_manager})); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::threeDimensions() { |
||||||
|
/* Same as the initial case in twoDimensions(), just in 3D and with a
|
||||||
|
varying Z (which shouldn't have any effect as it's rendering in an |
||||||
|
orthographic projection) */ |
||||||
|
|
||||||
|
Vector3 positions[]{ |
||||||
|
{-1.0f, -1.0f, +0.5f}, |
||||||
|
{+1.0f, -1.0f, +0.5f}, |
||||||
|
{+1.0f, +1.0f, -0.5f}, |
||||||
|
{-1.0f, +1.0f, -0.5f}, |
||||||
|
}; |
||||||
|
|
||||||
|
GL::Mesh mesh = compileLines(Trade::MeshData{MeshPrimitive::LineLoop, {}, positions, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::stridedArrayView(positions)} |
||||||
|
}}); |
||||||
|
|
||||||
|
Shaders::LineGL3D{} |
||||||
|
.setViewportSize({32, 32}) |
||||||
|
.setWidth(9) |
||||||
|
.setTransformationProjectionMatrix(Matrix4::scaling({Vector2{21.0f/32.0f}, 1.0f})) |
||||||
|
.draw(mesh); |
||||||
|
|
||||||
|
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||||
|
CORRADE_COMPARE_WITH( |
||||||
|
_framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), |
||||||
|
Utility::Path::join(MESHTOOLS_TEST_DIR, "CompileLinesTestFiles/miter.tga"), |
||||||
|
(DebugTools::CompareImageToFile{_manager})); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::linePrimitiveCompatibility() { |
||||||
|
struct Vertex { |
||||||
|
Vector2 position; |
||||||
|
Color3 color; |
||||||
|
} vertexData[]{ |
||||||
|
{{-1.0f, -1.0f}, 0xdcdcdc_rgbf}, |
||||||
|
{{+1.0f, -1.0f}, 0xdcdcdc_rgbf}, |
||||||
|
{{+1.0f, +1.0f}, 0x2f83cc_rgbf}, |
||||||
|
{{-1.0f, +1.0f}, 0x2f83cc_rgbf}, |
||||||
|
}; |
||||||
|
auto vertices = Containers::stridedArrayView(vertexData); |
||||||
|
|
||||||
|
/* Enabling blending and a half-transparent color to catch accidental
|
||||||
|
overlaps where they shouldn't be */ |
||||||
|
GL::Renderer::enable(GL::Renderer::Feature::Blending); |
||||||
|
GL::Renderer::setBlendFunction( |
||||||
|
GL::Renderer::BlendFunction::One, |
||||||
|
GL::Renderer::BlendFunction::OneMinusSourceAlpha); |
||||||
|
|
||||||
|
Trade::MeshData lineMeshData{MeshPrimitive::LineLoop, {}, vertexData, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Color, vertices.slice(&Vertex::color)}, |
||||||
|
}}; |
||||||
|
|
||||||
|
Shaders::FlatGL2D shader{Shaders::FlatGL2D::Configuration{} |
||||||
|
.setFlags(Shaders::FlatGL2D::Flag::VertexColor)}; |
||||||
|
shader |
||||||
|
.setTransformationProjectionMatrix(Matrix3::scaling(Vector2{21.0f/32.0f})) |
||||||
|
.setColor(0x80808080_rgbaf); |
||||||
|
|
||||||
|
/* Render the original */ |
||||||
|
shader.draw(compile(lineMeshData)); |
||||||
|
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||||
|
CORRADE_COMPARE_WITH( |
||||||
|
_framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), |
||||||
|
Utility::Path::join(MESHTOOLS_TEST_DIR, "CompileLinesTestFiles/line-primitive.tga"), |
||||||
|
(DebugTools::CompareImageToFile{_manager})); |
||||||
|
|
||||||
|
_framebuffer.clear(GL::FramebufferClear::Color); |
||||||
|
|
||||||
|
/* Render the line mesh with the primitive set back to lines. The index
|
||||||
|
buffer layout should be compatible with it, and produce the same |
||||||
|
result. */ |
||||||
|
shader.draw(compileLines(lineMeshData).setPrimitive(MeshPrimitive::Lines)); |
||||||
|
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||||
|
CORRADE_COMPARE_WITH( |
||||||
|
_framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), |
||||||
|
Utility::Path::join(MESHTOOLS_TEST_DIR, "CompileLinesTestFiles/line-primitive.tga"), |
||||||
|
(DebugTools::CompareImageToFile{_manager})); |
||||||
|
|
||||||
|
GL::Renderer::disable(GL::Renderer::Feature::Blending); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::conflictingAttributes() { |
||||||
|
auto&& data = ConflictingAttributesData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.name); |
||||||
|
|
||||||
|
/* Same as the initial case in twoDimensions(), should just warn but
|
||||||
|
produce correct result */ |
||||||
|
|
||||||
|
struct Vertex { |
||||||
|
Vector3 position; |
||||||
|
Vector3 extra; |
||||||
|
} vertexData[]{ |
||||||
|
{{-1.0f, -1.0f, +0.5f}, {}}, |
||||||
|
{{+1.0f, -1.0f, +0.5f}, {}}, |
||||||
|
{{+1.0f, +1.0f, -0.5f}, {}}, |
||||||
|
{{-1.0f, +1.0f, -0.5f}, {}}, |
||||||
|
}; |
||||||
|
auto vertices = Containers::stridedArrayView(vertexData); |
||||||
|
|
||||||
|
Trade::MeshData lineMesh{MeshPrimitive::LineLoop, {}, vertexData, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||||
|
Trade::MeshAttributeData{data.attribute, data.format, vertices.slice(&Vertex::extra)}, |
||||||
|
}}; |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
GL::Mesh mesh{NoCreate}; |
||||||
|
{ |
||||||
|
Warning redirectWarning{&out}; |
||||||
|
mesh = compileLines(lineMesh); |
||||||
|
} |
||||||
|
|
||||||
|
Shaders::LineGL3D{} |
||||||
|
.setViewportSize({32, 32}) |
||||||
|
.setWidth(9) |
||||||
|
.setTransformationProjectionMatrix(Matrix4::scaling({Vector2{21.0f/32.0f}, 1.0f})) |
||||||
|
.draw(mesh); |
||||||
|
|
||||||
|
MAGNUM_VERIFY_NO_GL_ERROR(); |
||||||
|
CORRADE_COMPARE_WITH( |
||||||
|
_framebuffer.read({{}, {32, 32}}, {PixelFormat::RGBA8Unorm}), |
||||||
|
Utility::Path::join(MESHTOOLS_TEST_DIR, "CompileLinesTestFiles/miter.tga"), |
||||||
|
(DebugTools::CompareImageToFile{_manager})); |
||||||
|
CORRADE_COMPARE(out.str(), data.expected); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::emptyMesh() { |
||||||
|
GL::Mesh mesh = compileLines(Trade::MeshData{MeshPrimitive::LineLoop, {}, nullptr, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector2, nullptr} |
||||||
|
}}); |
||||||
|
|
||||||
|
CORRADE_COMPARE(mesh.primitive(), GL::MeshPrimitive::Triangles); |
||||||
|
CORRADE_VERIFY(mesh.isIndexed()); |
||||||
|
CORRADE_COMPARE(mesh.count(), 0); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::notLines() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
Vector3 positions[3]{}; |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
compileLines(Trade::MeshData{MeshPrimitive::TriangleFan, {}, positions, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::stridedArrayView(positions)} |
||||||
|
}}); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::MeshTools::compileLines(): expected a line primitive, got MeshPrimitive::TriangleFan\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::noAttributes() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
compileLines(Trade::MeshData{MeshPrimitive::Lines, 12}); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::MeshTools::compileLines(): the mesh has no positions\n"); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesGLTest::noPositionAttribute() { |
||||||
|
CORRADE_SKIP_IF_NO_ASSERT(); |
||||||
|
|
||||||
|
Vector3 colors[2]{}; |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
compileLines(Trade::MeshData{MeshPrimitive::Lines, {}, colors, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Color, Containers::stridedArrayView(colors)} |
||||||
|
}}); |
||||||
|
CORRADE_COMPARE(out.str(), "Trade::MeshTools::compileLines(): the mesh has no positions\n"); |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CompileLinesGLTest) |
||||||
@ -0,0 +1,627 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
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 <sstream> |
||||||
|
#include <Corrade/TestSuite/Tester.h> |
||||||
|
#include <Corrade/TestSuite/Compare/Container.h> |
||||||
|
|
||||||
|
#include "Magnum/Math/PackingBatch.h" |
||||||
|
#include "Magnum/MeshTools/Implementation/GenerateLines.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace MeshTools { namespace Test { namespace { |
||||||
|
|
||||||
|
struct CompileLinesTest: TestSuite::Tester { |
||||||
|
explicit CompileLinesTest(); |
||||||
|
|
||||||
|
template<class T> void oneLoop(); |
||||||
|
|
||||||
|
void extraAttributes(); |
||||||
|
void zeroVertices(); |
||||||
|
void twoVerticesStrip(); |
||||||
|
void twoVerticesLoop(); |
||||||
|
/* Non-line primitives and absence of position attribute tested in
|
||||||
|
CompileLinesGLTest, to verify it's not accessed earlier than the |
||||||
|
assertion */ |
||||||
|
}; |
||||||
|
|
||||||
|
using namespace Math::Literals; |
||||||
|
|
||||||
|
const struct { |
||||||
|
const char* name; |
||||||
|
MeshPrimitive primitive; |
||||||
|
Containers::Array<Vector2> positions; |
||||||
|
Containers::Array<UnsignedInt> indices; |
||||||
|
bool expectedJoins; |
||||||
|
bool expectedJoinsFirstLast; |
||||||
|
} OneLoopData[]{ |
||||||
|
{"loose segments", MeshPrimitive::Lines, {InPlaceInit, { |
||||||
|
{-1.0f, -1.0f}, {+1.0f, -1.0f}, |
||||||
|
{+1.0f, -1.0f}, {+1.0f, +1.0f}, |
||||||
|
{+1.0f, +1.0f}, {-1.0f, +1.0f}, |
||||||
|
{-1.0f, +1.0f}, {-1.0f, -1.0f} |
||||||
|
}}, nullptr, false, false}, |
||||||
|
{"loose indexed segments", MeshPrimitive::Lines, {InPlaceInit, { |
||||||
|
{-1.0f, -1.0f}, |
||||||
|
{+1.0f, -1.0f}, |
||||||
|
{+1.0f, +1.0f}, |
||||||
|
{-1.0f, +1.0f}, |
||||||
|
}}, {InPlaceInit, { |
||||||
|
0, 1, 1, 2, 2, 3, 3, 0 |
||||||
|
}}, false, false}, |
||||||
|
/** @todo indexed segments that get connected */ |
||||||
|
{"loop", MeshPrimitive::LineLoop, {InPlaceInit, { |
||||||
|
{-1.0f, -1.0f}, |
||||||
|
{+1.0f, -1.0f}, |
||||||
|
{+1.0f, +1.0f}, |
||||||
|
{-1.0f, +1.0f}, |
||||||
|
}}, nullptr, true, true}, |
||||||
|
{"indexed loop", MeshPrimitive::LineLoop, {InPlaceInit, { |
||||||
|
{-1.0f, -1.0f}, |
||||||
|
{-1.0f, +1.0f}, |
||||||
|
{+1.0f, -1.0f}, |
||||||
|
{+1.0f, +1.0f}, |
||||||
|
}}, {InPlaceInit, { |
||||||
|
0, 2, 3, 1 |
||||||
|
}}, true, true}, |
||||||
|
{"strip", MeshPrimitive::LineStrip, {InPlaceInit, { |
||||||
|
{-1.0f, -1.0f}, |
||||||
|
{+1.0f, -1.0f}, |
||||||
|
{+1.0f, +1.0f}, |
||||||
|
{-1.0f, +1.0f}, |
||||||
|
{-1.0f, -1.0f}, |
||||||
|
}}, nullptr, true, false}, |
||||||
|
{"indexed strip", MeshPrimitive::LineStrip, {InPlaceInit, { |
||||||
|
{-1.0f, -1.0f}, |
||||||
|
{-1.0f, +1.0f}, |
||||||
|
{+1.0f, -1.0f}, |
||||||
|
{+1.0f, +1.0f}, |
||||||
|
}}, {InPlaceInit, { |
||||||
|
0, 2, 3, 1, 0 |
||||||
|
}}, true, false}, |
||||||
|
/** @todo closed (indexed) strip, once arbitrary index buffer looping is supported */ |
||||||
|
}; |
||||||
|
|
||||||
|
CompileLinesTest::CompileLinesTest() { |
||||||
|
addInstancedTests<CompileLinesTest>({ |
||||||
|
&CompileLinesTest::oneLoop<UnsignedInt>, |
||||||
|
&CompileLinesTest::oneLoop<UnsignedShort>, |
||||||
|
&CompileLinesTest::oneLoop<UnsignedByte>}, |
||||||
|
Containers::arraySize(OneLoopData)); |
||||||
|
|
||||||
|
addTests({&CompileLinesTest::extraAttributes, |
||||||
|
&CompileLinesTest::zeroVertices, |
||||||
|
&CompileLinesTest::twoVerticesStrip, |
||||||
|
&CompileLinesTest::twoVerticesLoop}); |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> void CompileLinesTest::oneLoop() { |
||||||
|
auto&& data = OneLoopData[testCaseInstanceId()]; |
||||||
|
setTestCaseTemplateName(Math::TypeTraits<T>::name()); |
||||||
|
setTestCaseDescription(data.name); |
||||||
|
|
||||||
|
Containers::Array<T> indices{NoInit, data.indices.size()}; |
||||||
|
Math::castInto(stridedArrayView(data.indices), stridedArrayView(indices)); |
||||||
|
|
||||||
|
Trade::MeshData lineMesh{data.primitive, |
||||||
|
{}, indices, indices ? Trade::MeshIndexData{indices} : Trade::MeshIndexData{}, |
||||||
|
{}, data.positions, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, stridedArrayView(data.positions)} |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::MeshData mesh = Implementation::generateLines(lineMesh); |
||||||
|
CORRADE_COMPARE(mesh.primitive(), MeshPrimitive::Triangles); |
||||||
|
CORRADE_COMPARE(mesh.attributeCount(), 4); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.isIndexed()); |
||||||
|
CORRADE_COMPARE(mesh.indexType(), MeshIndexType::UnsignedInt); |
||||||
|
if(data.expectedJoins && data.expectedJoinsFirstLast) |
||||||
|
CORRADE_COMPARE_AS(mesh.indices<UnsignedInt>(), Containers::arrayView<UnsignedInt>({ |
||||||
|
2, 0, 1, 1, 3, 2, |
||||||
|
2, 3, 4, 4, 3, 5, /* join */ |
||||||
|
6, 4, 5, 5, 7, 6, |
||||||
|
6, 7, 8, 8, 7, 9, /* join */ |
||||||
|
10, 8, 9, 9, 11, 10, |
||||||
|
10, 11, 12, 12, 11, 13, /* join */ |
||||||
|
14, 12, 13, 13, 15, 14, |
||||||
|
14, 15, 0, 0, 15, 1, /* join */ |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
else if(data.expectedJoins) |
||||||
|
CORRADE_COMPARE_AS(mesh.indices<UnsignedInt>(), Containers::arrayView<UnsignedInt>({ |
||||||
|
2, 0, 1, 1, 3, 2, |
||||||
|
2, 3, 4, 4, 3, 5, /* join */ |
||||||
|
6, 4, 5, 5, 7, 6, |
||||||
|
6, 7, 8, 8, 7, 9, /* join */ |
||||||
|
10, 8, 9, 9, 11, 10, |
||||||
|
10, 11, 12, 12, 11, 13, /* join */ |
||||||
|
14, 12, 13, 13, 15, 14, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
else |
||||||
|
CORRADE_COMPARE_AS(mesh.indices<UnsignedInt>(), Containers::arrayView<UnsignedInt>({ |
||||||
|
2, 0, 1, 1, 3, 2, |
||||||
|
6, 4, 5, 5, 7, 6, |
||||||
|
10, 8, 9, 9, 11, 10, |
||||||
|
14, 12, 13, 13, 15, 14, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Trade::MeshAttribute::Position)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Trade::MeshAttribute::Position), VertexFormat::Vector2); |
||||||
|
Containers::StridedArrayView1D<const Vector2> positions = mesh.attribute<Vector2>(Trade::MeshAttribute::Position); |
||||||
|
CORRADE_COMPARE_AS(positions, Containers::arrayView<Vector2>({ |
||||||
|
{-1.0f, -1.0f}, {-1.0f, -1.0f}, |
||||||
|
{+1.0f, -1.0f}, {+1.0f, -1.0f}, |
||||||
|
{+1.0f, -1.0f}, {+1.0f, -1.0f}, |
||||||
|
{+1.0f, +1.0f}, {+1.0f, +1.0f}, |
||||||
|
{+1.0f, +1.0f}, {+1.0f, +1.0f}, |
||||||
|
{-1.0f, +1.0f}, {-1.0f, +1.0f}, |
||||||
|
{-1.0f, +1.0f}, {-1.0f, +1.0f}, |
||||||
|
{-1.0f, -1.0f}, {-1.0f, -1.0f} |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributeNextPosition)); |
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributeAnnotation)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributePreviousPosition), VertexFormat::Vector2); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeNextPosition), VertexFormat::Vector2); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeAnnotation), VertexFormat::UnsignedInt); |
||||||
|
if(data.expectedJoins && data.expectedJoinsFirstLast) { |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributePreviousPosition), Containers::arrayView<Vector2>({ |
||||||
|
positions[12], positions[12], |
||||||
|
positions[0], positions[0], |
||||||
|
positions[0], positions[0], |
||||||
|
positions[4], positions[4], |
||||||
|
positions[4], positions[4], |
||||||
|
positions[8], positions[8], |
||||||
|
positions[8], positions[8], |
||||||
|
positions[12], positions[12], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributeNextPosition), Containers::arrayView<Vector2>({ |
||||||
|
positions[2], positions[2], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[10], positions[10], |
||||||
|
positions[10], positions[10], |
||||||
|
positions[14], positions[14], |
||||||
|
positions[14], positions[14], |
||||||
|
positions[2], positions[2], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Shaders::LineVertexAnnotations>(mesh.attribute(Implementation::MeshAttributeAnnotation))), Containers::arrayView<Shaders::LineVertexAnnotations>({ |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} else if(data.expectedJoins) { |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributePreviousPosition), Containers::arrayView<Vector2>({ |
||||||
|
{}, {}, |
||||||
|
positions[0], positions[0], |
||||||
|
positions[0], positions[0], |
||||||
|
positions[4], positions[4], |
||||||
|
positions[4], positions[4], |
||||||
|
positions[8], positions[8], |
||||||
|
positions[8], positions[8], |
||||||
|
positions[12], positions[12], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributeNextPosition), Containers::arrayView<Vector2>({ |
||||||
|
positions[2], positions[2], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[10], positions[10], |
||||||
|
positions[10], positions[10], |
||||||
|
positions[14], positions[14], |
||||||
|
positions[14], positions[14], |
||||||
|
{}, {} |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Shaders::LineVertexAnnotations>(mesh.attribute(Implementation::MeshAttributeAnnotation))), Containers::arrayView<Shaders::LineVertexAnnotations>({ |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up, |
||||||
|
{}, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} else { |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributePreviousPosition), Containers::arrayView<Vector2>({ |
||||||
|
{}, {}, |
||||||
|
positions[0], positions[0], |
||||||
|
{}, {}, |
||||||
|
positions[4], positions[4], |
||||||
|
{}, {}, |
||||||
|
positions[8], positions[8], |
||||||
|
{}, {}, |
||||||
|
positions[12], positions[12], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributeNextPosition), Containers::arrayView<Vector2>({ |
||||||
|
positions[2], positions[2], |
||||||
|
{}, {}, |
||||||
|
positions[6], positions[6], |
||||||
|
{}, {}, |
||||||
|
positions[10], positions[10], |
||||||
|
{}, {}, |
||||||
|
positions[14], positions[14], |
||||||
|
{}, {}, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Shaders::LineVertexAnnotations>(mesh.attribute(Implementation::MeshAttributeAnnotation))), Containers::arrayView<Shaders::LineVertexAnnotations>({ |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Up, |
||||||
|
{}, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Up, |
||||||
|
{}, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Up, |
||||||
|
{}, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Up, |
||||||
|
{}, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesTest::extraAttributes() { |
||||||
|
const struct Vertex { |
||||||
|
Color3ub color; |
||||||
|
Vector3b position; |
||||||
|
UnsignedShort objectId; |
||||||
|
} vertexData[]{ |
||||||
|
{0xdcdcdc_rgb, {-1, -1, 0}, 156}, |
||||||
|
{0xdcdcdc_rgb, {+1, -1, 1}, 223}, |
||||||
|
{0x2f83cc_rgb, {+1, +1, 0}, 999}, |
||||||
|
{0x2f83cc_rgb, {-1, +1, 1}, 768} |
||||||
|
}; |
||||||
|
auto vertices = Containers::stridedArrayView(vertexData); |
||||||
|
|
||||||
|
Trade::MeshData lineMesh{MeshPrimitive::LineLoop, |
||||||
|
{}, vertexData, { |
||||||
|
/* Having position not first to catch accidental use of first
|
||||||
|
attribute as position */ |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Color, vertices.slice(&Vertex::color)}, |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, vertices.slice(&Vertex::position)}, |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::ObjectId, vertices.slice(&Vertex::objectId)}, |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::MeshData mesh = Implementation::generateLines(lineMesh); |
||||||
|
CORRADE_COMPARE(mesh.primitive(), MeshPrimitive::Triangles); |
||||||
|
CORRADE_COMPARE(mesh.attributeCount(), 6); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.isIndexed()); |
||||||
|
CORRADE_COMPARE(mesh.indexType(), MeshIndexType::UnsignedInt); |
||||||
|
CORRADE_COMPARE_AS(mesh.indices<UnsignedInt>(), Containers::arrayView<UnsignedInt>({ |
||||||
|
2, 0, 1, 1, 3, 2, |
||||||
|
2, 3, 4, 4, 3, 5, /* join */ |
||||||
|
6, 4, 5, 5, 7, 6, |
||||||
|
6, 7, 8, 8, 7, 9, /* join */ |
||||||
|
10, 8, 9, 9, 11, 10, |
||||||
|
10, 11, 12, 12, 11, 13, /* join */ |
||||||
|
14, 12, 13, 13, 15, 14, |
||||||
|
14, 15, 0, 0, 15, 1, /* join */ |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Trade::MeshAttribute::Position)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Trade::MeshAttribute::Position), VertexFormat::Vector3b); |
||||||
|
Containers::StridedArrayView1D<const Vector3b> positions = mesh.attribute<Vector3b>(Trade::MeshAttribute::Position); |
||||||
|
CORRADE_COMPARE_AS(positions, Containers::arrayView<Vector3b>({ |
||||||
|
{-1, -1, 0}, {-1, -1, 0}, |
||||||
|
{+1, -1, 1}, {+1, -1, 1}, |
||||||
|
{+1, -1, 1}, {+1, -1, 1}, |
||||||
|
{+1, +1, 0}, {+1, +1, 0}, |
||||||
|
{+1, +1, 0}, {+1, +1, 0}, |
||||||
|
{-1, +1, 1}, {-1, +1, 1}, |
||||||
|
{-1, +1, 1}, {-1, +1, 1}, |
||||||
|
{-1, -1, 0}, {-1, -1, 0} |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Trade::MeshAttribute::Color)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Trade::MeshAttribute::Color), VertexFormat::Vector3ubNormalized); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Color3ub>(Trade::MeshAttribute::Color), Containers::arrayView<Color3ub>({ |
||||||
|
0xdcdcdc_rgb, 0xdcdcdc_rgb, |
||||||
|
0xdcdcdc_rgb, 0xdcdcdc_rgb, |
||||||
|
0xdcdcdc_rgb, 0xdcdcdc_rgb, |
||||||
|
0x2f83cc_rgb, 0x2f83cc_rgb, |
||||||
|
0x2f83cc_rgb, 0x2f83cc_rgb, |
||||||
|
0x2f83cc_rgb, 0x2f83cc_rgb, |
||||||
|
0x2f83cc_rgb, 0x2f83cc_rgb, |
||||||
|
0xdcdcdc_rgb, 0xdcdcdc_rgb, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Trade::MeshAttribute::ObjectId)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Trade::MeshAttribute::ObjectId), VertexFormat::UnsignedShort); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<UnsignedShort>(Trade::MeshAttribute::ObjectId), Containers::arrayView<UnsignedShort>({ |
||||||
|
156, 156, |
||||||
|
223, 223, |
||||||
|
223, 223, |
||||||
|
999, 999, |
||||||
|
999, 999, |
||||||
|
768, 768, |
||||||
|
768, 768, |
||||||
|
156, 156, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributeNextPosition)); |
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributeAnnotation)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributePreviousPosition), VertexFormat::Vector3b); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeNextPosition), VertexFormat::Vector3b); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeAnnotation), VertexFormat::UnsignedInt); |
||||||
|
|
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector3b>(Implementation::MeshAttributePreviousPosition), Containers::arrayView<Vector3b>({ |
||||||
|
positions[12], positions[12], |
||||||
|
positions[0], positions[0], |
||||||
|
positions[0], positions[0], |
||||||
|
positions[4], positions[4], |
||||||
|
positions[4], positions[4], |
||||||
|
positions[8], positions[8], |
||||||
|
positions[8], positions[8], |
||||||
|
positions[12], positions[12], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector3b>(Implementation::MeshAttributeNextPosition), Containers::arrayView<Vector3b>({ |
||||||
|
positions[2], positions[2], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[10], positions[10], |
||||||
|
positions[10], positions[10], |
||||||
|
positions[14], positions[14], |
||||||
|
positions[14], positions[14], |
||||||
|
positions[2], positions[2], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Shaders::LineVertexAnnotations>(mesh.attribute(Implementation::MeshAttributeAnnotation))), Containers::arrayView<Shaders::LineVertexAnnotations>({ |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesTest::zeroVertices() { |
||||||
|
Trade::MeshData lineMesh{MeshPrimitive::LineLoop, nullptr, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, VertexFormat::Vector3usNormalized, nullptr} |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::MeshData mesh = Implementation::generateLines(lineMesh); |
||||||
|
CORRADE_COMPARE(mesh.primitive(), MeshPrimitive::Triangles); |
||||||
|
CORRADE_COMPARE(mesh.attributeCount(), 4); |
||||||
|
CORRADE_COMPARE(mesh.vertexCount(), 0); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Trade::MeshAttribute::Position)); |
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributeAnnotation)); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesTest::twoVerticesStrip() { |
||||||
|
Vector2 positionData[]{ |
||||||
|
{-1.0f, 0.0f}, |
||||||
|
{+1.0f, 0.0f} |
||||||
|
}; |
||||||
|
|
||||||
|
Trade::MeshData lineMesh{MeshPrimitive::LineStrip, {}, positionData, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::stridedArrayView(positionData)} |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::MeshData mesh = Implementation::generateLines(lineMesh); |
||||||
|
CORRADE_COMPARE(mesh.primitive(), MeshPrimitive::Triangles); |
||||||
|
CORRADE_COMPARE(mesh.attributeCount(), 4); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.isIndexed()); |
||||||
|
CORRADE_COMPARE(mesh.indexType(), MeshIndexType::UnsignedInt); |
||||||
|
CORRADE_COMPARE_AS(mesh.indices<UnsignedInt>(), Containers::arrayView<UnsignedInt>({ |
||||||
|
2, 0, 1, 1, 3, 2, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Trade::MeshAttribute::Position)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Trade::MeshAttribute::Position), VertexFormat::Vector2); |
||||||
|
Containers::StridedArrayView1D<const Vector2> positions = mesh.attribute<Vector2>(Trade::MeshAttribute::Position); |
||||||
|
CORRADE_COMPARE_AS(positions, Containers::arrayView<Vector2>({ |
||||||
|
{-1.0f, 0.0f}, {-1.0f, 0.0f}, |
||||||
|
{+1.0f, 0.0f}, {+1.0f, 0.0f}, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributePreviousPosition), VertexFormat::Vector2); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributePreviousPosition), Containers::arrayView<Vector2>({ |
||||||
|
{}, {}, |
||||||
|
positions[0], positions[0], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeNextPosition), VertexFormat::Vector2); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributeNextPosition), Containers::arrayView<Vector2>({ |
||||||
|
positions[2], positions[2], |
||||||
|
{}, {}, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributeAnnotation)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeAnnotation), VertexFormat::UnsignedInt); |
||||||
|
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Shaders::LineVertexAnnotations>(mesh.attribute(Implementation::MeshAttributeAnnotation))), Containers::arrayView<Shaders::LineVertexAnnotations>({ |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Begin, |
||||||
|
Shaders::LineVertexAnnotation::Up, |
||||||
|
{}, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
|
||||||
|
void CompileLinesTest::twoVerticesLoop() { |
||||||
|
Vector2 positionData[]{ |
||||||
|
{-1.0f, 0.0f}, |
||||||
|
{+1.0f, 0.0f} |
||||||
|
}; |
||||||
|
|
||||||
|
Trade::MeshData lineMesh{MeshPrimitive::LineLoop, {}, positionData, { |
||||||
|
Trade::MeshAttributeData{Trade::MeshAttribute::Position, Containers::stridedArrayView(positionData)} |
||||||
|
}}; |
||||||
|
|
||||||
|
Trade::MeshData mesh = Implementation::generateLines(lineMesh); |
||||||
|
CORRADE_COMPARE(mesh.primitive(), MeshPrimitive::Triangles); |
||||||
|
CORRADE_COMPARE(mesh.attributeCount(), 4); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.isIndexed()); |
||||||
|
CORRADE_COMPARE(mesh.indexType(), MeshIndexType::UnsignedInt); |
||||||
|
CORRADE_COMPARE_AS(mesh.indices<UnsignedInt>(), Containers::arrayView<UnsignedInt>({ |
||||||
|
2, 0, 1, 1, 3, 2, |
||||||
|
2, 3, 4, 4, 3, 5, /* join */ |
||||||
|
6, 4, 5, 5, 7, 6, |
||||||
|
6, 7, 0, 0, 7, 1, /* join */ |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Trade::MeshAttribute::Position)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Trade::MeshAttribute::Position), VertexFormat::Vector2); |
||||||
|
Containers::StridedArrayView1D<const Vector2> positions = mesh.attribute<Vector2>(Trade::MeshAttribute::Position); |
||||||
|
CORRADE_COMPARE_AS(positions, Containers::arrayView<Vector2>({ |
||||||
|
{-1.0f, 0.0f}, {-1.0f, 0.0f}, |
||||||
|
{+1.0f, 0.0f}, {+1.0f, 0.0f}, |
||||||
|
{+1.0f, 0.0f}, {+1.0f, 0.0f}, |
||||||
|
{-1.0f, 0.0f}, {-1.0f, 0.0f}, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributePreviousPosition), VertexFormat::Vector2); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributePreviousPosition), Containers::arrayView<Vector2>({ |
||||||
|
positions[4], positions[4], |
||||||
|
positions[0], positions[0], |
||||||
|
positions[0], positions[0], |
||||||
|
positions[4], positions[4], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributePreviousPosition)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeNextPosition), VertexFormat::Vector2); |
||||||
|
CORRADE_COMPARE_AS(mesh.attribute<Vector2>(Implementation::MeshAttributeNextPosition), Containers::arrayView<Vector2>({ |
||||||
|
positions[2], positions[2], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[6], positions[6], |
||||||
|
positions[2], positions[2], |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
|
||||||
|
CORRADE_VERIFY(mesh.hasAttribute(Implementation::MeshAttributeAnnotation)); |
||||||
|
CORRADE_COMPARE(mesh.attributeFormat(Implementation::MeshAttributeAnnotation), VertexFormat::UnsignedInt); |
||||||
|
CORRADE_COMPARE_AS((Containers::arrayCast<1, const Shaders::LineVertexAnnotations>(mesh.attribute(Implementation::MeshAttributeAnnotation))), Containers::arrayView<Shaders::LineVertexAnnotations>({ |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Begin| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Up| |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
Shaders::LineVertexAnnotation::Join, |
||||||
|
}), TestSuite::Compare::Container); |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::CompileLinesTest) |
||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue