diff --git a/src/Magnum/MeshTools/Test/GenerateLinesTest.cpp b/src/Magnum/MeshTools/Test/GenerateLinesTest.cpp index 0baeae421..f7371cf92 100644 --- a/src/Magnum/MeshTools/Test/GenerateLinesTest.cpp +++ b/src/Magnum/MeshTools/Test/GenerateLinesTest.cpp @@ -25,6 +25,8 @@ #include +#include "Magnum/MeshTools/GenerateLines.h" + namespace Magnum { namespace MeshTools { namespace Test { namespace { struct GenerateLinesTest: TestSuite::Tester { diff --git a/src/Magnum/Shaders/FlatGL.cpp b/src/Magnum/Shaders/FlatGL.cpp index 21483822e..240e46dd3 100644 --- a/src/Magnum/Shaders/FlatGL.cpp +++ b/src/Magnum/Shaders/FlatGL.cpp @@ -164,7 +164,9 @@ template typename FlatGL::CompileState FlatG } #endif vert.addSource(rs.getString("generic.glsl")) - .addSource(rs.getString("Flat.vert")); + .addSource(rs.getString("Flat.vert")) + .submitCompile(); + frag.addSource(flags & Flag::Textured ? "#define TEXTURED\n" : "") #ifndef MAGNUM_TARGET_GLES2 .addSource(flags & Flag::TextureArrays ? "#define TEXTURE_ARRAYS\n" : "") @@ -189,10 +191,8 @@ template typename FlatGL::CompileState FlatG } #endif frag.addSource(rs.getString("generic.glsl")) - .addSource(rs.getString("Flat.frag")); - - vert.submitCompile(); - frag.submitCompile(); + .addSource(rs.getString("Flat.frag")) + .submitCompile(); FlatGL out{NoInit}; out._flags = flags; diff --git a/src/Magnum/Shaders/Line.frag b/src/Magnum/Shaders/Line.frag index aa507406a..d2ead3e96 100644 --- a/src/Magnum/Shaders/Line.frag +++ b/src/Magnum/Shaders/Line.frag @@ -176,17 +176,15 @@ void main() { lowp const vec4 color = materials[materialId].color; #endif + // TODO this comment is plain wrong /* Pixels with `abs(centerDistanceSigned) <= [d+w,w]` are foreground, 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 = step(edge, abs(centerDistanceSigned)); // TODO better names ffs highp vec2 distance_ = vec2(max(abs(centerDistanceSigned.x) - halfSegmentLength, 0.0), abs(centerDistanceSigned.y)); + // TODO document what is this if(hasCap < 0.0) distance_.x = 0.0; #ifdef CAP_STYLE_SQUARE @@ -207,7 +205,6 @@ void main() { const highp float factorX = factor.x; #endif -// fragmentColor.ba = vec2(0.0); fragmentColor = mix( #ifdef VERTEX_COLOR interpolatedVertexColor* diff --git a/src/Magnum/Shaders/Line.vert b/src/Magnum/Shaders/Line.vert index 5f0a00d09..556c34559 100644 --- a/src/Magnum/Shaders/Line.vert +++ b/src/Magnum/Shaders/Line.vert @@ -194,6 +194,7 @@ in highp mat4 instancedTransformationMatrix; /* Outputs */ +// TODO document, maybe join together? out highp vec2 centerDistanceSigned; out highp float halfSegmentLength; out lowp float hasCap; @@ -264,12 +265,14 @@ void main() { highp const vec2 neighborDirection = (gl_VertexID & 2) == 0 ? transformedPosition - transformedPreviousPosition : transformedNextPosition - transformedPosition; + highp const vec2 firstPoint = (gl_VertexID & 2) == 0 ? + transformedPosition : transformedPreviousPosition; + highp const vec2 neighborEndPoint = (gl_VertexID & 2) == 0 ? + transformedPreviousPosition : transformedNextPosition; 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? + // TODO zero-sized lines better? average from prev/next? 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 @@ -282,7 +285,7 @@ void main() { position is always either `A` or `B` for all four quad corners, the `d` comes in the direction attribute, `pd`/`nd` in neighborDirection and the vertex order, which is (4n +) 0/1/2/3, in gl_VertexID. - + // TODO redo all this here, the whole comment is outdated 0-d->-------2-d-> | / \ A---------B nd @@ -291,7 +294,6 @@ void main() { \ \ . nd . . v C . */ - // TODO redo all this here /* The perpendicular direction is rotating 90° counterclockwise. Which means for points 1 and 3 (i.e., gl_VertexID not divisible by 2) we need to negate it to point the other way. */ @@ -337,61 +339,70 @@ void main() { For points 0 and 1 it'll be in the negative direction `d`, for points 2 and 3 in positive `d`. */ - // TODO make the 0.7 configurable - if(all(isnan(neighborDirection)) || dot(normalize(direction), normalize(neighborDirection)) < -0.7) { + if(all(isnan(neighborDirection)) || + /* Cap limit */ + // TODO make the 0.7 configurable; no actually drop it altogether + dot(normalize(direction), normalize(neighborDirection)) < -0.99 || + /* Neighbor segment too short */ + // TODO why the 2*?? why the square?? + (abs(dot(perpendicular(normalize(direction))*viewportSize/2.0, (neighborEndPoint - firstPoint)*viewportSize/2.0)) < 2*edgeDistance*edgeDistance && + // TODO this is a wrong attempt to handle colinear, needs to + // calculate proper distance from a line segment instead or do + // something else entirely ffs + dot(direction, neighborDirection) <= 0.0) + ) { 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 `d` and neighbor direction `nd`, `normalized(d + nd)` is the "average" direction of the two and `perpendicular(normalized(d + nd))` gives us - the direction from B to 2: - - --------+----2 - | / alpha/2 - w | / j - |/ - --d->-B - alpha/2 / \ - / nd - / v - ----3 - - With `alpha` being the angle between `d` and `nd`, `alpha/2` appears in - two right triangles and the following holds, `w` being the edge distance - from above, and `j` being the length that's needed to scale `perpendicular(normalized(d + nd))` to get point 2: - - |d + nd| w 2 w - sin(alpha/2) = -------- = --- --> j = -------- - 2 |d| j |d + nd| + the direction from B to 2 (or from 3 to B): + + --------+---2 + | α/ + w | / j + |/ + +_-----d->-B + -_ α/α\ + -_ / nd + d + nd /-_ v + ----3 -_ \ + -+ + + With `2α` being the angle between `d` and `nd`, `α` appears in two right + triangles and the following holds, `w` being the edge distance from + above, and `j` being the length that's needed to scale + `perpendicular(normalized(d + nd))` to get point 2: + + |d + nd| w 2 w + sin(α) = -------- = --- --> j = -------- + 2 |d| j |d + nd| Point 3 is then just in the opposite direction; for the other side it's done equivalently. */ } else { -// edgeDirection = perpendicular(directionNormalized)*edgeSign*edgeDistance*2.0/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 highp float ex = sqrt(j*j - edgeDistance*edgeDistance); -// edgeDirection = -perpendicular(averageDirection)*(1.0*edgeDistance*edgeSign*capSign/averageDirectionLength) -// *2.0/viewportSize; - - // 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)); - - hasCap = -1.0; // TODO uhhh some extra offset here so 0 is in the center? + centerDistanceSigned.x = halfSegmentLength*capSign + ex*sign(dot(direction*capSign, (perpendicular(averageDirection))*edgeSign)); } + /* Cap is there only if neighbors are NaN, otherwise a joint is rendered */ + // TODO uhhhhh document why the sign comparison + if(all(isnan(neighborDirection)) || sign(centerDistanceSigned.x) != sign(halfSegmentLength*capSign)) + hasCap = abs(centerDistanceSigned.x); + else + hasCap = -abs(centerDistanceSigned.x); + gl_Position.xyzw = vec4(transformedPosition + edgeDirection, 0.0, 1.0); #elif defined(THREE_DIMENSIONS) // TODO 3D, how to handle perspective? multiply edgeDistance with w? diff --git a/src/Magnum/Shaders/Test/LineGLTest.cpp b/src/Magnum/Shaders/Test/LineGLTest.cpp index 13db421d0..da6d39fa1 100644 --- a/src/Magnum/Shaders/Test/LineGLTest.cpp +++ b/src/Magnum/Shaders/Test/LineGLTest.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,7 @@ #include "Magnum/GL/Renderbuffer.h" #include "Magnum/GL/RenderbufferFormat.h" #include "Magnum/Math/Color.h" +#include "Magnum/Math/FunctionsBatch.h" #include "Magnum/Math/Matrix3.h" #include "Magnum/Math/Matrix4.h" #include "Magnum/Shaders/Generic.h" @@ -122,6 +124,7 @@ struct LineGLTest: GL::OpenGLTester { GL::Framebuffer _framebuffer{NoCreate}; }; +using namespace Containers::Literals; using namespace Math::Literals; const struct { @@ -180,27 +183,153 @@ const struct { Containers::Array lineSegments; Float width; Float smoothness; + LineGL2D::CapStyle capStyle; + bool reverse; + Matrix3 transform; + bool expectOverlap; const char* expected; } Render2DData[]{ - // TODO cap variants, short & long + {"line caps default, flat", {InPlaceInit, { + {-0.8f, 0.8f}, {-0.8f, 0.8f}, + {-0.8f, 0.4f}, {-0.4f, 0.4f}, + {-0.8f, 0.0f}, { 0.0f, 0.0f}, + {-0.8f, -0.4f}, { 0.4f, -0.4f}, + {-0.8f, -0.8f}, { 0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, false, {}, + false, "line-caps-square-flat.tga"}, + {"line caps square", {InPlaceInit, { + {-0.8f, 0.8f}, {-0.8f, 0.8f}, + {-0.8f, 0.4f}, {-0.4f, 0.4f}, + {-0.8f, 0.0f}, { 0.0f, 0.0f}, + {-0.8f, -0.4f}, { 0.4f, -0.4f}, + {-0.8f, -0.8f}, { 0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Square, false, {}, + false, "line-caps-square.tga"}, + {"line caps round", {InPlaceInit, { + {-0.8f, 0.8f}, {-0.8f, 0.8f}, + {-0.8f, 0.4f}, {-0.4f, 0.4f}, + {-0.8f, 0.0f}, { 0.0f, 0.0f}, + {-0.8f, -0.4f}, { 0.4f, -0.4f}, + {-0.8f, -0.8f}, { 0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Round, false, {}, + false, "line-caps-round.tga"}, + {"line caps triangle", {InPlaceInit, { + {-0.8f, 0.8f}, {-0.8f, 0.8f}, + {-0.8f, 0.4f}, {-0.4f, 0.4f}, + {-0.8f, 0.0f}, { 0.0f, 0.0f}, + {-0.8f, -0.4f}, { 0.4f, -0.4f}, + {-0.8f, -0.8f}, { 0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Triangle, false, {}, + false, "line-caps-triangle.tga"}, {"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 + { 0.4f, 0.8f}, {0.4f, 0.4f}, {0.4f, 0.4f}, {0.8f, 0.4f}, + {-0.2f, 0.4f}, {0.2f, 0.0f}, {0.2f, 0.0f}, {0.8f, 0.0f}, + {-0.8f, -0.0f}, {0.2f, -0.4f}, {0.2f, -0.4f}, {0.8f, -0.4f}, + {-0.8f, -0.8f}, {0.2f, -0.8f}, {0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, false, {}, + false, "joint-angles-obtuse.tga"}, + {"joint angles, obtuse, reverse direction", {InPlaceInit, { + /* Same as "joint angles, obtuse" */ + { 0.4f, 0.8f}, {0.4f, 0.4f}, {0.4f, 0.4f}, {0.8f, 0.4f}, + {-0.2f, 0.4f}, {0.2f, 0.0f}, {0.2f, 0.0f}, {0.8f, 0.0f}, + {-0.8f, -0.0f}, {0.2f, -0.4f}, {0.2f, -0.4f}, {0.8f, -0.4f}, + {-0.8f, -0.8f}, {0.2f, -0.8f}, {0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, true, {}, + false, "joint-angles-obtuse.tga"}, + {"joint angles, obtuse, transformed", {InPlaceInit, { + /* Same as "joint angles, obtuse" */ + { 0.4f, 0.8f}, {0.4f, 0.4f}, {0.4f, 0.4f}, {0.8f, 0.4f}, + {-0.2f, 0.4f}, {0.2f, 0.0f}, {0.2f, 0.0f}, {0.8f, 0.0f}, + {-0.8f, -0.0f}, {0.2f, -0.4f}, {0.2f, -0.4f}, {0.8f, -0.4f}, + {-0.8f, -0.8f}, {0.2f, -0.8f}, {0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, true, + Matrix3::scaling({100.0f, 2.0f})*Matrix3::rotation(45.0_degf), + false, "joint-angles-obtuse.tga"}, + {"joint angles, obtuse, round caps", {InPlaceInit, { + /* Same as "joint angles, obtuse" */ + { 0.4f, 0.8f}, {0.4f, 0.4f}, {0.4f, 0.4f}, {0.8f, 0.4f}, + {-0.2f, 0.4f}, {0.2f, 0.0f}, {0.2f, 0.0f}, {0.8f, 0.0f}, + {-0.8f, -0.0f}, {0.2f, -0.4f}, {0.2f, -0.4f}, {0.8f, -0.4f}, + {-0.8f, -0.8f}, {0.2f, -0.8f}, {0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Round, false, {}, + false, "joint-angles-obtuse-round-caps.tga"}, + {"joint angles, obtuse, round caps, reverse direction", {InPlaceInit, { + /* Same as "joint angles, obtuse" */ + { 0.4f, 0.8f}, {0.4f, 0.4f}, {0.4f, 0.4f}, {0.8f, 0.4f}, + {-0.2f, 0.4f}, {0.2f, 0.0f}, {0.2f, 0.0f}, {0.8f, 0.0f}, + {-0.8f, -0.0f}, {0.2f, -0.4f}, {0.2f, -0.4f}, {0.8f, -0.4f}, + {-0.8f, -0.8f}, {0.2f, -0.8f}, {0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Round, true, {}, + false, "joint-angles-obtuse-round-caps.tga"}, {"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 + { 0.1f, 0.8f}, {-0.2f, 0.5f}, {-0.2f, 0.5f}, {0.8f, 0.5f}, + { 0.6f, 0.2f}, {-0.2f, -0.2f}, {-0.2f, -0.2f}, {0.8f, -0.2f}, + { 0.6f, -0.5f}, {-0.2f, -0.8f}, {-0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, false, {}, + false, "joint-angles-acute.tga"}, + // TODO joint styles + {"joint angles, acute, reverse direction", {InPlaceInit, { + /* Same as "joint angles, acute" */ + { 0.1f, 0.8f}, {-0.2f, 0.5f}, {-0.2f, 0.5f}, {0.8f, 0.5f}, + { 0.6f, 0.2f}, {-0.2f, -0.2f}, {-0.2f, -0.2f}, {0.8f, -0.2f}, + { 0.6f, -0.5f}, {-0.2f, -0.8f}, {-0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, true, {}, + false, "joint-angles-acute.tga"}, + {"joint angles, acute, transformed", {InPlaceInit, { + /* Same as "joint angles, transformed" */ + { 0.1f, 0.8f}, {-0.2f, 0.5f}, {-0.2f, 0.5f}, {0.8f, 0.5f}, + { 0.6f, 0.2f}, {-0.2f, -0.2f}, {-0.2f, -0.2f}, {0.8f, -0.2f}, + { 0.6f, -0.5f}, {-0.2f, -0.8f}, {-0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, false, + Matrix3::scaling({100.0f, 2.0f})*Matrix3::rotation(45.0_degf), + false, "joint-angles-acute.tga"}, + {"joint angles, acute, round caps", {InPlaceInit, { + /* Same as "joint angles, acute" */ + { 0.1f, 0.8f}, {-0.2f, 0.5f}, {-0.2f, 0.5f}, {0.8f, 0.5f}, + { 0.6f, 0.2f}, {-0.2f, -0.2f}, {-0.2f, -0.2f}, {0.8f, -0.2f}, + { 0.6f, -0.5f}, {-0.2f, -0.8f}, {-0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Round, false, {}, + false, "joint-angles-acute-round-caps.tga"}, + {"joint angles, acute, round caps, reverse direction", {InPlaceInit, { + /* Same as "joint angles, acute" */ + { 0.1f, 0.8f}, {-0.2f, 0.5f}, {-0.2f, 0.5f}, {0.8f, 0.5f}, + { 0.6f, 0.2f}, {-0.2f, -0.2f}, {-0.2f, -0.2f}, {0.8f, -0.2f}, + { 0.6f, -0.5f}, {-0.2f, -0.8f}, {-0.2f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Round, true, {}, + false, "joint-angles-acute-round-caps.tga"}, + {"joint angles, short cap", {InPlaceInit, { + {-0.3f, 0.6f}, {-0.6f, 0.6f}, {-0.6f, 0.6f}, {-0.6f, -0.6f}, {-0.6f, -0.6f}, {-0.4f, -0.6f}, + { 0.6f, 0.6f}, {0.5f, 0.6f}, {0.5f, 0.6f}, {0.5f, -0.6f}, {0.5f, -0.6f}, {0.51f, -0.6f}, + }}, 20.0f, 1.0f, LineGL2D::CapStyle::Round, false, {}, + true, "joint-angles-short-cap.tga"}, + {"joint angles, short cap, reversed", {InPlaceInit, { + {-0.3f, 0.6f}, {-0.6f, 0.6f}, {-0.6f, 0.6f}, {-0.6f, -0.6f}, {-0.6f, -0.6f}, {-0.4f, -0.6f}, + { 0.6f, 0.6f}, {0.5f, 0.6f}, {0.5f, 0.6f}, {0.5f, -0.6f}, {0.5f, -0.6f}, {0.51f, -0.6f}, + }}, 20.0f, 1.0f, LineGL2D::CapStyle::Round, true, {}, // TODO no difference + true, "joint-angles-short-cap.tga"}, + {"joint angles, short cap, acute", {InPlaceInit, { + { 0.6f, 0.8f}, {0.0f, 0.6f}, {0.0f, 0.6f}, {0.8f, 0.6f}, + { 0.6f, 0.2f}, {0.0f, 0.05f}, {0.0f, 0.05f}, {0.8f, 0.05f}, + { 0.6f, -0.35f}, {0.0f, -0.45f}, {0.0f, -0.45f}, {0.8f, -0.45f}, + { 0.6f, -0.8f}, {0.0f, -0.8f}, {0.0f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, false, {}, + true, "joint-angles-short-cap-acute.tga"}, + {"joint angles, short cap, acute reverse direction", {InPlaceInit, { + /* Same as "joint angles, short cap, acute" */ + { 0.6f, 0.8f}, {0.0f, 0.6f}, {0.0f, 0.6f}, {0.8f, 0.6f}, + { 0.6f, 0.2f}, {0.0f, 0.05f}, {0.0f, 0.05f}, {0.8f, 0.05f}, + { 0.6f, -0.35f}, {0.0f, -0.45f}, {0.0f, -0.45f}, {0.8f, -0.45f}, + { 0.6f, -0.8f}, {0.0f, -0.8f}, {0.0f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 0.0f, {}, true, {}, + true, "joint-angles-short-cap-acute.tga"}, + {"joint angles, short cap, acute, round", {InPlaceInit, { + /* Same as "joint angles, short cap, acute" */ + { 0.6f, 0.8f}, {0.0f, 0.6f}, {0.0f, 0.6f}, {0.8f, 0.6f}, + { 0.6f, 0.2f}, {0.0f, 0.05f}, {0.0f, 0.05f}, {0.8f, 0.05f}, + { 0.6f, -0.35f}, {0.0f, -0.45f}, {0.0f, -0.45f}, {0.8f, -0.45f}, + { 0.6f, -0.8f}, {0.0f, -0.8f}, {0.0f, -0.8f}, {0.8f, -0.8f}, + }}, 10.0f, 1.0f, LineGL2D::CapStyle::Round, false, {}, + true, "joint-angles-short-cap-acute-round.tga"}, }; LineGLTest::LineGLTest() { @@ -655,7 +784,7 @@ void LineGLTest::renderTeardown() { _color = GL::Renderbuffer{NoCreate}; } -template GL::Mesh generateLineMesh(Containers::ArrayView> lineSegments) { +template GL::Mesh generateLineMesh(Containers::StridedArrayView1D> lineSegments) { struct Vertex { VectorTypeFor previousPosition; VectorTypeFor position; @@ -663,7 +792,8 @@ template GL::Mesh generateLineMesh(Containers::ArrayView }; CORRADE_INTERNAL_ASSERT(lineSegments.size() % 2 == 0); - Containers::Array vertices{NoInit, lineSegments.size()*2}; + /* Not NoInit, because we're subsequently checking for NaNs */ + Containers::Array vertices{ValueInit, 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]; @@ -766,6 +896,13 @@ template void LineGLTest::renderDefaults2D() { .setFlags(flag)}; shader.setViewportSize(Vector2{RenderSize}); + /* Enabling blending and a half-transparent color -- there should be no + overlaps */ + GL::Renderer::enable(GL::Renderer::Feature::Blending); + GL::Renderer::setBlendFunction( + GL::Renderer::BlendFunction::One, + GL::Renderer::BlendFunction::OneMinusSourceAlpha); + if(flag == LineGL2D::Flag{}) { shader.draw(lines); } @@ -789,6 +926,8 @@ template void LineGLTest::renderDefaults2D() { #endif else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + GL::Renderer::disable(GL::Renderer::Feature::Blending); + MAGNUM_VERIFY_NO_GL_ERROR(); if(!(_manager.loadState("AnyImageImporter") & PluginManager::LoadState::Loaded) || @@ -817,19 +956,30 @@ template void LineGLTest::render2D() { } #endif - GL::Mesh lines = generateLineMesh<2>(data.lineSegments); + Containers::Array transformedLineSegments{NoInit, data.lineSegments.size()}; + Utility::copy(data.lineSegments, transformedLineSegments); + for(Vector2& i: transformedLineSegments) + i = data.transform.transformPoint(i); + + GL::Mesh lines = generateLineMesh<2>( + data.reverse ? stridedArrayView(transformedLineSegments).flipped<0>() : transformedLineSegments); LineGL2D shader{LineGL2D::Configuration{} - .setFlags(flag)}; + .setFlags(flag) + .setCapStyle(data.capStyle)}; shader.setViewportSize(Vector2{RenderSize}); shader .setWidth(data.width) .setSmoothness(data.smoothness) - // .setBackgroundColor(0xff0000ff_rgbaf) - // .setColor(0x557766_rgbf) - ; + .setTransformationProjectionMatrix(data.transform.inverted()) + .setColor(0x80808080_rgbaf); - // TODO test with blending -- there should be no self-intersection + /* Enabling blending and a half-transparent color -- there should be no + overlaps */ + GL::Renderer::enable(GL::Renderer::Feature::Blending); + GL::Renderer::setBlendFunction( + GL::Renderer::BlendFunction::One, + GL::Renderer::BlendFunction::OneMinusSourceAlpha); if(flag == LineGL2D::Flag{}) { shader.draw(lines); @@ -854,17 +1004,27 @@ template void LineGLTest::render2D() { #endif else CORRADE_INTERNAL_ASSERT_UNREACHABLE(); + GL::Renderer::disable(GL::Renderer::Feature::Blending); + 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."); + Image2D image = _framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}); + CORRADE_COMPARE_WITH( /* Dropping the alpha channel, as it's always 1.0 */ - Containers::arrayCast(_framebuffer.read(_framebuffer.viewport(), {PixelFormat::RGBA8Unorm}).pixels()), + Containers::arrayCast(image.pixels()), Utility::Path::join({SHADERS_TEST_DIR, "LineTestFiles", data.expected}), (DebugTools::CompareImageToFile{_manager})); + + { + CORRADE_EXPECT_FAIL_IF(data.expectOverlap, "Rendered with overlapping geometry at the moment."); + CORRADE_COMPARE(Math::max(image.pixels().asContiguous()), 0x888888ff_rgba); + } + } }}}} diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute-overlapping-cap.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute-overlapping-cap.tga new file mode 100644 index 000000000..173e6063b Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute-overlapping-cap.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute-round-caps.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute-round-caps.tga new file mode 100644 index 000000000..ba103de2d Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute-round-caps.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute.tga new file mode 100644 index 000000000..5a29e1f70 Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-acute.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse-round-caps.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse-round-caps.tga new file mode 100644 index 000000000..62003727c Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse-round-caps.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse.tga index a63a97739..cdb5db8e1 100644 Binary files a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse.tga and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-obtuse.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap-acute-round.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap-acute-round.tga new file mode 100644 index 000000000..77e5c476a Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap-acute-round.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap-acute.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap-acute.tga new file mode 100644 index 000000000..173e6063b Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap-acute.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap.tga b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap.tga new file mode 100644 index 000000000..0a197dca6 Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/joint-angles-short-cap.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/line-caps-round.tga b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-round.tga new file mode 100644 index 000000000..c0889887a Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-round.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/line-caps-square-flat.tga b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-square-flat.tga new file mode 100644 index 000000000..b34e9f723 Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-square-flat.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/line-caps-square.tga b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-square.tga new file mode 100644 index 000000000..5b87a4aab Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-square.tga differ diff --git a/src/Magnum/Shaders/Test/LineTestFiles/line-caps-triangle.tga b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-triangle.tga new file mode 100644 index 000000000..77c3179d5 Binary files /dev/null and b/src/Magnum/Shaders/Test/LineTestFiles/line-caps-triangle.tga differ