Add circle replay to WebGL renderer

This commit is contained in:
GaborFarkas
2016-10-30 16:33:04 +01:00
parent 86c914f3df
commit ac6408be3b
9 changed files with 695 additions and 7 deletions

View File

@@ -282,6 +282,7 @@ ol.render.canvas.ReplayGroup.prototype.replayHitDetection_ = function(
* number, boolean)>}
*/
ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_ = {
'Circle': ol.render.canvas.PolygonReplay,
'Image': ol.render.canvas.ImageReplay,
'LineString': ol.render.canvas.LineStringReplay,
'Polygon': ol.render.canvas.PolygonReplay,

View File

@@ -9,6 +9,7 @@ goog.require('ol.render.ReplayType');
*/
ol.render.replay.ORDER = [
ol.render.ReplayType.POLYGON,
ol.render.ReplayType.CIRCLE,
ol.render.ReplayType.LINE_STRING,
ol.render.ReplayType.IMAGE,
ol.render.ReplayType.TEXT

View File

@@ -5,6 +5,7 @@ goog.provide('ol.render.ReplayType');
* @enum {string}
*/
ol.render.ReplayType = {
CIRCLE: 'Circle',
IMAGE: 'Image',
LINE_STRING: 'LineString',
POLYGON: 'Polygon',

View File

@@ -0,0 +1,101 @@
//! NAMESPACE=ol.render.webgl.circlereplay.defaultshader
//! CLASS=ol.render.webgl.circlereplay.defaultshader
//! COMMON
varying vec2 v_center;
varying vec2 v_offset;
varying float v_halfWidth;
//! VERTEX
attribute vec2 a_position;
attribute float a_instruction;
attribute float a_radius;
uniform mat4 u_projectionMatrix;
uniform mat4 u_offsetScaleMatrix;
uniform mat4 u_offsetRotateMatrix;
uniform float u_lineWidth;
void main(void) {
mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;
v_center = vec4(u_projectionMatrix * vec4(a_position, 0., 1.)).xy;
float newX, newY;
float lineWidth = u_lineWidth;
if (lineWidth == 0.0) {
lineWidth = 2.0;
}
v_halfWidth = u_lineWidth / 2.0;
vec2 offset;
// Radius with anitaliasing (roughly).
float radius = a_radius + 3.0;
// 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;
// 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 {
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);
}
}
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;
}
//! FRAGMENT
uniform float u_opacity;
uniform vec4 u_fillColor;
uniform vec4 u_strokeColor;
uniform vec2 u_size;
uniform float u_pixelRatio;
void main(void) {
vec2 windowCenter = vec2((v_center.x + 1.0) / 2.0 * u_size.x * u_pixelRatio,
(v_center.y + 1.0) / 2.0 * u_size.y * u_pixelRatio);
vec2 windowOffset = vec2((v_offset.x + 1.0) / 2.0 * u_size.x * u_pixelRatio,
(v_offset.y + 1.0) / 2.0 * u_size.y * u_pixelRatio);
float radius = length(windowCenter - windowOffset);
float dist = length(windowCenter - gl_FragCoord.xy);
if (dist > (radius + v_halfWidth) * u_pixelRatio) {
if (u_strokeColor.a == 0.0) {
gl_FragColor = u_fillColor;
} else {
gl_FragColor = u_strokeColor;
}
gl_FragColor.a = gl_FragColor.a - (dist - (radius + v_halfWidth) * u_pixelRatio);
} else if (u_fillColor.a == 0.0) {
// Hooray, no fill, just stroke. We can use real antialiasing.
gl_FragColor = u_strokeColor;
if (dist < (radius - v_halfWidth) * u_pixelRatio) {
gl_FragColor.a = gl_FragColor.a - ((radius - v_halfWidth) * u_pixelRatio - dist);
}
} else {
gl_FragColor = u_fillColor;
float strokeDist = (radius - v_halfWidth) * u_pixelRatio;
if (dist > strokeDist) {
gl_FragColor = u_strokeColor;
} else if (dist >= strokeDist - 2.0) {
float step = smoothstep(strokeDist - 2.0, strokeDist, dist);
gl_FragColor = mix(u_fillColor, u_strokeColor, step);
}
}
gl_FragColor.a = gl_FragColor.a * u_opacity;
if (gl_FragColor.a <= 0.0) {
discard;
}
}

View File

