From 3b2ff5a2ee15525f3777ecba176a5fd44c08a593 Mon Sep 17 00:00:00 2001 From: GaborFarkas Date: Tue, 15 Nov 2016 17:11:16 +0100 Subject: [PATCH] Revamp WebGL CircleReplay --- .../webgl/circlereplay/defaultshader.glsl | 30 +++++++++++-------- .../webgl/circlereplay/defaultshader.js | 4 +-- src/ol/render/webgl/circlereplay/index.js | 17 +++++++++-- .../spec/ol/render/webgl/circlereplay.test.js | 9 +++--- 4 files changed, 39 insertions(+), 21 deletions(-) diff --git a/src/ol/render/webgl/circlereplay/defaultshader.glsl b/src/ol/render/webgl/circlereplay/defaultshader.glsl index dc85372ca6..da09b94cbe 100644 --- a/src/ol/render/webgl/circlereplay/defaultshader.glsl +++ b/src/ol/render/webgl/circlereplay/defaultshader.glsl @@ -36,26 +36,32 @@ void main(void) { // Until we get gl_VertexID in WebGL, we store an instruction. if (a_instruction == 0.0) { newX = a_position.x - radius; - newY = a_position.y - radius; + newY = a_position.y + radius; // Offsetting the edges of the triangle by lineWidth / 2 is necessary, however // we should also leave some space for the antialiasing, thus we offset by lineWidth. + offset = vec2(-lineWidth, lineWidth); + } else if (a_instruction == 1.0) { + newX = a_position.x - radius; + newY = a_position.y - radius; offset = vec2(-lineWidth, -lineWidth); + } else if (a_instruction == 2.0) { + newX = a_position.x + radius; + newY = a_position.y - radius; + offset = vec2(lineWidth, -lineWidth); } else { - float sqrtVal = sqrt(2.0) + 1.0; - if (a_instruction == 1.0) { - newX = a_position.x + sqrtVal * radius; - newY = a_position.y - radius; - offset = vec2(lineWidth * sqrtVal, -lineWidth); - } else { - newX = a_position.x - radius; - newY = a_position.y + sqrtVal * radius; - offset = vec2(-lineWidth, lineWidth * sqrtVal); - } + newX = a_position.x + radius; + newY = a_position.y + radius; + offset = vec2(lineWidth, lineWidth); } gl_Position = u_projectionMatrix * vec4(newX, newY, 0., 1.) + offsetMatrix * vec4(offset, 0., 0.); - v_offset = vec4(u_projectionMatrix * vec4(a_position.x + a_radius, a_position.y, 0., 1.)).xy; + v_offset = vec4(u_projectionMatrix * vec4(a_position.x + a_radius, a_position.y, + 0., 1.)).xy; + + if (distance(v_center, v_offset) > 20000.0) { + gl_Position = vec4(v_center, 0., 1.); + } } diff --git a/src/ol/render/webgl/circlereplay/defaultshader.js b/src/ol/render/webgl/circlereplay/defaultshader.js index bdf3b549eb..d79e5b3b91 100644 --- a/src/ol/render/webgl/circlereplay/defaultshader.js +++ b/src/ol/render/webgl/circlereplay/defaultshader.js @@ -58,14 +58,14 @@ ol.inherits(ol.render.webgl.circlereplay.defaultshader.Vertex, ol.webgl.Vertex); * @const * @type {string} */ -ol.render.webgl.circlereplay.defaultshader.Vertex.DEBUG_SOURCE = 'varying vec2 v_center;\nvarying vec2 v_offset;\nvarying float v_halfWidth;\nvarying float v_pixelRatio;\n\n\nattribute vec2 a_position;\nattribute float a_instruction;\nattribute float a_radius;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\nuniform float u_lineWidth;\nuniform float u_pixelRatio;\n\nvoid main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\n v_center = vec4(u_projectionMatrix * vec4(a_position, 0., 1.)).xy;\n v_pixelRatio = u_pixelRatio;\n float newX, newY;\n float lineWidth = u_lineWidth * u_pixelRatio;\n v_halfWidth = lineWidth / 2.0;\n if (lineWidth == 0.0) {\n lineWidth = 2.0 * u_pixelRatio;\n }\n vec2 offset;\n // Radius with anitaliasing (roughly).\n float radius = a_radius + 3.0 * u_pixelRatio;\n // Until we get gl_VertexID in WebGL, we store an instruction.\n if (a_instruction == 0.0) {\n newX = a_position.x - radius;\n newY = a_position.y - radius;\n // Offsetting the edges of the triangle by lineWidth / 2 is necessary, however\n // we should also leave some space for the antialiasing, thus we offset by lineWidth.\n offset = vec2(-lineWidth, -lineWidth);\n } else {\n float sqrtVal = sqrt(2.0) + 1.0;\n if (a_instruction == 1.0) {\n newX = a_position.x + sqrtVal * radius;\n newY = a_position.y - radius;\n offset = vec2(lineWidth * sqrtVal, -lineWidth);\n } else {\n newX = a_position.x - radius;\n newY = a_position.y + sqrtVal * radius;\n offset = vec2(-lineWidth, lineWidth * sqrtVal);\n }\n }\n\n gl_Position = u_projectionMatrix * vec4(newX, newY, 0., 1.) + offsetMatrix *\n vec4(offset, 0., 0.);\n v_offset = vec4(u_projectionMatrix * vec4(a_position.x + a_radius, a_position.y, 0., 1.)).xy;\n}\n\n\n'; +ol.render.webgl.circlereplay.defaultshader.Vertex.DEBUG_SOURCE = 'varying vec2 v_center;\nvarying vec2 v_offset;\nvarying float v_halfWidth;\nvarying float v_pixelRatio;\n\n\nattribute vec2 a_position;\nattribute float a_instruction;\nattribute float a_radius;\n\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\nuniform float u_lineWidth;\nuniform float u_pixelRatio;\n\nvoid main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\n v_center = vec4(u_projectionMatrix * vec4(a_position, 0., 1.)).xy;\n v_pixelRatio = u_pixelRatio;\n float newX, newY;\n float lineWidth = u_lineWidth * u_pixelRatio;\n v_halfWidth = lineWidth / 2.0;\n if (lineWidth == 0.0) {\n lineWidth = 2.0 * u_pixelRatio;\n }\n vec2 offset;\n // Radius with anitaliasing (roughly).\n float radius = a_radius + 3.0 * u_pixelRatio;\n // Until we get gl_VertexID in WebGL, we store an instruction.\n if (a_instruction == 0.0) {\n newX = a_position.x - radius;\n newY = a_position.y + radius;\n // Offsetting the edges of the triangle by lineWidth / 2 is necessary, however\n // we should also leave some space for the antialiasing, thus we offset by lineWidth.\n offset = vec2(-lineWidth, lineWidth);\n } else if (a_instruction == 1.0) {\n newX = a_position.x - radius;\n newY = a_position.y - radius;\n offset = vec2(-lineWidth, -lineWidth);\n } else if (a_instruction == 2.0) {\n newX = a_position.x + radius;\n newY = a_position.y - radius;\n offset = vec2(lineWidth, -lineWidth);\n } else {\n newX = a_position.x + radius;\n newY = a_position.y + radius;\n offset = vec2(lineWidth, lineWidth);\n }\n\n gl_Position = u_projectionMatrix * vec4(newX, newY, 0., 1.) + offsetMatrix *\n vec4(offset, 0., 0.);\n v_offset = vec4(u_projectionMatrix * vec4(a_position.x + a_radius, a_position.y,\n 0., 1.)).xy;\n\n if (distance(v_center, v_offset) > 20000.0) {\n gl_Position = vec4(v_center, 0., 1.);\n }\n}\n\n\n'; /** * @const * @type {string} */ -ol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;varying vec2 b;varying float c;varying float d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;void main(void){mat4 offsetMatrix=i*j;a=vec4(h*vec4(e,0.,1.)).xy;d=l;float newX,newY;float lineWidth=k*l;c=lineWidth/2.0;if(lineWidth==0.0){lineWidth=2.0*l;}vec2 offset;float radius=g+3.0*l;if(f==0.0){newX=e.x-radius;newY=e.y-radius;offset=vec2(-lineWidth,-lineWidth);}else{float sqrtVal=sqrt(2.0)+1.0;if(f==1.0){newX=e.x+sqrtVal*radius;newY=e.y-radius;offset=vec2(lineWidth*sqrtVal,-lineWidth);}else{newX=e.x-radius;newY=e.y+sqrtVal*radius;offset=vec2(-lineWidth,lineWidth*sqrtVal);}} gl_Position=h*vec4(newX,newY,0.,1.)+offsetMatrix*vec4(offset,0.,0.);b=vec4(h*vec4(e.x+g,e.y,0.,1.)).xy;}'; +ol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;varying vec2 b;varying float c;varying float d;attribute vec2 e;attribute float f;attribute float g;uniform mat4 h;uniform mat4 i;uniform mat4 j;uniform float k;uniform float l;void main(void){mat4 offsetMatrix=i*j;a=vec4(h*vec4(e,0.,1.)).xy;d=l;float newX,newY;float lineWidth=k*l;c=lineWidth/2.0;if(lineWidth==0.0){lineWidth=2.0*l;}vec2 offset;float radius=g+3.0*l;if(f==0.0){newX=e.x-radius;newY=e.y+radius;offset=vec2(-lineWidth,lineWidth);}else if(f==1.0){newX=e.x-radius;newY=e.y-radius;offset=vec2(-lineWidth,-lineWidth);}else if(f==2.0){newX=e.x+radius;newY=e.y-radius;offset=vec2(lineWidth,-lineWidth);}else{newX=e.x+radius;newY=e.y+radius;offset=vec2(lineWidth,lineWidth);}gl_Position=h*vec4(newX,newY,0.,1.)+offsetMatrix*vec4(offset,0.,0.);b=vec4(h*vec4(e.x+g,e.y,0.,1.)).xy;if(distance(a,b)>20000.0){gl_Position=vec4(a,0.,1.);}}'; /** diff --git a/src/ol/render/webgl/circlereplay/index.js b/src/ol/render/webgl/circlereplay/index.js index e947dc1505..c4821560bc 100644 --- a/src/ol/render/webgl/circlereplay/index.js +++ b/src/ol/render/webgl/circlereplay/index.js @@ -96,9 +96,20 @@ ol.render.webgl.CircleReplay.prototype.drawCoordinates_ = function( this.vertices[numVertices++] = 2; this.vertices[numVertices++] = this.radius_; - this.indices[numIndices++] = n++; - this.indices[numIndices++] = n++; - this.indices[numIndices++] = n++; + this.vertices[numVertices++] = flatCoordinates[i]; + this.vertices[numVertices++] = flatCoordinates[i + 1]; + this.vertices[numVertices++] = 3; + this.vertices[numVertices++] = this.radius_; + + this.indices[numIndices++] = n; + this.indices[numIndices++] = n + 1; + this.indices[numIndices++] = n + 2; + + this.indices[numIndices++] = n + 2; + this.indices[numIndices++] = n + 3; + this.indices[numIndices++] = n; + + n += 4; } }; diff --git a/test/spec/ol/render/webgl/circlereplay.test.js b/test/spec/ol/render/webgl/circlereplay.test.js index 8524928735..5b8d061e02 100644 --- a/test/spec/ol/render/webgl/circlereplay.test.js +++ b/test/spec/ol/render/webgl/circlereplay.test.js @@ -53,8 +53,8 @@ describe('ol.render.webgl.CircleReplay', function() { replay.setFillStrokeStyle(fillStyle, strokeStyle); replay.drawCircle(circle, null); - expect(replay.vertices).to.have.length(12); - expect(replay.indices).to.have.length(3); + expect(replay.vertices).to.have.length(16); + expect(replay.indices).to.have.length(6); expect(replay.state_.changed).to.be(false); expect(replay.startIndices).to.have.length(1); expect(replay.startIndicesFeature).to.have.length(1); @@ -91,8 +91,9 @@ describe('ol.render.webgl.CircleReplay', function() { replay.radius_ = 5000; replay.drawCoordinates_([0, 0], 0, 2, 2); - expect(replay.vertices).to.eql([0, 0, 0, 5000, 0, 0, 1, 5000, 0, 0, 2, 5000]); - expect(replay.indices).to.eql([0, 1, 2]); + expect(replay.vertices).to.eql([0, 0, 0, 5000, 0, 0, 1, 5000, + 0, 0, 2, 5000, 0, 0, 3, 5000]); + expect(replay.indices).to.eql([0, 1, 2, 2, 3, 0]); }); });