From fb71860a036965a796f06430b71a905ef7424b4d Mon Sep 17 00:00:00 2001 From: GaborFarkas Date: Tue, 14 Jun 2016 14:25:21 +0200 Subject: [PATCH] Adding linestring cap support --- src/ol/render/webgl/imagereplay/index.js | 78 ++++++++++++++++--- .../render/webgl/webgllinestringdefault.glsl | 30 ++++++- .../webgl/webgllinestringdefaultshader.js | 12 +-- .../render/webgl/webglpolygondefaultshader.js | 8 +- 4 files changed, 107 insertions(+), 21 deletions(-) diff --git a/src/ol/render/webgl/imagereplay/index.js b/src/ol/render/webgl/imagereplay/index.js index 4a67a57b09..50aea34db9 100644 --- a/src/ol/render/webgl/imagereplay/index.js +++ b/src/ol/render/webgl/imagereplay/index.js @@ -140,14 +140,15 @@ goog.inherits(ol.render.webgl.Replay, ol.render.VectorContext); ol.render.webgl.LineStringInstruction = { BEGIN_LINE: 0, END_LINE: 1, - SQUARE_CAP: 2, + BEGIN_LINE_CAP: 2, BEVEL_FIRST: 3, BEVEL_SECOND: 4, MITER_BOTTOM: 5, MITER_TOP: 6, ROUND_JOIN: 7, ROUND_CAP: 8, - ROUND_BOTH: 9 + ROUND_BOTH: 9, + END_LINE_CAP : 10 }; ol.render.webgl.Replay.prototype.getDeleteResourcesFunction = goog.abstractMethod; @@ -1041,9 +1042,8 @@ ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoord var i, ii; var numVertices = this.vertices_.length; var numIndices = this.indices_.length; - var lineJoin = this.state_.lineJoin; - var verticesPerPoint = lineJoin === 'bevel' ? 3 : 4; - //var lineCap = this.state_.lineCap; + var lineJoin = this.state_.lineJoin === 'bevel' ? false : true; + var lineCap = this.state_.lineCap === 'butt' ? false : true; var closed = this.isClosed_(flatCoordinates, offset, end, stride); var lastIndex; var lastSign = 1; @@ -1064,15 +1064,46 @@ ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoord //A closed line! Complete the circle. tempP = [flatCoordinates[end - stride] - this.origin_[0], flatCoordinates[end - stride + 1] - this.origin_[1]]; } else { - //Add the first two vertices. + //Add the first two/four vertices. p0 = undefined; + + if (lineCap) { + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = p2[0]; + this.vertices_[numVertices++] = p2[1]; + this.vertices_[numVertices++] = lastSign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.BEGIN_LINE_CAP; + + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = p2[0]; + this.vertices_[numVertices++] = p2[1]; + this.vertices_[numVertices++] = -lastSign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.BEGIN_LINE_CAP; + + this.indices_[numIndices++] = n + 2; + this.indices_[numIndices++] = n; + this.indices_[numIndices++] = n + 1; + + this.indices_[numIndices++] = n + 1; + this.indices_[numIndices++] = n + 3; + this.indices_[numIndices++] = n + 2; + + n = n + 2; + } + this.vertices_[numVertices++] = 0; this.vertices_[numVertices++] = 0; this.vertices_[numVertices++] = p1[0]; this.vertices_[numVertices++] = p1[1]; this.vertices_[numVertices++] = p2[0]; this.vertices_[numVertices++] = p2[1]; - this.vertices_[numVertices++] = 1; + this.vertices_[numVertices++] = lastSign; this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.BEGIN_LINE; this.vertices_[numVertices++] = 0; @@ -1081,7 +1112,7 @@ ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoord this.vertices_[numVertices++] = p1[1]; this.vertices_[numVertices++] = p2[0]; this.vertices_[numVertices++] = p2[1]; - this.vertices_[numVertices++] = -1; + this.vertices_[numVertices++] = -lastSign; this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.BEGIN_LINE; lastIndex = n + 1; @@ -1122,6 +1153,35 @@ ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoord this.indices_[numIndices++] = n + 1; this.indices_[numIndices++] = n; + if (lineCap) { + this.vertices_[numVertices++] = p0[0]; + this.vertices_[numVertices++] = p0[1]; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = lastSign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.END_LINE_CAP; + + this.vertices_[numVertices++] = p0[0]; + this.vertices_[numVertices++] = p0[1]; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = 0; + this.vertices_[numVertices++] = -lastSign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.END_LINE_CAP; + + this.indices_[numIndices++] = n + 2; + this.indices_[numIndices++] = n; + this.indices_[numIndices++] = n + 1; + + this.indices_[numIndices++] = n + 1; + this.indices_[numIndices++] = n + 3; + this.indices_[numIndices++] = n + 2; + + } + break; } } else { @@ -1178,7 +1238,7 @@ ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoord lastSign = sign; //Add miter - if (verticesPerPoint === 4) { + if (lineJoin) { this.vertices_[numVertices++] = p0[0]; this.vertices_[numVertices++] = p0[1]; this.vertices_[numVertices++] = p1[0]; diff --git a/src/ol/render/webgl/webgllinestringdefault.glsl b/src/ol/render/webgl/webgllinestringdefault.glsl index 67c2c5937a..d48c34eb54 100644 --- a/src/ol/render/webgl/webgllinestringdefault.glsl +++ b/src/ol/render/webgl/webgllinestringdefault.glsl @@ -30,14 +30,16 @@ void main(void) { vec2 dirVect = a_nextPos - a_position; vec2 normal = normalize(vec2(-dirVect.y, dirVect.x)); offset = v_halfWidth * normal * a_direction; - if (a_instruction == 4. && (u_round == 7. || u_round == 9.)) { + if ((a_instruction == 4. && (u_round == 7. || u_round == 9.)) || + (a_instruction == 0. && (u_round == 8. || u_round == 9.))) { v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.); } } else if (a_instruction == 1. || a_instruction == 3.) { vec2 dirVect = a_lastPos - a_position; vec2 normal = normalize(vec2(dirVect.y, -dirVect.x)); offset = v_halfWidth * normal * a_direction; - if (a_instruction == 3. && (u_round == 7. || u_round == 9.)) { + if ((a_instruction == 3. && (u_round == 7. || u_round == 9.)) || + (a_instruction == 1. && (u_round == 8. || u_round == 9.))) { v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.); } } else if (a_instruction == 5. || a_instruction == 6.) { @@ -77,6 +79,30 @@ void main(void) { offset = tmpNormal * a_direction * v_halfWidth; } } + } else if (a_instruction == 2.) { + vec2 dirVect = a_position - a_nextPos; + vec2 firstNormal = normalize(dirVect); + vec2 secondNormal = vec2(firstNormal.y * a_direction, -firstNormal.x * a_direction); + vec2 hypotenuse = normalize(firstNormal - secondNormal); + vec2 normal = vec2(hypotenuse.y * a_direction, -hypotenuse.x * a_direction); + float length = sqrt(v_halfWidth * v_halfWidth * 2.0); + offset = normal * length; + if (u_round == 8. || u_round == 9.) { + v_round = 1.0; + v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.); + } + } else if (a_instruction == 10.) { + vec2 dirVect = a_position - a_lastPos; + vec2 firstNormal = normalize(dirVect); + vec2 secondNormal = vec2(-firstNormal.y * a_direction, firstNormal.x * a_direction); + vec2 hypotenuse = normalize(firstNormal - secondNormal); + vec2 normal = vec2(-hypotenuse.y * a_direction, hypotenuse.x * a_direction); + float length = sqrt(v_halfWidth * v_halfWidth * 2.0); + offset = normal * length; + if (u_round == 8. || u_round == 9.) { + v_round = 1.0; + v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.); + } } vec4 offsets = u_offsetScaleMatrix * vec4(offset, 0., 0.); gl_Position = projPos + offsets; diff --git a/src/ol/render/webgl/webgllinestringdefaultshader.js b/src/ol/render/webgl/webgllinestringdefaultshader.js index 110a3b1600..5050d095f5 100644 --- a/src/ol/render/webgl/webgllinestringdefaultshader.js +++ b/src/ol/render/webgl/webgllinestringdefaultshader.js @@ -13,9 +13,9 @@ goog.require('ol.webgl.shader'); * @struct */ ol.render.webgl.linestringreplay.shader.DefaultFragment = function() { - goog.base(this, ol.render.webgl.linestringreplay.shader.DefaultFragment.SOURCE); + ol.webgl.shader.Fragment.call(this, ol.render.webgl.linestringreplay.shader.DefaultFragment.SOURCE); }; -goog.inherits(ol.render.webgl.linestringreplay.shader.DefaultFragment, ol.webgl.shader.Fragment); +ol.inherits(ol.render.webgl.linestringreplay.shader.DefaultFragment, ol.webgl.shader.Fragment); goog.addSingletonGetter(ol.render.webgl.linestringreplay.shader.DefaultFragment); @@ -48,9 +48,9 @@ ol.render.webgl.linestringreplay.shader.DefaultFragment.SOURCE = goog.DEBUG ? * @struct */ ol.render.webgl.linestringreplay.shader.DefaultVertex = function() { - goog.base(this, ol.render.webgl.linestringreplay.shader.DefaultVertex.SOURCE); + ol.webgl.shader.Vertex.call(this, ol.render.webgl.linestringreplay.shader.DefaultVertex.SOURCE); }; -goog.inherits(ol.render.webgl.linestringreplay.shader.DefaultVertex, ol.webgl.shader.Vertex); +ol.inherits(ol.render.webgl.linestringreplay.shader.DefaultVertex, ol.webgl.shader.Vertex); goog.addSingletonGetter(ol.render.webgl.linestringreplay.shader.DefaultVertex); @@ -58,14 +58,14 @@ goog.addSingletonGetter(ol.render.webgl.linestringreplay.shader.DefaultVertex); * @const * @type {string} */ -ol.render.webgl.linestringreplay.shader.DefaultVertex.DEBUG_SOURCE = 'varying float v_round;\nvarying vec4 v_roundVertex;\nvarying float v_halfWidth;\n\n\nattribute vec2 a_lastPos;\nattribute vec2 a_position;\nattribute vec2 a_nextPos;\nattribute float a_direction;\nattribute float a_instruction;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform float u_lineWidth;\nuniform float u_miterLimit;\nuniform float u_round;\n\nvoid main(void) {\n v_halfWidth = u_lineWidth / 2.0;\n vec2 offset;\n v_round = 0.0;\n vec4 projPos = u_projectionMatrix * vec4(a_position, 0., 1.);\n if (a_instruction == 0. || a_instruction == 4.) {\n vec2 dirVect = a_nextPos - a_position;\n vec2 normal = normalize(vec2(-dirVect.y, dirVect.x));\n offset = v_halfWidth * normal * a_direction;\n if (a_instruction == 4. && (u_round == 7. || u_round == 9.)) {\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n }\n } else if (a_instruction == 1. || a_instruction == 3.) {\n vec2 dirVect = a_lastPos - a_position;\n vec2 normal = normalize(vec2(dirVect.y, -dirVect.x));\n offset = v_halfWidth * normal * a_direction;\n if (a_instruction == 3. && (u_round == 7. || u_round == 9.)) {\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n }\n } else if (a_instruction == 5. || a_instruction == 6.) {\n vec2 dirVect = a_nextPos - a_position;\n vec2 tmpNormal = normalize(vec2(-dirVect.y, dirVect.x));\n vec2 tangent = normalize(normalize(a_nextPos - a_position) + normalize(a_position - a_lastPos));\n vec2 normal = vec2(tangent.y, -tangent.x);\n float miterLength = v_halfWidth / dot(normal, tmpNormal);\n if (a_instruction == 6.) {\n if (u_round == 7. || u_round == 9.) {\n offset = normal * a_direction * miterLength;\n v_round = 1.0;\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n } else if (miterLength > u_miterLimit) {\n offset = tmpNormal * a_direction * v_halfWidth;\n } else {\n offset = normal * a_direction * miterLength;\n }\n } else if (a_instruction == 5.) {\n offset = normal * a_direction * miterLength;\n vec4 defaultOffset = u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n vec4 firstProjPos = u_projectionMatrix * vec4(a_lastPos, 0., 1.) + defaultOffset;\n vec4 secondProjPos = projPos + defaultOffset;\n vec4 thirdProjPos = u_projectionMatrix * vec4(a_nextPos, 0., 1.) + defaultOffset;\n float firstSegLength = distance(secondProjPos.xy, firstProjPos.xy);\n float secondSegLength = distance(thirdProjPos.xy, secondProjPos.xy);\n float miterSegLength = distance(secondProjPos.xy, vec4(projPos + u_offsetScaleMatrix * vec4(offset, 0., 0.)).xy);\n //TODO: Write a more accurate method for identifying sharp angles.\n if (miterSegLength > min(firstSegLength, secondSegLength)) {\n if (firstSegLength < secondSegLength) {\n dirVect = a_lastPos - a_position;\n tmpNormal = normalize(vec2(dirVect.y, -dirVect.x));\n projPos = firstProjPos - defaultOffset;\n } else {\n projPos = thirdProjPos - defaultOffset;\n }\n offset = tmpNormal * a_direction * v_halfWidth;\n }\n }\n }\n vec4 offsets = u_offsetScaleMatrix * vec4(offset, 0., 0.);\n gl_Position = projPos + offsets;\n}\n\n\n'; +ol.render.webgl.linestringreplay.shader.DefaultVertex.DEBUG_SOURCE = 'varying float v_round;\nvarying vec4 v_roundVertex;\nvarying float v_halfWidth;\n\n\nattribute vec2 a_lastPos;\nattribute vec2 a_position;\nattribute vec2 a_nextPos;\nattribute float a_direction;\nattribute float a_instruction;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform float u_lineWidth;\nuniform float u_miterLimit;\nuniform float u_round;\n\nvoid main(void) {\n v_halfWidth = u_lineWidth / 2.0;\n vec2 offset;\n v_round = 0.0;\n vec4 projPos = u_projectionMatrix * vec4(a_position, 0., 1.);\n if (a_instruction == 0. || a_instruction == 4.) {\n vec2 dirVect = a_nextPos - a_position;\n vec2 normal = normalize(vec2(-dirVect.y, dirVect.x));\n offset = v_halfWidth * normal * a_direction;\n if ((a_instruction == 4. && (u_round == 7. || u_round == 9.)) ||\n (a_instruction == 0. && (u_round == 8. || u_round == 9.))) {\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n }\n } else if (a_instruction == 1. || a_instruction == 3.) {\n vec2 dirVect = a_lastPos - a_position;\n vec2 normal = normalize(vec2(dirVect.y, -dirVect.x));\n offset = v_halfWidth * normal * a_direction;\n if ((a_instruction == 3. && (u_round == 7. || u_round == 9.)) ||\n (a_instruction == 1. && (u_round == 8. || u_round == 9.))) {\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n }\n } else if (a_instruction == 5. || a_instruction == 6.) {\n vec2 dirVect = a_nextPos - a_position;\n vec2 tmpNormal = normalize(vec2(-dirVect.y, dirVect.x));\n vec2 tangent = normalize(normalize(a_nextPos - a_position) + normalize(a_position - a_lastPos));\n vec2 normal = vec2(tangent.y, -tangent.x);\n float miterLength = v_halfWidth / dot(normal, tmpNormal);\n if (a_instruction == 6.) {\n if (u_round == 7. || u_round == 9.) {\n offset = normal * a_direction * miterLength;\n v_round = 1.0;\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n } else if (miterLength > u_miterLimit) {\n offset = tmpNormal * a_direction * v_halfWidth;\n } else {\n offset = normal * a_direction * miterLength;\n }\n } else if (a_instruction == 5.) {\n offset = normal * a_direction * miterLength;\n vec4 defaultOffset = u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n vec4 firstProjPos = u_projectionMatrix * vec4(a_lastPos, 0., 1.) + defaultOffset;\n vec4 secondProjPos = projPos + defaultOffset;\n vec4 thirdProjPos = u_projectionMatrix * vec4(a_nextPos, 0., 1.) + defaultOffset;\n float firstSegLength = distance(secondProjPos.xy, firstProjPos.xy);\n float secondSegLength = distance(thirdProjPos.xy, secondProjPos.xy);\n float miterSegLength = distance(secondProjPos.xy, vec4(projPos + u_offsetScaleMatrix * vec4(offset, 0., 0.)).xy);\n //TODO: Write a more accurate method for identifying sharp angles.\n if (miterSegLength > min(firstSegLength, secondSegLength)) {\n if (firstSegLength < secondSegLength) {\n dirVect = a_lastPos - a_position;\n tmpNormal = normalize(vec2(dirVect.y, -dirVect.x));\n projPos = firstProjPos - defaultOffset;\n } else {\n projPos = thirdProjPos - defaultOffset;\n }\n offset = tmpNormal * a_direction * v_halfWidth;\n }\n }\n } else if (a_instruction == 2.) {\n vec2 dirVect = a_position - a_nextPos;\n vec2 firstNormal = normalize(dirVect);\n vec2 secondNormal = vec2(firstNormal.y * a_direction, -firstNormal.x * a_direction);\n vec2 hypotenuse = normalize(firstNormal - secondNormal);\n vec2 normal = vec2(hypotenuse.y * a_direction, -hypotenuse.x * a_direction);\n float length = sqrt(v_halfWidth * v_halfWidth * 2.0);\n offset = normal * length;\n if (u_round == 8. || u_round == 9.) {\n v_round = 1.0;\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n }\n } else if (a_instruction == 10.) {\n vec2 dirVect = a_position - a_lastPos;\n vec2 firstNormal = normalize(dirVect);\n vec2 secondNormal = vec2(-firstNormal.y * a_direction, firstNormal.x * a_direction);\n vec2 hypotenuse = normalize(firstNormal - secondNormal);\n vec2 normal = vec2(-hypotenuse.y * a_direction, hypotenuse.x * a_direction);\n float length = sqrt(v_halfWidth * v_halfWidth * 2.0);\n offset = normal * length;\n if (u_round == 8. || u_round == 9.) {\n v_round = 1.0;\n v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.);\n }\n }\n vec4 offsets = u_offsetScaleMatrix * vec4(offset, 0., 0.);\n gl_Position = projPos + offsets;\n}\n\n\n'; /** * @const * @type {string} */ -ol.render.webgl.linestringreplay.shader.DefaultVertex.OPTIMIZED_SOURCE = 'varying float a;varying vec4 b;varying float c;attribute vec2 d;attribute vec2 e;attribute vec2 f;attribute float g;attribute float h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;uniform float m;void main(void){c=k/2.0;vec2 offset;a=0.0;vec4 projPos=i*vec4(e,0.,1.);if(h==0.||h==4.){vec2 dirVect=f-e;vec2 normal=normalize(vec2(-dirVect.y,dirVect.x));offset=c*normal*g;if(h==4.&&(m==7.||m==9.)){b=projPos+j*vec4(0.,0.,0.,0.);}} else if(h==1.||h==3.){vec2 dirVect=d-e;vec2 normal=normalize(vec2(dirVect.y,-dirVect.x));offset=c*normal*g;if(h==3.&&(m==7.||m==9.)){b=projPos+j*vec4(0.,0.,0.,0.);}} else if(h==5.||h==6.){vec2 dirVect=f-e;vec2 tmpNormal=normalize(vec2(-dirVect.y,dirVect.x));vec2 tangent=normalize(normalize(f-e)+normalize(e-d));vec2 normal=vec2(tangent.y,-tangent.x);float miterLength=c/dot(normal,tmpNormal);if(h==6.){if(m==7.||m==9.){offset=normal*g*miterLength;a=1.0;b=projPos+j*vec4(0.,0.,0.,0.);}else if(miterLength>l){offset=tmpNormal*g*c;}else{offset=normal*g*miterLength;}} else if(h==5.){offset=normal*g*miterLength;vec4 defaultOffset=j*vec4(0.,0.,0.,0.);vec4 firstProjPos=i*vec4(d,0.,1.)+defaultOffset;vec4 secondProjPos=projPos+defaultOffset;vec4 thirdProjPos=i*vec4(f,0.,1.)+defaultOffset;float firstSegLength=distance(secondProjPos.xy,firstProjPos.xy);float secondSegLength=distance(thirdProjPos.xy,secondProjPos.xy);float miterSegLength=distance(secondProjPos.xy,vec4(projPos+j*vec4(offset,0.,0.)).xy);if(miterSegLength>min(firstSegLength,secondSegLength)){if(firstSegLength