@@ -0,0 +1,162 @@
// This file is automatically generated, do not edit
goog.provide('ol.render.webgl.circlereplay.defaultshader');
goog.require('ol');
goog.require('ol.webgl.Fragment');
goog.require('ol.webgl.Vertex');
/**
* @constructor
* @extends {ol.webgl.Fragment}
* @struct
*/
ol.render.webgl.circlereplay.defaultshader.Fragment = function() {
ol.webgl.Fragment.call(this, ol.render.webgl.circlereplay.defaultshader.Fragment.SOURCE);
};
ol.inherits(ol.render.webgl.circlereplay.defaultshader.Fragment, ol.webgl.Fragment);
/**
* @const
* @type {string}
*/
ol.render.webgl.circlereplay.defaultshader.Fragment.DEBUG_SOURCE = 'precision mediump float;\nvarying vec2 v_center;\nvarying vec2 v_offset;\nvarying float v_halfWidth;\n\n\n\nuniform float u_opacity;\nuniform vec4 u_fillColor;\nuniform vec4 u_strokeColor;\nuniform vec2 u_size;\nuniform float u_pixelRatio;\n\nvoid main(void) {\n vec2 windowCenter = vec2((v_center.x + 1.0) / 2.0 * u_size.x * u_pixelRatio,\n (v_center.y + 1.0) / 2.0 * u_size.y * u_pixelRatio);\n vec2 windowOffset = vec2((v_offset.x + 1.0) / 2.0 * u_size.x * u_pixelRatio,\n (v_offset.y + 1.0) / 2.0 * u_size.y * u_pixelRatio);\n float radius = length(windowCenter - windowOffset);\n float dist = length(windowCenter - gl_FragCoord.xy);\n if (dist > (radius + v_halfWidth) * u_pixelRatio) {\n if (u_strokeColor.a == 0.0) {\n gl_FragColor = u_fillColor;\n } else {\n gl_FragColor = u_strokeColor;\n }\n gl_FragColor.a = gl_FragColor.a - (dist - (radius + v_halfWidth) * u_pixelRatio);\n } else if (u_fillColor.a == 0.0) {\n // Hooray, no fill, just stroke. We can use real antialiasing.\n gl_FragColor = u_strokeColor;\n if (dist < (radius - v_halfWidth) * u_pixelRatio) {\n gl_FragColor.a = gl_FragColor.a - ((radius - v_halfWidth) * u_pixelRatio - dist);\n }\n } else {\n gl_FragColor = u_fillColor;\n float strokeDist = (radius - v_halfWidth) * u_pixelRatio;\n if (dist > strokeDist) {\n gl_FragColor = u_strokeColor;\n } else if (dist >= strokeDist - 2.0) {\n float step = smoothstep(strokeDist - 2.0, strokeDist, dist);\n gl_FragColor = mix(u_fillColor, u_strokeColor, step);\n }\n }\n gl_FragColor.a = gl_FragColor.a * u_opacity;\n if (gl_FragColor.a <= 0.0) {\n discard;\n }\n}\n';
/**
* @const
* @type {string}
*/
ol.render.webgl.circlereplay.defaultshader.Fragment.OPTIMIZED_SOURCE = 'precision mediump float;varying vec2 a;varying vec2 b;varying float c;uniform float k;uniform vec4 l;uniform vec4 m;uniform vec2 n;uniform float o;void main(void){vec2 windowCenter=vec2((a.x+1.0)/2.0*n.x*o,(a.y+1.0)/2.0*n.y*o);vec2 windowOffset=vec2((b.x+1.0)/2.0*n.x*o,(b.y+1.0)/2.0*n.y*o);float radius=length(windowCenter-windowOffset);float dist=length(windowCenter-gl_FragCoord.xy);if(dist>(radius+c)*o){if(m.a==0.0){gl_FragColor=l;}else{gl_FragColor=m;}gl_FragColor.a=gl_FragColor.a-(dist-(radius+c)*o);}else if(l.a==0.0){gl_FragColor=m;if(dist<(radius-c)*o){gl_FragColor.a=gl_FragColor.a-((radius-c)*o-dist);}} else{gl_FragColor=l;float strokeDist=(radius-c)*o;if(dist>strokeDist){gl_FragColor=m;}else if(dist>=strokeDist-2.0){float step=smoothstep(strokeDist-2.0,strokeDist,dist);gl_FragColor=mix(l,m,step);}} gl_FragColor.a=gl_FragColor.a*k;if(gl_FragColor.a<=0.0){discard;}}';
/**
* @const
* @type {string}
*/
ol.render.webgl.circlereplay.defaultshader.Fragment.SOURCE = ol.DEBUG ?
ol.render.webgl.circlereplay.defaultshader.Fragment.DEBUG_SOURCE :
ol.render.webgl.circlereplay.defaultshader.Fragment.OPTIMIZED_SOURCE;
ol.render.webgl.circlereplay.defaultshader.fragment = new ol.render.webgl.circlereplay.defaultshader.Fragment();
/**
* @constructor
* @extends {ol.webgl.Vertex}
* @struct
*/
ol.render.webgl.circlereplay.defaultshader.Vertex = function() {
ol.webgl.Vertex.call(this, ol.render.webgl.circlereplay.defaultshader.Vertex.SOURCE);
};
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;\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;\n\nvoid main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix * u_offsetRotateMatrix;\n v_center = vec4(u_projectionMatrix * vec4(a_position, 0., 1.)).xy;\n float newX, newY;\n float lineWidth = u_lineWidth;\n if (lineWidth == 0.0) {\n lineWidth = 2.0;\n }\n v_halfWidth = u_lineWidth / 2.0;\n vec2 offset;\n // Radius with anitaliasing (roughly).\n float radius = a_radius + 3.0;\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';
/**
* @const
* @type {string}
*/
ol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE = 'varying vec2 a;varying vec2 b;varying float c;attribute vec2 d;attribute float e;attribute float f;uniform mat4 g;uniform mat4 h;uniform mat4 i;uniform float j;void main(void){mat4 offsetMatrix=h*i;a=vec4(g*vec4(d,0.,1.)).xy;float newX,newY;float lineWidth=j;if(lineWidth==0.0){lineWidth=2.0;}c=j/2.0;vec2 offset;float radius=f+3.0;if(e==0.0){newX=d.x-radius;newY=d.y-radius;offset=vec2(-lineWidth,-lineWidth);}else{float sqrtVal=sqrt(2.0)+1.0;if(e==1.0){newX=d.x+sqrtVal*radius;newY=d.y-radius;offset=vec2(lineWidth*sqrtVal,-lineWidth);}else{newX=d.x-radius;newY=d.y+sqrtVal*radius;offset=vec2(-lineWidth,lineWidth*sqrtVal);}} gl_Position=g*vec4(newX,newY,0.,1.)+offsetMatrix*vec4(offset,0.,0.);b=vec4(g*vec4(d.x+f,d.y,0.,1.)).xy;}';
/**
* @const
* @type {string}
*/
ol.render.webgl.circlereplay.defaultshader.Vertex.SOURCE = ol.DEBUG ?
ol.render.webgl.circlereplay.defaultshader.Vertex.DEBUG_SOURCE :
ol.render.webgl.circlereplay.defaultshader.Vertex.OPTIMIZED_SOURCE;
ol.render.webgl.circlereplay.defaultshader.vertex = new ol.render.webgl.circlereplay.defaultshader.Vertex();
/**
* @constructor
* @param {WebGLRenderingContext} gl GL.
* @param {WebGLProgram} program Program.
* @struct
*/
ol.render.webgl.circlereplay.defaultshader.Locations = function(gl, program) {
/**
* @type {WebGLUniformLocation}
*/
this.u_fillColor = gl.getUniformLocation(
program, ol.DEBUG ? 'u_fillColor' : 'l');
/**
* @type {WebGLUniformLocation}
*/
this.u_lineWidth = gl.getUniformLocation(
program, ol.DEBUG ? 'u_lineWidth' : 'j');
/**
* @type {WebGLUniformLocation}
*/
this.u_offsetRotateMatrix = gl.getUniformLocation(
program, ol.DEBUG ? 'u_offsetRotateMatrix' : 'i');
/**
* @type {WebGLUniformLocation}
*/
this.u_offsetScaleMatrix = gl.getUniformLocation(
program, ol.DEBUG ? 'u_offsetScaleMatrix' : 'h');
/**
* @type {WebGLUniformLocation}
*/
this.u_opacity = gl.getUniformLocation(
program, ol.DEBUG ? 'u_opacity' : 'k');
/**
* @type {WebGLUniformLocation}
*/
this.u_pixelRatio = gl.getUniformLocation(
program, ol.DEBUG ? 'u_pixelRatio' : 'o');
/**
* @type {WebGLUniformLocation}
*/
this.u_projectionMatrix = gl.getUniformLocation(
program, ol.DEBUG ? 'u_projectionMatrix' : 'g');
/**
* @type {WebGLUniformLocation}
*/
this.u_size = gl.getUniformLocation(
program, ol.DEBUG ? 'u_size' : 'n');
/**
* @type {WebGLUniformLocation}
*/
this.u_strokeColor = gl.getUniformLocation(
program, ol.DEBUG ? 'u_strokeColor' : 'm');
/**
* @type {number}
*/
this.a_instruction = gl.getAttribLocation(
program, ol.DEBUG ? 'a_instruction' : 'e');
/**
* @type {number}
*/
this.a_position = gl.getAttribLocation(
program, ol.DEBUG ? 'a_position' : 'd');
/**
* @type {number}
*/
this.a_radius = gl.getAttribLocation(
program, ol.DEBUG ? 'a_radius' : 'f');
};

