Browse Source

[wip]

pull/610/head
Vladimír Vondruš 4 years ago
parent
commit
defc3b3ac9
  1. 1
      src/Magnum/MeshTools/Test/CMakeLists.txt
  2. 39
      src/Magnum/MeshTools/Test/GenerateLinesTest.cpp
  3. 31
      src/Magnum/Shaders/Line.frag
  4. 79
      src/Magnum/Shaders/Line.vert
  5. 12
      src/Magnum/Shaders/LineGL.cpp
  6. 31
      src/Magnum/Shaders/LineGL.h
  7. 262
      src/Magnum/Shaders/Test/LineGLTest.cpp
  8. BIN
      src/Magnum/Shaders/Test/LineTestFiles/defaults2D.tga
  9. BIN
      src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse.tga
  10. 8
      src/Magnum/Shaders/generic.glsl

1
src/Magnum/MeshTools/Test/CMakeLists.txt

@ -35,6 +35,7 @@ corrade_add_test(MeshToolsDuplicateTest DuplicateTest.cpp LIBRARIES MagnumMeshTo
corrade_add_test(MeshToolsFilterAttributesTest FilterAttributesTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsFlipNormalsTest FlipNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsGenerateIndicesTest GenerateIndicesTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsGenerateLinesTest GenerateLinesTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsGenerateNormalsTest GenerateNormalsTest.cpp LIBRARIES MagnumMeshToolsTestLib MagnumPrimitives)
corrade_add_test(MeshToolsInterleaveTest InterleaveTest.cpp LIBRARIES MagnumMeshToolsTestLib)
corrade_add_test(MeshToolsReferenceTest ReferenceTest.cpp LIBRARIES MagnumMeshToolsTestLib MagnumPrimitives)

39
src/Magnum/MeshTools/Test/GenerateLinesTest.cpp

@ -0,0 +1,39 @@
/*
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/TestSuite/Tester.h>
namespace Magnum { namespace MeshTools { namespace Test { namespace {
struct GenerateLinesTest: TestSuite::Tester {
explicit GenerateLinesTest();
};
GenerateLinesTest::GenerateLinesTest() {
}
}}}}
CORRADE_TEST_MAIN(Magnum::MeshTools::Test::GenerateLinesTest)

31
src/Magnum/Shaders/Line.frag

@ -133,6 +133,7 @@ layout(std140
in highp vec2 centerDistanceSigned;
in highp float halfSegmentLength;
in lowp float hasCap;
#ifdef VERTEX_COLOR
in lowp vec4 interpolatedVertexColor;
@ -179,17 +180,39 @@ void main() {
pixels with `abs(centerDistanceSigned) > [d+w+s,w+s]` are background,
smoothstep in between */
highp const vec2 edge = vec2(halfSegmentLength+0.5*width, width*0.5);
lowp const vec2 factor = smoothstep( // TODO CSE
edge - vec2(smoothness),
edge + vec2(smoothness), abs(centerDistanceSigned));
// lowp const vec2 factor = smoothstep( // TODO CSE
// edge - vec2(smoothness),
// edge + vec2(smoothness), abs(centerDistanceSigned));
// lowp const vec2 factor = step(edge, abs(centerDistanceSigned));
// TODO better names ffs
highp vec2 distance_ = vec2(max(abs(centerDistanceSigned.x) - halfSegmentLength, 0.0), abs(centerDistanceSigned.y));
if(hasCap < 0.0) distance_.x = 0.0;
#ifdef CAP_STYLE_SQUARE
const highp float distanceS = max(distance_.x, distance_.y);
#elif defined(CAP_STYLE_ROUND)
const highp float distanceS = length(distance_);
#elif defined(CAP_STYLE_TRIANGLE)
const highp float distanceS = distance_.x + distance_.y;
#else
#error
#endif
const highp float factor = smoothstep(width*0.5 - smoothness, width*0.5 + smoothness, distanceS);
#if 1
const highp float factorX = distance(abs(centerDistanceSigned), vec2(halfSegmentLength, 0.0));
#else
const highp float factorX = factor.x;
#endif
// fragmentColor.ba = vec2(0.0);
fragmentColor = mix(
#ifdef VERTEX_COLOR
interpolatedVertexColor*
#endif
color, backgroundColor, max(factor.x, factor.y)); // TODO huh*/
color, backgroundColor, factor);
#ifdef OBJECT_ID
// TODO how to handle smoothness here?

