diff --git a/src/ol/render/webgl/imagereplay/index.js b/src/ol/render/webgl/imagereplay/index.js index 1d6f5e69af..9306999eac 100644 --- a/src/ol/render/webgl/imagereplay/index.js +++ b/src/ol/render/webgl/imagereplay/index.js @@ -104,6 +104,20 @@ ol.render.webgl.ImageReplay = function(tolerance, maxExtent) { */ this.indicesBuffer_ = null; + /** + * Start index per feature (the index). + * @type {Array.} + * @private + */ + this.startIndices_ = []; + + /** + * Start index per feature (the feature). + * @type {Array.} + * @private + */ + this.startIndicesFeature_ = []; + /** * @type {Array.} * @private @@ -119,6 +133,23 @@ ol.render.webgl.ImageReplay = function(tolerance, maxExtent) { }; goog.inherits(ol.render.webgl.Replay, ol.render.VectorContext); + +/** + * @enum {number} + */ +ol.render.webgl.LineStringInstruction = { + BEGIN_LINE: 0, + END_LINE: 1, + SQUARE_CAP: 2, + BEVEL_FIRST: 3, + BEVEL_SECOND: 4, + MITER_BOTTOM: 5, + MITER_TOP: 6, + ROUND_JOIN: 7, + ROUND_CAP: 8, + ROUND_BOTH: 9 +}; + ol.render.webgl.Replay.prototype.getDeleteResourcesFunction = goog.abstractMethod; ol.render.webgl.Replay.prototype.finish = goog.abstractMethod; @@ -162,7 +193,7 @@ ol.render.webgl.Replay.prototype.replay = function(context, 'indicesBuffer must not be null'); context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); - var locations = this.setUpProgram_(gl, context); + var locations = this.setUpProgram_(gl, context, size); // set the "uniform" values var projectionMatrix = ol.transform.reset(this.projectionMatrix_); @@ -207,6 +238,21 @@ ol.render.webgl.Replay.prototype.replay = function(context, return result; }; +/** + * @private + * @param {WebGLRenderingContext} gl gl. + * @param {number} start Start index. + * @param {number} end End index. + * @param {number} elementType Element type. + * @param {number} elementSize Element Size. + */ +ol.render.webgl.Replay.prototype.drawElements_ = function( + gl, start, end, elementType, elementSize) { + var numItems = end - start; + var offsetInBytes = start * elementSize; + gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes); +}; + /** * @constructor * @extends {ol.render.webgl.Replay} @@ -326,20 +372,6 @@ ol.render.webgl.ImageReplay = function(tolerance, maxExtent) { */ this.hitDetectionTextures_ = []; - /** - * Start index per feature (the index). - * @type {Array.} - * @private - */ - this.startIndices_ = []; - - /** - * Start index per feature (the feature). - * @type {Array.} - * @private - */ - this.startIndicesFeature_ = []; - /** * @type {number|undefined} * @private @@ -620,9 +652,10 @@ ol.render.webgl.ImageReplay.prototype.createTextures_ = function(textures, image * @private * @param {WebGLRenderingContext} gl gl. * @param {ol.webgl.Context} context Context. + * @param {ol.Size} size Size. * @return {ol.render.webgl.imagereplay.shader.Default.Locations} Locations. */ -ol.render.webgl.ImageReplay.prototype.setUpProgram_ = function(gl, context) { +ol.render.webgl.ImageReplay.prototype.setUpProgram_ = function(gl, context, size) { // get the program var fragmentShader = ol.render.webgl.imagereplay.defaultshader.fragment; var vertexShader = ol.render.webgl.imagereplay.defaultshader.vertex; @@ -768,22 +801,6 @@ ol.render.webgl.ImageReplay.prototype.drawReplaySkipping_ = function(gl, skipped }; -/** - * @private - * @param {WebGLRenderingContext} gl gl. - * @param {number} start Start index. - * @param {number} end End index. - * @param {number} elementType Element type. - * @param {number} elementSize Element Size. - */ -ol.render.webgl.ImageReplay.prototype.drawElements_ = function( - gl, start, end, elementType, elementSize) { - var numItems = end - start; - var offsetInBytes = start * elementSize; - gl.drawElements(ol.webgl.TRIANGLES, numItems, elementType, offsetInBytes); -}; - - /** * @private * @param {WebGLRenderingContext} gl gl. @@ -1020,29 +1037,182 @@ goog.inherits(ol.render.webgl.LineStringReplay, ol.render.webgl.Replay); * @private */ ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoordinates, offset, end, stride) { + var i, ii; var numVertices = this.vertices_.length; var numIndices = this.indices_.length; - var n = this.indices_.length > 0 ? this.indices_[numIndices - 1] + 1 : 0; + var lineJoin = this.state_.lineJoin; + var verticesPerPoint = lineJoin === 'bevel' ? 3 : 4; + //var lineCap = this.state_.lineCap; + var closed = this.isClosed_(flatCoordinates, offset, end, stride); + var lastIndex; + var lastSign = 1; + //We need the adjacent vertices to define normals in joins. p0 = last, p1 = current, p2 = next. + //We rotate those points, thus every point is RTE corrected only once. + var p0, p1, p2, tempP; - // Shift the indices to take into account previously handled lines - for (i = offset, ii = end - stride; i < ii; i += stride) { + for (i = offset, ii = end; i < ii; i += stride) { - if (i == offset) { - this.vertices_[numVertices++] = flatCoordinates[i] - this.origin_[0]; - this.vertices_[numVertices++] = flatCoordinates[i + 1] - this.origin_[1]; + var n = numVertices / 8; - i += stride; + tempP = tempP || p1; + p1 = p2 || [flatCoordinates[i] - this.origin_[0], flatCoordinates[i + 1] - this.origin_[1]]; + //First vertex. + if (i === offset) { + p2 = [flatCoordinates[i + stride] - this.origin_[0], flatCoordinates[i + stride + 1] - this.origin_[1]]; + if (closed) { + //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. + p0 = undefined; + 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++] = ol.render.webgl.LineStringInstruction.BEGIN_LINE; + + 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++] = ol.render.webgl.LineStringInstruction.BEGIN_LINE; + + lastIndex = n + 1; + + continue; + } + } else if (i === end - stride) { + //Last vertex. + if (closed) { + p2 = [flatCoordinates[offset] - this.origin_[0], flatCoordinates[offset + 1] - this.origin_[1]]; + } else { + p2 = undefined; + p0 = tempP || p0; + + 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; + + 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; + + this.indices_[numIndices++] = n; + this.indices_[numIndices++] = lastIndex - 1; + this.indices_[numIndices++] = lastIndex; + + this.indices_[numIndices++] = lastIndex; + this.indices_[numIndices++] = n + 1; + this.indices_[numIndices++] = n; + + break; + } + } else { + p2 = [flatCoordinates[i + stride] - this.origin_[0], flatCoordinates[i + stride + 1] - this.origin_[1]]; } + //Sort out duplicate points. + if (ol.array.equals(p1, p2)) continue; + p0 = tempP || p0; + tempP = undefined; + //The sign of the area determines the line segment's orientation. + var sign = ol.geom.flat.orient.linearRingIsClockwise([p0[0], p0[1], p1[0], p1[1], p2[0], p2[1]], 0, 6, 2) + ? 1 : -1; - this.vertices_[numVertices++] = flatCoordinates[i] - this.origin_[0]; - this.vertices_[numVertices++] = flatCoordinates[i + 1] - this.origin_[1]; + this.vertices_[numVertices++] = p0[0]; + this.vertices_[numVertices++] = p0[1]; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = p2[0]; + this.vertices_[numVertices++] = p2[1]; + this.vertices_[numVertices++] = sign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.BEVEL_FIRST; + + this.vertices_[numVertices++] = p0[0]; + this.vertices_[numVertices++] = p0[1]; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = p2[0]; + this.vertices_[numVertices++] = p2[1]; + this.vertices_[numVertices++] = sign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.BEVEL_SECOND; + + this.vertices_[numVertices++] = p0[0]; + this.vertices_[numVertices++] = p0[1]; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = p2[0]; + this.vertices_[numVertices++] = p2[1]; + this.vertices_[numVertices++] = -sign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.MITER_BOTTOM; - this.indices_[numIndices++] = n++; this.indices_[numIndices++] = n; + this.indices_[numIndices++] = lastIndex - 1; + this.indices_[numIndices++] = lastIndex; + + this.indices_[numIndices++] = n + 2; + this.indices_[numIndices++] = n; + this.indices_[numIndices++] = lastSign * sign > 0 ? lastIndex : lastIndex - 1; + + this.indices_[numIndices++] = n; + this.indices_[numIndices++] = n + 2; + this.indices_[numIndices++] = n + 1; + + lastIndex = n + 2; + lastSign = sign; + + //Add miter + if (verticesPerPoint === 4) { + this.vertices_[numVertices++] = p0[0]; + this.vertices_[numVertices++] = p0[1]; + this.vertices_[numVertices++] = p1[0]; + this.vertices_[numVertices++] = p1[1]; + this.vertices_[numVertices++] = p2[0]; + this.vertices_[numVertices++] = p2[1]; + this.vertices_[numVertices++] = sign; + this.vertices_[numVertices++] = ol.render.webgl.LineStringInstruction.MITER_TOP; + + this.indices_[numIndices++] = n + 1; + this.indices_[numIndices++] = n + 3; + this.indices_[numIndices++] = n; + } } }; +/** + * Check if the linestring is a boundary. + * @param {Array.} flatCoordinates Flat coordinates. + * @param {number} offset Offset. + * @param {number} end End. + * @param {number} stride Stride. + * @return {boolean} The linestring is a boundary. + * @private + */ +ol.render.webgl.LineStringReplay.prototype.isClosed_ = function(flatCoordinates, offset, end, stride) { + var lastCoord = end - stride; + if (flatCoordinates[offset] === flatCoordinates[lastCoord] && + flatCoordinates[offset + 1] === flatCoordinates[lastCoord + 1]) { + return true; + } + return false; +}; + /** * @inheritDoc @@ -1050,8 +1220,12 @@ ol.render.webgl.LineStringReplay.prototype.drawCoordinates_ = function(flatCoord ol.render.webgl.LineStringReplay.prototype.drawLineString = function(lineStringGeometry, feature) { var flatCoordinates = lineStringGeometry.getFlatCoordinates(); var stride = lineStringGeometry.getStride(); - this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); + if (flatCoordinates.length > stride) { + this.startIndices_.push(this.indices_.length); + this.startIndicesFeature_.push(feature); + this.drawCoordinates_( + flatCoordinates, 0, flatCoordinates.length, stride); + } }; @@ -1059,13 +1233,12 @@ ol.render.webgl.LineStringReplay.prototype.drawLineString = function(lineStringG * @inheritDoc */ ol.render.webgl.LineStringReplay.prototype.drawMultiLineString = function(multiLineStringGeometry, feature) { + this.startIndices_.push(this.indices_.length); + this.startIndicesFeature_.push(feature); var lineStringGeometries = multiLineStringGeometry.getLineStrings(); var i, ii; for (i = 0, ii = lineStringGeometries.length; i < ii; ++i) { - var flatCoordinates = lineStringGeometries[i].getFlatCoordinates(); - var stride = lineStringGeometries[i].getStride(); - this.drawCoordinates_( - flatCoordinates, 0, flatCoordinates.length, stride); + this.drawLineString(lineStringGeometries[i], feature); } }; @@ -1074,6 +1247,8 @@ ol.render.webgl.LineStringReplay.prototype.drawMultiLineString = function(multiL * @param {ol.webgl.Context} context Context. **/ ol.render.webgl.LineStringReplay.prototype.finish = function(context) { + this.startIndices_.push(this.indices_.length); + // create, bind, and populate the vertices buffer this.verticesBuffer_ = new ol.webgl.Buffer(this.vertices_); context.bindBuffer(goog.webgl.ARRAY_BUFFER, this.verticesBuffer_); @@ -1081,6 +1256,9 @@ ol.render.webgl.LineStringReplay.prototype.finish = function(context) { // create, bind, and populate the indices buffer this.indicesBuffer_ = new ol.webgl.Buffer(this.indices_); context.bindBuffer(goog.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer_); + + this.vertices_ = null; + this.indices_ = null; }; @@ -1108,9 +1286,10 @@ ol.render.webgl.LineStringReplay.prototype.getDeleteResourcesFunction = function * @private * @param {WebGLRenderingContext} gl gl. * @param {ol.webgl.Context} context Context. + * @param {ol.Size} size Size. * @return {ol.render.webgl.linestringreplay.shader.Default.Locations} Locations. */ -ol.render.webgl.LineStringReplay.prototype.setUpProgram_ = function(gl, context) { +ol.render.webgl.LineStringReplay.prototype.setUpProgram_ = function(gl, context, size) { // get the program var fragmentShader, vertexShader; fragmentShader = @@ -1132,12 +1311,37 @@ ol.render.webgl.LineStringReplay.prototype.setUpProgram_ = function(gl, context) context.useProgram(program); // enable the vertex attrib arrays + gl.enableVertexAttribArray(locations.a_lastPos); + gl.vertexAttribPointer(locations.a_lastPos, 2, goog.webgl.FLOAT, + false, 32, 0); + gl.enableVertexAttribArray(locations.a_position); gl.vertexAttribPointer(locations.a_position, 2, goog.webgl.FLOAT, - false, 8, 0); + false, 32, 8); + + gl.enableVertexAttribArray(locations.a_nextPos); + gl.vertexAttribPointer(locations.a_nextPos, 2, goog.webgl.FLOAT, + false, 32, 16); + + gl.enableVertexAttribArray(locations.a_direction); + gl.vertexAttribPointer(locations.a_direction, 1, goog.webgl.FLOAT, + false, 32, 24); + + gl.enableVertexAttribArray(locations.a_instruction); + gl.vertexAttribPointer(locations.a_instruction, 1, goog.webgl.FLOAT, + false, 32, 28); + + var round = this.state_.lineJoin === 'round' && this.state_.lineCap === 'round' ? + ol.render.webgl.LineStringInstruction.ROUND_BOTH : this.state_.lineJoin === 'round' ? + ol.render.webgl.LineStringInstruction.ROUND_JOIN : this.state_.lineCap === 'round' ? + ol.render.webgl.LineStringInstruction.ROUND_CAP : 0; // enable renderer specific uniforms gl.uniform4fv(locations.u_color, this.state_.strokeColor); + gl.uniform1f(locations.u_lineWidth, this.state_.lineWidth); + gl.uniform1f(locations.u_miterLimit, this.state_.miterLimit); + gl.uniform2fv(locations.u_size, size); + gl.uniform1f(locations.u_round, round); return locations; }; @@ -1150,16 +1354,19 @@ ol.render.webgl.LineStringReplay.prototype.setUpProgram_ = function(gl, context) * @param {Object} skippedFeaturesHash Ids of features to skip. */ ol.render.webgl.LineStringReplay.prototype.drawReplay_ = function(gl, context, skippedFeaturesHash) { + var elementType = context.hasOESElementIndexUint ? + goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT; + var elementSize = context.hasOESElementIndexUint ? 4 : 2; + if (!goog.object.isEmpty(skippedFeaturesHash)) { // TODO: draw by blocks to skip features } else { - var numItems = this.indices_.length; - // FIXME: not compatible with batching, hardcoding some arbitrary value - if (this.state_.lineWidth) { - gl.lineWidth(this.state_.lineWidth); + var i, ii; + for (i = 0, ii = this.startIndices_.length - 1; i < ii; ++i) { + var start = this.startIndices_[i]; + var end = this.startIndices_[i + 1]; + this.drawElements_(gl, start, end, elementType, elementSize); } - gl.drawElements(goog.webgl.LINES, numItems, goog.webgl.UNSIGNED_SHORT, 0); - gl.lineWidth(1); } }; @@ -1203,9 +1410,21 @@ ol.render.webgl.LineStringReplay.prototype.setFillStrokeStyle = function(fillSty ol.color.asArray(strokeStyleColor).map(function(c, i) { return i != 3 ? c / 255 : c; }) : ol.render.webgl.defaultStrokeStyle; + var strokeStyleLineCap = strokeStyle.getLineCap(); + this.state_.lineCap = strokeStyleLineCap !== undefined ? + strokeStyleLineCap : ol.render.webgl.defaultLineCap; + var strokeStyleLineDash = strokeStyle.getLineDash(); + this.state_.lineDash = strokeStyleLineDash ? + strokeStyleLineDash : ol.render.webgl.defaultLineDash; + var strokeStyleLineJoin = strokeStyle.getLineJoin(); + this.state_.lineJoin = strokeStyleLineJoin !== undefined ? + strokeStyleLineJoin : ol.render.webgl.defaultLineJoin; var strokeStyleWidth = strokeStyle.getWidth(); this.state_.lineWidth = strokeStyleWidth !== undefined ? strokeStyleWidth : ol.render.webgl.defaultLineWidth; + var strokeStyleMiterLimit = strokeStyle.getMiterLimit(); + this.state_.miterLimit = strokeStyleMiterLimit !== undefined ? + strokeStyleMiterLimit : ol.render.webgl.defaultMiterLimit; }; diff --git a/src/ol/render/webgl/webgllinestringdefault.glsl b/src/ol/render/webgl/webgllinestringdefault.glsl index 8b81af911e..67c2c5937a 100644 --- a/src/ol/render/webgl/webgllinestringdefault.glsl +++ b/src/ol/render/webgl/webgllinestringdefault.glsl @@ -3,19 +3,83 @@ //! COMMON +varying float v_round; +varying vec4 v_roundVertex; +varying float v_halfWidth; //! VERTEX +attribute vec2 a_lastPos; attribute vec2 a_position; +attribute vec2 a_nextPos; +attribute float a_direction; +attribute float a_instruction; uniform mat4 u_projectionMatrix; uniform mat4 u_offsetScaleMatrix; -uniform mat4 u_offsetRotateMatrix; +uniform float u_lineWidth; +uniform float u_miterLimit; +uniform float u_round; void main(void) { - mat4 offsetMatrix = u_offsetScaleMatrix; - vec4 offsets = offsetMatrix * vec4(0., 0., 0., 0.); - gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + offsets; + v_halfWidth = u_lineWidth / 2.0; + vec2 offset; + v_round = 0.0; + vec4 projPos = u_projectionMatrix * vec4(a_position, 0., 1.); + if (a_instruction == 0. || a_instruction == 4.) { + 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.)) { + 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.)) { + v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.); + } + } else if (a_instruction == 5. || a_instruction == 6.) { + vec2 dirVect = a_nextPos - a_position; + vec2 tmpNormal = normalize(vec2(-dirVect.y, dirVect.x)); + vec2 tangent = normalize(normalize(a_nextPos - a_position) + normalize(a_position - a_lastPos)); + vec2 normal = vec2(tangent.y, -tangent.x); + float miterLength = v_halfWidth / dot(normal, tmpNormal); + if (a_instruction == 6.) { + if (u_round == 7. || u_round == 9.) { + offset = normal * a_direction * miterLength; + v_round = 1.0; + v_roundVertex = projPos + u_offsetScaleMatrix * vec4(0., 0., 0., 0.); + } else if (miterLength > u_miterLimit) { + offset = tmpNormal * a_direction * v_halfWidth; + } else { + offset = normal * a_direction * miterLength; + } + } else if (a_instruction == 5.) { + offset = normal * a_direction * miterLength; + vec4 defaultOffset = u_offsetScaleMatrix * vec4(0., 0., 0., 0.); + vec4 firstProjPos = u_projectionMatrix * vec4(a_lastPos, 0., 1.) + defaultOffset; + vec4 secondProjPos = projPos + defaultOffset; + vec4 thirdProjPos = u_projectionMatrix * vec4(a_nextPos, 0., 1.) + defaultOffset; + float firstSegLength = distance(secondProjPos.xy, firstProjPos.xy); + float secondSegLength = distance(thirdProjPos.xy, secondProjPos.xy); + float miterSegLength = distance(secondProjPos.xy, vec4(projPos + u_offsetScaleMatrix * vec4(offset, 0., 0.)).xy); + //TODO: Write a more accurate method for identifying sharp angles. + if (miterSegLength > min(firstSegLength, secondSegLength)) { + if (firstSegLength < secondSegLength) { + dirVect = a_lastPos - a_position; + tmpNormal = normalize(vec2(dirVect.y, -dirVect.x)); + projPos = firstProjPos - defaultOffset; + } else { + projPos = thirdProjPos - defaultOffset; + } + offset = tmpNormal * a_direction * v_halfWidth; + } + } + } + vec4 offsets = u_offsetScaleMatrix * vec4(offset, 0., 0.); + gl_Position = projPos + offsets; } @@ -23,8 +87,15 @@ void main(void) { uniform float u_opacity; uniform vec4 u_color; +uniform vec2 u_size; void main(void) { + if (v_round > 0.0) { + vec2 windowCoords = vec2((v_roundVertex.x + 1.0) / 2.0 * u_size.x, (v_roundVertex.y + 1.0) / 2.0 * u_size.y); + if (length(windowCoords - gl_FragCoord.xy) > v_halfWidth) { + discard; + } + } gl_FragColor = u_color; float alpha = u_color.a * u_opacity; if (alpha == 0.0) { diff --git a/src/ol/render/webgl/webgllinestringdefaultshader.js b/src/ol/render/webgl/webgllinestringdefaultshader.js index d886ff52fb..110a3b1600 100644 --- a/src/ol/render/webgl/webgllinestringdefaultshader.js +++ b/src/ol/render/webgl/webgllinestringdefaultshader.js @@ -23,14 +23,14 @@ goog.addSingletonGetter(ol.render.webgl.linestringreplay.shader.DefaultFragment) * @const * @type {string} */ -ol.render.webgl.linestringreplay.shader.DefaultFragment.DEBUG_SOURCE = 'precision mediump float;\n\n\n\nuniform float u_opacity;\nuniform vec4 u_color;\n\nvoid main(void) {\n gl_FragColor = u_color;\n float alpha = u_color.a * u_opacity;\n if (alpha == 0.0) {\n discard;\n }\n gl_FragColor.a = alpha;\n}\n'; +ol.render.webgl.linestringreplay.shader.DefaultFragment.DEBUG_SOURCE = 'precision mediump float;\nvarying float v_round;\nvarying vec4 v_roundVertex;\nvarying float v_halfWidth;\n\n\n\nuniform float u_opacity;\nuniform vec4 u_color;\nuniform vec2 u_size;\n\nvoid main(void) {\n if (v_round > 0.0) {\n vec2 windowCoords = vec2((v_roundVertex.x + 1.0) / 2.0 * u_size.x, (v_roundVertex.y + 1.0) / 2.0 * u_size.y);\n if (length(windowCoords - gl_FragCoord.xy) > v_halfWidth) {\n discard;\n }\n }\n gl_FragColor = u_color;\n float alpha = u_color.a * u_opacity;\n if (alpha == 0.0) {\n discard;\n }\n gl_FragColor.a = alpha;\n}\n'; /** * @const * @type {string} */ -ol.render.webgl.linestringreplay.shader.DefaultFragment.OPTIMIZED_SOURCE = 'precision mediump float;uniform float e;uniform vec4 f;void main(void){gl_FragColor=f;float alpha=f.a*e;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}'; +ol.render.webgl.linestringreplay.shader.DefaultFragment.OPTIMIZED_SOURCE = 'precision mediump float;varying float a;varying vec4 b;varying float c;uniform float n;uniform vec4 o;uniform vec2 p;void main(void){if(a>0.0){vec2 windowCoords=vec2((b.x+1.0)/2.0*p.x,(b.y+1.0)/2.0*p.y);if(length(windowCoords-gl_FragCoord.xy)>c){discard;}} gl_FragColor=o;float alpha=o.a*n;if(alpha==0.0){discard;}gl_FragColor.a=alpha;}'; /** @@ -58,14 +58,14 @@ goog.addSingletonGetter(ol.render.webgl.linestringreplay.shader.DefaultVertex); * @const * @type {string} */ -ol.render.webgl.linestringreplay.shader.DefaultVertex.DEBUG_SOURCE = '\n\nattribute vec2 a_position;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\n\nvoid main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix;\n vec4 offsets = offsetMatrix * vec4(0., 0., 0., 0.);\n gl_Position = u_projectionMatrix * vec4(a_position, 0., 1.) + 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 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'; /** * @const * @type {string} */ -ol.render.webgl.linestringreplay.shader.DefaultVertex.OPTIMIZED_SOURCE = 'attribute vec2 a;uniform mat4 b;uniform mat4 c;uniform mat4 d;void main(void){mat4 offsetMatrix=c;vec4 offsets=offsetMatrix*vec4(0.,0.,0.,0.);gl_Position=b*vec4(a,0.,1.)+offsets;}'; +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