Wrap ol.render.webgl code in define condition

This commit is contained in:
Andreas Hocevar
2017-01-02 21:24:23 +01:00
parent ab3d97d6de
commit 446807825e
9 changed files with 3417 additions and 3378 deletions

View File

@@ -1,68 +1,72 @@
goog.provide('ol.render.webgl'); goog.provide('ol.render.webgl');
/** if (ol.ENABLE_WEBGL) {
* @const
* @type {ol.Color}
*/
ol.render.webgl.defaultFillStyle = [0.0, 0.0, 0.0, 1.0];
/** /**
* @const * @const
* @type {string} * @type {ol.Color}
*/ */
ol.render.webgl.defaultLineCap = 'round'; ol.render.webgl.defaultFillStyle = [0.0, 0.0, 0.0, 1.0];
/**
* @const
* @type {string}
*/
ol.render.webgl.defaultLineCap = 'round';
/** /**
* @const * @const
* @type {Array.<number>} * @type {Array.<number>}
*/ */
ol.render.webgl.defaultLineDash = []; ol.render.webgl.defaultLineDash = [];
/** /**
* @const * @const
* @type {string} * @type {string}
*/ */
ol.render.webgl.defaultLineJoin = 'round'; ol.render.webgl.defaultLineJoin = 'round';
/** /**
* @const * @const
* @type {number} * @type {number}
*/ */
ol.render.webgl.defaultMiterLimit = 10; ol.render.webgl.defaultMiterLimit = 10;
/** /**
* @const * @const
* @type {ol.Color} * @type {ol.Color}
*/ */
ol.render.webgl.defaultStrokeStyle = [0.0, 0.0, 0.0, 1.0]; ol.render.webgl.defaultStrokeStyle = [0.0, 0.0, 0.0, 1.0];
/** /**
* @const * @const
* @type {number} * @type {number}
*/ */
ol.render.webgl.defaultLineWidth = 1; ol.render.webgl.defaultLineWidth = 1;
/** /**
* Calculates the orientation of a triangle based on the determinant method. * Calculates the orientation of a triangle based on the determinant method.
* @param {number} x1 First X coordinate. * @param {number} x1 First X coordinate.
* @param {number} y1 First Y coordinate. * @param {number} y1 First Y coordinate.
* @param {number} x2 Second X coordinate. * @param {number} x2 Second X coordinate.
* @param {number} y2 Second Y coordinate. * @param {number} y2 Second Y coordinate.
* @param {number} x3 Third X coordinate. * @param {number} x3 Third X coordinate.
* @param {number} y3 Third Y coordinate. * @param {number} y3 Third Y coordinate.
* @return {boolean|undefined} Triangle is clockwise. * @return {boolean|undefined} Triangle is clockwise.
*/ */
ol.render.webgl.triangleIsCounterClockwise = function(x1, y1, x2, y2, x3, y3) { ol.render.webgl.triangleIsCounterClockwise = function(x1, y1, x2, y2, x3, y3) {
var area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1); var area = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
return (area <= ol.render.webgl.EPSILON && area >= -ol.render.webgl.EPSILON) ? return (area <= ol.render.webgl.EPSILON && area >= -ol.render.webgl.EPSILON) ?
undefined : area > 0; undefined : area > 0;
}; };
/** /**
* @const * @const
* @type {number} * @type {number}
*/ */
ol.render.webgl.EPSILON = Number.EPSILON || 2.220446049250313e-16; ol.render.webgl.EPSILON = Number.EPSILON || 2.220446049250313e-16;
}

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -9,325 +9,329 @@ goog.require('ol.render.webgl.ReplayGroup');
goog.require('ol.render.webgl'); goog.require('ol.render.webgl');
/** if (ol.ENABLE_WEBGL) {
* @constructor
* @extends {ol.render.VectorContext}
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {ol.Extent} extent Extent.
* @param {number} pixelRatio Pixel ratio.
* @struct
*/
ol.render.webgl.Immediate = function(context, center, resolution, rotation, size, extent, pixelRatio) {
ol.render.VectorContext.call(this);
/** /**
* @private * @constructor
* @extends {ol.render.VectorContext}
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {ol.Extent} extent Extent.
* @param {number} pixelRatio Pixel ratio.
* @struct
*/ */
this.context_ = context; ol.render.webgl.Immediate = function(context, center, resolution, rotation, size, extent, pixelRatio) {
ol.render.VectorContext.call(this);
/**
* @private
*/
this.context_ = context;
/**
* @private
*/
this.center_ = center;
/**
* @private
*/
this.extent_ = extent;
/**
* @private
*/
this.pixelRatio_ = pixelRatio;
/**
* @private
*/
this.size_ = size;
/**
* @private
*/
this.rotation_ = rotation;
/**
* @private
*/
this.resolution_ = resolution;
/**
* @private
* @type {ol.style.Image}
*/
this.imageStyle_ = null;
/**
* @private
* @type {ol.style.Fill}
*/
this.fillStyle_ = null;
/**
* @private
* @type {ol.style.Stroke}
*/
this.strokeStyle_ = null;
};
ol.inherits(ol.render.webgl.Immediate, ol.render.VectorContext);
/** /**
* @private * Set the rendering style. Note that since this is an immediate rendering API,
* any `zIndex` on the provided style will be ignored.
*
* @param {ol.style.Style} style The rendering style.
* @api
*/ */
this.center_ = center; ol.render.webgl.Immediate.prototype.setStyle = function(style) {
this.setFillStrokeStyle(style.getFill(), style.getStroke());
this.setImageStyle(style.getImage());
};
/** /**
* @private * Render a geometry into the canvas. Call
* {@link ol.render.webgl.Immediate#setStyle} first to set the rendering style.
*
* @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render.
* @api
*/ */
this.extent_ = extent; ol.render.webgl.Immediate.prototype.drawGeometry = function(geometry) {
var type = geometry.getType();
switch (type) {
case ol.geom.GeometryType.POINT:
this.drawPoint(/** @type {ol.geom.Point} */ (geometry), null);
break;
case ol.geom.GeometryType.LINE_STRING:
this.drawLineString(/** @type {ol.geom.LineString} */ (geometry), null);
break;
case ol.geom.GeometryType.POLYGON:
this.drawPolygon(/** @type {ol.geom.Polygon} */ (geometry), null);
break;
case ol.geom.GeometryType.MULTI_POINT:
this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry), null);
break;
case ol.geom.GeometryType.MULTI_LINE_STRING:
this.drawMultiLineString(/** @type {ol.geom.MultiLineString} */ (geometry), null);
break;
case ol.geom.GeometryType.MULTI_POLYGON:
this.drawMultiPolygon(/** @type {ol.geom.MultiPolygon} */ (geometry), null);
break;
case ol.geom.GeometryType.GEOMETRY_COLLECTION:
this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry), null);
break;
case ol.geom.GeometryType.CIRCLE:
this.drawCircle(/** @type {ol.geom.Circle} */ (geometry), null);
break;
default:
// pass
}
};
/** /**
* @private * @inheritDoc
* @api
*/ */
this.pixelRatio_ = pixelRatio; ol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) {
var geometry = style.getGeometryFunction()(feature);
if (!geometry ||
!ol.extent.intersects(this.extent_, geometry.getExtent())) {
return;
}
this.setStyle(style);
this.drawGeometry(geometry);
};
/** /**
* @private * @inheritDoc
*/ */
this.size_ = size; ol.render.webgl.Immediate.prototype.drawGeometryCollection = function(geometry, data) {
var geometries = geometry.getGeometriesArray();
var i, ii;
for (i = 0, ii = geometries.length; i < ii; ++i) {
this.drawGeometry(geometries[i]);
}
};
/** /**
* @private * @inheritDoc
*/ */
this.rotation_ = rotation; ol.render.webgl.Immediate.prototype.drawPoint = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.ImageReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
replay.setImageStyle(this.imageStyle_);
replay.drawPoint(geometry, data);
replay.finish(context);
// default colors
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/** /**
* @private * @inheritDoc
*/ */
this.resolution_ = resolution; ol.render.webgl.Immediate.prototype.drawMultiPoint = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.ImageReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
replay.setImageStyle(this.imageStyle_);
replay.drawMultiPoint(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/** /**
* @private * @inheritDoc
* @type {ol.style.Image}
*/ */
this.imageStyle_ = null; ol.render.webgl.Immediate.prototype.drawLineString = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.LineStringReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));
replay.setFillStrokeStyle(null, this.strokeStyle_);
replay.drawLineString(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/** /**
* @private * @inheritDoc
* @type {ol.style.Fill}
*/ */
this.fillStyle_ = null; ol.render.webgl.Immediate.prototype.drawMultiLineString = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.LineStringReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));
replay.setFillStrokeStyle(null, this.strokeStyle_);
replay.drawMultiLineString(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/** /**
* @private * @inheritDoc
* @type {ol.style.Stroke}
*/ */
this.strokeStyle_ = null; ol.render.webgl.Immediate.prototype.drawPolygon = function(geometry, data) {
var context = this.context_;
}; var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
ol.inherits(ol.render.webgl.Immediate, ol.render.VectorContext); var replay = /** @type {ol.render.webgl.PolygonReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));
replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
replay.drawPolygon(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/** /**
* Set the rendering style. Note that since this is an immediate rendering API, * @inheritDoc
* any `zIndex` on the provided style will be ignored. */
* ol.render.webgl.Immediate.prototype.drawMultiPolygon = function(geometry, data) {
* @param {ol.style.Style} style The rendering style. var context = this.context_;
* @api var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
*/ var replay = /** @type {ol.render.webgl.PolygonReplay} */ (
ol.render.webgl.Immediate.prototype.setStyle = function(style) { replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));
this.setFillStrokeStyle(style.getFill(), style.getStroke()); replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
this.setImageStyle(style.getImage()); replay.drawMultiPolygon(geometry, data);
}; replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/** /**
* Render a geometry into the canvas. Call * @inheritDoc
* {@link ol.render.webgl.Immediate#setStyle} first to set the rendering style. */
* ol.render.webgl.Immediate.prototype.drawCircle = function(geometry, data) {
* @param {ol.geom.Geometry|ol.render.Feature} geometry The geometry to render. var context = this.context_;
* @api var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
*/ var replay = /** @type {ol.render.webgl.CircleReplay} */ (
ol.render.webgl.Immediate.prototype.drawGeometry = function(geometry) { replayGroup.getReplay(0, ol.render.ReplayType.CIRCLE));
var type = geometry.getType(); replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
switch (type) { replay.drawCircle(geometry, data);
case ol.geom.GeometryType.POINT: replay.finish(context);
this.drawPoint(/** @type {ol.geom.Point} */ (geometry), null); var opacity = 1;
break; var skippedFeatures = {};
case ol.geom.GeometryType.LINE_STRING: var featureCallback;
this.drawLineString(/** @type {ol.geom.LineString} */ (geometry), null); var oneByOne = false;
break; replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
case ol.geom.GeometryType.POLYGON: this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
this.drawPolygon(/** @type {ol.geom.Polygon} */ (geometry), null); oneByOne);
break; replay.getDeleteResourcesFunction(context)();
case ol.geom.GeometryType.MULTI_POINT: };
this.drawMultiPoint(/** @type {ol.geom.MultiPoint} */ (geometry), null);
break;
case ol.geom.GeometryType.MULTI_LINE_STRING:
this.drawMultiLineString(/** @type {ol.geom.MultiLineString} */ (geometry), null);
break;
case ol.geom.GeometryType.MULTI_POLYGON:
this.drawMultiPolygon(/** @type {ol.geom.MultiPolygon} */ (geometry), null);
break;
case ol.geom.GeometryType.GEOMETRY_COLLECTION:
this.drawGeometryCollection(/** @type {ol.geom.GeometryCollection} */ (geometry), null);
break;
case ol.geom.GeometryType.CIRCLE:
this.drawCircle(/** @type {ol.geom.Circle} */ (geometry), null);
break;
default:
// pass
}
};
/** /**
* @inheritDoc * @inheritDoc
* @api */
*/ ol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) {
ol.render.webgl.Immediate.prototype.drawFeature = function(feature, style) { this.imageStyle_ = imageStyle;
var geometry = style.getGeometryFunction()(feature); };
if (!geometry ||
!ol.extent.intersects(this.extent_, geometry.getExtent())) {
return;
}
this.setStyle(style);
this.drawGeometry(geometry);
};
/** /**
* @inheritDoc * @inheritDoc
*/ */
ol.render.webgl.Immediate.prototype.drawGeometryCollection = function(geometry, data) { ol.render.webgl.Immediate.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
var geometries = geometry.getGeometriesArray(); this.fillStyle_ = fillStyle;
var i, ii; this.strokeStyle_ = strokeStyle;
for (i = 0, ii = geometries.length; i < ii; ++i) { };
this.drawGeometry(geometries[i]);
}
};
}
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.drawPoint = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.ImageReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
replay.setImageStyle(this.imageStyle_);
replay.drawPoint(geometry, data);
replay.finish(context);
// default colors
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.drawMultiPoint = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.ImageReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.IMAGE));
replay.setImageStyle(this.imageStyle_);
replay.drawMultiPoint(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.drawLineString = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.LineStringReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));
replay.setFillStrokeStyle(null, this.strokeStyle_);
replay.drawLineString(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.drawMultiLineString = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.LineStringReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.LINE_STRING));
replay.setFillStrokeStyle(null, this.strokeStyle_);
replay.drawMultiLineString(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.drawPolygon = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.PolygonReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));
replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
replay.drawPolygon(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.drawMultiPolygon = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.PolygonReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.POLYGON));
replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
replay.drawMultiPolygon(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.drawCircle = function(geometry, data) {
var context = this.context_;
var replayGroup = new ol.render.webgl.ReplayGroup(1, this.extent_);
var replay = /** @type {ol.render.webgl.CircleReplay} */ (
replayGroup.getReplay(0, ol.render.ReplayType.CIRCLE));
replay.setFillStrokeStyle(this.fillStyle_, this.strokeStyle_);
replay.drawCircle(geometry, data);
replay.finish(context);
var opacity = 1;
var skippedFeatures = {};
var featureCallback;
var oneByOne = false;
replay.replay(this.context_, this.center_, this.resolution_, this.rotation_,
this.size_, this.pixelRatio_, opacity, skippedFeatures, featureCallback,
oneByOne);
replay.getDeleteResourcesFunction(context)();
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.setImageStyle = function(imageStyle) {
this.imageStyle_ = imageStyle;
};
/**
* @inheritDoc
*/
ol.render.webgl.Immediate.prototype.setFillStrokeStyle = function(fillStyle, strokeStyle) {
this.fillStyle_ = fillStyle;
this.strokeStyle_ = strokeStyle;
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -7,353 +7,358 @@ goog.require('ol.transform');
goog.require('ol.vec.Mat4'); goog.require('ol.vec.Mat4');
goog.require('ol.webgl'); goog.require('ol.webgl');
/**
* @constructor if (ol.ENABLE_WEBGL) {
* @extends {ol.render.VectorContext}
* @param {number} tolerance Tolerance. /**
* @param {ol.Extent} maxExtent Max extent. * @constructor
* @struct * @extends {ol.render.VectorContext}
*/ * @param {number} tolerance Tolerance.
ol.render.webgl.Replay = function(tolerance, maxExtent) { * @param {ol.Extent} maxExtent Max extent.
ol.render.VectorContext.call(this); * @struct
*/
ol.render.webgl.Replay = function(tolerance, maxExtent) {
ol.render.VectorContext.call(this);
/**
* @protected
* @type {number}
*/
this.tolerance = tolerance;
/**
* @protected
* @const
* @type {ol.Extent}
*/
this.maxExtent = maxExtent;
/**
* The origin of the coordinate system for the point coordinates sent to
* the GPU. To eliminate jitter caused by precision problems in the GPU
* we use the "Rendering Relative to Eye" technique described in the "3D
* Engine Design for Virtual Globes" book.
* @protected
* @type {ol.Coordinate}
*/
this.origin = ol.extent.getCenter(maxExtent);
/**
* @private
* @type {ol.Transform}
*/
this.projectionMatrix_ = ol.transform.create();
/**
* @private
* @type {ol.Transform}
*/
this.offsetRotateMatrix_ = ol.transform.create();
/**
* @private
* @type {ol.Transform}
*/
this.offsetScaleMatrix_ = ol.transform.create();
/**
* @private
* @type {Array.<number>}
*/
this.tmpMat4_ = ol.vec.Mat4.create();
/**
* @protected
* @type {Array.<number>}
*/
this.indices = [];
/**
* @protected
* @type {?ol.webgl.Buffer}
*/
this.indicesBuffer = null;
/**
* Start index per feature (the index).
* @protected
* @type {Array.<number>}
*/
this.startIndices = [];
/**
* Start index per feature (the feature).
* @protected
* @type {Array.<ol.Feature|ol.render.Feature>}
*/
this.startIndicesFeature = [];
/**
* @protected
* @type {Array.<number>}
*/
this.vertices = [];
/**
* @protected
* @type {?ol.webgl.Buffer}
*/
this.verticesBuffer = null;
/**
* Optional parameter for PolygonReplay instances.
* @protected
* @type {ol.render.webgl.LineStringReplay|undefined}
*/
this.lineStringReplay = undefined;
};
ol.inherits(ol.render.webgl.Replay, ol.render.VectorContext);
/**
* @abstract
* @param {ol.webgl.Context} context WebGL context.
* @return {function()} Delete resources function.
*/
ol.render.webgl.Replay.prototype.getDeleteResourcesFunction = function(context) {};
/**
* @abstract
* @param {ol.webgl.Context} context Context.
*/
ol.render.webgl.Replay.prototype.finish = function(context) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @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.
*/
ol.render.webgl.Replay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @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.
*/
ol.render.webgl.Replay.prototype.shutDownProgram = function(gl, locations) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {boolean} hitDetection Hit detection mode.
*/
ol.render.webgl.Replay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.Replay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash, featureCallback, opt_hitExtent) {};
/** /**
* @protected * @protected
* @type {number} * @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/ */
this.tolerance = tolerance; ol.render.webgl.Replay.prototype.drawHitDetectionReplay = function(gl, context, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent) {
/** if (!oneByOne) {
* @protected // draw all hit-detection features in "once" (by texture group)
* @const return this.drawHitDetectionReplayAll(gl, context,
* @type {ol.Extent} skippedFeaturesHash, featureCallback);
*/ } else {
this.maxExtent = maxExtent; // draw hit-detection features one by one
return this.drawHitDetectionReplayOneByOne(gl, context,
/** skippedFeaturesHash, featureCallback, opt_hitExtent);
* The origin of the coordinate system for the point coordinates sent to
* the GPU. To eliminate jitter caused by precision problems in the GPU
* we use the "Rendering Relative to Eye" technique described in the "3D
* Engine Design for Virtual Globes" book.
* @protected
* @type {ol.Coordinate}
*/
this.origin = ol.extent.getCenter(maxExtent);
/**
* @private
* @type {ol.Transform}
*/
this.projectionMatrix_ = ol.transform.create();
/**
* @private
* @type {ol.Transform}
*/
this.offsetRotateMatrix_ = ol.transform.create();
/**
* @private
* @type {ol.Transform}
*/
this.offsetScaleMatrix_ = ol.transform.create();
/**
* @private
* @type {Array.<number>}
*/
this.tmpMat4_ = ol.vec.Mat4.create();
/**
* @protected
* @type {Array.<number>}
*/
this.indices = [];
/**
* @protected
* @type {?ol.webgl.Buffer}
*/
this.indicesBuffer = null;
/**
* Start index per feature (the index).
* @protected
* @type {Array.<number>}
*/
this.startIndices = [];
/**
* Start index per feature (the feature).
* @protected
* @type {Array.<ol.Feature|ol.render.Feature>}
*/
this.startIndicesFeature = [];
/**
* @protected
* @type {Array.<number>}
*/
this.vertices = [];
/**
* @protected
* @type {?ol.webgl.Buffer}
*/
this.verticesBuffer = null;
/**
* Optional parameter for PolygonReplay instances.
* @protected
* @type {ol.render.webgl.LineStringReplay|undefined}
*/
this.lineStringReplay = undefined;
};
ol.inherits(ol.render.webgl.Replay, ol.render.VectorContext);
/**
* @abstract
* @param {ol.webgl.Context} context WebGL context.
* @return {function()} Delete resources function.
*/
ol.render.webgl.Replay.prototype.getDeleteResourcesFunction = function(context) {};
/**
* @abstract
* @param {ol.webgl.Context} context Context.
*/
ol.render.webgl.Replay.prototype.finish = function(context) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @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.
*/
ol.render.webgl.Replay.prototype.setUpProgram = function(gl, context, size, pixelRatio) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @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.
*/
ol.render.webgl.Replay.prototype.shutDownProgram = function(gl, locations) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {boolean} hitDetection Hit detection mode.
*/
ol.render.webgl.Replay.prototype.drawReplay = function(gl, context, skippedFeaturesHash, hitDetection) {};
/**
* @abstract
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.Replay.prototype.drawHitDetectionReplayOneByOne = function(gl, context, skippedFeaturesHash, featureCallback, opt_hitExtent) {};
/**
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.Replay.prototype.drawHitDetectionReplay = function(gl, context, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent) {
if (!oneByOne) {
// draw all hit-detection features in "once" (by texture group)
return this.drawHitDetectionReplayAll(gl, context,
skippedFeaturesHash, featureCallback);
} else {
// draw hit-detection features one by one
return this.drawHitDetectionReplayOneByOne(gl, context,
skippedFeaturesHash, featureCallback, opt_hitExtent);
}
};
/**
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.Replay.prototype.drawHitDetectionReplayAll = function(gl, context, skippedFeaturesHash,
featureCallback) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
this.drawReplay(gl, context, skippedFeaturesHash, true);
var result = featureCallback(null);
if (result) {
return result;
} else {
return undefined;
}
};
/**
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.Replay.prototype.replay = function(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent) {
var gl = context.getGL();
var tmpStencil, tmpStencilFunc, tmpStencilMaskVal, tmpStencilRef, tmpStencilMask,
tmpStencilOpFail, tmpStencilOpPass, tmpStencilOpZFail;
if (this.lineStringReplay) {
tmpStencil = gl.isEnabled(gl.STENCIL_TEST);
tmpStencilFunc = gl.getParameter(gl.STENCIL_FUNC);
tmpStencilMaskVal = gl.getParameter(gl.STENCIL_VALUE_MASK);
tmpStencilRef = gl.getParameter(gl.STENCIL_REF);
tmpStencilMask = gl.getParameter(gl.STENCIL_WRITEMASK);
tmpStencilOpFail = gl.getParameter(gl.STENCIL_FAIL);
tmpStencilOpPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS);
tmpStencilOpZFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL);
gl.enable(gl.STENCIL_TEST);
gl.clear(gl.STENCIL_BUFFER_BIT);
gl.stencilMask(255);
gl.stencilFunc(gl.ALWAYS, 1, 255);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
this.lineStringReplay.replay(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent);
gl.stencilMask(0);
gl.stencilFunc(gl.NOTEQUAL, 1, 255);
}
context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.verticesBuffer);
context.bindBuffer(ol.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
var locations = this.setUpProgram(gl, context, size, pixelRatio);
// set the "uniform" values
var projectionMatrix = ol.transform.reset(this.projectionMatrix_);
ol.transform.scale(projectionMatrix, 2 / (resolution * size[0]), 2 / (resolution * size[1]));
ol.transform.rotate(projectionMatrix, -rotation);
ol.transform.translate(projectionMatrix, -(center[0] - this.origin[0]), -(center[1] - this.origin[1]));
var offsetScaleMatrix = ol.transform.reset(this.offsetScaleMatrix_);
ol.transform.scale(offsetScaleMatrix, 2 / size[0], 2 / size[1]);
var offsetRotateMatrix = ol.transform.reset(this.offsetRotateMatrix_);
if (rotation !== 0) {
ol.transform.rotate(offsetRotateMatrix, -rotation);
}
gl.uniformMatrix4fv(locations.u_projectionMatrix, false,
ol.vec.Mat4.fromTransform(this.tmpMat4_, projectionMatrix));
gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false,
ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetScaleMatrix));
gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false,
ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetRotateMatrix));
gl.uniform1f(locations.u_opacity, opacity);
// draw!
var result;
if (featureCallback === undefined) {
this.drawReplay(gl, context, skippedFeaturesHash, false);
} else {
// draw feature by feature for the hit-detection
result = this.drawHitDetectionReplay(gl, context, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent);
}
// disable the vertex attrib arrays
this.shutDownProgram(gl, locations);
if (this.lineStringReplay) {
if (!tmpStencil) {
gl.disable(gl.STENCIL_TEST);
} }
gl.clear(gl.STENCIL_BUFFER_BIT); };
gl.stencilFunc(/** @type {number} */ (tmpStencilFunc),
/** @type {number} */ (tmpStencilRef), /** @type {number} */ (tmpStencilMaskVal));
gl.stencilMask(/** @type {number} */ (tmpStencilMask));
gl.stencilOp(/** @type {number} */ (tmpStencilOpFail),
/** @type {number} */ (tmpStencilOpZFail), /** @type {number} */ (tmpStencilOpPass));
}
return result;
};
/** /**
* @protected * @protected
* @param {WebGLRenderingContext} gl gl. * @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context. * @param {ol.webgl.Context} context Context.
* @param {number} start Start index. * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* @param {number} end End index. * to skip.
*/ * @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
ol.render.webgl.Replay.prototype.drawElements = function( * @return {T|undefined} Callback result.
gl, context, start, end) { * @template T
var elementType = context.hasOESElementIndexUint ? */
ol.webgl.UNSIGNED_INT : ol.webgl.UNSIGNED_SHORT; ol.render.webgl.Replay.prototype.drawHitDetectionReplayAll = function(gl, context, skippedFeaturesHash,
var elementSize = context.hasOESElementIndexUint ? 4 : 2; featureCallback) {
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
this.drawReplay(gl, context, skippedFeaturesHash, true);
var numItems = end - start; var result = featureCallback(null);
var offsetInBytes = start * elementSize; if (result) {
gl.drawElements(ol.webgl.TRIANGLES, numItems, elementType, offsetInBytes); return result;
}; } else {
return undefined;
}
};
/**
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.Replay.prototype.replay = function(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent) {
var gl = context.getGL();
var tmpStencil, tmpStencilFunc, tmpStencilMaskVal, tmpStencilRef, tmpStencilMask,
tmpStencilOpFail, tmpStencilOpPass, tmpStencilOpZFail;
if (this.lineStringReplay) {
tmpStencil = gl.isEnabled(gl.STENCIL_TEST);
tmpStencilFunc = gl.getParameter(gl.STENCIL_FUNC);
tmpStencilMaskVal = gl.getParameter(gl.STENCIL_VALUE_MASK);
tmpStencilRef = gl.getParameter(gl.STENCIL_REF);
tmpStencilMask = gl.getParameter(gl.STENCIL_WRITEMASK);
tmpStencilOpFail = gl.getParameter(gl.STENCIL_FAIL);
tmpStencilOpPass = gl.getParameter(gl.STENCIL_PASS_DEPTH_PASS);
tmpStencilOpZFail = gl.getParameter(gl.STENCIL_PASS_DEPTH_FAIL);
gl.enable(gl.STENCIL_TEST);
gl.clear(gl.STENCIL_BUFFER_BIT);
gl.stencilMask(255);
gl.stencilFunc(gl.ALWAYS, 1, 255);
gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);
this.lineStringReplay.replay(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent);
gl.stencilMask(0);
gl.stencilFunc(gl.NOTEQUAL, 1, 255);
}
context.bindBuffer(ol.webgl.ARRAY_BUFFER, this.verticesBuffer);
context.bindBuffer(ol.webgl.ELEMENT_ARRAY_BUFFER, this.indicesBuffer);
var locations = this.setUpProgram(gl, context, size, pixelRatio);
// set the "uniform" values
var projectionMatrix = ol.transform.reset(this.projectionMatrix_);
ol.transform.scale(projectionMatrix, 2 / (resolution * size[0]), 2 / (resolution * size[1]));
ol.transform.rotate(projectionMatrix, -rotation);
ol.transform.translate(projectionMatrix, -(center[0] - this.origin[0]), -(center[1] - this.origin[1]));
var offsetScaleMatrix = ol.transform.reset(this.offsetScaleMatrix_);
ol.transform.scale(offsetScaleMatrix, 2 / size[0], 2 / size[1]);
var offsetRotateMatrix = ol.transform.reset(this.offsetRotateMatrix_);
if (rotation !== 0) {
ol.transform.rotate(offsetRotateMatrix, -rotation);
}
gl.uniformMatrix4fv(locations.u_projectionMatrix, false,
ol.vec.Mat4.fromTransform(this.tmpMat4_, projectionMatrix));
gl.uniformMatrix4fv(locations.u_offsetScaleMatrix, false,
ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetScaleMatrix));
gl.uniformMatrix4fv(locations.u_offsetRotateMatrix, false,
ol.vec.Mat4.fromTransform(this.tmpMat4_, offsetRotateMatrix));
gl.uniform1f(locations.u_opacity, opacity);
// draw!
var result;
if (featureCallback === undefined) {
this.drawReplay(gl, context, skippedFeaturesHash, false);
} else {
// draw feature by feature for the hit-detection
result = this.drawHitDetectionReplay(gl, context, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent);
}
// disable the vertex attrib arrays
this.shutDownProgram(gl, locations);
if (this.lineStringReplay) {
if (!tmpStencil) {
gl.disable(gl.STENCIL_TEST);
}
gl.clear(gl.STENCIL_BUFFER_BIT);
gl.stencilFunc(/** @type {number} */ (tmpStencilFunc),
/** @type {number} */ (tmpStencilRef), /** @type {number} */ (tmpStencilMaskVal));
gl.stencilMask(/** @type {number} */ (tmpStencilMask));
gl.stencilOp(/** @type {number} */ (tmpStencilOpFail),
/** @type {number} */ (tmpStencilOpZFail), /** @type {number} */ (tmpStencilOpPass));
}
return result;
};
/**
* @protected
* @param {WebGLRenderingContext} gl gl.
* @param {ol.webgl.Context} context Context.
* @param {number} start Start index.
* @param {number} end End index.
*/
ol.render.webgl.Replay.prototype.drawElements = function(
gl, context, start, end) {
var elementType = context.hasOESElementIndexUint ?
ol.webgl.UNSIGNED_INT : ol.webgl.UNSIGNED_SHORT;
var elementSize = context.hasOESElementIndexUint ? 4 : 2;
var numItems = end - start;
var offsetInBytes = start * elementSize;
gl.drawElements(ol.webgl.TRIANGLES, numItems, elementType, offsetInBytes);
};
}

