Merge pull request #3108 from tsauerwein/webgl-point-skipFeatures
Support skipping features in the WebGL renderer
This commit is contained in:
@@ -598,22 +598,22 @@ ol.Map.prototype.forEachFeatureAtPixel =
|
||||
* filter function, only layers which are visible and for which this
|
||||
* function returns `true` will be tested for features. By default, all
|
||||
* visible layers will be tested. Feature overlays will always be tested.
|
||||
* @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
|
||||
* @param {U=} opt_this Value to use as `this` when executing `layerFilter`.
|
||||
* @return {boolean} Is there a feature at the given pixel?
|
||||
* @template U
|
||||
* @api
|
||||
*/
|
||||
ol.Map.prototype.hasFeatureAtPixel =
|
||||
function(pixel, opt_layerFilter, opt_this2) {
|
||||
function(pixel, opt_layerFilter, opt_this) {
|
||||
if (goog.isNull(this.frameState_)) {
|
||||
return false;
|
||||
}
|
||||
var coordinate = this.getCoordinateFromPixel(pixel);
|
||||
var layerFilter = goog.isDef(opt_layerFilter) ?
|
||||
opt_layerFilter : goog.functions.TRUE;
|
||||
var thisArg2 = goog.isDef(opt_this2) ? opt_this2 : null;
|
||||
var thisArg = goog.isDef(opt_this) ? opt_this : null;
|
||||
return this.renderer_.hasFeatureAtPixel(
|
||||
coordinate, this.frameState_, layerFilter, thisArg2);
|
||||
coordinate, this.frameState_, layerFilter, thisArg);
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -669,11 +669,12 @@ ol.render.webgl.ImageReplay.prototype.replay = function(context,
|
||||
// draw!
|
||||
var result;
|
||||
if (!goog.isDef(featureCallback)) {
|
||||
this.drawReplay_(gl, context);
|
||||
this.drawReplay_(gl, context, skippedFeaturesHash,
|
||||
this.textures_, this.groupIndices_);
|
||||
} else {
|
||||
// draw feature by feature for the hit-detection
|
||||
result = this.drawHitDetectionReplay_(gl, context, featureCallback,
|
||||
oneByOne, opt_hitExtent);
|
||||
result = this.drawHitDetectionReplay_(gl, context, skippedFeaturesHash,
|
||||
featureCallback, oneByOne, opt_hitExtent);
|
||||
}
|
||||
|
||||
// disable the vertex attrib arrays
|
||||
@@ -691,30 +692,125 @@ ol.render.webgl.ImageReplay.prototype.replay = function(context,
|
||||
* @private
|
||||
* @param {WebGLRenderingContext} gl gl.
|
||||
* @param {ol.webgl.Context} context Context.
|
||||
* @param {Object} skippedFeaturesHash Ids of features to skip.
|
||||
* @param {Array.<WebGLTexture>} textures Textures.
|
||||
* @param {Array.<number>} groupIndices Texture group indices.
|
||||
*/
|
||||
ol.render.webgl.ImageReplay.prototype.drawReplay_ =
|
||||
function(gl, context) {
|
||||
goog.asserts.assert(this.textures_.length === this.groupIndices_.length);
|
||||
function(gl, context, skippedFeaturesHash, textures, groupIndices) {
|
||||
goog.asserts.assert(textures.length === groupIndices.length);
|
||||
var elementType = context.hasOESElementIndexUint ?
|
||||
goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT;
|
||||
var elementSize = context.hasOESElementIndexUint ? 4 : 2;
|
||||
|
||||
var i, ii, start;
|
||||
for (i = 0, ii = this.textures_.length, start = 0; i < ii; ++i) {
|
||||
gl.bindTexture(goog.webgl.TEXTURE_2D, this.textures_[i]);
|
||||
var end = this.groupIndices_[i];
|
||||
var numItems = end - start;
|
||||
var offsetInBytes = start * elementSize;
|
||||
gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes);
|
||||
start = end;
|
||||
if (!goog.object.isEmpty(skippedFeaturesHash)) {
|
||||
this.drawReplaySkipping_(
|
||||
gl, skippedFeaturesHash, textures, groupIndices,
|
||||
elementType, elementSize);
|
||||
} else {
|
||||
var i, ii, start;
|
||||
for (i = 0, ii = textures.length, start = 0; i < ii; ++i) {
|
||||
gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]);
|
||||
var end = groupIndices[i];
|
||||
this.drawElements_(gl, start, end, elementType, elementSize);
|
||||
start = end;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Draw the replay while paying attention to skipped features.
|
||||
*
|
||||
* This functions creates groups of features that can be drawn to together,
|
||||
* so that the number of `drawElements` calls is minimized.
|
||||
*
|
||||
* For example given the following texture groups:
|
||||
*
|
||||
* Group 1: A B C
|
||||
* Group 2: D [E] F G
|
||||
*
|
||||
* If feature E should be skipped, the following `drawElements` calls will be
|
||||
* made:
|
||||
*
|
||||
* drawElements with feature A, B and C
|
||||
* drawElements with feature D
|
||||
* drawElements with feature F and G
|
||||
*
|
||||
* @private
|
||||
* @param {WebGLRenderingContext} gl gl.
|
||||
* @param {Object} skippedFeaturesHash Ids of features to skip.
|
||||
* @param {Array.<WebGLTexture>} textures Textures.
|
||||
* @param {Array.<number>} groupIndices Texture group indices.
|
||||
* @param {number} elementType Element type.
|
||||
* @param {number} elementSize Element Size.
|
||||
*/
|
||||
ol.render.webgl.ImageReplay.prototype.drawReplaySkipping_ =
|
||||
function(gl, skippedFeaturesHash, textures, groupIndices,
|
||||
elementType, elementSize) {
|
||||
var featureIndex = 0;
|
||||
|
||||
var i, ii;
|
||||
for (i = 0, ii = textures.length; i < ii; ++i) {
|
||||
gl.bindTexture(goog.webgl.TEXTURE_2D, textures[i]);
|
||||
var groupStart = (i > 0) ? groupIndices[i - 1] : 0;
|
||||
var groupEnd = groupIndices[i];
|
||||
|
||||
var start = groupStart;
|
||||
var end = groupStart;
|
||||
while (featureIndex < this.startIndices_.length &&
|
||||
this.startIndices_[featureIndex] <= groupEnd) {
|
||||
var feature = this.startIndicesFeature_[featureIndex];
|
||||
|
||||
var featureUid = goog.getUid(feature).toString();
|
||||
if (goog.isDef(skippedFeaturesHash[featureUid])) {
|
||||
// feature should be skipped
|
||||
if (start !== end) {
|
||||
// draw the features so far
|
||||
this.drawElements_(gl, start, end, elementType, elementSize);
|
||||
}
|
||||
// continue with the next feature
|
||||
start = (featureIndex === this.startIndices_.length - 1) ?
|
||||
groupEnd : this.startIndices_[featureIndex + 1];
|
||||
end = start;
|
||||
} else {
|
||||
// the feature is not skipped, augment the end index
|
||||
end = (featureIndex === this.startIndices_.length - 1) ?
|
||||
groupEnd : this.startIndices_[featureIndex + 1];
|
||||
}
|
||||
featureIndex++;
|
||||
}
|
||||
|
||||
if (start !== end) {
|
||||
// draw the remaining features (in case there was no skipped feature
|
||||
// in this texture group, all features of a group are drawn together)
|
||||
this.drawElements_(gl, start, end, elementType, elementSize);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {WebGLRenderingContext} gl gl.
|
||||
* @param {number} start Start index.
|
||||
* @param {number} end End index.
|
||||
* @param {number} elementType Element type.
|
||||
* @param {number} elementSize Element Size.
|
||||
*/
|
||||
ol.render.webgl.ImageReplay.prototype.drawElements_ = function(
|
||||
gl, start, end, elementType, elementSize) {
|
||||
var numItems = end - start;
|
||||
var offsetInBytes = start * elementSize;
|
||||
gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {WebGLRenderingContext} gl gl.
|
||||
* @param {ol.webgl.Context} context Context.
|
||||
* @param {Object} skippedFeaturesHash Ids of features to skip.
|
||||
* @param {function(ol.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
|
||||
@@ -723,21 +819,16 @@ ol.render.webgl.ImageReplay.prototype.drawReplay_ =
|
||||
* @template T
|
||||
*/
|
||||
ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplay_ =
|
||||
function(gl, context, featureCallback, oneByOne, opt_hitExtent) {
|
||||
goog.asserts.assert(this.hitDetectionTextures_.length ===
|
||||
this.hitDetectionGroupIndices_.length);
|
||||
var elementType = context.hasOESElementIndexUint ?
|
||||
goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT;
|
||||
var elementSize = context.hasOESElementIndexUint ? 4 : 2;
|
||||
|
||||
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, featureCallback,
|
||||
elementType, elementSize);
|
||||
return this.drawHitDetectionReplayAll_(gl, context,
|
||||
skippedFeaturesHash, featureCallback);
|
||||
} else {
|
||||
// draw hit-detection features one by one
|
||||
return this.drawHitDetectionReplayOneByOne_(gl, context, featureCallback,
|
||||
elementType, elementSize, opt_hitExtent);
|
||||
return this.drawHitDetectionReplayOneByOne_(gl, context,
|
||||
skippedFeaturesHash, featureCallback, opt_hitExtent);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -746,24 +837,16 @@ ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplay_ =
|
||||
* @private
|
||||
* @param {WebGLRenderingContext} gl gl.
|
||||
* @param {ol.webgl.Context} context Context.
|
||||
* @param {Object} skippedFeaturesHash Ids of features to skip.
|
||||
* @param {function(ol.Feature): T|undefined} featureCallback Feature callback.
|
||||
* @param {number} elementType Element type.
|
||||
* @param {number} elementSize Element size.
|
||||
* @return {T|undefined} Callback result.
|
||||
* @template T
|
||||
*/
|
||||
ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayAll_ =
|
||||
function(gl, context, featureCallback, elementType, elementSize) {
|
||||
var i, ii, start;
|
||||
for (i = 0, ii = this.hitDetectionTextures_.length, start = 0; i < ii; ++i) {
|
||||
gl.bindTexture(goog.webgl.TEXTURE_2D, this.hitDetectionTextures_[i]);
|
||||
var end = this.hitDetectionGroupIndices_[i];
|
||||
var numItems = end - start;
|
||||
var offsetInBytes = start * elementSize;
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
gl.drawElements(goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes);
|
||||
start = end;
|
||||
}
|
||||
function(gl, context, skippedFeaturesHash, featureCallback) {
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
this.drawReplay_(gl, context, skippedFeaturesHash,
|
||||
this.hitDetectionTextures_, this.hitDetectionGroupIndices_);
|
||||
|
||||
var result = featureCallback(null);
|
||||
if (result) {
|
||||
@@ -778,20 +861,24 @@ ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayAll_ =
|
||||
* @private
|
||||
* @param {WebGLRenderingContext} gl gl.
|
||||
* @param {ol.webgl.Context} context Context.
|
||||
* @param {Object} skippedFeaturesHash Ids of features to skip.
|
||||
* @param {function(ol.Feature): T|undefined} featureCallback Feature callback.
|
||||
* @param {number} elementType Element type.
|
||||
* @param {number} elementSize Element size.
|
||||
* @param {ol.Extent=} opt_hitExtent Hit extent: Only features intersecting
|
||||
* this extent are checked.
|
||||
* @return {T|undefined} Callback result.
|
||||
* @template T
|
||||
*/
|
||||
ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayOneByOne_ =
|
||||
function(gl, context, featureCallback, elementType, elementSize,
|
||||
opt_hitExtent) {
|
||||
var i, groupStart, numItems, start, end, feature;
|
||||
var featureIndex = this.startIndices_.length - 1;
|
||||
function(gl, context, skippedFeaturesHash, featureCallback,
|
||||
opt_hitExtent) {
|
||||
goog.asserts.assert(this.hitDetectionTextures_.length ===
|
||||
this.hitDetectionGroupIndices_.length);
|
||||
var elementType = context.hasOESElementIndexUint ?
|
||||
goog.webgl.UNSIGNED_INT : goog.webgl.UNSIGNED_SHORT;
|
||||
var elementSize = context.hasOESElementIndexUint ? 4 : 2;
|
||||
|
||||
var i, groupStart, start, end, feature, featureUid;
|
||||
var featureIndex = this.startIndices_.length - 1;
|
||||
for (i = this.hitDetectionTextures_.length - 1; i >= 0; --i) {
|
||||
gl.bindTexture(goog.webgl.TEXTURE_2D, this.hitDetectionTextures_[i]);
|
||||
groupStart = (i > 0) ? this.hitDetectionGroupIndices_[i - 1] : 0;
|
||||
@@ -801,15 +888,14 @@ ol.render.webgl.ImageReplay.prototype.drawHitDetectionReplayOneByOne_ =
|
||||
while (featureIndex >= 0 &&
|
||||
this.startIndices_[featureIndex] >= groupStart) {
|
||||
start = this.startIndices_[featureIndex];
|
||||
numItems = end - start;
|
||||
feature = this.startIndicesFeature_[featureIndex];
|
||||
featureUid = goog.getUid(feature).toString();
|
||||
|
||||
if (!goog.isDef(opt_hitExtent) || ol.extent.intersects(
|
||||
opt_hitExtent, feature.getGeometry().getExtent())) {
|
||||
var offsetInBytes = start * elementSize;
|
||||
if (!goog.isDef(skippedFeaturesHash[featureUid]) &&
|
||||
(!goog.isDef(opt_hitExtent) || ol.extent.intersects(
|
||||
opt_hitExtent, feature.getGeometry().getExtent()))) {
|
||||
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
|
||||
gl.drawElements(
|
||||
goog.webgl.TRIANGLES, numItems, elementType, offsetInBytes);
|
||||
this.drawElements_(gl, start, end, elementType, elementSize);
|
||||
|
||||
var result = featureCallback(feature);
|
||||
if (result) {
|
||||
|
||||
Reference in New Issue
Block a user