createDrawLineSegmentsCommand = function(regl, opts) {
const DEFAULT_LINE_COLOR = [0.3, 0.4, 0.9, 0.9];
const DEFAULT_LINE_WIDTH = 2;
const unsplitBuffer = regl.buffer([[0, -1], [1, -1], [0, 1], [1, 1]]);
return regl({
vert: `
precision highp float;
${opts.positionFunction}
uniform float uAspect, uScaleFactor, uMitreLimit;
attribute vec3 aP0, aP1, aP2, aP3;
attribute float aWidth1, aWidth2;
attribute vec4 aColor1, aColor2;
attribute vec2 aLinePosition;
varying vec4 vColor;
varying vec2 vStrokeEdges;
vec2 lineNormal (vec4 a, vec4 b, float aspect) {
return normalize((a.yx / a.w - b.yx / b.w) * vec2(1, aspect));
}
void main () {
bool isStart = aLinePosition.x < 0.5;
float lineWidth = isStart ? aWidth1 : aWidth2;
vColor = isStart ? aColor1 : aColor2;
// Compute the position of two adjacent points
vec4 p1 = computePosition(aP1);
vec4 p2 = computePosition(aP2);
// Compute the position of an adjacent point--the preceeding point
// if the start of the segment, the next point otherwise.
vec4 pE = computePosition(isStart ? aP0 : aP3);
vec2 n12 = lineNormal(p1, p2, uAspect);
vec2 t12 = vec2(-n12.y, n12);
// Compute the normal of the adjacent (previous or next) segment
vec2 nE = lineNormal(isStart ? pE : p2, isStart ? p1 : pE, uAspect);
// Compute the bisector normal at the vertex
vec2 n = normalize(nE + n12);
// Compute the orientation of the normal with respect to the which
// corner of the line segment quad we're on
float orientation = sign(aLinePosition.y) * (isStart ? 1.0 : -1.0);
// Scale the normal. Unfortunately we need to jump through a bunch of hoops here in order to
// get the difference between > and >= just right so that straight lines don't flip the bevel
// incorrectly.
n *= (dot(t12, n) * (isStart ? 1.0 : -1.0) > 0.0 ? 1.0 : -1.0) * (isStart ? orientation : -orientation);
// Compute the extension of the full mitre
float mitreSize = 1.0 / dot(n, n12);
// Scale the mean normal, then step back along
n *= mitreSize;
float maxMitre = -dot(n, vec2(-nE.y, nE.x)) * orientation;
mitreSize = max(0.0, min(maxMitre, mitreSize - uMitreLimit));
// If we've overextended beyond the mitre limit, step back along
// the segment tangent by the necessary amount
n -= t12 * orientation * mitreSize;
gl_Position = mix(p1, p2, aLinePosition.x);
gl_Position.xy += (n / vec2(-uAspect, 1) * aLinePosition.y * lineWidth) * gl_Position.w * uScaleFactor;
}`,
attributes: {
aLinePosition: unsplitBuffer,
aP0: attr('position', null, 3, 0),
aP1: attr('position', null, 3, 1),
aP2: attr('position', null, 3, 2),
aP3: attr('position', null, 3, 3),
aWidth1: attr('width', DEFAULT_LINE_WIDTH, 1, 1),
aWidth2: attr('width', DEFAULT_LINE_WIDTH, 1, 2),
aColor1: attr('color', DEFAULT_LINE_COLOR, 4, 1),
aColor2: attr('color', DEFAULT_LINE_COLOR, 4, 2)
},
instances: (ctx, props) => {
if (props.count !== undefined) return props.count - 3;
if (
props.position[0] !== undefined &&
props.position[0].length !== undefined
)
return props.position.length - 3;
if (props.position.length !== undefined)
return props.position.length / 3 - 3;
return null;
},
count: 4
});
}