View File

@@ -13,306 +13,311 @@ goog.require('ol.render.webgl.LineStringReplay');
goog.require('ol.render.webgl.PolygonReplay'); goog.require('ol.render.webgl.PolygonReplay');
goog.require('ol.render.webgl.TextReplay'); goog.require('ol.render.webgl.TextReplay');
/**
* @constructor if (ol.ENABLE_WEBGL) {
* @extends {ol.render.ReplayGroup}
* @param {number} tolerance Tolerance.
* @param {ol.Extent} maxExtent Max extent.
* @param {number=} opt_renderBuffer Render buffer.
* @struct
*/
ol.render.webgl.ReplayGroup = function(tolerance, maxExtent, opt_renderBuffer) {
ol.render.ReplayGroup.call(this);
/** /**
* @type {ol.Extent} * @constructor
* @private * @extends {ol.render.ReplayGroup}
* @param {number} tolerance Tolerance.
* @param {ol.Extent} maxExtent Max extent.
* @param {number=} opt_renderBuffer Render buffer.
* @struct
*/ */
this.maxExtent_ = maxExtent; ol.render.webgl.ReplayGroup = function(tolerance, maxExtent, opt_renderBuffer) {
ol.render.ReplayGroup.call(this);
/** /**
* @type {number} * @type {ol.Extent}
* @private * @private
*/ */
this.tolerance_ = tolerance; this.maxExtent_ = maxExtent;
/** /**
* @type {number|undefined} * @type {number}
* @private * @private
*/ */
this.renderBuffer_ = opt_renderBuffer; this.tolerance_ = tolerance;
/** /**
* @private * @type {number|undefined}
* @type {!Object.<string, * @private
* Object.<ol.render.ReplayType, ol.render.webgl.Replay>>} */
*/ this.renderBuffer_ = opt_renderBuffer;
this.replaysByZIndex_ = {};
}; /**
ol.inherits(ol.render.webgl.ReplayGroup, ol.render.ReplayGroup); * @private
* @type {!Object.<string,
* Object.<ol.render.ReplayType, ol.render.webgl.Replay>>}
*/
this.replaysByZIndex_ = {};
/**
* @param {ol.webgl.Context} context WebGL context.
* @return {function()} Delete resources function.
*/
ol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = function(context) {
var functions = [];
var zKey;
for (zKey in this.replaysByZIndex_) {
var replays = this.replaysByZIndex_[zKey];
var replayKey;
for (replayKey in replays) {
functions.push(
replays[replayKey].getDeleteResourcesFunction(context));
}
}
return function() {
var length = functions.length;
var result;
for (var i = 0; i < length; i++) {
result = functions[i].apply(this, arguments);
}
return result;
}; };
}; ol.inherits(ol.render.webgl.ReplayGroup, ol.render.ReplayGroup);
/** /**
* @param {ol.webgl.Context} context Context. * @param {ol.webgl.Context} context WebGL context.
*/ * @return {function()} Delete resources function.
ol.render.webgl.ReplayGroup.prototype.finish = function(context) { */
var zKey; ol.render.webgl.ReplayGroup.prototype.getDeleteResourcesFunction = function(context) {
for (zKey in this.replaysByZIndex_) { var functions = [];
var replays = this.replaysByZIndex_[zKey]; var zKey;
var replayKey; for (zKey in this.replaysByZIndex_) {
for (replayKey in replays) { var replays = this.replaysByZIndex_[zKey];
replays[replayKey].finish(context); var replayKey;
} for (replayKey in replays) {
} functions.push(
}; replays[replayKey].getDeleteResourcesFunction(context));
/**
* @inheritDoc
*/
ol.render.webgl.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';
var replays = this.replaysByZIndex_[zIndexKey];
if (replays === undefined) {
replays = {};
this.replaysByZIndex_[zIndexKey] = replays;
}
var replay = replays[replayType];
if (replay === undefined) {
var Constructor = ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];
replay = new Constructor(this.tolerance_, this.maxExtent_);
replays[replayType] = replay;
}
return replay;
};
/**
* @inheritDoc
*/
ol.render.webgl.ReplayGroup.prototype.isEmpty = function() {
return ol.obj.isEmpty(this.replaysByZIndex_);
};
/**
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
*/
ol.render.webgl.ReplayGroup.prototype.replay = function(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash) {
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(ol.array.numberSafeCompareFunction);
var i, ii, j, jj, replays, replay;
for (i = 0, ii = zs.length; i < ii; ++i) {
replays = this.replaysByZIndex_[zs[i].toString()];
for (j = 0, jj = ol.render.replay.ORDER.length; j < jj; ++j) {
replay = replays[ol.render.replay.ORDER[j]];
if (replay !== undefined) {
replay.replay(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
undefined, false);
} }
} }
} return function() {
}; var length = functions.length;
var result;
for (var i = 0; i < length; i++) {
result = functions[i].apply(this, arguments);
}
return result;
};
};
/** /**
* @private * @param {ol.webgl.Context} context Context.
* @param {ol.webgl.Context} context Context. */
* @param {ol.Coordinate} center Center. ol.render.webgl.ReplayGroup.prototype.finish = function(context) {
* @param {number} resolution Resolution. var zKey;
* @param {number} rotation Rotation. for (zKey in this.replaysByZIndex_) {
* @param {ol.Size} size Size. var replays = this.replaysByZIndex_[zKey];
* @param {number} pixelRatio Pixel ratio. var replayKey;
* @param {number} opacity Global opacity. for (replayKey in replays) {
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features replays[replayKey].finish(context);
* to skip. }
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback. }
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion. };
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context,
center, resolution, rotation, size, pixelRatio, opacity,
skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) {
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(function(a, b) {
return b - a;
});
var i, ii, j, replays, replay, result;
for (i = 0, ii = zs.length; i < ii; ++i) { /**
replays = this.replaysByZIndex_[zs[i].toString()]; * @inheritDoc
for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) { */
replay = replays[ol.render.replay.ORDER[j]]; ol.render.webgl.ReplayGroup.prototype.getReplay = function(zIndex, replayType) {
if (replay !== undefined) { var zIndexKey = zIndex !== undefined ? zIndex.toString() : '0';
result = replay.replay(context, var replays = this.replaysByZIndex_[zIndexKey];
center, resolution, rotation, size, pixelRatio, opacity, if (replays === undefined) {
skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent); replays = {};
if (result) { this.replaysByZIndex_[zIndexKey] = replays;
return result; }
var replay = replays[replayType];
if (replay === undefined) {
var Constructor = ol.render.webgl.ReplayGroup.BATCH_CONSTRUCTORS_[replayType];
replay = new Constructor(this.tolerance_, this.maxExtent_);
replays[replayType] = replay;
}
return replay;
};
/**
* @inheritDoc
*/
ol.render.webgl.ReplayGroup.prototype.isEmpty = function() {
return ol.obj.isEmpty(this.replaysByZIndex_);
};
/**
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
*/
ol.render.webgl.ReplayGroup.prototype.replay = function(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash) {
/** @type {Array.<number>} */
var zs = Object.keys(this.replaysByZIndex_).map(Number);
zs.sort(ol.array.numberSafeCompareFunction);
var i, ii, j, jj, replays, replay;
for (i = 0, ii = zs.length; i < ii; ++i) {
replays = this.replaysByZIndex_[zs[i].toString()];
for (j = 0, jj = ol.render.replay.ORDER.length; j < jj; ++j) {
replay = replays[ol.render.replay.ORDER[j]];
if (replay !== undefined) {
replay.replay(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
undefined, false);
} }
} }
} }
} };
return undefined;
};
/**
* @param {ol.Coordinate} coordinate Coordinate.
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} callback Feature callback.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
coordinate, context, center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
callback) {
var gl = context.getGL();
gl.bindFramebuffer(
gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());
/** /**
* @type {ol.Extent} * @private
* @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/ */
var hitExtent; ol.render.webgl.ReplayGroup.prototype.replayHitDetection_ = function(context,
if (this.renderBuffer_ !== undefined) { center, resolution, rotation, size, pixelRatio, opacity,
// build an extent around the coordinate, so that only features that skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent) {
// intersect this extent are checked /** @type {Array.<number>} */
hitExtent = ol.extent.buffer( var zs = Object.keys(this.replaysByZIndex_).map(Number);
ol.extent.createOrUpdateFromCoordinate(coordinate), zs.sort(function(a, b) {
resolution * this.renderBuffer_); return b - a;
} });
return this.replayHitDetection_(context, var i, ii, j, replays, replay, result;
coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_, for (i = 0, ii = zs.length; i < ii; ++i) {
pixelRatio, opacity, skippedFeaturesHash, replays = this.replaysByZIndex_[zs[i].toString()];
/** for (j = ol.render.replay.ORDER.length - 1; j >= 0; --j) {
* @param {ol.Feature|ol.render.Feature} feature Feature. replay = replays[ol.render.replay.ORDER[j]];
* @return {?} Callback result. if (replay !== undefined) {
*/ result = replay.replay(context,
function(feature) { center, resolution, rotation, size, pixelRatio, opacity,
var imageData = new Uint8Array(4); skippedFeaturesHash, featureCallback, oneByOne, opt_hitExtent);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
if (imageData[3] > 0) {
var result = callback(feature);
if (result) { if (result) {
return result; return result;
} }
} }
}, true, hitExtent); }
}; }
return undefined;
};
/** /**
* @param {ol.Coordinate} coordinate Coordinate. * @param {ol.Coordinate} coordinate Coordinate.
* @param {ol.webgl.Context} context Context. * @param {ol.webgl.Context} context Context.
* @param {ol.Coordinate} center Center. * @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution. * @param {number} resolution Resolution.
* @param {number} rotation Rotation. * @param {number} rotation Rotation.
* @param {ol.Size} size Size. * @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio. * @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity. * @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features * @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip. * to skip.
* @return {boolean} Is there a feature at the given coordinate? * @param {function((ol.Feature|ol.render.Feature)): T|undefined} callback Feature callback.
*/ * @return {T|undefined} Callback result.
ol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function( * @template T
coordinate, context, center, resolution, rotation, size, pixelRatio, */
opacity, skippedFeaturesHash) { ol.render.webgl.ReplayGroup.prototype.forEachFeatureAtCoordinate = function(
var gl = context.getGL(); coordinate, context, center, resolution, rotation, size, pixelRatio,
gl.bindFramebuffer( opacity, skippedFeaturesHash,
gl.FRAMEBUFFER, context.getHitDetectionFramebuffer()); callback) {
var gl = context.getGL();
gl.bindFramebuffer(
gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());
var hasFeature = this.replayHitDetection_(context,
coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_,
pixelRatio, opacity, skippedFeaturesHash,
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
* @return {boolean} Is there a feature?
*/
function(feature) {
var imageData = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
return imageData[3] > 0;
}, false);
return hasFeature !== undefined; /**
}; * @type {ol.Extent}
*/
var hitExtent;
if (this.renderBuffer_ !== undefined) {
// build an extent around the coordinate, so that only features that
// intersect this extent are checked
hitExtent = ol.extent.buffer(
ol.extent.createOrUpdateFromCoordinate(coordinate),
resolution * this.renderBuffer_);
}
/** return this.replayHitDetection_(context,
* @const coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_,
* @private pixelRatio, opacity, skippedFeaturesHash,
* @type {Array.<number>} /**
*/ * @param {ol.Feature|ol.render.Feature} feature Feature.
ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_ = [1, 1]; * @return {?} Callback result.
*/
function(feature) {
var imageData = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
/** if (imageData[3] > 0) {
* @const var result = callback(feature);
* @private if (result) {
* @type {Object.<ol.render.ReplayType, return result;
* function(new: ol.render.webgl.Replay, number, }
* ol.Extent)>} }
*/ }, true, hitExtent);
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, * @param {ol.Coordinate} coordinate Coordinate.
'Text': ol.render.webgl.TextReplay * @param {ol.webgl.Context} context Context.
}; * @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.
* @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @return {boolean} Is there a feature at the given coordinate?
*/
ol.render.webgl.ReplayGroup.prototype.hasFeatureAtCoordinate = function(
coordinate, context, center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash) {
var gl = context.getGL();
gl.bindFramebuffer(
gl.FRAMEBUFFER, context.getHitDetectionFramebuffer());
var hasFeature = this.replayHitDetection_(context,
coordinate, resolution, rotation, ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_,
pixelRatio, opacity, skippedFeaturesHash,
/**
* @param {ol.Feature|ol.render.Feature} feature Feature.
* @return {boolean} Is there a feature?
*/
function(feature) {
var imageData = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, imageData);
return imageData[3] > 0;
}, false);
return hasFeature !== undefined;
};
/**
* @const
* @private
* @type {Array.<number>}
*/
ol.render.webgl.ReplayGroup.HIT_DETECTION_SIZE_ = [1, 1];
/**
* @const
* @private
* @type {Object.<ol.render.ReplayType,
* function(new: ol.render.webgl.Replay, number,
* 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,
'Text': ol.render.webgl.TextReplay
};
}

View File

@@ -2,64 +2,69 @@ goog.provide('ol.render.webgl.TextReplay');
goog.require('ol'); goog.require('ol');
/**
* @constructor
* @param {number} tolerance Tolerance.
* @param {ol.Extent} maxExtent Max extent.
* @struct
*/
ol.render.webgl.TextReplay = function(tolerance, maxExtent) {};
/** if (ol.ENABLE_WEBGL) {
* @param {ol.style.Text} textStyle Text style.
*/
ol.render.webgl.TextReplay.prototype.setTextStyle = function(textStyle) {};
/** /**
* @param {ol.webgl.Context} context Context. * @constructor
* @param {ol.Coordinate} center Center. * @param {number} tolerance Tolerance.
* @param {number} resolution Resolution. * @param {ol.Extent} maxExtent Max extent.
* @param {number} rotation Rotation. * @struct
* @param {ol.Size} size Size. */
* @param {number} pixelRatio Pixel ratio. ol.render.webgl.TextReplay = function(tolerance, maxExtent) {};
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.TextReplay.prototype.replay = function(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent) {
return undefined;
};
/** /**
* @param {Array.<number>} flatCoordinates Flat coordinates. * @param {ol.style.Text} textStyle Text style.
* @param {number} offset Offset. */
* @param {number} end End. ol.render.webgl.TextReplay.prototype.setTextStyle = function(textStyle) {};
* @param {number} stride Stride.
* @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
* @param {ol.Feature|ol.render.Feature} feature Feature.
*/
ol.render.webgl.TextReplay.prototype.drawText = function(flatCoordinates, offset,
end, stride, geometry, feature) {};
/** /**
* @abstract * @param {ol.webgl.Context} context Context.
* @param {ol.webgl.Context} context Context. * @param {ol.Coordinate} center Center.
*/ * @param {number} resolution Resolution.
ol.render.webgl.TextReplay.prototype.finish = function(context) {}; * @param {number} rotation Rotation.
* @param {ol.Size} size Size.
* @param {number} pixelRatio Pixel ratio.
* @param {number} opacity Global opacity.
* @param {Object.<string, boolean>} skippedFeaturesHash Ids of features
* to skip.
* @param {function((ol.Feature|ol.render.Feature)): T|undefined} featureCallback Feature callback.
* @param {boolean} oneByOne Draw features one-by-one for the hit-detecion.
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
* this extent are checked.
* @return {T|undefined} Callback result.
* @template T
*/
ol.render.webgl.TextReplay.prototype.replay = function(context,
center, resolution, rotation, size, pixelRatio,
opacity, skippedFeaturesHash,
featureCallback, oneByOne, opt_hitExtent) {
return undefined;
};
/** /**
* @param {ol.webgl.Context} context WebGL context. * @param {Array.<number>} flatCoordinates Flat coordinates.
* @return {function()} Delete resources function. * @param {number} offset Offset.
*/ * @param {number} end End.
ol.render.webgl.TextReplay.prototype.getDeleteResourcesFunction = function(context) { * @param {number} stride Stride.
return ol.nullFunction; * @param {ol.geom.Geometry|ol.render.Feature} geometry Geometry.
}; * @param {ol.Feature|ol.render.Feature} feature Feature.
*/
ol.render.webgl.TextReplay.prototype.drawText = function(flatCoordinates, offset,
end, stride, geometry, feature) {};
/**
* @abstract
* @param {ol.webgl.Context} context Context.
*/
ol.render.webgl.TextReplay.prototype.finish = function(context) {};
/**
* @param {ol.webgl.Context} context WebGL context.
* @return {function()} Delete resources function.
*/
ol.render.webgl.TextReplay.prototype.getDeleteResourcesFunction = function(context) {
return ol.nullFunction;
};
}