View File

@@ -0,0 +1,418 @@
goog.provide('ol.render.webgl.CircleReplay');
goog.require('ol');
goog.require('ol.color');
goog.require('ol.extent');
goog.require('ol.obj');
goog.require('ol.geom.flat.transform');
goog.require('ol.render.webgl.circlereplay.defaultshader');
goog.require('ol.render.webgl.Replay');
goog.require('ol.render.webgl');
goog.require('ol.webgl');
goog.require('ol.webgl.Buffer');
/**
* @constructor
* @extends {ol.render.webgl.Replay}
* @param {number} tolerance Tolerance.
* @param {ol.Extent} maxExtent Max extent.
* @struct
*/
ol.render.webgl.CircleReplay = function(tolerance, maxExtent) {
ol.render.webgl.Replay.call(this, tolerance, maxExtent);
/**
* @private
* @type {ol.render.webgl.circlereplay.defaultshader.Locations}
*/
this.defaultLocations_ = null;
/**
* @private
* @type {Array.<Array.<Array.<number>|number>>}
*/
this.styles_ = [];
/**
* @private
* @type {Array.<number>}
*/
this.styleIndices_ = [];
/**
* @private
* @type {number}
*/
this.radius_ = 0;
/**
* @private
* @type {{fillColor: (Array.<number>|null),
* strokeColor: (Array.<number>|null),
* lineDash: Array.<number>,
* lineWidth: (number|undefined),
* changed: boolean}|null}
*/
this.state_ = {
fillColor: null,
strokeColor: null,
lineDash: null,
lineWidth: undefined,
changed: false
};
};
ol.inherits(ol.render.webgl.CircleReplay, ol.render.webgl.Replay);
/**
* @private
* @param {Array.<number>} flatCoordinates Flat coordinates.
* @param {number} offset Offset.
* @param {number} end End.
* @param {number} stride Stride.
*/
ol.render.webgl.CircleReplay.prototype.drawCoordinates_ = function(
flatCoordinates, offset, end, stride) {
var numVertices = this.vertices.length;
var numIndices = this.indices.length;
var n = numVertices / 4;
var i, ii;
for (i = offset, ii = end; i < ii; i += stride) {
this.vertices[numVertices++] = flatCoordinates[i];
this.vertices[numVertices++] = flatCoordinates[i + 1];
this.vertices[numVertices++] = 0;
this.vertices[numVertices++] = this.radius_;
this.vertices[numVertices++] = flatCoordinates[i];
this.vertices[numVertices++] = flatCoordinates[i + 1];
this.vertices[numVertices++] = 1;
this.vertices[numVertices++] = this.radius_;
this.vertices[numVertices++] = flatCoordinates[i];
this.vertices[numVertices++] = flatCoordinates[i + 1];
this.vertices[numVertices++] = 2;
this.vertices[numVertices++] = this.radius_;
this.indices[numIndices++] = n++;
this.indices[numIndices++] = n++;
this.indices[numIndices++] = n++;
}
};
/**
* @inheritDoc
*/
ol.render.webgl.CircleReplay.prototype.drawCircle = function(circleGeometry, feature) {
var radius = circleGeometry.getRadius();
var stride = circleGeometry.getStride();
if (radius) {
this.startIndices.push(this.indices.length);
this.startIndicesFeature.push(feature);
if (this.state_.changed) {
this.styleIndices_.push(this.indices.length);
this.state_.changed = false;
}
this.radius_ = radius;
var flatCoordinates = circleGeometry.getFlatCoordinates();
flatCoordinates = ol.geom.flat.transform.translate(flatCoordinates, 0, 2,
stride, -this.origin[0], -this.origin[1]);
this.drawCoordinates_(flatCoordinates, 0, 2, stride);
} else {
if (this.state_.changed) {
this.styles_.pop();
if (this.styles_.length) {
var lastState = this.styles_[this.styles_.length - 1];
this.state_.fillColor = /** @type {Array.<number>} */ (lastState[0]);
this.state_.strokeColor = /** @type {Array.<number>} */ (lastState[1]);
this.state_.lineWidth = /** @type {number} */ (lastState[2]);
this.state_.changed = false;
}
}
}
};
/**
* @inheritDoc
**/
ol.render.webgl.CircleReplay.prototype.finish = function(context) {
// create, bind, and populate the vertices buffer
this.verticesBuffer = new ol.webgl.Buffer(this.vertices);
// create, bind, and populate the indices buffer
this.indicesBuffer = new ol.webgl.Buffer(this.indices);
this.startIndices.push(this.indices.length);
//Clean up, if there is nothing to draw
if (this.styleIndices_.length === 0 && this.styles_.length > 0) {
this.styles_ = [];
}
this.vertices = null;
this.indices = null;
};
/**
* @inheritDoc
*/
ol.render.webgl.CircleReplay.prototype.getDeleteResourcesFunction = function(context) {
// We only delete our stuff here. The shaders and the program may
// be used by other PolygonReplay instances (for other layers). And
// they will be deleted when disposing of the ol.webgl.Context
// object.
ol.DEBUG && console.assert(this.verticesBuffer,
'verticesBuffer must not be null');
ol.DEBUG && console.assert(this.indicesBuffer,
'indicesBuffer must not be null');
var verticesBuffer = this.verticesBuffer;
var indicesBuffer = this.indicesBuffer;
return function() {
context.deleteBuffer(verticesBuffer);
context.deleteBuffer(indicesBuffer);
};
};
/**
* @inheritDoc
*/
ol.render.webgl.CircleReplay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {
// get the program
var fragmentShader, vertexShader;
fragmentShader = ol.render.webgl.circlereplay.defaultshader.fragment;
vertexShader = ol.render.webgl.circlereplay.defaultshader.vertex;
var program = context.getProgram(fragmentShader, vertexShader);
// get the locations
var locations;
if (!this.defaultLocations_) {
locations =
new ol.render.webgl.circlereplay.defaultshader.Locations(gl, program);
this.defaultLocations_ = locations;
} else {
locations = this.defaultLocations_;
}
context.useProgram(program);
// enable the vertex attrib arrays
gl.enableVertexAttribArray(locations.a_position);
gl.vertexAttribPointer(locations.a_position, 2, ol.webgl.FLOAT,
false, 16, 0);
gl.enableVertexAttribArray(locations.a_instruction);
gl.vertexAttribPointer(locations.a_instruction, 1, ol.webgl.FLOAT,
false, 16, 8);
gl.enableVertexAttribArray(locations.a_radius);
gl.vertexAttribPointer(locations.a_radius, 1, ol.webgl.FLOAT,
false, 16, 12);
// Enable renderer specific uniforms.
gl.uniform2fv(locations.u_size, size);
gl.uniform1f(locations.u_pixelRatio, pixelRatio);
return locations;
};
/**
* @inheritDoc
*/
ol.render.webgl.CircleReplay.prototype.shutDownProgram = function(gl, locations) {
gl.disableVertexAttribArray(locations.a_position);
gl.disableVertexAttribArray(locations.a_instruction);
gl.disableVertexAttribArray(locations.a_radius);
};
/**
* @inheritDoc
*/
ol.render.webgl.CircleReplay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {
if (!ol.obj.isEmpty(skippedFeaturesHash)) {
this.drawReplaySkipping_(gl, context, skippedFeaturesHash);
} else {
ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,
'number of styles and styleIndices match');
//Draw by style groups to minimize drawElements() calls.
var i, start, end, nextStyle;
end = this.startIndices[this.startIndices.length - 1];
for (i = this.styleIndices_.length - 1; i >= 0; --i) {
start = this.styleIndices_[i];
nextStyle = this.styles_[i];
this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));
this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),
/** @type {number} */ (nextStyle[2]));
this.drawElements(gl, context, start, end);
end = start;
}
}
};
/**
* @inheritDoc
*/
ol.render.webgl.CircleReplay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash,
featureCallback, opt_hitExtent) {
ol.DEBUG && console.assert(this.styles_.length === this.styleIndices_.length,
'number of styles and styleIndices match');
ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,
'number of startIndices and startIndicesFeature match');
var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex;
featureIndex = this.startIndices.length - 2;
end = this.startIndices[featureIndex + 1];
for (i = this.styleIndices_.length - 1; i >= 0; --i) {
nextStyle = this.styles_[i];
this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));
this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),
/** @type {number} */ (nextStyle[2]));
groupStart = this.styleIndices_[i];
while (featureIndex >= 0 &&
this.startIndices[featureIndex] >= groupStart) {
start = this.startIndices[featureIndex];
feature = this.startIndicesFeature[featureIndex];
featureUid = ol.getUid(feature).toString();
if (skippedFeaturesHash[featureUid] === undefined &&
feature.getGeometry() &&
(opt_hitExtent === undefined || ol.extent.intersects(
/** @type {Array<number>} */ (opt_hitExtent),
feature.getGeometry().getExtent()))) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
this.drawElements(gl, context, start, end);
var result = featureCallback(feature);
if (result) {
return result;
}
}
featureIndex--;
end = start;
}
}
return undefined;
};
/**
* @private
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object} skippedFeaturesHash Ids of features to skip.
*/
ol.render.webgl.CircleReplay.prototype.drawReplaySkipping_ = function(gl, context, skippedFeaturesHash) {
ol.DEBUG && console.assert(this.startIndices.length - 1 === this.startIndicesFeature.length,
'number of startIndices and startIndicesFeature match');
var i, start, end, nextStyle, groupStart, feature, featureUid, featureIndex, featureStart;
featureIndex = this.startIndices.length - 2;
end = start = this.startIndices[featureIndex + 1];
for (i = this.styleIndices_.length - 1; i >= 0; --i) {
nextStyle = this.styles_[i];
this.setFillStyle_(gl, /** @type {Array.<number>} */ (nextStyle[0]));
this.setStrokeStyle_(gl, /** @type {Array.<number>} */ (nextStyle[1]),
/** @type {number} */ (nextStyle[2]));
groupStart = this.styleIndices_[i];
while (featureIndex >= 0 &&
this.startIndices[featureIndex] >= groupStart) {
featureStart = this.startIndices[featureIndex];
feature = this.startIndicesFeature[featureIndex];
featureUid = ol.getUid(feature).toString();
if (skippedFeaturesHash[featureUid]) {
if (start !== end) {
this.drawElements(gl, context, start, end);
}
end = featureStart;
}
featureIndex--;
start = featureStart;
}
if (start !== end) {
this.drawElements(gl, context, start, end);
}
}
};
/**
* @private
* @param {WebGLRenderingContext} gl gl.
* @param {Array.<number>} color Color.
*/
ol.render.webgl.CircleReplay.prototype.setFillStyle_ = function(gl, color) {
gl.uniform4fv(this.defaultLocations_.u_fillColor, color);
};
/**
* @private
* @param {WebGLRenderingContext} gl gl.
* @param {Array.<number>} color Color.
* @param {number} lineWidth Line width.
*/
ol.render.webgl.CircleReplay.prototype.setStrokeStyle_ = function(gl, color, lineWidth) {
gl.uniform4fv(this.defaultLocations_.u_strokeColor, color);
gl.uniform1f(this.defaultLocations_.u_lineWidth, lineWidth);
};
/**
* @inheritDoc
*/
ol.render.webgl.CircleReplay.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
ol.DEBUG && console.assert(this.state_, 'this.state_ should not be null');
var strokeStyleColor, strokeStyleWidth;
if (strokeStyle) {
var strokeStyleLineDash = strokeStyle.getLineDash();
this.state_.lineDash = strokeStyleLineDash ?
strokeStyleLineDash : ol.render.webgl.defaultLineDash;
strokeStyleColor = strokeStyle.getColor();
if (!(strokeStyleColor instanceof CanvasGradient) &&
!(strokeStyleColor instanceof CanvasPattern)) {
strokeStyleColor = ol.color.asArray(strokeStyleColor).map(function(c, i) {
return i != 3 ? c / 255 : c;
}) || ol.render.webgl.defaultStrokeStyle;
} else {
strokeStyleColor = ol.render.webgl.defaultStrokeStyle;
}
strokeStyleWidth = strokeStyle.getWidth();
strokeStyleWidth = strokeStyleWidth !== undefined ?
strokeStyleWidth : ol.render.webgl.defaultLineWidth;
} else {
strokeStyleColor = [0, 0, 0, 0];
strokeStyleWidth = 0;
}
var fillStyleColor = fillStyle ? fillStyle.getColor() : [0, 0, 0, 0];
if (!(fillStyleColor instanceof CanvasGradient) &&
!(fillStyleColor instanceof CanvasPattern)) {
fillStyleColor = ol.color.asArray(fillStyleColor).map(function(c, i) {
return i != 3 ? c / 255 : c;
}) || ol.render.webgl.defaultFillStyle;
} else {
fillStyleColor = ol.render.webgl.defaultFillStyle;
}
if (!this.state_.strokeColor || !ol.array.equals(this.state_.strokeColor, strokeStyleColor) ||
!this.state_.fillColor || !ol.array.equals(this.state_.fillColor, fillStyleColor) ||
this.state_.lineWidth !== strokeStyleWidth) {
this.state_.changed = true;
this.state_.fillColor = fillStyleColor;
this.state_.strokeColor = strokeStyleColor;
this.state_.lineWidth = strokeStyleWidth;
this.styles_.push([fillStyleColor, strokeStyleColor, strokeStyleWidth]);
}
};