79
src/Magnum/Shaders/Line.vert

@ -144,23 +144,23 @@ in highp vec4 position;
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = LINE_DIRECTION_ATTRIBUTE_LOCATION)
layout(location = LINE_PREVIOUS_POSITION_ATTRIBUTE_LOCATION)
#endif
#ifdef TWO_DIMENSIONS
in highp vec2 direction_;
in highp vec2 previousPosition;
#elif defined(THREE_DIMENSIONS)
in highp vec3 direction_;
in highp vec3 previousPosition;
#else
#error
#endif
#ifdef EXPLICIT_ATTRIB_LOCATION
layout(location = LINE_NEIGHBOR_DIRECTION_ATTRIBUTE_LOCATION)
layout(location = LINE_NEXT_POSITION_ATTRIBUTE_LOCATION)
#endif
#ifdef TWO_DIMENSIONS
in highp vec2 neighborDirection_;
in highp vec2 nextPosition;
#elif defined(THREE_DIMENSIONS)
in highp vec3 neighborDirection_;
in highp vec3 nextPosition;
#else
#error
#endif
@ -196,6 +196,7 @@ in highp mat4 instancedTransformationMatrix;
out highp vec2 centerDistanceSigned;
out highp float halfSegmentLength;
out lowp float hasCap;
#ifdef VERTEX_COLOR
out lowp vec4 interpolatedVertexColor;
@ -237,38 +238,45 @@ void main() {
#endif
#endif
// TODO look at the precision qualifiers, same for *.frag
#ifdef TWO_DIMENSIONS
const vec2 lineCenterPosition = (transformationProjectionMatrix*
highp const vec2 transformedPosition = (transformationProjectionMatrix*
#ifdef INSTANCED_TRANSFORMATION
instancedTransformationMatrix*
#endif
vec3(position, 1.0)).xy;
// TODO take prev/next positions, this makes no sense
const vec2 direction = (transformationProjectionMatrix*
highp const vec2 transformedPreviousPosition = (transformationProjectionMatrix*
#ifdef INSTANCED_TRANSFORMATION
instancedTransformationMatrix*
#endif
vec3(position + direction_, 1.0)).xy - lineCenterPosition;
vec3(previousPosition, 1.0)).xy;
const vec2 neighborDirection = (transformationProjectionMatrix*
highp const vec2 transformedNextPosition = (transformationProjectionMatrix*
#ifdef INSTANCED_TRANSFORMATION
instancedTransformationMatrix*
#endif
vec3(position + neighborDirection_, 1.0)).xy - lineCenterPosition;
vec3(nextPosition, 1.0)).xy;
const float directionLength = length(direction);
highp const vec2 direction = (gl_VertexID & 2) == 0 ?
transformedNextPosition - transformedPosition :
transformedPosition - transformedPreviousPosition;
highp const vec2 neighborDirection = (gl_VertexID & 2) == 0 ?
transformedPosition - transformedPreviousPosition :
transformedNextPosition - transformedPosition;
highp const float directionLength = length(direction);
// TODO since this is used just for AA, set to a special value in case of
// a line joint that shouldn't be AAd?
halfSegmentLength = length(direction*0.5*viewportSize/2.0);
// TODO zero-sized lines better?
const vec2 directionNormalized = directionLength == 0.0 ? vec2(1.0, 0.0) : direction/directionLength;
highp const vec2 directionNormalized = directionLength == 0.0 ? vec2(1.0, 0.0) : direction/directionLength;
/* Line width includes also twice the smoothness radius, some extra padding
on top, and is rounded to whole pixels. So for the edge distance we need
half of it. */
// TODO ref the paper here; actually just drop all that, smoothstep FTW
const float edgeDistance = ceil(width + 2.0*smoothness)*0.5;
highp const float edgeDistance = ceil(width + 2.0*smoothness)*0.5;
/* Copied from MeshTools::generateLines() internals for completenes. The
position is always either `A` or `B` for all four quad corners, the `d`
@ -288,21 +296,26 @@ void main() {
means for points 1 and 3 (i.e., gl_VertexID not divisible by 2) we need
to negate it to point the other way. */
// TODO zero-sized lines do what?
const float edgeSign = (gl_VertexID & 1) == 0 ? 1.0 : -1.0;
const float capSign = (gl_VertexID & 2) == 0 ? -1.0 : 1.0;
const float edgeDistanceSigned = edgeDistance*edgeSign;
highp const float edgeSign = (gl_VertexID & 1) == 0 ? 1.0 : -1.0;
highp const float capSign = (gl_VertexID & 2) == 0 ? -1.0 : 1.0;
highp const float edgeDistanceSigned = edgeDistance*edgeSign;
// vec2 edgeDirection = perpendicular(directionNormalized)*edgeDistanceSigned*2.0/viewportSize;
// float centerDirection
vec2 edgeDirection;
highp vec2 edgeDirection;
/* Distance to center, passed to the fragment shader. It's chosen in a way
that interpolates to a zero vector in the quad center, and the area
where `abs(centerDirection) <= [d+w,w]` is inside the line. Inside the
where `abs(centerDirection) <= [d+w,w]` is inside the line.
On the left is shown a line segment that has caps on both sides, thus
has
Inside the
line strip (where there's no line caps, shown on the left) the X value
is always 0, resulting in no antialiasing done on the beginning/end edge
in order to join tightly with the neigboring segments.
TODO what the hell, this is never 0, this is all wrong
0------------------2 0-----------------------------2
[0,+w]-------------[0,+w] [-d-w,+w]------------------[+d+w,+w]
| | | | | |
@ -310,7 +323,6 @@ void main() {
| | | | | |
[0,-w]-------------[0,-w] [-d-w,-w]------------------[+d+w,-w]
1------------------3 1-----------------------------3 */
// TODO handle caps
centerDistanceSigned.y = edgeDistanceSigned;
/* If the neighbor direction is a NaN, it means we're at the line cap --
@ -325,12 +337,14 @@ void main() {
For points 0 and 1 it'll be in the negative direction `d`, for points 2
and 3 in positive `d`. */
if(all(isnan(neighborDirection))) {
// TODO make the 0.7 configurable
if(all(isnan(neighborDirection)) || dot(normalize(direction), normalize(neighborDirection)) < -0.7) {
edgeDirection =
(directionNormalized*capSign +
perpendicular(directionNormalized)*edgeSign)*edgeDistance*2.0/viewportSize
;
centerDistanceSigned.x = (edgeDistance + halfSegmentLength)*capSign;
hasCap = 1.0; // TODO uhhhhhhh some extra offset for the cap here??
/* Otherwise we need to create a tight joint with the neighboring line
segment, as shown with the points 2 and 3. Given normalized direction
@ -361,26 +375,27 @@ void main() {
} else {
// edgeDirection = perpendicular(directionNormalized)*edgeSign*edgeDistance*2.0/viewportSize;
const vec2 averageDirection = capSign*directionNormalized + normalize(neighborDirection);
const float averageDirectionLength = length(averageDirection);
edgeDirection = perpendicular(averageDirection)*(capSign*edgeSign*edgeDistance*4.0/averageDirectionLength)/viewportSize;
const highp vec2 averageDirection = capSign*(directionNormalized + normalize(neighborDirection));
const highp float averageDirectionLength = length(averageDirection);
const highp float j = 2.0*edgeDistance/averageDirectionLength;
edgeDirection = (normalize(perpendicular(averageDirection))*capSign*edgeSign*j)*2.0/viewportSize;
// const float ex = sqrt((4.0*edgeDistance*edgeDistance/(averageDirectionLength*averageDirectionLength)) - edgeDistance*edgeDistance);
const float ex = sqrt(dot(edgeDirection, edgeDirection) - edgeDistance*edgeDistance);
const highp float ex = sqrt(j*j - edgeDistance*edgeDistance);
// edgeDirection = -perpendicular(averageDirection)*(1.0*edgeDistance*edgeSign*capSign/averageDirectionLength)
// *2.0/viewportSize;
// TODO it can't be 0!! it also has to include the skew in here but
// then somehow be marked to not smooth
centerDistanceSigned.x = halfSegmentLength*capSign;// + ex*sign(dot(direction*capSign, edgeDirection));
}
// TODO the ex should be included in here, why it isn't??
centerDistanceSigned.x = halfSegmentLength*capSign;// + ex*sign(dot(direction*capSign, (perpendicular(averageDirection))*capSign*edgeSign));
// TODO cap ends / joints, depending on neighborDirection size
hasCap = -1.0; // TODO uhhh some extra offset here so 0 is in the center?
}
gl_Position.xyzw = vec4(lineCenterPosition + edgeDirection, 0.0, 1.0);
gl_Position.xyzw = vec4(transformedPosition + edgeDirection, 0.0, 1.0);
#elif defined(THREE_DIMENSIONS)
// TODO 3D, how to handle perspective? multiply edgeDistance with w?
// TODO also how to handle depth?
gl_Position = transformationProjectionMatrix*
#ifdef INSTANCED_TRANSFORMATION
instancedTransformationMatrix*

12
src/Magnum/Shaders/LineGL.cpp

@ -130,6 +130,13 @@ template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineG
.addSource(configuration.flags() >= Flag::InstancedObjectId ? "#define INSTANCED_OBJECT_ID\n" : "")
#endif
;
if(configuration.capStyle() == CapStyle::Square)
frag.addSource("#define CAP_STYLE_SQUARE\n");
else if(configuration.capStyle() == CapStyle::Round)
frag.addSource("#define CAP_STYLE_ROUND\n");
else if(configuration.capStyle() == CapStyle::Triangle)
frag.addSource("#define CAP_STYLE_TRIANGLE\n");
else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); /* LCOV_EXCL_LINE */
#ifndef MAGNUM_TARGET_GLES2
if(configuration.flags() >= Flag::UniformBuffers) {
frag.addSource(Utility::formatString(
@ -149,6 +156,7 @@ template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineG
LineGL<dimensions> out{NoInit};
out._flags = configuration.flags();
out._capStyle = configuration.capStyle();
#ifndef MAGNUM_TARGET_GLES2
out._materialCount = configuration.materialCount();
out._drawCount = configuration.drawCount();
@ -164,8 +172,8 @@ template<UnsignedInt dimensions> typename LineGL<dimensions>::CompileState LineG
#endif
{
out.bindAttributeLocation(Position::Location, "position");
out.bindAttributeLocation(LineDirection::Location, "direction");
out.bindAttributeLocation(LineNeighborDirection::Location, "neighborDirection");
out.bindAttributeLocation(PreviousPosition::Location, "direction");
out.bindAttributeLocation(NextPosition::Location, "neighborDirection");
if(configuration.flags() & Flag::VertexColor)
out.bindAttributeLocation(Color3::Location, "vertexColor"); /* Color4 is the same */
#ifndef MAGNUM_TARGET_GLES2

31
src/Magnum/Shaders/LineGL.h

@ -47,6 +47,13 @@ namespace Implementation {
#endif
};
typedef Containers::EnumSet<LineGLFlag> LineGLFlags;
// TODO this is GL-independent probably, what to do? put in Line.h?
enum class LineGLCapStyle: UnsignedByte {
Square,
Round,
Triangle
};
}
template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::AbstractShaderProgram {
@ -57,8 +64,8 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
typedef typename GenericGL<dimensions>::Position Position;
// TODO move to Generic
typedef GL::Attribute<3, VectorTypeFor<dimensions, Float>> LineDirection;
typedef GL::Attribute<5, VectorTypeFor<dimensions, Float>> LineNeighborDirection;
typedef GL::Attribute<3, VectorTypeFor<dimensions, Float>> PreviousPosition;
typedef GL::Attribute<5, VectorTypeFor<dimensions, Float>> NextPosition;
typedef typename GenericGL<dimensions>::Color3 Color3;
@ -103,11 +110,20 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
* @see @ref flags()
*/
typedef Containers::EnumSet<Flag> Flags;
enum class CapStyle: UnsignedByte {
Square,
Round,
Triangle
};
#else
/* Done this way to be prepared for possible future diversion of 2D
and 3D flags (e.g. introducing 3D-specific features) */
typedef Implementation::LineGLFlag Flag;
typedef Implementation::LineGLFlags Flags;
//
typedef Implementation::LineGLCapStyle CapStyle;
#endif
static CompileState compile(const Configuration& configuration = Configuration{});
@ -177,6 +193,7 @@ template<UnsignedInt dimensions> class MAGNUM_SHADERS_EXPORT LineGL: public GL::
explicit LineGL(NoInitT);
Flags _flags;
CapStyle _capStyle;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _materialCount{}, _drawCount{};
#endif
@ -209,6 +226,15 @@ template<UnsignedInt dimensions> class LineGL<dimensions>::Configuration {
Flags flags() const { return _flags; }
Configuration& setCapStyle(CapStyle style) {
_capStyle = style;
return *this;
}
CapStyle capStyle() const { return _capStyle; }
// TODO joint style
#ifndef MAGNUM_TARGET_GLES2
Configuration& setMaterialCount(UnsignedInt count) {
_materialCount = count;
@ -227,6 +253,7 @@ template<UnsignedInt dimensions> class LineGL<dimensions>::Configuration {
private:
Flags _flags;
CapStyle _capStyle = CapStyle::Square;
#ifndef MAGNUM_TARGET_GLES2
UnsignedInt _materialCount{1};
UnsignedInt _drawCount{1};

262
src/Magnum/Shaders/Test/LineGLTest.cpp

@ -114,7 +114,6 @@ struct LineGLTest: GL::OpenGLTester {
private:
PluginManager::Manager<Trade::AbstractImporter> _manager{"nonexistent"};
Containers::String _testDir;
GL::Renderbuffer _color{NoCreate};
#ifndef MAGNUM_TARGET_GLES2
@ -163,7 +162,7 @@ const struct {
// };
#ifndef MAGNUM_TARGET_GLES2
constexpr struct {
const struct {
const char* name;
LineGL2D::Flags flags;
UnsignedInt materialCount, drawCount;
@ -176,6 +175,34 @@ constexpr struct {
};
#endif
const struct {
const char* name;
Containers::Array<Vector2> lineSegments;
Float width;
Float smoothness;
const char* expected;
} Render2DData[]{
// TODO cap variants, short & long
{"joint angles, obtuse", {InPlaceInit, {
{ 0.2f, 0.8f}, {0.2f, 0.4f}, {0.2f, 0.4f}, {0.8f, 0.4f},
{-0.4f, 0.4f}, {0.0f, 0.0f}, {0.0f, 0.0f}, {0.8f, 0.0f},
{-0.8f, -0.0f}, {0.0f, -0.4f}, {0.0f, -0.4f}, {0.8f, -0.4f},
{-0.8f, -0.8f}, {0.0f, -0.8f}, {0.0f, -0.8f}, {0.8f, -0.8f},
}}, 10.0f, 0.0f, "joint-angles-obtuse.tga"},
// TODO cap variants here also
{"joint angles, acute", {InPlaceInit, {
{ 0.4f, 0.8f}, {0.0f, 0.4f}, {0.0f, 0.4f}, {0.8f, 0.4f},
{ 0.8f, 0.0f}, {0.0f, -0.4f}, {0.0f, -0.4f}, {0.8f, -0.4f},
{ 0.8f, -0.8f}, {0.0f, -0.8f}, {0.0f, -0.8f}, {0.8f, -0.8f},
}}, 10.0f, 0.0f, "joint-angles-acute.tga"},
// TODO cap variants here also
{"joint angles, acute, short", {InPlaceInit, {
{ -0.25f, 0.45f}, {-0.3f, 0.4f}, {-0.3f, 0.4f}, {0.6f, 0.4f},
{ -0.25f, -0.45f}, {-0.3f, -0.4f}, {-0.3f, -0.4f}, {0.6f, -0.4f},
}}, 20.0f, 0.0f, "joint-angles-acute-short.tga"},
// TODO cap variants here also
};
LineGLTest::LineGLTest() {
addInstancedTests<LineGLTest>({
&LineGLTest::construct<2>,
@ -253,6 +280,17 @@ LineGLTest::LineGLTest() {
&LineGLTest::renderSetup,
&LineGLTest::renderTeardown);
/* MSVC needs explicit type due to default template args */
addInstancedTests<LineGLTest>({
&LineGLTest::render2D,
#ifndef MAGNUM_TARGET_GLES2
// &LineGLTest::render2D<LineGL2D::Flag::UniformBuffers>,
#endif
},
Containers::arraySize(Render2DData),
&LineGLTest::renderSetup,
&LineGLTest::renderTeardown);
/* 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
@ -617,6 +655,88 @@ void LineGLTest::renderTeardown() {
_color = GL::Renderbuffer{NoCreate};
}
template<UnsignedInt dimensions> GL::Mesh generateLineMesh(Containers::ArrayView<const VectorTypeFor<dimensions, Float>> lineSegments) {
struct Vertex {
VectorTypeFor<dimensions, Float> previousPosition;
VectorTypeFor<dimensions, Float> position;
VectorTypeFor<dimensions, Float> nextPosition;
};
CORRADE_INTERNAL_ASSERT(lineSegments.size() % 2 == 0);
Containers::Array<Vertex> vertices{NoInit, lineSegments.size()*2};
for(std::size_t i = 0; i != lineSegments.size(); ++i)
vertices[i*2 + 0].position = vertices[i*2 + 1].position = lineSegments[i];
/* Mark prev/next positions with NaN if it's the beginning, the end or the
segments are disjoint */
vertices[0].previousPosition =
vertices[1].previousPosition =
vertices[vertices.size() - 2].nextPosition =
vertices[vertices.size() - 1].nextPosition =
VectorTypeFor<dimensions, Float>{Constants::nan()};
for(std::size_t i = 4; i < vertices.size(); i += 4) {
if(vertices[i - 2].position == vertices[i].position) continue;
vertices[i - 2].nextPosition =
vertices[i - 1].nextPosition =
vertices[i + 0].previousPosition =
vertices[i + 1].previousPosition =
VectorTypeFor<dimensions, Float>{Constants::nan()};
}
/* Prev positions for first vertices */
for(std::size_t i = 2; i < Containers::arraySize(vertices); i += 4) {
if(Math::isNan(vertices[i].previousPosition)) continue;
vertices[i + 0].previousPosition = vertices[i + 1].previousPosition =
vertices[i - 2].position;
}
/* Prev positions for last vertices */
for(std::size_t i = 4; i < Containers::arraySize(vertices); i += 4) {
if(Math::isNan(vertices[i].previousPosition)) continue;
vertices[i + 0].previousPosition = vertices[i + 1].previousPosition =
vertices[i - 4].position;
}
/* Next positions for first vertices */
for(std::size_t i = 0; i < Containers::arraySize(vertices) - 2; i += 4) {
if(Math::isNan(vertices[i].nextPosition)) continue;
vertices[i + 0].nextPosition = vertices[i + 1].nextPosition =
vertices[i + 2].position;
}
/* Next positions for last vertices */
for(std::size_t i = 2; i < Containers::arraySize(vertices) - 4; i += 4) {
if(Math::isNan(vertices[i].nextPosition)) continue;
vertices[i + 0].nextPosition = vertices[i + 1].nextPosition =
vertices[i + 4].position;
}
Containers::Array<UnsignedInt> indices{NoInit, lineSegments.size()*6/2};
for(std::size_t i = 0; i != lineSegments.size()/2; ++i) {
indices[i*6 + 0] = i*4 + 0;
indices[i*6 + 1] = i*4 + 1;
indices[i*6 + 2] = i*4 + 2;
indices[i*6 + 3] = i*4 + 2;
indices[i*6 + 4] = i*4 + 1;
indices[i*6 + 5] = i*4 + 3;
}
GL::Mesh mesh;
mesh.addVertexBuffer(GL::Buffer{vertices}, 0,
LineGL2D::PreviousPosition{},
LineGL2D::Position{},
LineGL2D::NextPosition{})
.setIndexBuffer(GL::Buffer{indices}, 0, GL::MeshIndexType::UnsignedInt)
.setCount(indices.size());
return mesh;
}
GL::Mesh generateLineMesh(std::initializer_list<Vector2> lineSegments) {
return generateLineMesh<2>(Containers::arrayView(lineSegments));
}
// GL::Mesh generateLineMesh(std::initializer_list<Vector3> lineSegments) {
// return generateLineMesh<3>(Containers::arrayView(lineSegments));
// }
template<LineGL2D::Flag flag> void LineGLTest::renderDefaults2D() {
#ifndef MAGNUM_TARGET_GLES2
if(flag == LineGL2D::Flag::UniformBuffers) {
@ -629,89 +749,88 @@ template<LineGL2D::Flag flag> void LineGLTest::renderDefaults2D() {
}
#endif
// TODO drop this crap, use MeshTools once things settle down
struct Vertex {
Vector2 neighborDirection;
Vector2 position;
Vector2 direction;
} vertices[]{
/* Two connected line segments, down and then to the right */
{Vector2{Constants::nan()}, {-0.25f, 0.5f}, {}},
{Vector2{Constants::nan()}, {-0.25f, 0.5f}, {}},
{{}, {-0.5f, -0.5f}, {}},
{{}, {-0.5f, -0.5f}, {}},
{{}, {-0.5f, -0.5f}, {}},
{{}, {-0.5f, -0.5f}, {}},
{Vector2{Constants::nan()}, {0.5f, -0.25f}, {}},
{Vector2{Constants::nan()}, {0.5f, -0.25f}, {}},
/* Singular horizontal and vertical segment */
{Vector2{Constants::nan()}, {-0.75f, 0.25f}, {}},
{Vector2{Constants::nan()}, {-0.75f, 0.25f}, {}},
{Vector2{Constants::nan()}, {-0.75f, 0.75f}, {}},
{Vector2{Constants::nan()}, {-0.75f, 0.75f}, {}},
{Vector2{Constants::nan()}, {-0.25f, -0.75f}, {}},
{Vector2{Constants::nan()}, {-0.25f, -0.75f}, {}},
{Vector2{Constants::nan()}, {0.75f, -0.75f}, {}},
{Vector2{Constants::nan()}, {0.75f, -0.75f}, {}},
/* A single point */
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}},
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}},
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}},
{Vector2{Constants::nan()}, {0.5f, 0.5f}, {}},
};
GL::Mesh lines = generateLineMesh({
/* A / line from the top to bottom */
{-0.0f, 0.5f}, {-0.5f, -0.5f},
/* A / line from the bottom to top */
{-0.5f, -0.5f}, {0.5f, -0.25f},
/* A | line from the bottom to top */
{-0.75f, -0.25f}, {-0.75f, 0.75f},
/* A _ line from the left to right */
{-0.25f, -0.75f}, {0.75f, -0.75f},
/* A zero-size line that should be visible as a point */
{0.5f, 0.5f}, {0.5f, 0.5f}
});
/* Prev directions */
for(std::size_t i = 4; i < Containers::arraySize(vertices); i += 4) {
if(Math::isNan(vertices[i + 0].neighborDirection)) continue;
vertices[i + 0].neighborDirection = vertices[i + 1].neighborDirection =
vertices[i - 4].position - vertices[i + 0].position;
LineGL2D shader{LineGL2D::Configuration{}
.setFlags(flag)};
shader.setViewportSize(Vector2{RenderSize});
if(flag == LineGL2D::Flag{}) {
shader.draw(lines);
}
/* Segment directions */
for(std::size_t i = 0; i < Containers::arraySize(vertices); i += 4) {
vertices[i + 0].direction = vertices[i + 1].direction =
vertices[i + 2].direction = vertices[i + 3].direction =
vertices[i + 2].position - vertices[i + 0].position;
#ifndef MAGNUM_TARGET_GLES2
else if(flag == LineGL2D::Flag::UniformBuffers) {
GL::Buffer transformationProjectionUniform{GL::Buffer::TargetHint::Uniform, {
TransformationProjectionUniform2D{}
}};
GL::Buffer drawUniform{GL::Buffer::TargetHint::Uniform, {
LineDrawUniform{}
}};
GL::Buffer materialUniform{GL::Buffer::TargetHint::Uniform, {
LineMaterialUniform{}
}};
shader
.bindTransformationProjectionBuffer(transformationProjectionUniform)
.bindDrawBuffer(drawUniform)
.bindMaterialBuffer(materialUniform)
.draw(lines);
}
/* Next directions */
for(std::size_t i = 2; i < Containers::arraySize(vertices) - 4; i += 4) {
if(Math::isNan(vertices[i + 0].neighborDirection)) continue;
vertices[i + 0].neighborDirection = vertices[i + 1].neighborDirection =
vertices[i + 4].position - vertices[i + 0].position;
#endif
else CORRADE_INTERNAL_ASSERT_UNREACHABLE();
MAGNUM_VERIFY_NO_GL_ERROR();
if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) ||
!(_manager.loadState("TgaImporter") & PluginManager::LoadState::Loaded))
CORRADE_SKIP("AnyImageImporter / TgaImporter plugins not found.");
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Path::join(SHADERS_TEST_DIR, "LineTestFiles/defaults2D.tga"),
(DebugTools::CompareImageToFile{_manager}));
}
!Debug{} << Containers::stridedArrayView(vertices).slice(&Vertex::position).prefix(8);
!Debug{} << Containers::stridedArrayView(vertices).slice(&Vertex::direction).prefix(8);
!Debug{} << Containers::stridedArrayView(vertices).slice(&Vertex::neighborDirection).prefix(8);
template<LineGL2D::Flag flag> void LineGLTest::render2D() {
auto&& data = Render2DData[testCaseInstanceId()];
setTestCaseDescription(data.name);
const UnsignedInt indices[]{
0, 1, 2, 2, 1, 3,
4, 5, 6, 6, 5, 7,
8, 9, 10, 10, 9, 11,
12, 13, 14, 14, 13, 15,
16, 17, 18, 18, 17, 19
};
#ifndef MAGNUM_TARGET_GLES2
if(flag == LineGL2D::Flag::UniformBuffers) {
setTestCaseTemplateName("Flag::UniformBuffers");
GL::Mesh lines;
lines.addVertexBuffer(GL::Buffer{vertices}, 0,
LineGL2D::LineNeighborDirection{},
LineGL2D::Position{},
LineGL2D::LineDirection{})
.setIndexBuffer(GL::Buffer{indices}, 0, GL::MeshIndexType::UnsignedInt)
.setCount(Containers::arraySize(indices));
#ifndef MAGNUM_TARGET_GLES
if(!GL::Context::current().isExtensionSupported<GL::Extensions::ARB::uniform_buffer_object>())
CORRADE_SKIP(GL::Extensions::ARB::uniform_buffer_object::string() << "is not supported.");
#endif
}
#endif
GL::Mesh lines = generateLineMesh<2>(data.lineSegments);
LineGL2D shader{LineGL2D::Configuration{}
.setFlags(flag)};
shader.setViewportSize(Vector2{RenderSize});
shader
.setWidth(5.0f)
.setSmoothness(1.0f)
.setWidth(data.width)
.setSmoothness(data.smoothness)
// .setBackgroundColor(0xff0000ff_rgbaf)
// .setColor(0x557766_rgbf)
;
// TODO test with blending -- there should be no self-intersection
if(flag == LineGL2D::Flag{}) {
shader.draw(lines);
}
@ -744,9 +863,8 @@ template<LineGL2D::Flag flag> void LineGLTest::renderDefaults2D() {
CORRADE_COMPARE_WITH(
/* Dropping the alpha channel, as it's always 1.0 */
Containers::arrayCast<Color3ub>(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels<Color4ub>()),
Utility::Path::join(_testDir, "LineTestFiles/defaults2D.tga"),
/* SwiftShader has 8 different pixels on the edges */
(DebugTools::CompareImageToFile{_manager, 238.0f, 0.2975f}));
Utility::Path::join({SHADERS_TEST_DIR, "LineTestFiles", data.expected}),
(DebugTools::CompareImageToFile{_manager}));
}
}}}}

BIN
src/Magnum/Shaders/Test/LineTestFiles/defaults2D.tga

Binary file not shown.

BIN
src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse.tga

Binary file not shown.

8
src/Magnum/Shaders/generic.glsl

@ -28,12 +28,12 @@
#define POSITION_ATTRIBUTE_LOCATION 0
#define TEXTURECOORDINATES_ATTRIBUTE_LOCATION 1
#define COLOR_ATTRIBUTE_LOCATION 2
#define TANGENT_ATTRIBUTE_LOCATION 3 /* also LineDirection */
#define LINE_DIRECTION_ATTRIBUTE_LOCATION 3 /* also Tangent */
#define TANGENT_ATTRIBUTE_LOCATION 3 /* also LinePreviousPosition */
#define LINE_PREVIOUS_POSITION_ATTRIBUTE_LOCATION 3 /* also Tangent */
#define BITANGENT_ATTRIBUTE_LOCATION 4 /* also ObjectId */
#define OBJECT_ID_ATTRIBUTE_LOCATION 4 /* also Bitangent */
#define NORMAL_ATTRIBUTE_LOCATION 5 /* also LineNeighborDirection */
#define LINE_NEIGHBOR_DIRECTION_ATTRIBUTE_LOCATION 5 /* also Normal */
#define NORMAL_ATTRIBUTE_LOCATION 5 /* also LineNextPosition */
#define LINE_NEXT_POSITION_ATTRIBUTE_LOCATION 5 /* also Normal */
#define TRANSFORMATION_MATRIX_ATTRIBUTE_LOCATION 8
#define NORMAL_MATRIX_ATTRIBUTE_LOCATION 12

Loading…
Cancel
Save