summaryrefslogtreecommitdiff
path: root/src/location/quickmapitems/rhi/shaders/polyline.vert
diff options
context:
space:
mode:
Diffstat (limited to 'src/location/quickmapitems/rhi/shaders/polyline.vert')
-rw-r--r--src/location/quickmapitems/rhi/shaders/polyline.vert104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/location/quickmapitems/rhi/shaders/polyline.vert b/src/location/quickmapitems/rhi/shaders/polyline.vert
new file mode 100644
index 00000000..27b69b60
--- /dev/null
+++ b/src/location/quickmapitems/rhi/shaders/polyline.vert
@@ -0,0 +1,104 @@
+#version 440
+
+layout(location = 0) in vec4 vertex;
+layout(location = 1) in vec4 previous;
+layout(location = 2) in vec4 next;
+layout(location = 3) in float direction;
+layout(location = 4) in float triangletype;
+layout(location = 5) in float vertextype; // -1.0 if it is the "left" end of the segment, 1.0 if it is the "right" end.
+layout(location = 0) out vec4 primitivecolor;
+
+layout(std140, binding = 0) uniform buf {
+ mat4 qt_Matrix;
+ mat4 mapProjection;
+ vec4 center;
+ vec4 center_lowpart;
+ float lineWidth;
+ float aspect;
+ int miter; // currently unused
+ vec4 color;
+ float wrapOffset;
+};
+
+
+vec4 wrapped(in vec4 v) { return vec4(v.x + wrapOffset, v.y, 0.0, 1.0); }
+void main() { // ln 22
+ primitivecolor = color;
+ vec2 aspectVec = vec2(aspect, 1.0);
+ mat4 projViewModel = qt_Matrix * mapProjection;
+ vec4 cur = wrapped(vertex) - center;
+ cur = cur - center_lowpart;
+ vec4 prev = wrapped(previous) - center;
+ prev = prev - center_lowpart;
+ vec4 nex = wrapped(next) - center;
+ nex = nex - center_lowpart;
+
+ vec4 centerProjected = projViewModel * (center + vec4(0.0, 0.0, 0.0, 1.0));
+ vec4 previousProjected = projViewModel * prev;
+ vec4 currentProjected = projViewModel * cur;
+ vec4 nextProjected = projViewModel * nex;
+
+ //get 2D screen space with W divide and aspect correction
+ vec2 currentScreen = (currentProjected.xy / currentProjected.w) * aspectVec;
+ vec2 previousScreen = (previousProjected.xy / previousProjected.w) * aspectVec;
+ vec2 nextScreen = (nextProjected.xy / nextProjected.w) * aspectVec;
+ float len = (lineWidth);
+ float orientation = direction;
+ bool clipped = false;
+ bool otherEndBelowFrustum = false;
+ //starting point uses (next - current)
+ vec2 dir = vec2(0.0);
+ if (vertextype < 0.0) {
+ dir = normalize(nextScreen - currentScreen);
+ if (nextProjected.z < 0.0) dir = -dir;
+ } else {
+ dir = normalize(currentScreen - previousScreen);
+ if (previousProjected.z < 0.0) dir = -dir;
+ }
+// first, clip current, and make sure currentProjected.z is > 0
+ if (currentProjected.z < 0.0) {
+ if ((nextProjected.z > 0.0 && vertextype < 0.0) || (vertextype > 0.0 && previousProjected.z > 0.0)) {
+ dir = -dir;
+ clipped = true;
+ if (vertextype < 0.0 && nextProjected.y / nextProjected.w < -1.0) otherEndBelowFrustum = true;
+ else if (vertextype > 0.0 && previousProjected.y / previousProjected.w < -1.0) otherEndBelowFrustum = true;
+ } else {
+ primitivecolor = vec4(0.0,0.0,0.0,0.0);
+ gl_Position = vec4(-10000000.0, -1000000000.0, -1000000000.0, 1); // get the vertex out of the way if the segment is fully invisible
+ return;
+ }
+ } else if (triangletype < 2.0) { // vertex in the view, try to miter
+ //get directions from (C - B) and (B - A)
+ vec2 dirA = normalize((currentScreen - previousScreen));
+ if (previousProjected.z < 0.0) dirA = -dirA;
+ vec2 dirB = normalize((nextScreen - currentScreen));
+ //now compute the miter join normal and length
+ if (nextProjected.z < 0.0) dirB = -dirB;
+ vec2 tangent = normalize(dirA + dirB);
+ vec2 perp = vec2(-dirA.y, dirA.x);
+ vec2 vmiter = vec2(-tangent.y, tangent.x);
+ len = lineWidth / dot(vmiter, perp);
+// The following is an attempt to have a segment-length based miter threshold.
+// A mediocre workaround until better mitering will be added.
+ float lenTreshold = clamp( min(length((currentProjected.xy - previousProjected.xy) / aspectVec),
+ length((nextProjected.xy - currentProjected.xy) / aspectVec)), 3.0, 6.0 ) * 0.5;
+ if (len < lineWidth * lenTreshold && len > -lineWidth * lenTreshold) {
+ dir = tangent;
+ } else {
+ len = lineWidth;
+ }
+ }
+ vec4 offset;
+ if (!clipped) {
+ vec2 normal = normalize(vec2(-dir.y, dir.x));
+ normal *= len; // fracZL apparently was needed before the (-2.0 / qt_Matrix[1][1]) factor was introduced
+ normal /= aspectVec; // straighten the normal up again
+ float scaleFactor = currentProjected.w / centerProjected.w;
+ offset = vec4(normal * orientation * scaleFactor * (centerProjected.w / (-2.0 / qt_Matrix[1][1])), 0.0, 0.0); // ToDo: figure out why (-2.0 / qt_Matrix[1][1]), that is empirically what works
+ gl_Position = currentProjected + offset;
+ } else {
+ if (otherEndBelowFrustum) offset = vec4((dir * 1.0) / aspectVec, 0.0, 0.0); // the if is necessary otherwise it seems the direction vector still flips in some obscure cases.
+ else offset = vec4((dir * 500000000000.0) / aspectVec, 0.0, 0.0); // Hack alert: just 1 triangle, long enough to look like a rectangle.
+ if (vertextype < 0.0) gl_Position = nextProjected - offset; else gl_Position = previousProjected + offset;
+ }
+}