View File

@@ -132,7 +132,8 @@ ol.render.webgl.Replay.prototype.finish = function(context) {};
* @param {ol.webgl.Context} context Context.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @return {ol.render.webgl.imagereplay.defaultshader.Locations|
* @return {ol.render.webgl.circlereplay.defaultshader.Locations|
ol.render.webgl.imagereplay.defaultshader.Locations|
ol.render.webgl.linestringreplay.defaultshader.Locations|
ol.render.webgl.polygonreplay.defaultshader.Locations} Locations.
*/
@@ -143,7 +144,8 @@ ol.render.webgl.Replay.prototype.setUpProgram = function(gl, context, size, pixe
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.render.webgl.imagereplay.defaultshader.Locations|
* @param {ol.render.webgl.circlereplay.defaultshader.Locations|
ol.render.webgl.imagereplay.defaultshader.Locations|
ol.render.webgl.linestringreplay.defaultshader.Locations|
ol.render.webgl.polygonreplay.defaultshader.Locations} locations Locations.
*/

View File

@@ -4,6 +4,7 @@ goog.require('ol');
goog.require('ol.array');
goog.require('ol.render.ReplayGroup');
goog.require('ol.render.webgl');
goog.require('ol.render.webgl.CircleReplay');
goog.require('ol.render.webgl.ImageReplay');
goog.require('ol.render.webgl.LineStringReplay');
goog.require('ol.render.webgl.PolygonReplay');
@@ -104,7 +105,7 @@ ol.render.webgl.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
var Constructor = ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];
ol.DEBUG && console.assert(Constructor !== undefined,
replayType +
' constructor missing from ol.render.canvas.ReplayGroup.BATCH_CONSTRUCTORS_');
' constructor missing from ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_');
replay = new Constructor(this.tolerance_, this.maxExtent_);
replays[replayType] = replay;
}
@@ -308,6 +309,7 @@ ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_ = [1, 1];
* ol.Extent)>}
*/
ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_ = {
'Circle': ol.render.webgl.CircleReplay,
'Image': ol.render.webgl.ImageReplay,
'LineString': ol.render.webgl.LineStringReplay,
'Polygon': ol.render.webgl.PolygonReplay

View File

@@ -47,10 +47,10 @@ ol.renderer.vector.renderCircleGeometry_ = function(replayGroup, geometry, style
var fillStyle = style.getFill();
var strokeStyle = style.getStroke();
if (fillStyle || strokeStyle) {
var polygonReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.POLYGON);
polygonReplay.setFillStrokeStyle(fillStyle, strokeStyle);
polygonReplay.drawCircle(geometry, feature);
var circleReplay = replayGroup.getReplay(
style.getZIndex(), ol.render.ReplayType.CIRCLE);
circleReplay.setFillStrokeStyle(fillStyle, strokeStyle);
circleReplay.drawCircle(geometry, feature);
}
var textStyle = style.getText();
if (textStyle) {